mirror of
https://github.com/beetbox/beets.git
synced 2026-01-01 05:23:05 +01:00
consolidated key and id3desc into StorageStyle
--HG-- extra : convert_revision : svn%3A41726ec3-264d-0410-9c23-a9f1637257cc/trunk%4083
This commit is contained in:
parent
1dd57e1aaa
commit
605343fb57
1 changed files with 137 additions and 82 deletions
|
|
@ -99,6 +99,8 @@ class StorageStyle(object):
|
|||
"""Parameterizes the storage behavior of a single field for a certain tag
|
||||
format."""
|
||||
def __init__(self,
|
||||
# The Mutagen key used to access the data for this field.
|
||||
key,
|
||||
# Store item as a single object or as first element of a list.
|
||||
list_elem = True,
|
||||
# Which type the value is stored as (unicode, int, or bool).
|
||||
|
|
@ -108,11 +110,16 @@ class StorageStyle(object):
|
|||
# None. (Makes as_type irrelevant).
|
||||
packing = None,
|
||||
# If the value is packed, in which position it is stored.
|
||||
pack_pos = 0):
|
||||
pack_pos = 0,
|
||||
# ID3 storage only: match against this 'desc' field as well
|
||||
# as the key.
|
||||
id3_desc = None):
|
||||
self.key = key
|
||||
self.list_elem = list_elem
|
||||
self.as_type = as_type
|
||||
self.packing = packing
|
||||
self.pack_pos = pack_pos
|
||||
self.id3_desc = id3_desc
|
||||
|
||||
|
||||
|
||||
|
|
@ -120,51 +127,47 @@ class StorageStyle(object):
|
|||
|
||||
class MediaField(object):
|
||||
"""A descriptor providing access to a particular (abstract) metadata
|
||||
field. The various messy parameters control the translation to concrete
|
||||
metadata manipulations in the language of mutagen."""
|
||||
field. out_type is the type that users of MediaFile should see and can
|
||||
be unicode, int, or bool. id3, mp4, and flac are StorageStyle instances
|
||||
parameterizing the field's storage for each type."""
|
||||
|
||||
def __init__(self, id3key, mp4key, flackey,
|
||||
# in ID3 tags, use only the frame with this "desc" field
|
||||
id3desc=None,
|
||||
# the field's semantic (exterior) type
|
||||
def __init__(self,
|
||||
# The field's semantic (exterior) type.
|
||||
out_type = unicode,
|
||||
# StorageStyle instances parameterizing the field's storage
|
||||
id3_style = StorageStyle(),
|
||||
mp4_style = StorageStyle(),
|
||||
flac_style = StorageStyle()
|
||||
# A hash whose keys are 'mp3', 'mp4', and 'flac' and whose values
|
||||
# are StorageStyle instances parameterizing the field's storage for
|
||||
# each type.
|
||||
**kwargs
|
||||
):
|
||||
|
||||
self.id3desc = id3desc
|
||||
self.out_type = out_type
|
||||
self.keys = { 'mp3': id3key,
|
||||
'mp4': mp4key,
|
||||
'flac': flackey }
|
||||
self.styles = { 'mp3': id3_style,
|
||||
'mp4': mp4_style,
|
||||
'flac': flac_style }
|
||||
if not set(['mp3', 'mp4', 'flac']) == set(kwargs):
|
||||
raise TypeError('MediaField constructor must have keyword '
|
||||
'arguments mp3, mp4, and flac only')
|
||||
self.styles = kwargs
|
||||
|
||||
def _fetchdata(self, obj):
|
||||
"""Get the value associated with this descriptor's key (and id3desc if
|
||||
"""Get the value associated with this descriptor's key (and id3_desc if
|
||||
present) from the mutagen tag dict. Unwraps from a list if
|
||||
necessary."""
|
||||
(key, style) = self._params(obj)
|
||||
style = self._style(obj)
|
||||
|
||||
try:
|
||||
# fetch the value, which may be a scalar or a list
|
||||
if obj.type == 'mp3':
|
||||
if self.id3desc is not None: # also match on 'desc' field
|
||||
frames = obj.mgfile.tags.getall(key)
|
||||
if style.id3_desc is not None: # also match on 'desc' field
|
||||
frames = obj.mgfile.tags.getall(style.key)
|
||||
entry = None
|
||||
for frame in frames:
|
||||
if frame.desc == self.id3desc:
|
||||
if frame.desc == style.id3_desc:
|
||||
entry = frame.text
|
||||
break
|
||||
if entry is None: # no desc match
|
||||
return None
|
||||
else:
|
||||
entry = obj.mgfile[key].text
|
||||
entry = obj.mgfile[style.key].text
|
||||
else:
|
||||
entry = obj.mgfile[key]
|
||||
entry = obj.mgfile[style.key]
|
||||
|
||||
# possibly index the list
|
||||
if style.list_elem:
|
||||
|
|
@ -176,44 +179,42 @@ class MediaField(object):
|
|||
|
||||
def _storedata(self, obj, val):
|
||||
"""Store val for this descriptor's key in the tag dictionary. Store it
|
||||
as a single-item list if necessary. Uses id3desc if present."""
|
||||
(key, style) = self._params(obj)
|
||||
as a single-item list if necessary. Uses id3_desc if present."""
|
||||
style = self._style(obj)
|
||||
|
||||
# wrap as a list if necessary
|
||||
if style.list_elem: out = [val]
|
||||
else: out = val
|
||||
|
||||
if obj.type == 'mp3':
|
||||
if self.id3desc is not None: # match on id3desc
|
||||
frames = obj.mgfile.tags.getall(key)
|
||||
if style.id3_desc is not None: # match on desc field
|
||||
frames = obj.mgfile.tags.getall(style.key)
|
||||
|
||||
# try modifying in place
|
||||
found = False
|
||||
for frame in frames:
|
||||
if frame.desc == self.id3desc:
|
||||
if frame.desc == style.id3_desc:
|
||||
frame.text = out
|
||||
found = True
|
||||
break
|
||||
|
||||
# need to make a new frame?
|
||||
if not found:
|
||||
frame = mutagen.id3.Frames[key](
|
||||
encoding=3, desc=self.id3desc, text=val)
|
||||
frame = mutagen.id3.Frames[style.key](
|
||||
encoding=3, desc=style.id3_desc, text=val)
|
||||
obj.mgfile.tags.add(frame)
|
||||
|
||||
else: # no match on desc; just replace based on key
|
||||
frame = mutagen.id3.Frames[key](encoding=3, text=val)
|
||||
obj.mgfile.tags.setall(key, [frame])
|
||||
frame = mutagen.id3.Frames[style.key](encoding=3, text=val)
|
||||
obj.mgfile.tags.setall(style.key, [frame])
|
||||
else:
|
||||
obj.mgfile[key] = out
|
||||
obj.mgfile[style.key] = out
|
||||
|
||||
def _params(self, obj):
|
||||
return (self.keys[obj.type],
|
||||
self.styles[obj.type])
|
||||
def _style(self, obj): return self.styles[obj.type]
|
||||
|
||||
def __get__(self, obj, owner):
|
||||
"""Retrieve the value of this metadata field."""
|
||||
(key, style) = self._params(obj)
|
||||
style = self._style(obj)
|
||||
out = self._fetchdata(obj)
|
||||
|
||||
# deal with slashed and tuple storage
|
||||
|
|
@ -246,7 +247,7 @@ class MediaField(object):
|
|||
|
||||
def __set__(self, obj, val):
|
||||
"""Set the value of this metadata field."""
|
||||
(key, style) = self._params(obj)
|
||||
style = self._style(obj)
|
||||
|
||||
if style.packing:
|
||||
# fetch the existing value so we can preserve half of it
|
||||
|
|
@ -335,45 +336,99 @@ class MediaFile(object):
|
|||
|
||||
#### field definitions ####
|
||||
|
||||
title = MediaField('TIT2', "\xa9nam", 'title')
|
||||
artist = MediaField('TPE1', "\xa9ART", 'artist')
|
||||
album = MediaField('TALB', "\xa9alb", 'album')
|
||||
genre = MediaField('TCON', "\xa9gen", 'genre')
|
||||
composer = MediaField('TCOM', "\xa9wrt", 'composer')
|
||||
grouping = MediaField('TIT1', "\xa9grp", 'grouping')
|
||||
year = MediaField('TDRC', "\xa9day", 'date', out_type=int)
|
||||
track = MediaField('TRCK', 'trkn', 'tracknumber',
|
||||
id3_style = StorageStyle(packing = packing.SLASHED,
|
||||
pack_pos = 0),
|
||||
mp4_style = StorageStyle(packing = packing.TUPLE,
|
||||
pack_pos = 0),
|
||||
out_type = int)
|
||||
tracktotal = MediaField('TRCK', 'trkn', 'tracktotal',
|
||||
id3_style = StorageStyle(packing = packing.SLASHED,
|
||||
pack_pos = 1),
|
||||
mp4_style = StorageStyle(packing = packing.TUPLE,
|
||||
pack_pos = 1),
|
||||
out_type = int)
|
||||
disc = MediaField('TPOS', 'disk', 'disc',
|
||||
id3_style = StorageStyle(packing = packing.SLASHED,
|
||||
pack_pos = 0),
|
||||
mp4_style = StorageStyle(packing = packing.TUPLE,
|
||||
pack_pos = 0),
|
||||
out_type = int)
|
||||
disctotal = MediaField('TPOS', 'disk', 'disctotal',
|
||||
id3_style = StorageStyle(packing = packing.SLASHED,
|
||||
pack_pos = 1),
|
||||
mp4_style = StorageStyle(packing = packing.TUPLE,
|
||||
pack_pos = 1),
|
||||
out_type = int)
|
||||
lyrics = MediaField(u"USLT", "\xa9lyr", 'lyrics',
|
||||
id3desc = u'',
|
||||
id3_style = StorageStyle(list_elem = False))
|
||||
comments = MediaField(u"COMM", "\xa9cmt", 'description',
|
||||
id3desc = u'')
|
||||
bpm = MediaField('TBPM', 'tmpo', 'bpm',
|
||||
mp4_style = StorageStyle(as_type = int),
|
||||
out_type = int)
|
||||
comp = MediaField('TCMP', 'cpil', 'compilation',
|
||||
mp4_style = StorageStyle(list_elem = False, as_type = bool),
|
||||
out_type = bool)
|
||||
title = MediaField(
|
||||
mp3 = StorageStyle('TIT2'),
|
||||
mp4 = StorageStyle("\xa9nam"),
|
||||
flac = StorageStyle('title')
|
||||
)
|
||||
artist = MediaField(
|
||||
mp3 = StorageStyle('TPE1'),
|
||||
mp4 = StorageStyle("\xa9ART"),
|
||||
flac = StorageStyle('artist')
|
||||
)
|
||||
album = MediaField(
|
||||
mp3 = StorageStyle('TALB'),
|
||||
mp4 = StorageStyle("\xa9alb"),
|
||||
flac = StorageStyle('album')
|
||||
)
|
||||
genre = MediaField(
|
||||
mp3 = StorageStyle('TCON'),
|
||||
mp4 = StorageStyle("\xa9gen"),
|
||||
flac = StorageStyle('genre')
|
||||
)
|
||||
composer = MediaField(
|
||||
mp3 = StorageStyle('TCOM'),
|
||||
mp4 = StorageStyle("\xa9wrt"),
|
||||
flac = StorageStyle('composer')
|
||||
)
|
||||
grouping = MediaField(
|
||||
mp3 = StorageStyle('TIT1'),
|
||||
mp4 = StorageStyle("\xa9grp"),
|
||||
flac = StorageStyle('grouping')
|
||||
)
|
||||
year = MediaField(out_type=int,
|
||||
mp3 = StorageStyle('TDRC'),
|
||||
mp4 = StorageStyle("\xa9day"),
|
||||
flac = StorageStyle('date')
|
||||
)
|
||||
track = MediaField(out_type = int,
|
||||
mp3 = StorageStyle('TRCK',
|
||||
packing = packing.SLASHED,
|
||||
pack_pos = 0),
|
||||
mp4 = StorageStyle('trkn',
|
||||
packing = packing.TUPLE,
|
||||
pack_pos = 0),
|
||||
flac = StorageStyle('tracknumber')
|
||||
)
|
||||
tracktotal = MediaField(out_type = int,
|
||||
mp3 = StorageStyle('TRCK',
|
||||
packing = packing.SLASHED,
|
||||
pack_pos = 1),
|
||||
mp4 = StorageStyle('trkn',
|
||||
packing = packing.TUPLE,
|
||||
pack_pos = 1),
|
||||
flac = StorageStyle('tracktotal')
|
||||
)
|
||||
disc = MediaField(out_type = int,
|
||||
mp3 = StorageStyle('TPOS',
|
||||
packing = packing.SLASHED,
|
||||
pack_pos = 0),
|
||||
mp4 = StorageStyle('disk',
|
||||
packing = packing.TUPLE,
|
||||
pack_pos = 0),
|
||||
flac = StorageStyle('disc')
|
||||
)
|
||||
disctotal = MediaField(out_type = int,
|
||||
mp3 = StorageStyle('TPOS',
|
||||
packing = packing.SLASHED,
|
||||
pack_pos = 1),
|
||||
mp4 = StorageStyle('disk',
|
||||
packing = packing.TUPLE,
|
||||
pack_pos = 1),
|
||||
flac = StorageStyle('disctotal')
|
||||
)
|
||||
lyrics = MediaField(
|
||||
mp3 = StorageStyle('USLT',
|
||||
list_elem = False,
|
||||
id3_desc = u''),
|
||||
mp4 = StorageStyle("\xa9lyr"),
|
||||
flac = StorageStyle('lyrics')
|
||||
)
|
||||
comments = MediaField(
|
||||
mp3 = StorageStyle('COMM', id3_desc = u''),
|
||||
mp4 = StorageStyle("\xa9cmt"),
|
||||
flac = StorageStyle('description')
|
||||
)
|
||||
bpm = MediaField(out_type = int,
|
||||
mp3 = StorageStyle('TBPM'),
|
||||
mp4 = StorageStyle('tmpo', as_type = int),
|
||||
flac = StorageStyle('bpm')
|
||||
)
|
||||
comp = MediaField(out_type = bool,
|
||||
mp3 = StorageStyle('TCMP'),
|
||||
mp4 = StorageStyle('cpil',
|
||||
list_elem = False,
|
||||
as_type = bool),
|
||||
flac = StorageStyle('compilation')
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue