diff --git a/beets/mediafile.py b/beets/mediafile.py index acc9dbc46..b2a72d84c 100644 --- a/beets/mediafile.py +++ b/beets/mediafile.py @@ -270,10 +270,23 @@ def _sc_encode(gain, peak): # Cover art and other images. +def _wider_test_jpeg(data): + """Test for a jpeg file following the UNIX file implementation which + uses the magic bytes rather than just looking for the bytes b'JFIF' + or b'EXIF' at a fixed position. + """ + if data[:2] == b'\xff\xd8': + return 'jpeg' + + def _image_mime_type(data): """Return the MIME type of the image data (a bytestring). """ - kind = imghdr.what(None, h=data) + # This checks for a jpeg file with only the magic bytes (unrecognized by + # imghdr.what). imghdr.what returns none for that type of file, so + # _wider_test_jpeg is run in that case. It still returns None if it didn't + # match such a jpeg file. + kind = imghdr.what(None, h=data) or _wider_test_jpeg(data) if kind in ['gif', 'jpeg', 'png', 'tiff', 'bmp']: return 'image/{0}'.format(kind) elif kind == 'pgm': diff --git a/test/rsrc/only-magic-bytes.jpg b/test/rsrc/only-magic-bytes.jpg new file mode 100644 index 000000000..ca0cf220f Binary files /dev/null and b/test/rsrc/only-magic-bytes.jpg differ diff --git a/test/test_mediafile_edge.py b/test/test_mediafile_edge.py index 3e828ac3e..7a17fe86a 100644 --- a/test/test_mediafile_edge.py +++ b/test/test_mediafile_edge.py @@ -78,6 +78,17 @@ class EdgeTest(unittest.TestCase): f = beets.mediafile.MediaFile(os.path.join(_common.RSRC, 'oldape.ape')) self.assertEqual(f.bitrate, 0) + def test_only_magic_bytes_jpeg(self): + # Some jpeg files can only be recognized by their magic bytes and as + # such aren't recognized by imghdr. Ensure that this still works thanks + # to our own follow up mimetype detection based on + # https://github.com/file/file/blob/master/magic/Magdir/jpeg#L12 + f = open(os.path.join(_common.RSRC, 'only-magic-bytes.jpg'), 'rb') + jpg_data = f.read() + self.assertEqual( + beets.mediafile._image_mime_type(jpg_data), + 'image/jpeg') + class InvalidValueToleranceTest(unittest.TestCase):