From a0877dc092d006490bff365d66bb73b48b17c7c1 Mon Sep 17 00:00:00 2001 From: "nathdwek@laptop" Date: Mon, 7 Nov 2016 16:01:57 +0100 Subject: [PATCH 1/5] images: Make sure all jpegs work everywhere Apply #1545 to a public function used everywhere --- beets/art.py | 1 - beets/mediafile.py | 17 ++++++++++++++--- beetsplug/fetchart.py | 4 ++-- test/test_mediafile_edge.py | 2 +- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/beets/art.py b/beets/art.py index 4f873fc60..b371c2c95 100644 --- a/beets/art.py +++ b/beets/art.py @@ -22,7 +22,6 @@ from __future__ import division, absolute_import, print_function import subprocess import platform from tempfile import NamedTemporaryFile -import imghdr import os from beets.util import displayable_path, syspath, bytestring_path diff --git a/beets/mediafile.py b/beets/mediafile.py index 6dd7bc816..616587597 100644 --- a/beets/mediafile.py +++ b/beets/mediafile.py @@ -308,6 +308,17 @@ def _sc_encode(gain, peak): # Cover art and other images. +def _imghdr_what_wrapper(data): + """A wrapper around imghdr.what to account for jpeg files that can only be + identified as such using their magic bytes + See #1545 + See https://github.com/file/file/blob/master/magic/Magdir/jpeg#L12 + """ + # imghdr.what returns none for jpegs with only the magic bytes, so + # _wider_test_jpeg is run in that case. It still returns None if it didn't + # match such a jpeg file. + return imghdr.what(None, h=data) or _wider_test_jpeg(data) + def _wider_test_jpeg(data): """Test for a jpeg file following the UNIX file implementation which @@ -318,14 +329,14 @@ def _wider_test_jpeg(data): return 'jpeg' -def _image_mime_type(data): +def image_mime_type(data): """Return the MIME type of the image data (a bytestring). """ # 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) + kind = _imghdr_what_wrapper(data) if kind in ['gif', 'jpeg', 'png', 'tiff', 'bmp']: return 'image/{0}'.format(kind) elif kind == 'pgm': @@ -394,7 +405,7 @@ class Image(object): @property def mime_type(self): if self.data: - return _image_mime_type(self.data) + return image_mime_type(self.data) @property def type_index(self): diff --git a/beetsplug/fetchart.py b/beetsplug/fetchart.py index 4db22397e..27ffa49cb 100644 --- a/beetsplug/fetchart.py +++ b/beetsplug/fetchart.py @@ -29,7 +29,7 @@ from beets import importer from beets import ui from beets import util from beets import config -from beets.mediafile import _image_mime_type +from beets.mediafile import image_mime_type from beets.util.artresizer import ArtResizer from beets.util import confit from beets.util import syspath, bytestring_path, py3_path @@ -250,7 +250,7 @@ class RemoteArtSource(ArtSource): # server didn't return enough data, i.e. corrupt image return - real_ct = _image_mime_type(header) + real_ct = image_mime_type(header) if real_ct is None: # detection by file magic failed, fall back to the # server-supplied Content-Type diff --git a/test/test_mediafile_edge.py b/test/test_mediafile_edge.py index 4e053192a..d09b11fb8 100644 --- a/test/test_mediafile_edge.py +++ b/test/test_mediafile_edge.py @@ -91,7 +91,7 @@ class EdgeTest(unittest.TestCase): with open(magic_bytes_file, 'rb') as f: jpg_data = f.read() self.assertEqual( - beets.mediafile._image_mime_type(jpg_data), + beets.mediafile.image_mime_type(jpg_data), 'image/jpeg') def test_soundcheck_non_ascii(self): From 92ee141662d8948177fb724ce1da07da50cda2bb Mon Sep 17 00:00:00 2001 From: "nathdwek@laptop" Date: Mon, 7 Nov 2016 16:03:05 +0100 Subject: [PATCH 2/5] images: use jpg extensions for jpeg files everywhere fix #2254 --- beets/art.py | 2 +- beets/mediafile.py | 7 +++++++ beets/util/collections.py | 27 +++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 beets/util/collections.py diff --git a/beets/art.py b/beets/art.py index b371c2c95..979a6f722 100644 --- a/beets/art.py +++ b/beets/art.py @@ -193,7 +193,7 @@ def extract(log, outpath, item): return # Add an extension to the filename. - ext = imghdr.what(None, h=art) + ext = mediafile.image_extension(art) if not ext: log.warning(u'Unknown image type in {0}.', displayable_path(item.path)) diff --git a/beets/mediafile.py b/beets/mediafile.py index 616587597..3faf2f60e 100644 --- a/beets/mediafile.py +++ b/beets/mediafile.py @@ -59,6 +59,7 @@ import enum from beets import logging from beets.util import displayable_path, syspath, as_string +from beets.util.collections import IdentityUnlessDict import six @@ -81,6 +82,8 @@ TYPES = { 'aiff': 'AIFF', } +PREFERRED_IMAGE_EXTENSIONS = IdentityUnlessDict({'jpeg': 'jpg'}) + # Exceptions. @@ -351,6 +354,10 @@ def image_mime_type(data): return 'image/x-{0}'.format(kind) +def image_extension(data): + return PREFERRED_IMAGE_EXTENSIONS[_imghdr_what_wrapper(data)] + + class ImageType(enum.Enum): """Indicates the kind of an `Image` stored in a file's tag. """ diff --git a/beets/util/collections.py b/beets/util/collections.py new file mode 100644 index 000000000..dad49a4a4 --- /dev/null +++ b/beets/util/collections.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# This file is part of beets. +# Copyright 2016, Adrian Sampson. +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +"""Custom collections classes +""" + + +class IdentityUnlessDict(dict): + """A dictionary which is "transparent" (maps keys to themselves) for all + keys not in it. + """ + def __getitem__(self, key): + try: + return dict.__getitem__(self, key) + except KeyError: + return key From e782885e5050fa1f40cd93aade900650bf1c90fc Mon Sep 17 00:00:00 2001 From: "nathdwek@laptop" Date: Tue, 8 Nov 2016 18:42:19 +0100 Subject: [PATCH 3/5] embedart: Adapt tests for #2254 --- test/rsrc/image-jpeg.mp3 | Bin 0 -> 10452 bytes test/test_embedart.py | 11 +++++++++++ test/test_mediafile_edge.py | 3 +-- 3 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 test/rsrc/image-jpeg.mp3 diff --git a/test/rsrc/image-jpeg.mp3 b/test/rsrc/image-jpeg.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..3f2d22ffb1f44b9169a1d491f4315afa8d1d1632 GIT binary patch literal 10452 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

ubVk*w_L)d3%KM7PM%l~LiPF`5Nvqplf(}mR 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 Date: Tue, 8 Nov 2016 12:10:17 +0100 Subject: [PATCH 4/5] utils.collections: rename IdentityUnlessDict to IdentityFallbackDict --- beets/mediafile.py | 4 ++-- beets/util/collections.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/beets/mediafile.py b/beets/mediafile.py index 3faf2f60e..784695c1a 100644 --- a/beets/mediafile.py +++ b/beets/mediafile.py @@ -59,7 +59,7 @@ import enum from beets import logging from beets.util import displayable_path, syspath, as_string -from beets.util.collections import IdentityUnlessDict +from beets.util.collections import IdentityFallbackDict import six @@ -82,7 +82,7 @@ TYPES = { 'aiff': 'AIFF', } -PREFERRED_IMAGE_EXTENSIONS = IdentityUnlessDict({'jpeg': 'jpg'}) +PREFERRED_IMAGE_EXTENSIONS = IdentityFallbackDict({'jpeg': 'jpg'}) # Exceptions. diff --git a/beets/util/collections.py b/beets/util/collections.py index dad49a4a4..6813b95df 100644 --- a/beets/util/collections.py +++ b/beets/util/collections.py @@ -16,7 +16,7 @@ """ -class IdentityUnlessDict(dict): +class IdentityFallbackDict(dict): """A dictionary which is "transparent" (maps keys to themselves) for all keys not in it. """ From f236816431a3fdf18ae79eeaf35499cad69cdcc3 Mon Sep 17 00:00:00 2001 From: "nath@home" Date: Tue, 8 Nov 2016 12:10:34 +0100 Subject: [PATCH 5/5] embedart: Changelog for #2255 --- docs/changelog.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 08be98a5c..7c03e230d 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -52,6 +52,12 @@ The are a couple of small new features: And there are a few bug fixes too: +* :doc:`/plugins/embedart`: The plugin now uses ``jpg`` as an extension rather + than ``jpeg``, to ensure consistency with :doc:`plugins/fetchart`. + Thanks to :user:`tweitzel`. :bug:`2254` :bug:`2255` +* :doc:`/plugins/embedart`: The plugin now works for all jpeg files, including + those that are only recognizable by their magic bytes. + :bug:`1545` :bug:`2255` * :doc:`/plugins/web`: The JSON output is no longer pretty-printed (for a space savings). :bug:`2050` * :doc:`/plugins/permissions`: Fix a regression in the previous release where @@ -70,7 +76,7 @@ And there are a few bug fixes too: This is fixed. :bug:`2168` * :doc:`/plugins/embyupdate`: Fixes authentication header problem that caused a problem that it was not possible to get tokens from the Emby API. -* :doc:`/plugins/lyrics`: Search for lyrics using the title part preceding the +* :doc:`/plugins/lyrics`: Search for lyrics using the title part preceding the colon character. :bug:`2206` * Fix a crash when a query contains a date field that is not set for all the items. :bug:`1938`