diff --git a/beets/mediafile.py b/beets/mediafile.py index 64ab49ac2b..5fe1fa3081 100644 --- a/beets/mediafile.py +++ b/beets/mediafile.py @@ -215,9 +215,9 @@ def _sc_decode(soundcheck): # SoundCheck tags consist of 10 numbers, each represented by 8 # characters of ASCII hex preceded by a space. try: - soundcheck = soundcheck.replace(' ', '').decode('hex') + soundcheck = soundcheck.replace(b' ', b'').decode('hex') soundcheck = struct.unpack(b'!iiiiiiiiii', soundcheck) - except (struct.error, TypeError, UnicodeEncodeError): + except (struct.error, TypeError): # SoundCheck isn't in the format we expect, so return default # values. return 0.0, 0.0 diff --git a/docs/changelog.rst b/docs/changelog.rst index 27567f2832..700a16d6dd 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -56,6 +56,8 @@ Fixes: * :doc:`/plugins/duplicates`: Fix a crash when merging items. :bug:`1699` * :doc:`/plugins/smartplaylist`: More gracefully handle malformed queries and missing configuration. +* Fix a crash with some files with unreadable iTunes SoundCheck metadata. + :bug:`1666` .. _Emby Server: http://emby.media diff --git a/test/rsrc/soundcheck-nonascii.m4a b/test/rsrc/soundcheck-nonascii.m4a new file mode 100644 index 0000000000..29f5de5310 Binary files /dev/null and b/test/rsrc/soundcheck-nonascii.m4a differ diff --git a/test/test_mediafile_edge.py b/test/test_mediafile_edge.py index 7a17fe86ad..7886abdd2a 100644 --- a/test/test_mediafile_edge.py +++ b/test/test_mediafile_edge.py @@ -89,6 +89,13 @@ def test_only_magic_bytes_jpeg(self): beets.mediafile._image_mime_type(jpg_data), 'image/jpeg') + def test_soundcheck_non_ascii(self): + # Make sure we don't crash when the iTunes SoundCheck field contains + # non-ASCII binary data. + f = beets.mediafile.MediaFile(os.path.join(_common.RSRC, + 'soundcheck-nonascii.m4a')) + self.assertEqual(f.rg_track_gain, 0.0) + class InvalidValueToleranceTest(unittest.TestCase): @@ -269,19 +276,19 @@ def test_round_trip(self): self.assertEqual(peak, 1.0) def test_decode_zero(self): - data = u' 80000000 80000000 00000000 00000000 00000000 00000000 ' \ - u'00000000 00000000 00000000 00000000' + data = b' 80000000 80000000 00000000 00000000 00000000 00000000 ' \ + b'00000000 00000000 00000000 00000000' gain, peak = beets.mediafile._sc_decode(data) self.assertEqual(gain, 0.0) self.assertEqual(peak, 0.0) def test_malformatted(self): - gain, peak = beets.mediafile._sc_decode(u'foo') + gain, peak = beets.mediafile._sc_decode(b'foo') self.assertEqual(gain, 0.0) self.assertEqual(peak, 0.0) def test_special_characters(self): - gain, peak = beets.mediafile._sc_decode(u'caf\xe9') + gain, peak = beets.mediafile._sc_decode(u'caf\xe9'.encode('utf8')) self.assertEqual(gain, 0.0) self.assertEqual(peak, 0.0)