#!/usr/bin/env python3 # flacmover.py -i sourcedir -o -destdir -f formatstring import sys, getopt, os, fnmatch import shutil, re from mutagen import File from mutagen.flac import FLAC, Picture def walk(root): for root, dirnames, filenames in os.walk(root): cover = None for filename in fnmatch.filter(filenames, '*.flac'): filepath = root + '/' + filename print(filename) tag = File(filepath) ext = os.path.splitext(filename)[1] directory, filename = buildpath(tag, ext) new_path = outpath + directory + '/' new_filepath = new_path + filename new_coverpath = new_path + 'folder.jpg' print(new_filepath) copy(filepath, new_filepath) if not os.path.isfile(new_coverpath): cover = getcover(filepath) if cover != None: print('Writing Albumart to {}'.format(new_coverpath)) cdata = open(new_coverpath, 'wb') cdata.write(cover.data) cdata.close() def getcover(filepath): covers = FLAC(filepath).pictures for cover in covers: if cover.type == 3: print(str(cover)) return(cover) return None def buildpath(tag, ext): parts = filenameformat.split('%') for index, part in enumerate(parts): if part != '': if part in tag: if part == 'tracknumber': parts[index] = tag[part][0].zfill(2) else: parts[index] = replacer(tag[part][0]) else: parts[index] = part else: parts[index] = part path = ''.join(parts) + ext directory = '/'.join(path.split('/')[:-1]) filename = ''.join(path.split('/')[-1]) return directory, filename def replacer(content): table = { ord(u'Å'): 'Aa', ord(u'Å'): 'aa', ord(u'Ä'): 'Ae', ord(u'ä'): 'ae', ord(u'Æ'): 'Ae', ord(u'æ'): 'ae', ord(u'Á'): 'A', ord(u'á'): 'a', ord(u'À'): 'A', ord(u'à'): 'a', ord(u'Ã'): 'a', ord(u'ã'): 'a', ord(u'Ć'): 'C', ord(u'ć'): 'c', ord(u'Ç'): 'C', ord(u'ç'): 'c', ord(u'¢'): 'c', ord(u'Ð'): 'D', ord(u'ð'): 'd', ord(u'É'): 'E', ord(u'é'): 'e', ord(u'È'): 'E', ord(u'è'): 'e', ord(u'Ẽ'): 'E', ord(u'ẽ'): 'e', ord(u'Í'): 'I', ord(u'í'): 'i', ord(u'Í'): 'I', ord(u'í'): 'i', ord(u'Ì'): 'I', ord(u'ì'): 'i', ord(u'Ĩ'): 'I', ord(u'ĩ'): 'i', ord(u'ł'): 'l', ord(u'Ñ'): 'N', ord(u'ñ'): 'n', ord(u'Ö'): 'Oe', ord(u'ö'): 'oe', ord(u'Ø'): 'Oe', ord(u'ø'): 'oe', ord(u'Œ'): 'Oe', ord(u'œ'): 'oe', ord(u'Ó'): 'O', ord(u'ó'): 'o', ord(u'Ò'): 'O', ord(u'ò'): 'o', ord(u'Õ'): 'O', ord(u'õ'): 'o', ord(u'Ü'): 'Ue', ord(u'ü'): 'ue', ord(u'Ú'): 'U', ord(u'ú'): 'u', ord(u'Ù'): 'U', ord(u'ù'): 'u', ord(u'Ũ'): 'U', ord(u'ũ'): 'u', ord(u'ß'): 'ss', } content = content.translate(table) content = re.sub('[^\w\-_\. ]','_', content) return content def copy(srcfile, dstfile): if not os.path.exists(os.path.dirname(dstfile)): try: os.makedirs(os.path.dirname(dstfile)) except OSError as exc: # Guard against race condition if exc.errno != errno.EEXIST: raise print('Copying {} to {}'.format(srcfile, dstfile)) shutil.copy(srcfile, dstfile) def usage(help = False): if help: print('This program is intended to copy FLAC music libraries into another directory using a defined structure.\n') print('Copies all files within a source directory recursively to another directory and (re)names directories and filenames according to a specified format taken from the files Metadata.\nFor each folder in source an albumart image is exported from a FLAC file if possible.\n') print('flacmover.py -i SRCDIR -o DESTDIR -f FORMATSTRING \n' + ' -i SRCDIR source root of files; defaults to current dir \n' + ' -o DESTDIR destination root of the renamed dirs and files \n' + ' -f FORMATSTRING any format of directory file structure \n' + ' with / as dir delimiter and %variable% for any variable \n' + ' found in FLAC file tags as used by mutagen. \n' + ' ex.: \n' + ' %albumartist%/%albumartist%.%originalyear%.%album%/%discnumber%.%tracknumber%.%artist%.%title%') exit(1) def main(argv): global inpath, outpath, filenameformat inpath = os.getcwd() outpath = None filenameformat = None try: opts, args = getopt.getopt(argv,'hi:o:f:',['input=','output=','format=']) except getopt.GetoptError: usage() for opt, arg in opts: if opt == '-h': usage(True) elif opt in ('-i', '--input'): inpath = arg elif opt in ('-o', '--output'): outpath = arg elif opt in ('-f', '--format'): filenameformat = arg else: usage() print('Input path is {}'.format(inpath)) if outpath == None: print('No output directory set!') usage() if not outpath.endswith('/'): outpath = outpath + '/' walk(inpath) if __name__ == '__main__': main(sys.argv[1:])