diff --git a/perplex.py b/perplex.py index c3f837e..133ace6 100755 --- a/perplex.py +++ b/perplex.py @@ -1,9 +1,10 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python # -*- coding: utf8 -*- # Perplex - A Movie Renamer for Plex Metadata # Copyright (c) 2015 Konrad Rieck (konrad@mlsec.org) import argparse +import datetime import gzip import json import os @@ -14,23 +15,29 @@ import progressbar as pb # Chars to remove from titles -del_chars = '.[]()' +del_chars = '.' +forbiddenCharsInNames = '\\', '/',':','*','?','"','<','>','|' + def find_db(plex_dir, name): """ Search for database file in directory """ - for root, dirs, files in os.walk(plex_dir): + for root, dirs, files in os.walk(plex_dir, onerror=errorOut): for file in files: if file == name: - return os.path.join(root, file) + databasePath = os.path.join(root, file) + print("Found Database: " + databasePath) + return databasePath return None + def build_db(plex_dir, movies={}): """ Build movie database from sqlite database """ - print "Analyzing Plex database:", + print("Analyzing Plex database:") dbfile = find_db(plex_dir, "com.plexapp.plugins.library.db") + db = sqlite3.connect(dbfile) # Select only movies with year @@ -39,8 +46,8 @@ def build_db(plex_dir, movies={}): WHERE metadata_type = 1 AND originally_available_at """ for row in db.execute(query): - title = filter(lambda x: x not in del_chars, row[1]) - year = row[2].split('-')[0] + title = convert([x for x in row[1] if x not in del_chars]) + year = datetime.date.fromtimestamp(row[2]).strftime("%Y") movies[row[0]] = (title, year, []) # Get files for each movie @@ -50,63 +57,111 @@ def build_db(plex_dir, movies={}): files = 0 for id in movies: - for file in db.execute(query % id): - movies[id][2].append(file[0]) - files += 1 - + try: + for file in db.execute(query % id): + movies[id][2].append(file[0]) + files += 1 + except Exception as e: + errorOut(e); db.close() - print "%d movies and %d files" % (len(movies), files) + print(("%d movies and %d files" % (len(movies), files))) return movies +def print_doubles(files): + print("Found multiple files :") + for old_name in enumerate(files): + print(old_name) + +def errorOut(error): + print("Error occured: " + str(error)); + sys.exit(-1) + +def convert(s): + new = "" + for x in s: + if x not in forbiddenCharsInNames: + new += x + return new -def build_map(movies, dest, mapping=[]): +def build_map(movies, dest,printDoubles, directoryToRunOn = "" ,mapping=[] ): """ Build mapping to new names """ - for title, year, files in movies.values(): + for title, year, files in list(movies.values()): + counter = 0; for i, old_name in enumerate(files): + modifyedDirectory = str(directoryToRunOn).replace("\\", "/") + modifyedOldName = str(old_name).replace("\\", "/") + if modifyedDirectory is not "" and not str(modifyedOldName).__contains__(modifyedDirectory): + print("skipping file because not in given directory " + old_name) + continue + counter = counter + 1; + if counter > 1 and printDoubles: + print_doubles(files) _, ext = os.path.splitext(old_name) template = "%s (%s)/%s (%s)" % (title, year, title, year) template += " - part%d" % (i + 1) if len(files) > 1 else "" template += ext - dest = os.path.normpath(dest) + if dest is None: + dest, garbage = str(_).rsplit("/", 1) + else: + dest = os.path.normpath(dest) + new_name = os.path.join(dest, *template.split("/")) + if new_name == old_name: + continue mapping.append((old_name, new_name)) - mapping = filter(lambda (x,y): x.lower() != y.lower(), mapping) + mapping = [x_y for x_y in mapping if x_y[0].lower() != x_y[1].lower()] return mapping - -def copy_rename(mapping, dest, dry): - """ Copy and rename files to destination """ +def progressbar(dry): if dry: widgets = [''] else: widgets = [pb.Percentage(), ' ', pb.Bar(), ' ', pb.ETA()] - pbar = pb.ProgressBar(widgets=widgets) + return pb.ProgressBar(widgets=widgets) + +def rename(mapping,dry): + pbar=progressbar(dry) + for old_name, new_name in pbar(mapping): + try: + if not os.path.exists(os.path.dirname(new_name)): + if not dry: + os.makedirs(os.path.dirname(new_name)) + if not os.path.exists(new_name): + if dry: + print(("%s\n %s" % (old_name, new_name))) + else: + os.rename(old_name, new_name) + except Exception as e: + print("Exception on file " + old_name + " : " + str(e)) + + +def copy_rename(mapping, dest, dry): + """ Copy and rename files to destination """ + pbar = progressbar(dry) for old_name, new_name in pbar(mapping): dp = os.path.join(dest, os.path.dirname(new_name)) fp = os.path.join(dp, os.path.basename(new_name)) - try: if not os.path.exists(dp): if not dry: os.makedirs(dp) - if not os.path.exists(fp): if dry: - print "%s\n %s" % (old_name,fp) + print(("%s\n %s" % (old_name, fp))) else: shutil.copy(old_name, fp) - - except Exception, e: - print str(e) + except Exception as e: + print("Exception on file " + old_name + " : " + str(e)) if __name__ == "__main__": # Parse command-line arguments + parser = argparse.ArgumentParser(description='Plex-based Movie Renamer.') parser.add_argument('--plex', metavar='