some
This commit is contained in:
parent
c716e824dd
commit
e5b036d9b8
2 changed files with 132 additions and 1 deletions
1
.dummy
1
.dummy
|
@ -1 +0,0 @@
|
|||
.
|
132
unsync.py
Executable file
132
unsync.py
Executable file
|
@ -0,0 +1,132 @@
|
|||
#!/bin/python2
|
||||
|
||||
# only using python2 because mutagen
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import sys
|
||||
import mutagen
|
||||
import mutagen.id3
|
||||
import mutagen.easyid3
|
||||
|
||||
def popm_any(id3):
|
||||
for k, v in id3.iteritems():
|
||||
if k.startswith('POPM'):
|
||||
return v
|
||||
|
||||
def byte2rating(b):
|
||||
if b >= 224: return 5
|
||||
if b >= 160: return 4
|
||||
if b >= 96: return 3
|
||||
if b >= 32: return 2
|
||||
if b >= 1: return 1
|
||||
return 0
|
||||
|
||||
def rating_get(id3, key):
|
||||
try:
|
||||
return list(id3['TXXX:RATING'])
|
||||
except KeyError:
|
||||
try:
|
||||
return list(unicode(byte2rating(popm_any(id3).rating)))
|
||||
except AttributeError:
|
||||
return
|
||||
def rating_set(id3, key, val):
|
||||
# TODO: test
|
||||
try:
|
||||
frame = id3["TXXX:RATING"]
|
||||
except KeyError:
|
||||
id3.add(mutagen.id3.TXXX(encoding=3, desc=u'RATING', text=val))
|
||||
else:
|
||||
frame.encoding = 3
|
||||
frame.text = val
|
||||
def rating_delete(id3, key):
|
||||
# TODO: delete POPM too?
|
||||
del(id3["TXXX:RATING"])
|
||||
|
||||
mutagen.easyid3.EasyID3.RegisterTXXXKey('sync', 'SYNC')
|
||||
mutagen.easyid3.EasyID3.RegisterKey('rating', rating_get, rating_set, rating_delete)
|
||||
|
||||
def safetydance(d, k):
|
||||
if k in d: return d[k]
|
||||
|
||||
def shouldsync(md):
|
||||
rating = -1
|
||||
sync = u''
|
||||
if safetydance(md, 'rating'):
|
||||
try:
|
||||
rating = int(md['rating'][0])
|
||||
except ValueError:
|
||||
pass
|
||||
if safetydance(md, 'sync'):
|
||||
sync = md['sync'][0].lower()
|
||||
|
||||
if sync == u'no' or sync == u'space':
|
||||
return False
|
||||
if sync == u'yes' or sync == u'share':
|
||||
return True
|
||||
if rating >= 3:
|
||||
return True
|
||||
return False
|
||||
|
||||
def findmatching(haystack, needle):
|
||||
artist = safetydance(needle, 'artist')
|
||||
album = safetydance(needle, 'album')
|
||||
title = safetydance(needle, 'title')
|
||||
for match in haystack:
|
||||
if artist == safetydance(match, 'artist') \
|
||||
and album == safetydance(match, 'album') \
|
||||
and title == safetydance(match, 'title'):
|
||||
return match
|
||||
|
||||
def run(args):
|
||||
if not len(args) in (2, 3):
|
||||
print("I need a path or two!", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
inonly = len(args) == 2
|
||||
|
||||
# BUG: doesn't work with my .m4a files?
|
||||
goodexts = ('.mp3', '.m4a', '.flac', '.ogg')
|
||||
tosync = []
|
||||
indir = args[1]
|
||||
walker = os.walk(indir)
|
||||
|
||||
# TODO: abstract to mdloop(callback)
|
||||
for root, _, files in walker:
|
||||
for f in files:
|
||||
ext = os.path.splitext(f)[1].lower()
|
||||
if not ext in goodexts: continue
|
||||
path = os.path.join(root, f)
|
||||
md = mutagen.File(path, easy=True)
|
||||
if shouldsync(md):
|
||||
if inonly: print(path)
|
||||
else: tosync.append(md)
|
||||
|
||||
if inonly: return
|
||||
print("Beginning matching...", file=sys.stderr)
|
||||
|
||||
outdir = args[2]
|
||||
walker = os.walk(outdir)
|
||||
for root, _, files in walker:
|
||||
for f in files:
|
||||
ext = os.path.splitext(f)[1].lower()
|
||||
if not ext in goodexts: continue
|
||||
path = os.path.join(root, f)
|
||||
md = mutagen.File(path, easy=True)
|
||||
match = findmatching(tosync, md)
|
||||
# TODO: don't print anything
|
||||
# TODO: don't match mismatched lengths (Xing?)
|
||||
# TODO: update important tags on mostly matching files
|
||||
# TODO: don't sync files that wouldn't match!
|
||||
# TODO: convert files in loop that works on altered tosync
|
||||
if match:
|
||||
print("MATCHING", path)
|
||||
else:
|
||||
# TODO: just delete missing ones here
|
||||
print("MISSING", path)
|
||||
|
||||
try:
|
||||
run(sys.argv)
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(1)
|
Loading…
Reference in a new issue