mediafile: prefer latin-1 encoding for ID3 APIC descriptions. Fixes #899

iTunes has problems with everything but latin-1
Try to use latin-1 if possible and fall back to utf-16.
This commit is contained in:
Christoph Reiter 2016-11-18 01:07:02 +01:00
parent 02bd7946c1
commit 31898111ed
2 changed files with 28 additions and 23 deletions

View file

@ -920,7 +920,16 @@ class MP3ImageStorageStyle(ListStorageStyle, MP3StorageStyle):
frame.data = image.data
frame.mime = image.mime_type
frame.desc = image.desc or u''
frame.encoding = 3 # UTF-8 encoding of desc
# For compatibility with OS X/iTunes prefer latin-1 if possible.
# See issue #899
try:
frame.desc.encode("latin-1")
except UnicodeEncodeError:
frame.encoding = 1 # utf-16
else:
frame.encoding = 0 # latin-1 if possible
frame.type = image.type_index
return frame

View file

@ -375,30 +375,26 @@ class ID3v23Test(unittest.TestCase, TestHelper):
finally:
self._delete_test()
def test_v24_image_encoding(self):
mf = self._make_test(id3v23=False)
try:
mf.images = [beets.mediafile.Image(b'test data')]
mf.save()
frame = mf.mgfile.tags.getall('APIC')[0]
self.assertEqual(frame.encoding, 3)
finally:
self._delete_test()
def test_image_encoding(self):
"""For compatibility with OS X/iTunes.
@unittest.skip("a bug, see #899")
def test_v23_image_encoding(self):
"""For compatibility with OS X/iTunes (and strict adherence to
the standard), ID3v2.3 tags need to use an inferior text
encoding: UTF-8 is not supported.
See https://github.com/beetbox/beets/issues/899#issuecomment-62437773
"""
mf = self._make_test(id3v23=True)
try:
mf.images = [beets.mediafile.Image(b'test data')]
mf.save()
frame = mf.mgfile.tags.getall('APIC')[0]
self.assertEqual(frame.encoding, 1)
finally:
self._delete_test()
for v23 in [True, False]:
mf = self._make_test(id3v23=v23)
try:
mf.images = [
beets.mediafile.Image(b'data', desc=u""),
beets.mediafile.Image(b'data', desc=u"foo"),
beets.mediafile.Image(b'data', desc=u"\u0185"),
]
mf.save()
apic_frames = mf.mgfile.tags.getall('APIC')
encodings = dict([(f.desc, f.encoding) for f in apic_frames])
self.assertEqual(encodings, {u"": 0, u"foo": 0, u"\u0185": 1})
finally:
self._delete_test()
def suite():