diff --git a/unsync.py b/unsync.py index 56ca89b..780062a 100755 --- a/unsync.py +++ b/unsync.py @@ -13,6 +13,10 @@ import mutagen import mutaext import convert +# BUG: doesn't work with my .m4a files? +goodexts = ('.mp3', '.m4a', '.flac', '.ogg') + +matchtags = ['artist', 'album', 'title'] updatabletags = [\ 'albumartist', 'composer', 'comment' \ 'tracknumber', 'discnumber', \ @@ -20,99 +24,71 @@ updatabletags = [\ ] updatabletags.extend(mutaext.replaygain_tags) updatabletags.extend(mutaext.extra_tags) - alltags = list(updatabletags) -alltags.extend(['artist', 'album', 'title']) +alltags.extend(matchtags) -def walkfiles(walker): - for root, _, files in walker: - for f in files: - yield os.path.join(root, f) - -def filterext(paths, exts): - for p in paths: - ext = os.path.splitext(p)[1].lower() - if ext in exts: - yield p +lament = lambda *args, **kwargs: print(*args, file=sys.stderr, **kwargs) +walkfiles = lambda w: (os.path.join(r, f) for r, _, fs in w for f in fs) +extof = lambda p: os.path.splitext(p)[1].lower() +filterext = lambda ps, es: (p for p in ps if extof(p) in es) def shouldsync(md): rating = md.get('rating') sync = md.get('sync', u'') try: rating = int(rating[0]) - except: + except (IndexError, ValueError): pass if sync: sync = sync[0].lower() - if sync == u'no' or sync == u'space': - return False - if sync == u'yes' or sync == u'share': - return True - if type(rating) == int and rating >= 3: - return True - return False + return sync == 'yes' or type(rating) == int and rating >= 3 and not sync is 'no' and not sync is 'space' def fixmetadata(md): - md['artist'] = md.get('artist', "Unknown Artist") - md['album'] = md.get('album', "Unknown Album") + md['artist'] = md.get('artist', u"Unknown Artist") + md['album'] = md.get('album', u"Unknown Album") if 'title' not in md: fn = os.path.basename(md.path) fn = os.path.splitext(fn)[0] # TODO: attempt to infer trackNum/discNum from fn - md['title'] = fn + md['title'] = unicode(fn) def findmatching(haystack, needle): - # TODO: don't match mismatched lengths (Xing?) - artist = needle.get('artist') - album = needle.get('album') - title = needle.get('title') - match = None - for hay in haystack: - if artist == hay.get('artist') \ - and album == hay.get('album') \ - and title == hay.get('title'): - match = hay - if match.seen: - # TODO: check other tags and filename and such? - print("Warning: duplicate match found:", file=sys.stderr) - print("{0} by {1} from {2}".format(artist,album,title), file=sys.stderr) - else: - match.seen = True - break - return match + matchme = [needle[t] for t in matchtags] + ismatch = lambda hay: [hay[t] for t in matchtags] == matchme + for match in (hay for hay in haystack if ismatch(hay)): + if match.seen: + # TODO: check other tags and filename and such? + lament("Warning: duplicate match found:") + lament(u"%(title)s by %(artist)s from %(album)s" % locals()) + match.seen = True + return match def updatemetadata(mdold, mdnew): modified = False for tag in updatabletags: + # checking for length b/c sometimes (ID3 genre) exists but empty if tag in mdnew and len(mdnew[tag]): if not tag in mdold or mdnew[tag][0] != mdold[tag][0]: mdold[tag] = mdnew[tag] modified = True elif tag in mdold: del mdold[tag] - print('del', tag) modified = True return modified def makefilename(md): - fn = "" title = md['title'][0] artist = md['artist'][0] album = md['album'][0] - fn = u"{1} - {2} - {0}".format(title,artist,album) - fn += ".ogg" - return fn + return u"%(artist)s - %(album)s - %(title)s.ogg" % locals() def run(args): if not len(args) in (2, 3): - print("I need a path or two!", file=sys.stderr) + lament("I need a path or two!") return 1 - inonly = len(args) == 2 - # BUG: doesn't work with my .m4a files? - goodexts = ('.mp3', '.m4a', '.flac', '.ogg') tosync = [] indir = args[1] paths = lambda dir: filterext(walkfiles(os.walk(dir)), goodexts) @@ -132,19 +108,18 @@ def run(args): if inonly: return 0 - print("Matching...", file=sys.stderr) + lament("Matching...") outdir = args[2] for p in paths(outdir): md = mutagen.File(p, easy=True) match = findmatching(tosync, md) - if match: - if updatemetadata(md, match): - print("UPD", p) - md.save() - else: + if not match: print("DEL", p) os.remove(p) + elif updatemetadata(md, match): + print("UPD", p) + md.save() for md in tosync: if md.seen: