From 806d3cc6e9a596f0d2de83f14a4b451067e2b41b Mon Sep 17 00:00:00 2001 From: Thomas Scholtes Date: Sun, 9 Mar 2014 00:56:44 +0100 Subject: [PATCH] Implement ImageListField for Vorbis comments --- beets/mediafile.py | 56 +++++++++++++++++++++-------------------- test/rsrc/image.ogg | Bin 0 -> 9786 bytes test/test_mediafile.py | 3 ++- 3 files changed, 31 insertions(+), 28 deletions(-) create mode 100644 test/rsrc/image.ogg diff --git a/beets/mediafile.py b/beets/mediafile.py index e23bd64e9..106e0afc6 100644 --- a/beets/mediafile.py +++ b/beets/mediafile.py @@ -720,43 +720,45 @@ class VorbisImageStorageStyle(ListStorageStyle): formats = ['opus', 'ogg', 'ape', 'wv', 'mpc'] def __init__(self): - super(VorbisImageStorageStyle, self).__init__(key='') + super(VorbisImageStorageStyle, self).__init__( + key='metadata_block_picture') self.as_type = str def fetch(self, mutagen_file): + images = [] if 'metadata_block_picture' not in mutagen_file: # Try legacy COVERART tags. - if 'coverart' in mutagen_file and mutagen_file['coverart']: - return base64.b64decode(mutagen_file['coverart'][0]) - return [] - - pics = [] + if 'coverart' in mutagen_file: + for data in mutagen_file['coverart']: + images.append(TagImage(base64.b64decode(data))) + return images for data in mutagen_file["metadata_block_picture"]: try: - pics.append(mutagen.flac.Picture(base64.b64decode(data)).data) + pic = mutagen.flac.Picture(base64.b64decode(data)) except (TypeError, AttributeError): - pass - return pics + continue + images.append(TagImage(data=pic.data, desc=pic.desc, + type=pic.type)) + return images def store(self, mutagen_file, image_data): # Strip all art, including legacy COVERART. - if 'metadata_block_picture' in mutagen_file: - if 'metadata_block_picture' in mutagen_file: - del mutagen_file['metadata_block_picture'] - if 'coverart' in mutagen_file: - del mutagen_file['coverart'] - if 'coverartmime' in mutagen_file: - del mutagen_file['coverartmime'] + if 'coverart' in mutagen_file: + del mutagen_file['coverart'] + if 'coverartmime' in mutagen_file: + del mutagen_file['coverartmime'] + super(VorbisImageStorageStyle, self).store(mutagen_file, image_data) - image_data = image_data[0] - # Add new art if provided. - if image_data is not None: - pic = mutagen.flac.Picture() - pic.data = image_data - pic.mime = _image_mime_type(image_data) - mutagen_file['metadata_block_picture'] = [ - base64.b64encode(pic.write()) - ] + + def serialize(self, image): + """Turn a TagImage into a base64 encoded FLAC picture block. + """ + pic = mutagen.flac.Picture() + pic.data = image.data + pic.type = image.type_index or 3 # Front cover + pic.mime = image.mime_type + pic.desc = image.desc or u'' + return base64.b64encode(pic.write()) class FlacImageStorageStyle(ListStorageStyle): @@ -969,7 +971,7 @@ class CoverArtField(MediaField): ) def __get__(self, mediafile, _): - if mediafile.type in ['mp3', 'flac']: + if mediafile.type in ['mp3', 'flac'] + VorbisImageStorageStyle.formats: try: return mediafile.images[0].data except IndexError: @@ -978,7 +980,7 @@ class CoverArtField(MediaField): return style.get(mediafile.mgfile) def __set__(self, mediafile, data): - if mediafile.type in ['mp3', 'flac']: + if mediafile.type in ['mp3', 'flac'] + VorbisImageStorageStyle.formats: if data: mediafile.images = [TagImage(data=data)] else: diff --git a/test/rsrc/image.ogg b/test/rsrc/image.ogg new file mode 100644 index 0000000000000000000000000000000000000000..4852448e2767ac1895f52cbb0d5a00ef6bce757d GIT binary patch literal 9786 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