Implement Genre list

This commit is contained in:
Thomas Scholtes 2014-02-04 18:50:51 +01:00
parent a0dac7b9f7
commit 813510a50d
2 changed files with 104 additions and 2 deletions

View file

@ -475,7 +475,7 @@ class MP3StorageStyle(StorageStyle):
def fetch(self, mediafile):
try:
frame = mediafile.mgfile[self.key]
frame = mediafile.mgfile[self.key]
except KeyError:
return None
try:
@ -489,6 +489,54 @@ class MP3StorageStyle(StorageStyle):
frame = mutagen.id3.Frames[self.key](encoding=3, text=[value])
mediafile.mgfile.tags.setall(self.key, [frame])
class MP3ListStorageStyle(MP3StorageStyle):
def __init__(self, *args, **kwargs):
super(MP3ListStorageStyle, self).__init__(*args, **kwargs)
if self.packing:
raise NotImplementedError('packing is not implemented for lists')
def fetch(self, mediafile):
try:
return mediafile.mgfile[self.key].text
except KeyError:
return []
def get_list(self, mediafile):
data = self.fetch(mediafile)
if self.packing:
try:
data = self.unpack(data)[self.pack_pos]
except IndexError:
data = None
if self.suffix and isinstance(data, unicode):
if data.endswith(self.suffix):
data = data[:-len(self.suffix)]
return data
def get(self, mediafile):
try:
return self.get_list(mediafile)[0]
except IndexError:
return None
def store(self, mediafile, values):
frame = mutagen.id3.Frames[self.key](encoding=3, text=values)
mediafile.mgfile.tags.setall(self.key, [frame])
def set(self, mediafile, value):
self.set_list(mediafile, [value])
def set_list(self, mediafile, values):
data = []
for value in values:
if value is None:
value = self._none_value()
data.append(self.serialize(value))
self.store(mediafile, data)
class MP3UFIDStorageStyle(MP3StorageStyle):
@ -571,6 +619,13 @@ class MediaField(object):
'arguments mp3, mp4, asf, and etc')
self.styles = kwargs
def listField(self):
options = self.styles.copy()
options['out_type'] = self.out_type
return MediaFieldList(**options)
def _styles(self, obj):
if obj.type in ('mp3', 'asf'):
styles = self.styles[obj.type]
@ -599,6 +654,20 @@ class MediaField(object):
for style in self._styles(obj):
style.set(obj, val)
class MediaFieldList(MediaField):
def __get__(self, mediafile, _):
values = []
for style in self._styles(mediafile):
values.extend(style.get_list(mediafile))
return [_safe_cast(self.out_type, value) for value in values]
def __set__(self, mediafile, values):
for style in self._styles(mediafile):
style.set_list(mediafile, values)
class CompositeDateField(object):
"""A MediaFile field for conveniently accessing the year, month, and
day fields as a datetime.date object. Allows both getting and
@ -932,11 +1001,13 @@ class MediaFile(object):
asf=StorageStyle('WM/AlbumTitle'),
)
genre = MediaField(
mp3=MP3StorageStyle('TCON'),
mp3=MP3ListStorageStyle('TCON'),
mp4=MP4StorageStyle("\xa9gen"),
etc=StorageStyle('GENRE'),
asf=StorageStyle('WM/Genre'),
)
genres = genre.listField()
composer = MediaField(
mp3=MP3StorageStyle('TCOM'),
mp4=MP4StorageStyle("\xa9wrt"),

View file

@ -323,6 +323,37 @@ class MP3Test(ReadWriteTestBase, PartialTestMixin, unittest.TestCase):
'bitdepth': 0,
'channels': 1,
}
def test_read_genre_list(self):
mediafile = self._mediafile_fixture('full')
self.assertEqual(mediafile.genres, ['the genre'])
def test_write_genre_list(self):
mediafile = self._mediafile_fixture('empty')
mediafile.genres = ['one', 'two']
mediafile.save()
mediafile = MediaFile(mediafile.path)
self.assertEqual(mediafile.genres, ['one', 'two'])
def test_write_genre_list_get_first(self):
mediafile = self._mediafile_fixture('empty')
mediafile.genres = ['one', 'two']
mediafile.save()
mediafile = MediaFile(mediafile.path)
self.assertEqual(mediafile.genre, 'one')
def test_append_genre_list(self):
mediafile = self._mediafile_fixture('full')
self.assertEqual(mediafile.genre, 'the genre')
mediafile.genres += ['another']
mediafile.save()
mediafile = MediaFile(mediafile.path)
self.assertEqual(mediafile.genres, ['the genre', 'another'])
class MP4Test(ReadWriteTestBase, PartialTestMixin, unittest.TestCase):
extension = 'm4a'
audio_properties = {