Skip to content

Commit

Permalink
MediaFile: improve cover art detection
Browse files Browse the repository at this point in the history
Filter media file images on their type.
Detection is still not deterministic when 0 or multiple image
have type ImageType.front.

Fix #1332.
  • Loading branch information
brunal committed Feb 20, 2015
1 parent 2dec90d commit a847726
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 5 deletions.
21 changes: 17 additions & 4 deletions beets/mediafile.py
Original file line number Diff line number Diff line change
Expand Up @@ -1246,18 +1246,31 @@ def __delete__(self, mediafile):

class CoverArtField(MediaField):
"""A descriptor that provides access to the *raw image data* for the
first image on a file. This is used for backwards compatibility: the
cover image on a file. This is used for backwards compatibility: the
full `ImageListField` provides richer `Image` objects.
When there are multiple images we try to pick the most likely to be a front
cover.
"""
def __init__(self):
pass

def __get__(self, mediafile, _):
try:
return mediafile.images[0].data
except IndexError:
candidates = mediafile.images
if candidates:
return self.guess_cover_image(candidates).data
else:
return None

@staticmethod
def guess_cover_image(candidates):
if len(candidates) == 1:
return candidates[0]
try:
return next(c for c in candidates if c.type == ImageType.front)
except StopIteration:
return candidates[0]

def __set__(self, mediafile, data):
if data:
mediafile.images = [Image(data=data)]
Expand Down
13 changes: 12 additions & 1 deletion test/test_mediafile.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
from test._common import unittest
from beets.mediafile import MediaFile, MediaField, Image, \
MP3DescStorageStyle, StorageStyle, MP4StorageStyle, \
ASFStorageStyle, ImageType
ASFStorageStyle, ImageType, CoverArtField
from beets.library import Item
from beets.plugins import BeetsPlugin

Expand Down Expand Up @@ -161,6 +161,13 @@ def test_delete_image_structures(self):
mediafile = MediaFile(mediafile.path)
self.assertEqual(len(mediafile.images), 0)

def test_guess_cover(self):
mediafile = self._mediafile_fixture('image')
self.assertEqual(len(mediafile.images), 2)
cover = CoverArtField.guess_cover_image(mediafile.images)
self.assertEqual(cover.desc, 'album cover')
self.assertEqual(mediafile.art, cover.data)

def assertExtendedImageAttributes(self, image, **kwargs):
"""Ignore extended image attributes in the base tests.
"""
Expand Down Expand Up @@ -758,6 +765,10 @@ def test_add_tiff_image_fails(self):
with self.assertRaises(ValueError):
mediafile.images = [Image(data=self.tiff_data)]

def test_guess_cover(self):
# There is no metadata associated with images, we pick one at random
pass


class AlacTest(ReadWriteTestBase, unittest.TestCase):
extension = 'alac.m4a'
Expand Down

0 comments on commit a847726

Please sign in to comment.