mirror of
https://github.com/beetbox/beets.git
synced 2025-12-14 20:43:41 +01:00
Implement Genre list
This commit is contained in:
parent
a0dac7b9f7
commit
813510a50d
2 changed files with 104 additions and 2 deletions
|
|
@ -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"),
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
Loading…
Reference in a new issue