From 20d7d2c6d227d7d95102b2cddb2ea395402716de Mon Sep 17 00:00:00 2001 From: Eric Renfro Date: Sun, 26 Aug 2018 14:26:21 -0400 Subject: [PATCH] Fixed more code, added includes --- musicman.py | 112 +++++++++++++++++++++++++------------ musicman/utils/__init__.py | 6 ++ 2 files changed, 83 insertions(+), 35 deletions(-) diff --git a/musicman.py b/musicman.py index 147c4bb..041015c 100755 --- a/musicman.py +++ b/musicman.py @@ -50,7 +50,7 @@ def clearLine(): def sanitize(text): newtext = text - newtext = newtext.replace('<', '').replace('>', '').replace(':', '').replace('"', '').replace('|', '').replace('?', '').replace('*', '') + newtext = newtext.replace('<', '').replace('>', '').replace(':', '').replace('"', '').replace('|', '').replace('?', '').replace('*', '').replace('$', '') newtext = newtext.replace('/', '-') newtext = newtext.strip() #if newtext != text: @@ -59,12 +59,27 @@ def sanitize(text): # print(" new:", newtext) return newtext -def getLibrary(path, excludeDirs=[]): +def escape(text): + newtext = text + newtext = newtext.replace('$', '\$') + return newtext + +def getLibrary(path, libFormat=None, excludeDirs=[], includeDirs=[]): + #print("DEBUG: libFormat={0}".format(libFormat)) + global originFormat; if os.path.isdir(path): for root, directories, filenames in sorted(os.walk(path)): if root not in excludeDirs: - for filename in filenames: - yield os.path.join(root, filename) + #if any(root in s for s in includeDirs): + #if [s for s in [root] if any (xs in s for xs in includeDirs)] or len(includeDirs) == 0: + # print("DEBUG: Matched: {0}".format(root)) + #print("DEBUG: Found: {0}".format(root)) + #if any(root in s for s in includeDirs) or len(includeDirs) == 0: + if [s for s in [root] if any (xs in s for xs in includeDirs)] or len(includeDirs) == 0: + for filename in filenames: + #print("DEBUG: filename: {0}".format(filename)) + if filename.endswith(libFormat): + yield os.path.join(root, filename) # files=[] # @@ -95,6 +110,16 @@ def getLibrary(path, excludeDirs=[]): # print("Scan complete!") # return files +def ensure_dir(file_path): + directory = os.path.dirname(file_path) + if not os.path.exists(directory): + os.makedirs(directory) + +def copy_file(src, dest): + from shutil import copyfile + ensure_dir(dest) + copyfile(src, dest) + def getEmptyDirs(path, excludeDirs=[]): if os.path.isdir(path): for root, directories, filenames in sorted(os.walk(path)): @@ -148,13 +173,11 @@ def getSong(file, orgDir=None, tmpDir=None, dstDir=None): if song['totaldiscs'] > 1: song['outPath'] = os.path.join(song['artistName'], song['albumName']) - song['outFile'] = '{0:d}-{1:02d}-{2}'.format(song['discnumber'], - song['tracknumber'], - song['titleName']) + song['outFile'] = '{0:d}-{1:02d}-{2}'.format(song['discnumber'], song['tracknumber'], song['titleName']) else: if metadata.tags.get("tracknumber") is not None: song['outPath'] = os.path.join(song['artistName'], song['albumName']) - song['outFile'] = '{0:02d}-{1}'.format(song['tracknumber'], song['titleName']) + song['outFile'] = '{0:d}-{1:02d}-{2}'.format(song['discnumber'], song['tracknumber'], song['titleName']) else: song['outPath'] = os.path.join(song['artistName'], song['albumName']) outFile = '{0}'.format(song['titleName']) @@ -164,6 +187,7 @@ def getSong(file, orgDir=None, tmpDir=None, dstDir=None): song['targetFile'] = os.path.join(dstDir, song['outPath'], song['outFile']) song['originExt'] = os.path.splitext(file)[1] song['targetExt'] = '.' + targetFormat + song['targetDir'] = targetDir return song else: @@ -202,14 +226,16 @@ def cleanLibrary(rootDir, excludeDirs=[], act=False, verbose=0): #print("Processing Complete!") -def renameLibrary(rootDir, excludeDirs=[], act=False, verbose=0): +def renameLibrary(rootDir, libFormat, excludeDirs=[], includeDirs=[], act=False, verbose=0): global config if excludeDirs is None: excludeDirs=[] + if includeDirs is None: + includeDirs=[] print("Renaming:", rootDir) - for file in getLibrary(rootDir, excludeDirs): + for file in getLibrary(rootDir, libFormat, excludeDirs, includeDirs): if (os.path.isdir(os.path.dirname(file)) and os.path.isfile(file)): clearLine() print("Processing:", os.path.dirname(os.path.dirname(file)), next(spinner), end="\r") @@ -239,14 +265,16 @@ def renameLibrary(rootDir, excludeDirs=[], act=False, verbose=0): clearLine() #print("Processing Complete!") -def findUntagged(rootDir, excludeDirs=[], verbose=0): +def findUntagged(rootDir, libFormat, excludeDirs=[], includeDirs=[], verbose=0): global config if excludeDirs is None: excludeDirs=[] + if includeDirs is None: + includeDirs=[] print("Find Untagged:", rootDir) - for file in getLibrary(rootDir, excludeDirs): + for file in getLibrary(rootDir, libFormat, excludeDirs, includeDirs): if (os.path.isdir(os.path.dirname(file)) and os.path.isfile(file)): clearLine() print("Processing:", os.path.dirname(os.path.dirname(file)), next(spinner), end="\r") @@ -260,14 +288,16 @@ def findUntagged(rootDir, excludeDirs=[], verbose=0): clearLine() #print("Processing Complete!") -def findNew(rootDir, tmpDir, dstDir, dstFormat, excludeDirs=[], verbose=0): +def findNew(rootDir, libFormat, tmpDir, dstDir, dstFormat, excludeDirs=[], includeDirs=[], verbose=0): global config if excludeDirs is None: excludeDirs=[] + if includeDirs is None: + includeDirs=[] print("Find New Media") - for file in getLibrary(rootDir, excludeDirs): + for file in getLibrary(rootDir, libFormat, excludeDirs, includeDirs): if (os.path.isdir(os.path.dirname(file)) and os.path.isfile(file)): clearLine() print("Processing:", os.path.dirname(os.path.dirname(file)), next(spinner), end="\r") @@ -292,15 +322,17 @@ def findNew(rootDir, tmpDir, dstDir, dstFormat, excludeDirs=[], verbose=0): #clearLine() #print("Processing Complete!") -def syncWorking(tmpDir, excludeDirs=[], act=False, verbose=0): +def syncWorking(tmpDir, libFormat, excludeDirs=[], includeDirs=[], act=False, verbose=0): global config if excludeDirs is None: excludeDirs=[] + if includeDirs is None: + includeDirs=[] print("Sync Target Media") - for file in getLibrary(tmpDir, excludeDirs): + for file in getLibrary(tmpDir, libFormat, excludeDirs, includeDirs): if (os.path.isdir(os.path.dirname(file)) and os.path.isfile(file)): clearLine() print("Processing:", os.path.dirname(os.path.dirname(file)), next(spinner), end="\r") @@ -315,13 +347,14 @@ def syncWorking(tmpDir, excludeDirs=[], act=False, verbose=0): filename = os.path.basename(file) file_ext = os.path.splitext(filename)[1] - if not os.path.isfile(song['targetDir'] + song['originExt']): + if not os.path.isfile(song['targetFile'] + song['originExt']): print("Sync:", file) if verbose > 0: - print(" To:", song['targetFile'], song['originExt']) + print(" To:", song['targetFile'] + song['originExt']) if act: - print("would've acted") + copy_file(file, song['targetFile'] + song['originExt']) + #print("would've acted") #if not os.path.isfile(os.path.join(destDir, song['outPath'], song['outFile'] + file_ext)): @@ -335,7 +368,7 @@ def syncWorking(tmpDir, excludeDirs=[], act=False, verbose=0): #clearLine() #print("Processing Complete!") -def convertMedia(rootDir, tmpDir, dstDir, dstFormat, excludeDirs=[], act=False, verbose=0): +def convertMedia(rootDir, originFormat, tmpDir, dstDir, dstFormat, excludeDirs=[], includeDirs=[], act=False, verbose=0): import subprocess from musicman.utils.copytags import ( copy_tags @@ -343,10 +376,12 @@ def convertMedia(rootDir, tmpDir, dstDir, dstFormat, excludeDirs=[], act=False, if excludeDirs is None: excludeDirs=[] + if includeDirs is None: + includeDirs=[] print("Convert Library Media") - for file in getLibrary(rootDir, excludeDirs): + for file in getLibrary(rootDir, originFormat, excludeDirs, includeDirs): if (os.path.isdir(os.path.dirname(file)) and os.path.isfile(file)): clearLine() print("Processing:", os.path.dirname(os.path.dirname(file)), next(spinner), end="\r") @@ -374,7 +409,9 @@ def convertMedia(rootDir, tmpDir, dstDir, dstFormat, excludeDirs=[], act=False, os.makedirs(os.path.dirname(song['workingFile'])) #subprocess.call("ffmpeg", "-loglevel", "quiet", "-stats", "-i", file, "-vn", "-c:a", "libfdk_aac", "-vbr", "5", "-nostdin", "-y", song['workingFile'] + song['targetExt']) try: - subprocess.call('/usr/bin/ffmpeg -loglevel quiet -stats -i "{0}" -vn -c:a libfdk_aac -vbr 5 -nostdin -y "{1}"'.format(file, song['workingFile'] + song['targetExt']), shell=True) + #subprocess.call('/usr/bin/ffmpeg -loglevel quiet -stats -i "{0}" -vn -c:a libfdk_aac -vbr 5 -nostdin -y "{1}"'.format(file, song['workingFile'] + song['targetExt']), shell=True) + #subprocess.call('/usr/bin/ffmpeg -i "{0}" -f caf - | /usr/bin/fdkaac -I -p 29 -m 5 -o "{1}" -'.format(file, song['workingFile'] + song['targetExt']), shell=True) + subprocess.call('/usr/bin/ffmpeg -i "{0}" -f caf - | /usr/bin/fdkaac -I -p 2 -m 5 -o "{1}" -'.format(escape(file), escape(song['workingFile'] + song['targetExt'])), shell=True) #new = MetaData(song['workingFile'] + song['targetExt']) #new.update(song['metadata']) #new.save() @@ -397,7 +434,7 @@ def convertMedia(rootDir, tmpDir, dstDir, dstFormat, excludeDirs=[], act=False, if __name__ == '__main__': global opt global config - global originPath, targetPath, targetFormat, workPath + global originPath, originFormat, targetPath, targetFormat, workPath import configparser opt = musicman.utils.parse_args() @@ -410,6 +447,11 @@ if __name__ == '__main__': except AttributeError: originDir = config['origin']['path'] + try: + originFormat = config['origin']['format'] if opt.origFormat is None else opt.origFormat + except AttributeError: + originFormat = config['origin']['format'] + try: targetDir = config['target']['path'] if opt.targetDir is None else opt.targetDir except AttributeError: @@ -432,30 +474,30 @@ if __name__ == '__main__': try: if opt.mode == 'clean': - cleanLibrary(originDir, opt.excludeDirs, opt.act, opt.verbose) - cleanLibrary(targetDir, opt.excludeDirs, opt.act, opt.verbose) - cleanLibrary(workingDir, opt.excludeDirs, opt.act, opt.verbose) + cleanLibrary(originDir, originFormat, opt.excludeDirs, opt.includeDirs, opt.act, opt.verbose) + cleanLibrary(targetDir, targetFormat, opt.excludeDirs, opt.includeDirs, opt.act, opt.verbose) + cleanLibrary(workingDir, targetFormat, opt.excludeDirs, opt.includeDirs, opt.act, opt.verbose) elif opt.mode == 'rename': - renameLibrary(originDir, opt.excludeDirs, opt.act, opt.verbose) - renameLibrary(targetDir, opt.excludeDirs, opt.act, opt.verbose) - renameLibrary(workingDir, opt.excludeDirs, opt.act, opt.verbose) + renameLibrary(originDir, originFormat, opt.excludeDirs, opt.includeDirs, opt.act, opt.verbose) + renameLibrary(targetDir, targetFormat, opt.excludeDirs, opt.includeDirs, opt.act, opt.verbose) + renameLibrary(workingDir, targetFormat, opt.excludeDirs, opt.includeDirs, opt.act, opt.verbose) elif opt.mode == 'scan': if opt.scanMode is None: print("ERROR: Subcommand for scan not provided.") sys.exit(1) elif opt.scanMode == 'untagged': - findUntagged(originDir, opt.excludeDirs, opt.verbose) - findUntagged(targetDir, opt.excludeDirs, opt.verbose) - findUntagged(workingDir, opt.excludeDirs, opt.verbose) + findUntagged(originDir, originFormat, opt.excludeDirs, opt.includeDirs, opt.verbose) + findUntagged(targetDir, targetFormat, opt.excludeDirs, opt.includeDirs, opt.verbose) + findUntagged(workingDir, targetFormat, opt.excludeDirs, opt.includeDirs, opt.verbose) elif opt.scanMode == 'new': - findNew(originDir, workingDir, targetDir, targetFormat, opt.excludeDirs, opt.verbose) + findNew(originDir, originFormat, workingDir, targetDir, targetFormat, opt.excludeDirs, opt.includeDirs, opt.verbose) elif opt.mode == 'sync': - syncWorking(workingDir, targetDir, opt.excludeDirs, opt.act, opt.verbose) + syncWorking(workingDir, targetFormat, opt.excludeDirs, opt.includeDirs, opt.act, opt.verbose) elif opt.mode == 'convert': - convertMedia(originDir, workingDir, targetDir, targetFormat, opt.excludeDirs, opt.act, opt.verbose) + convertMedia(originDir, originFormat, workingDir, targetDir, targetFormat, opt.excludeDirs, opt.includeDirs, opt.act, opt.verbose) except KeyboardInterrupt: clearLine() print(end='\r') diff --git a/musicman/utils/__init__.py b/musicman/utils/__init__.py index 9b8846b..05b5e48 100644 --- a/musicman/utils/__init__.py +++ b/musicman/utils/__init__.py @@ -26,6 +26,7 @@ def parse_args(): clean_lib.add_argument('-t', '--target', help="Target Directory for Library (overrides config)", metavar="DIR", type=str, dest="targetDir") clean_lib.add_argument('-w', '--work', help="Working Directory for new processed files (overrides config)", metavar="DIR", type=str, dest="workingDir") clean_lib.add_argument('-e', '--exclude', help="Exclude Directory from origin (can be used multiple times)", metavar="DIR", dest='excludeDirs', action='append') + clean_lib.add_argument('-i', '--include', help="Include Directory from origin (can be used multiple times)", metavar="DIR", dest='includeDirs', action='append') clean_act = clean.add_argument_group('Action Options') clean_act.add_argument('-g', '--go', help="Clean up library (default just shows what would be done)", dest="act", action='store_true') clean.set_defaults(act=False) @@ -37,6 +38,7 @@ def parse_args(): convert_lib.add_argument('-w', '--work', help="Working Directory for new processed files (overrides config)", metavar="DIR", type=str, dest="workingDir") convert_lib.add_argument('--format', help="Target directory library format", metavar="FORMAT", type=str, dest="targetFormat") convert_lib.add_argument('-e', '--exclude', help="Exclude Directory from origin (can be used multiple times)", metavar="DIR", dest='excludeDirs', action='append') + convert_lib.add_argument('-i', '--include', help="Include Directory from origin (can be used multiple times)", metavar="DIR", dest='includeDirs', action='append') convert_act = convert.add_argument_group('Action Options') convert_act.add_argument('-g', '--go', help="Convert media (default just shows new items)", dest="act", action='store_true') convert.set_defaults(act=False) @@ -47,7 +49,9 @@ def parse_args(): rename = subparsers.add_parser('rename', help='Rename Mode', description='Library rename tool renames media into their respective Artist/Album/[Disc-][Track-]Title in relation to their metadata.') rename_lib = rename.add_argument_group('Library Options') rename_lib.add_argument('-o', '--origin', help="Origin Directory for Library (overrides config)", metavar="DIR", type=str, dest="originDir") + rename_lib.add_argument('-f', '--format', help="Origin Format (flac, m4a, mp3, ...) (overrides config)", metavar="FMT", type=str, dest="origFormat") rename_lib.add_argument('-e', '--exclude', help="Exclude Directory from origin (can be used multiple times)", metavar="DIR", dest='excludeDirs', action='append') + rename_lib.add_argument('-i', '--include', help="Include Directory from origin (can be used multiple times)", metavar="DIR", dest='includeDirs', action='append') rename_act = rename.add_argument_group('Action Options') rename_act.add_argument('-g', '--go', help="Process renaming (default just shows what would be done", dest="act", action='store_true') rename.set_defaults(act=False) @@ -59,6 +63,7 @@ def parse_args(): scan_lib.add_argument('-w', '--work', help="Working Directory for new processed files (overrides config)", metavar="DIR", type=str, dest="workingDir") scan_lib.add_argument('--format', help="Target directory library format", metavar="FORMAT", type=str, dest="targetFormat") scan_lib.add_argument('-e', '--exclude', help="Exclude Directory from origin (can be used multiple times)", metavar="DIR", dest='excludeDirs', action='append') + scan_lib.add_argument('-i', '--include', help="Include Directory from origin (can be used multiple times)", metavar="DIR", dest='includeDirs', action='append') scan_subparsers = scan.add_subparsers(title='Scan Modes', dest='scanMode') scan_untagged = scan_subparsers.add_parser('untagged', help='Find untagged media', description='Scans for untagged or insufficiently tagged media in the library.') scan_new = scan_subparsers.add_parser('new', help='Find new unconverted media', description='Scans for new media that is not in the target library for conversion.') @@ -69,6 +74,7 @@ def parse_args(): sync_lib.add_argument('-t', '--target', help="Target Directory for Library (overrides config)", metavar="DIR", type=str, dest="targetDir") sync_lib.add_argument('-w', '--work', help="Working Directory for new processed files (overrides config)", metavar="DIR", type=str, dest="workingDir") sync_lib.add_argument('-e', '--exclude', help="Exclude Directory from origin (can be used multiple times)", metavar="DIR", dest='excludeDirs', action='append') + sync_lib.add_argument('-i', '--include', help="Include Directory from origin (can be used multiple times)", metavar="DIR", dest='includeDirs', action='append') sync_act = sync.add_argument_group('Action Options') sync_act.add_argument('-g', '--go', help="Move media (default just what would be done)", dest="act", action='store_true')