mirror of
https://github.com/beetbox/beets.git
synced 2025-12-26 02:24:33 +01:00
Add deserialize method to storage styles
This commit is contained in:
parent
9fe212feea
commit
0a3e47c965
1 changed files with 58 additions and 59 deletions
|
|
@ -274,6 +274,15 @@ def _image_mime_type(data):
|
|||
class StorageStyle(object):
|
||||
"""Parameterizes the storage behavior of a single field for a
|
||||
certain tag format.
|
||||
|
||||
The ``get()`` method retrieves data from tags of a mutagen file. It
|
||||
uses the fetch method to obtain the raw mutagen value. It then uses
|
||||
the ``deserialize()`` method to convert it into a python value.
|
||||
|
||||
``set()`` uses ``serialize()`` to convert the passed value into a
|
||||
suitable mutagen type. The ``store()`` method is then used to write
|
||||
that value to the tags.
|
||||
|
||||
- key: The Mutagen key used to access the field's data.
|
||||
- as_type: Which type the value is stored as (unicode, int,
|
||||
bool, or str).
|
||||
|
|
@ -286,20 +295,26 @@ class StorageStyle(object):
|
|||
|
||||
# TODO Use mutagen file types instead of MediaFile formats
|
||||
formats = ['flac', 'opus', 'ogg', 'ape', 'wv', 'mpc']
|
||||
"""List of file format the StorageStyle can handle.
|
||||
|
||||
def __init__(self, key, as_type=unicode, suffix=None,
|
||||
float_places=2, formats=None):
|
||||
Format names correspond to those returned by ``mediafile.type``.
|
||||
"""
|
||||
|
||||
def __init__(self, key, as_type=unicode, suffix=None, float_places=2):
|
||||
self.key = key
|
||||
self.as_type = as_type
|
||||
self.suffix = suffix
|
||||
self.float_places = float_places
|
||||
if formats:
|
||||
self.formats = formats
|
||||
|
||||
# Convert suffix to correct string type.
|
||||
if self.suffix and self.as_type == unicode:
|
||||
self.suffix = self.as_type(self.suffix)
|
||||
|
||||
def get(self, mutagen_file):
|
||||
"""Fetches raw data from tags and deserializes it into a python value.
|
||||
"""
|
||||
return self.deserialize(self.fetch(mutagen_file))
|
||||
|
||||
def fetch(self, mutagen_file):
|
||||
"""Retrieve the first raw value of this tag from the mediafile."""
|
||||
try:
|
||||
|
|
@ -307,21 +322,20 @@ class StorageStyle(object):
|
|||
except KeyError:
|
||||
return None
|
||||
|
||||
def get(self, mutagen_file):
|
||||
data = self.fetch(mutagen_file)
|
||||
data = self._strip_possible_suffix(data)
|
||||
return data
|
||||
def deserialize(self, mutagen_value):
|
||||
if self.suffix and isinstance(mutagen_value, unicode) \
|
||||
and mutagen_value.endswith(self.suffix):
|
||||
return mutagen_value[:-len(self.suffix)]
|
||||
else:
|
||||
return mutagen_value
|
||||
|
||||
def set(self, mutagen_file, value):
|
||||
self.store(mutagen_file, self.serialize(value))
|
||||
|
||||
def store(self, mutagen_file, value):
|
||||
"""Stores a serialized value in the mediafile."""
|
||||
mutagen_file[self.key] = [value]
|
||||
|
||||
def set(self, mutagen_file, value):
|
||||
if value is None:
|
||||
value = self._none_value()
|
||||
value = self.serialize(value)
|
||||
self.store(mutagen_file, value)
|
||||
|
||||
def serialize(self, value):
|
||||
"""Convert value to a type that is suitable for storing in a tag."""
|
||||
if value is None:
|
||||
|
|
@ -379,8 +393,7 @@ class ListStorageStyle(StorageStyle):
|
|||
return None
|
||||
|
||||
def get_list(self, mutagen_file):
|
||||
data = self.fetch(mutagen_file)
|
||||
return [self._strip_possible_suffix(item) for item in data]
|
||||
return [self.deserialize(item) for item in self.fetch(mutagen_file)]
|
||||
|
||||
def fetch(self, mutagen_file):
|
||||
try:
|
||||
|
|
@ -449,25 +462,24 @@ class MP4TupleStorageStyle(MP4StorageStyle):
|
|||
"""Store values as part of a numeric pair.
|
||||
"""
|
||||
|
||||
def __init__(self, key, pack_pos=0, **kwargs):
|
||||
def __init__(self, key, index=0, **kwargs):
|
||||
super(MP4TupleStorageStyle, self).__init__(key, **kwargs)
|
||||
self.pack_pos = pack_pos
|
||||
self.index = index
|
||||
|
||||
def _fetch_unpacked(self, mutagen_file):
|
||||
items = super(MP4TupleStorageStyle, self).fetch(mutagen_file) or []
|
||||
def deserialize(self, mutagen_value):
|
||||
items = mutagen_value or []
|
||||
packing_length = 2
|
||||
return list(items) + [0] * (packing_length - len(items))
|
||||
|
||||
def get(self, mutagen_file):
|
||||
data = self._fetch_unpacked(mutagen_file)[self.pack_pos]
|
||||
return self._strip_possible_suffix(data)
|
||||
return super(MP4TupleStorageStyle, self).get(mutagen_file)[self.index]
|
||||
|
||||
def set(self, mutagen_file, value):
|
||||
if value is None:
|
||||
value = 0
|
||||
data = self._fetch_unpacked(mutagen_file)
|
||||
data[self.pack_pos] = int(value)
|
||||
self.store(mutagen_file, data)
|
||||
items = self.deserialize(self.fetch(mutagen_file))
|
||||
items[self.index] = int(value)
|
||||
self.store(mutagen_file, items)
|
||||
|
||||
|
||||
class MP4ListStorageStyle(ListStorageStyle, MP4StorageStyle):
|
||||
|
|
@ -503,8 +515,8 @@ class MP4ImageStorageStyle(MP4ListStorageStyle):
|
|||
def __init__(self, **kwargs):
|
||||
super(MP4ImageStorageStyle, self).__init__(key='covr', **kwargs)
|
||||
|
||||
def get_list(self, mutagen_file):
|
||||
return [Image(data) for data in self.fetch(mutagen_file)]
|
||||
def deserialize(self, data):
|
||||
return Image(data)
|
||||
|
||||
def serialize(self, image):
|
||||
if image.mime_type == 'image/png':
|
||||
|
|
@ -619,7 +631,7 @@ class MP3SlashPackStorageStyle(MP3StorageStyle):
|
|||
self.pack_pos = pack_pos
|
||||
|
||||
def _fetch_unpacked(self, mutagen_file):
|
||||
data = super(MP3SlashPackStorageStyle, self).fetch(mutagen_file) or ''
|
||||
data = self.fetch(mutagen_file) or ''
|
||||
items = unicode(data).split('/')
|
||||
packing_length = 2
|
||||
return list(items) + [None] * (packing_length - len(items))
|
||||
|
|
@ -649,15 +661,13 @@ class MP3ImageStorageStyle(ListStorageStyle, MP3StorageStyle):
|
|||
super(MP3ImageStorageStyle, self).__init__(key='APIC')
|
||||
self.as_type = str
|
||||
|
||||
def deserialize(self, apic_frame):
|
||||
"""Convert APIC frame into Image."""
|
||||
return Image(data=apic_frame.data, desc=apic_frame.desc,
|
||||
type=apic_frame.type)
|
||||
|
||||
def fetch(self, mutagen_file):
|
||||
"""Return a list of Images obtained from all APIC frames.
|
||||
"""
|
||||
frames = mutagen_file.tags.getall(self.key)
|
||||
images = []
|
||||
for frame in mutagen_file.tags.getall(self.key):
|
||||
images.append(Image(data=frame.data, desc=frame.desc,
|
||||
type=frame.type))
|
||||
return images
|
||||
return mutagen_file.tags.getall(self.key)
|
||||
|
||||
def store(self, mutagen_file, frames):
|
||||
mutagen_file.tags.setall(self.key, frames)
|
||||
|
|
@ -689,18 +699,9 @@ class ASFImageStorageStyle(ListStorageStyle):
|
|||
def __init__(self):
|
||||
super(ASFImageStorageStyle, self).__init__(key='WM/Picture')
|
||||
|
||||
def fetch(self, mutagen_file):
|
||||
if 'WM/Picture' not in mutagen_file:
|
||||
return []
|
||||
|
||||
pictures = []
|
||||
for picture in mutagen_file['WM/Picture']:
|
||||
try:
|
||||
mime, data, type, desc = _unpack_asf_image(picture.value)
|
||||
except:
|
||||
continue
|
||||
pictures.append(Image(data, desc=desc, type=type))
|
||||
return pictures
|
||||
def deserialize(self, asf_picture):
|
||||
mime, data, type, desc = _unpack_asf_image(asf_picture.value)
|
||||
return Image(data, desc=desc, type=type)
|
||||
|
||||
def serialize(self, image):
|
||||
pic = mutagen.asf.ASFByteArrayAttribute()
|
||||
|
|
@ -766,13 +767,11 @@ class FlacImageStorageStyle(ListStorageStyle):
|
|||
super(FlacImageStorageStyle, self).__init__(key='')
|
||||
|
||||
def fetch(self, mutagen_file):
|
||||
"""Return a list of Images stored in the tags.
|
||||
"""
|
||||
images = []
|
||||
for picture in mutagen_file.pictures:
|
||||
images.append(Image(data=picture.data, desc=picture.desc,
|
||||
type=picture.type))
|
||||
return images
|
||||
return mutagen_file.pictures
|
||||
|
||||
def deserialize(self, flac_picture):
|
||||
return Image(data=flac_picture.data, desc=flac_picture.desc,
|
||||
type=flac_picture.type)
|
||||
|
||||
def store(self, mutagen_file, pictures):
|
||||
"""``pictures`` is a list of mutagen.flac.Picture instances.
|
||||
|
|
@ -1200,7 +1199,7 @@ class MediaFile(object):
|
|||
)
|
||||
track = MediaField(
|
||||
MP3SlashPackStorageStyle('TRCK', pack_pos=0),
|
||||
MP4TupleStorageStyle('trkn', pack_pos=0),
|
||||
MP4TupleStorageStyle('trkn', index=0),
|
||||
StorageStyle('TRACK'),
|
||||
StorageStyle('TRACKNUMBER'),
|
||||
ASFStorageStyle('WM/TrackNumber'),
|
||||
|
|
@ -1208,7 +1207,7 @@ class MediaFile(object):
|
|||
)
|
||||
tracktotal = MediaField(
|
||||
MP3SlashPackStorageStyle('TRCK', pack_pos=1),
|
||||
MP4TupleStorageStyle('trkn', pack_pos=1),
|
||||
MP4TupleStorageStyle('trkn', index=1),
|
||||
StorageStyle('TRACKTOTAL'),
|
||||
StorageStyle('TRACKC'),
|
||||
StorageStyle('TOTALTRACKS'),
|
||||
|
|
@ -1217,7 +1216,7 @@ class MediaFile(object):
|
|||
)
|
||||
disc = MediaField(
|
||||
MP3SlashPackStorageStyle('TPOS', pack_pos=0),
|
||||
MP4TupleStorageStyle('disk', pack_pos=0),
|
||||
MP4TupleStorageStyle('disk', index=0),
|
||||
StorageStyle('DISC'),
|
||||
StorageStyle('DISCNUMBER'),
|
||||
ASFStorageStyle('WM/PartOfSet'),
|
||||
|
|
@ -1225,7 +1224,7 @@ class MediaFile(object):
|
|||
)
|
||||
disctotal = MediaField(
|
||||
MP3SlashPackStorageStyle('TPOS', pack_pos=1),
|
||||
MP4TupleStorageStyle('disk', pack_pos=1),
|
||||
MP4TupleStorageStyle('disk', index=1),
|
||||
StorageStyle('DISCTOTAL'),
|
||||
StorageStyle('DISCC'),
|
||||
StorageStyle('TOTALDISCS'),
|
||||
|
|
|
|||
Loading…
Reference in a new issue