Skip to content

Commit

Permalink
Merge pull request #11 from windowslucker1121/master
Browse files Browse the repository at this point in the history
Update to newest Plex Version and Rename Function instead of copying the whole database
  • Loading branch information
rieck authored Feb 26, 2023
2 parents 649e76d + b4f9261 commit 8fafe1d
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 36 deletions.
150 changes: 115 additions & 35 deletions perplex.py
Original file line number Diff line number Diff line change
@@ -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 ([email protected])

import argparse
import datetime
import gzip
import json
import os
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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 != "" 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='<dir>', type=str,
help='set directory of Plex database.')
Expand All @@ -118,26 +173,51 @@ def copy_rename(mapping, dest, dry):
help='load database of movie titles and files')
parser.add_argument('--dry', action='store_true',
help='show dry run of what will happen')
parser.add_argument('--justRename', metavar='<dir>', type=str,
help='renames the original files instead of copying them - provide the <dir> to rename files in')
parser.add_argument('--printDoubles', action='store_true',
help='Print double movies with locations if found')


parser.set_defaults(dry=False)
parser.set_defaults(printDoubles=False)
args = parser.parse_args()

if (args.justRename is not None and args.justRename is not False) and (args.dest is not None):
errorOut("Cant provide --dest and --justRename Args at the same time");


if args.plex:
movies = build_db(args.plex)
elif args.load:
print "Loading metadata from " + args.load
print(("Loading metadata from " + args.load))
movies = json.load(gzip.open(args.load))
else:
print "Error: Provide a Plex database or stored database."
print("Error: Provide a Plex database or stored database.")
sys.exit(-1)

if args.save:
print "Saving metadata to " + args.save
json.dump(movies, gzip.open(args.save, 'w'))
print(("Saving metadata to " + args.save))
with gzip.open(args.save, 'wt', encoding='ascii') as file:
json.dump(movies, file)

if args.printDoubles:
printDoubles = True
else:
printDoubles = False

if args.justRename:
print(("Building file mapping for each Movie itself"))
mapping = build_map(movies, None, printDoubles , args.justRename)
print(("Start Renaming the files in their original path"))
rename(mapping,args.dry)
elif args.dest:
print(("Building file mapping for " + args.dest))
mapping = build_map(movies, args.dest, printDoubles)
print(("Copying renamed files to " + args.dest))
copy_rename(mapping, args.dest, args.dry)
else:
if args.printDoubles:
print("Print doubles can only be used when building the mapping, try it with the --dry parameter")

if args.dest:
print "Building file mapping for " + args.dest
mapping = build_map(movies, args.dest)
print "Copying renamed files to " + args.dest
copy_rename(mapping, args.dest,args.dry)

3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
progressbar==2.3
progressbar==2.5

0 comments on commit 8fafe1d

Please sign in to comment.