with her finger and her thumb
This commit is contained in:
parent
6ae05ac68d
commit
14014e2e93
2 changed files with 113 additions and 47 deletions
84
mutaext.py
Normal file
84
mutaext.py
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
import mutagen
|
||||||
|
import mutagen.id3
|
||||||
|
import mutagen.easyid3
|
||||||
|
|
||||||
|
# TODO: custom interface to tracknumber/tracktotal/disc...
|
||||||
|
|
||||||
|
def popms(id3):
|
||||||
|
for k, v in id3.iteritems():
|
||||||
|
if k.startswith('POPM'):
|
||||||
|
yield k, 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 rating2byte(r):
|
||||||
|
if r == 5: return 256
|
||||||
|
if r == 4: return 192
|
||||||
|
if r == 3: return 128
|
||||||
|
if r == 2: return 64
|
||||||
|
if r == 1: return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def rating_get(id3, key):
|
||||||
|
try:
|
||||||
|
rating = id3['TXXX:RATING']
|
||||||
|
except KeyError:
|
||||||
|
try:
|
||||||
|
_, popm = popms(id3).next()
|
||||||
|
except StopIteration:
|
||||||
|
return []
|
||||||
|
else:
|
||||||
|
return [byte2rating(popm.rating)]
|
||||||
|
else:
|
||||||
|
return list(rating.text)
|
||||||
|
|
||||||
|
def _canconv(r):
|
||||||
|
try:
|
||||||
|
if int(r) != str(int(r)):
|
||||||
|
return False
|
||||||
|
return int(r) >= 1 and int(r) <= 5
|
||||||
|
except ValueError, TypeError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def rating_set(id3, key, val):
|
||||||
|
rating_delete(id3, key)
|
||||||
|
if _canconv(val):
|
||||||
|
popm = mutagen.id3.POPM()
|
||||||
|
popm.email = "Windows Media Player 9 Series"
|
||||||
|
popm.count = 0
|
||||||
|
popm.rating = rating2byte(int(val))
|
||||||
|
id3.add(popm)
|
||||||
|
else:
|
||||||
|
if 'TXXX:RATING' in id3:
|
||||||
|
del(id3['TXXX:RATING'])
|
||||||
|
id3.add(mutagen.id3.TXXX(encoding=3, desc='RATING', text=unicode(val)))
|
||||||
|
|
||||||
|
def rating_delete(id3, key):
|
||||||
|
for k, v in popms(id3):
|
||||||
|
del(id3[k])
|
||||||
|
if 'TXXX:RATING' in id3:
|
||||||
|
del(id3['TXXX:RATING'])
|
||||||
|
|
||||||
|
def tracknumber_get(id3, key):
|
||||||
|
# TODO: use for both track and disc
|
||||||
|
pass
|
||||||
|
|
||||||
|
def tracknumber_set(id3, key, val):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def tracknumber_delete(id3, key):
|
||||||
|
pass
|
||||||
|
|
||||||
|
replaygain_tags = ('replaygain_album_gain', 'replaygain_album_peak', \
|
||||||
|
'replaygain_track_gain', 'replaygain_track_peak')
|
||||||
|
|
||||||
|
for tag in replaygain_tags:
|
||||||
|
mutagen.easyid3.EasyID3.RegisterTXXXKey(tag, tag)
|
||||||
|
mutagen.easyid3.EasyID3.RegisterTXXXKey('sync', 'SYNC')
|
||||||
|
mutagen.easyid3.EasyID3.RegisterKey('rating', rating_get, rating_set, rating_delete)
|
76
unsync.py
76
unsync.py
|
@ -7,45 +7,7 @@ import os
|
||||||
import os.path
|
import os.path
|
||||||
import sys
|
import sys
|
||||||
import mutagen
|
import mutagen
|
||||||
import mutagen.id3
|
import mutaext
|
||||||
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 G(d, k):
|
def G(d, k):
|
||||||
try:
|
try:
|
||||||
|
@ -67,11 +29,8 @@ def filterext(paths, exts):
|
||||||
def shouldsync(md):
|
def shouldsync(md):
|
||||||
rating = G(md, 'rating')
|
rating = G(md, 'rating')
|
||||||
sync = G(md, 'sync')
|
sync = G(md, 'sync')
|
||||||
if rating != None:
|
if rating:
|
||||||
try:
|
rating = rating[0]
|
||||||
rating = int(rating[0])
|
|
||||||
except ValueError:
|
|
||||||
rating = None
|
|
||||||
if sync:
|
if sync:
|
||||||
sync = sync[0].lower()
|
sync = sync[0].lower()
|
||||||
else:
|
else:
|
||||||
|
@ -93,7 +52,7 @@ def fixmetadata(md):
|
||||||
if 'title' not in md:
|
if 'title' not in md:
|
||||||
fn = os.path.basename(md.path)
|
fn = os.path.basename(md.path)
|
||||||
fn = os.path.splitext(fn)[0]
|
fn = os.path.splitext(fn)[0]
|
||||||
# TODO: attempt to infer trackNum/diskNum from fn
|
# TODO: attempt to infer trackNum/discNum from fn
|
||||||
md['title'] = fn
|
md['title'] = fn
|
||||||
|
|
||||||
def findmatching(haystack, needle):
|
def findmatching(haystack, needle):
|
||||||
|
@ -116,6 +75,28 @@ def findmatching(haystack, needle):
|
||||||
break
|
break
|
||||||
return match
|
return match
|
||||||
|
|
||||||
|
def updatemetadata(mdold, mdnew):
|
||||||
|
modified = False
|
||||||
|
updatabletags = ('rating', 'sync', 'comment')
|
||||||
|
# TODO:
|
||||||
|
# composer : probably safe
|
||||||
|
# genre : might need deep equal?
|
||||||
|
# trackNum : TRCK with optional /[total]
|
||||||
|
# discNum : TPOS " " "
|
||||||
|
# total tracks : ?
|
||||||
|
# total discs : ?
|
||||||
|
# [replaygain] : TXXX:* in id3
|
||||||
|
# albumArtist : TPE2 in id3
|
||||||
|
for tag in updatabletags:
|
||||||
|
if tag in mdnew:
|
||||||
|
if not tag in mdold or mdnew[tag] != mdold[tag]:
|
||||||
|
mdold[tag] = mdnew[tag]
|
||||||
|
modified = True
|
||||||
|
elif tag in mdold:
|
||||||
|
del mdold[tag]
|
||||||
|
modified = True
|
||||||
|
return modified
|
||||||
|
|
||||||
def run(args):
|
def run(args):
|
||||||
if not len(args) in (2, 3):
|
if not len(args) in (2, 3):
|
||||||
print("I need a path or two!", file=sys.stderr)
|
print("I need a path or two!", file=sys.stderr)
|
||||||
|
@ -151,8 +132,9 @@ def run(args):
|
||||||
md = mutagen.File(p, easy=True)
|
md = mutagen.File(p, easy=True)
|
||||||
match = findmatching(tosync, md)
|
match = findmatching(tosync, md)
|
||||||
if match:
|
if match:
|
||||||
print("UPD", p)
|
if updatemetadata(md, match):
|
||||||
# update tags here if updatemetadata returns true
|
print("UPD", p)
|
||||||
|
# save here
|
||||||
else:
|
else:
|
||||||
print("DEL", p)
|
print("DEL", p)
|
||||||
# delete files here
|
# delete files here
|
||||||
|
|
Loading…
Add table
Reference in a new issue