[Python-apps-commits] r13568 - in packages/picard/trunk/debian (6 files)
sramacher at users.alioth.debian.org
sramacher at users.alioth.debian.org
Sat Aug 27 12:04:07 UTC 2016
Date: Saturday, August 27, 2016 @ 12:04:05
Author: sramacher
Revision: 13568
* Team upload.
* debian/patches/mutagen.patch: Backport upstream patch to fix issues with
newer mutagen. (Closes: #833679)
* debian/control:
- Bump python-mutagen (B-)D to 1.22.
- Bump Standards-Version.
* debian/rules: Run with LC_ALL=C.UTF-8.
Added:
packages/picard/trunk/debian/patches/
packages/picard/trunk/debian/patches/mutagen.patch
packages/picard/trunk/debian/patches/series
Modified:
packages/picard/trunk/debian/changelog
packages/picard/trunk/debian/control
packages/picard/trunk/debian/rules
Modified: packages/picard/trunk/debian/changelog
===================================================================
--- packages/picard/trunk/debian/changelog 2016-08-26 21:44:07 UTC (rev 13567)
+++ packages/picard/trunk/debian/changelog 2016-08-27 12:04:05 UTC (rev 13568)
@@ -1,3 +1,15 @@
+picard (1.3.2-4) unstable; urgency=medium
+
+ * Team upload.
+ * debian/patches/mutagen.patch: Backport upstream patch to fix issues with
+ newer mutagen. (Closes: #833679)
+ * debian/control:
+ - Bump python-mutagen (B-)D to 1.22.
+ - Bump Standards-Version.
+ * debian/rules: Run with LC_ALL=C.UTF-8.
+
+ -- Sebastian Ramacher <sramacher at debian.org> Sat, 27 Aug 2016 14:03:22 +0200
+
picard (1.3.2-3) unstable; urgency=medium
* Team upload.
Modified: packages/picard/trunk/debian/control
===================================================================
--- packages/picard/trunk/debian/control 2016-08-26 21:44:07 UTC (rev 13567)
+++ packages/picard/trunk/debian/control 2016-08-27 12:04:05 UTC (rev 13568)
@@ -10,8 +10,8 @@
imagemagick,
pkg-config,
python-qt4 (>= 4.5),
- python-mutagen (>= 1.20)
-Standards-Version: 3.9.6
+ python-mutagen (>= 1.22)
+Standards-Version: 3.9.8
Homepage: http://picard.musicbrainz.org/
Vcs-Browser: http://anonscm.debian.org/viewvc/python-apps/packages/picard/trunk
Vcs-Svn: svn://anonscm.debian.org/python-apps/packages/picard/trunk/
@@ -21,7 +21,7 @@
Architecture: any
Depends: ${misc:Depends}, ${shlibs:Depends}, ${python:Depends},
python-qt4 (>= 4.5),
- python-mutagen (>= 1.20),
+ python-mutagen (>= 1.22),
python-libdiscid,
libchromaprint-tools
Suggests: hicolor-icon-theme
Added: packages/picard/trunk/debian/patches/mutagen.patch
===================================================================
--- packages/picard/trunk/debian/patches/mutagen.patch (rev 0)
+++ packages/picard/trunk/debian/patches/mutagen.patch 2016-08-27 12:04:05 UTC (rev 13568)
@@ -0,0 +1,424 @@
+Description: Remove various mutagen hacks which no longer work with newer mutagen
+Origin: upstream, https://github.com/metabrainz/picard/pull/479
+Last-Update: 2016-08-27
+
+--- a/picard/formats/id3.py
++++ b/picard/formats/id3.py
+@@ -32,39 +32,6 @@
+ from urlparse import urlparse
+
+
+-# Ugly, but... I need to save the text in ISO-8859-1 even if it contains
+-# unsupported characters and this better than encoding, decoding and
+-# again encoding.
+-def patched_EncodedTextSpec_write(self, frame, value):
+- try:
+- enc, term = self._encodings[frame.encoding]
+- except AttributeError:
+- enc, term = self.encodings[frame.encoding]
+- return value.encode(enc, 'ignore') + term
+-
+-id3.EncodedTextSpec.write = patched_EncodedTextSpec_write
+-
+-
+-# One more "monkey patch". The ID3 spec says that multiple text
+-# values should be _separated_ by the string terminator, which
+-# means that e.g. 'a\x00' are two values, 'a' and ''.
+-def patched_MultiSpec_write(self, frame, value):
+- data = self._write_orig(frame, value)
+- spec = self.specs[-1]
+- if isinstance(spec, id3.EncodedTextSpec):
+- try:
+- term = spec._encodings[frame.encoding][1]
+- except AttributeError:
+- term = spec.encodings[frame.encoding][1]
+- if data.endswith(term):
+- data = data[:-len(term)]
+- return data
+-
+-
+-id3.MultiSpec._write_orig = id3.MultiSpec.write
+-id3.MultiSpec.write = patched_MultiSpec_write
+-
+-
+ id3.TCMP = compatid3.TCMP
+ id3.TSO2 = compatid3.TSO2
+ id3.TSOC = compatid3.TSOC
+@@ -85,6 +52,16 @@
+ __ID3_REVERSE_IMAGE_TYPE_MAP = dict([(v, k) for k, v in __ID3_IMAGE_TYPE_MAP.iteritems()])
+
+
++def id3text(text, encoding):
++ """Returns a string which only contains code points which can
++ be encododed with the given numeric id3 encoding.
++ """
++
++ if encoding == 0:
++ return text.encode("latin1", "replace").decode("latin1")
++ return text
++
++
+ def image_type_from_id3_num(id3type):
+ return __ID3_REVERSE_IMAGE_TYPE_MAP.get(id3type, "other")
+
+@@ -311,14 +288,14 @@
+ text = '%s/%s' % (metadata['tracknumber'], metadata['totaltracks'])
+ else:
+ text = metadata['tracknumber']
+- tags.add(id3.TRCK(encoding=0, text=text))
++ tags.add(id3.TRCK(encoding=0, text=id3text(text, 0)))
+
+ if 'discnumber' in metadata:
+ if 'totaldiscs' in metadata:
+ text = '%s/%s' % (metadata['discnumber'], metadata['totaldiscs'])
+ else:
+ text = metadata['discnumber']
+- tags.add(id3.TPOS(encoding=0, text=text))
++ tags.add(id3.TPOS(encoding=0, text=id3text(text, 0)))
+
+ # This is necessary because mutagens HashKey for APIC frames only
+ # includes the FrameID (APIC) and description - it's basically
+@@ -336,7 +313,7 @@
+ tags.add(id3.APIC(encoding=0,
+ mime=image.mimetype,
+ type=image_type_as_id3_num(image.maintype),
+- desc=desctag,
++ desc=id3text(desctag, 0),
+ data=image.data))
+
+ tmcl = mutagen.id3.TMCL(encoding=encoding, people=[])
+@@ -344,6 +321,9 @@
+
+ tags.delall('TCMP')
+ for name, values in metadata.rawitems():
++ values = [id3text(v, encoding) for v in values]
++ name = id3text(name, encoding)
++
+ if name.startswith('performer:'):
+ role = name.split(':', 1)[1]
+ for value in values:
+@@ -420,11 +400,12 @@
+ tags.add(tipl)
+
+ if config.setting['write_id3v23']:
+- tags.update_to_v23(join_with=config.setting['id3v23_join_with'])
+- tags.save(encode_filename(filename), v2=3, v1=v1)
++ tags.update_to_v23()
++ separator = config.setting['id3v23_join_with']
++ tags.save(encode_filename(fielname), v2_version=3, v1=v1, v23_sep=separator)
+ else:
+ tags.update_to_v24()
+- tags.save(encode_filename(filename), v2=4, v1=v1)
++ tags.save(encode_filename(filename), v2_version=4, v1=v1)
+
+ if self._IsMP3 and config.setting["remove_ape_from_mp3"]:
+ try:
+--- a/picard/formats/mutagenext/compatid3.py
++++ b/picard/formats/mutagenext/compatid3.py
+@@ -18,12 +18,7 @@
+ # along with this program; if not, write to the Free Software
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+-import struct
+-from struct import pack, unpack
+-import mutagen
+-from mutagen._util import insert_bytes
+-from mutagen.id3 import ID3, Frames, Frames_2_2, TextFrame, TORY, \
+- TYER, TIME, APIC, IPLS, TDAT, BitPaddedInt, MakeID3v1
++from mutagen.id3 import ID3, Frames, Frames_2_2, TextFrame
+
+
+ class TCMP(TextFrame):
+@@ -50,14 +45,13 @@
+
+ """
+ Additional features over mutagen.id3.ID3:
+- * ID3v2.3 writing
+ * iTunes' TCMP frame
++ * Allow some v2.4 frames also in v2.3
+ """
+
+ PEDANTIC = False
+
+ def __init__(self, *args, **kwargs):
+- self.unknown_frames = []
+ if args:
+ known_frames = dict(Frames)
+ known_frames.update(dict(Frames_2_2))
+@@ -69,200 +63,13 @@
+ kwargs["known_frames"] = known_frames
+ super(CompatID3, self).__init__(*args, **kwargs)
+
+- def save(self, filename=None, v1=1, v2=4):
+- """Save changes to a file.
+-
+- If no filename is given, the one most recently loaded is used.
+-
+- Keyword arguments:
+- v1 -- if 0, ID3v1 tags will be removed
+- if 1, ID3v1 tags will be updated but not added
+- if 2, ID3v1 tags will be created and/or updated
+- v2 -- version of ID3v2 tags (3 or 4). By default Mutagen saves ID3v2.4
+- tags. If you want to save ID3v2.3 tags, you must call method
+- update_to_v23 before saving the file.
+-
+- The lack of a way to update only an ID3v1 tag is intentional.
+- """
+-
+- # Sort frames by 'importance'
+- order = ["TIT2", "TPE1", "TRCK", "TALB", "TPOS", "TDRC", "TCON"]
+- order = dict(zip(order, range(len(order))))
+- last = len(order)
+- frames = self.items()
+- frames.sort(lambda a, b: cmp(order.get(a[0][:4], last),
+- order.get(b[0][:4], last)))
+-
+- framedata = [self.__save_frame(frame, v2) for (key, frame) in frames]
+- framedata.extend([data for data in self.unknown_frames
+- if len(data) > 10])
+- if not framedata:
+- try:
+- self.delete(filename)
+- except EnvironmentError as err:
+- from errno import ENOENT
+- if err.errno != ENOENT:
+- raise
+- return
+-
+- framedata = ''.join(framedata)
+- framesize = len(framedata)
+-
+- if filename is None:
+- filename = self.filename
+- try:
+- f = open(filename, 'rb+')
+- except IOError as err:
+- from errno import ENOENT
+- if err.errno != ENOENT:
+- raise
+- f = open(filename, 'ab') # create, then reopen
+- f = open(filename, 'rb+')
+- try:
+- idata = f.read(10)
+- try:
+- id3, vmaj, vrev, flags, insize = unpack('>3sBBB4s', idata)
+- except struct.error:
+- id3, insize = '', 0
+- insize = BitPaddedInt(insize)
+- if id3 != 'ID3':
+- insize = -10
+-
+- if insize >= framesize:
+- outsize = insize
+- else:
+- outsize = (framesize + 1023) & ~0x3FF
+- framedata += '\x00' * (outsize - framesize)
+-
+- framesize = BitPaddedInt.to_str(outsize, width=4)
+- flags = 0
+- header = pack('>3sBBB4s', 'ID3', v2, 0, flags, framesize)
+- data = header + framedata
+-
+- if (insize < outsize):
+- insert_bytes(f, outsize - insize, insize + 10)
+- f.seek(0)
+- f.write(data)
+-
+- try:
+- f.seek(-128, 2)
+- except IOError as err:
+- from errno import EINVAL
+- if err.errno != EINVAL:
+- raise
+- f.seek(0, 2) # ensure read won't get "TAG"
+-
+- if f.read(3) == "TAG":
+- f.seek(-128, 2)
+- if v1 > 0:
+- f.write(MakeID3v1(self))
+- else:
+- f.truncate()
+- elif v1 == 2:
+- f.seek(0, 2)
+- f.write(MakeID3v1(self))
+-
+- finally:
+- f.close()
+-
+- def __save_frame(self, frame, v2):
+- flags = 0
+- if self.PEDANTIC and isinstance(frame, TextFrame):
+- if len(str(frame)) == 0:
+- return ''
+- framedata = frame._writeData()
+- if v2 == 3:
+- bits = 8
+- else:
+- bits = 7
+- datasize = BitPaddedInt.to_str(len(framedata), width=4, bits=bits)
+- header = pack('>4s4sH', type(frame).__name__, datasize, flags)
+- return header + framedata
+-
+- def update_to_v23(self, join_with="/"):
+- """Convert older (and newer) tags into an ID3v2.3 tag.
+-
+- This updates incompatible ID3v2 frames to ID3v2.3 ones. If you
+- intend to save tags as ID3v2.3, you must call this function
+- at some point.
+- """
+-
+- if self.version < (2, 3, 0):
+- del self.unknown_frames[:]
+-
+- # TMCL, TIPL -> TIPL
+- if "TIPL" in self or "TMCL" in self:
+- people = []
+- if "TIPL" in self:
+- f = self.pop("TIPL")
+- people.extend(f.people)
+- if "TMCL" in self:
+- f = self.pop("TMCL")
+- people.extend(f.people)
+- if "IPLS" not in self:
+- self.add(IPLS(encoding=f.encoding, people=people))
+-
+- # TODO:
+- # * EQU2 -> EQUA
+- # * RVA2 -> RVAD
+-
+- # TDOR -> TORY
+- if "TDOR" in self:
+- f = self.pop("TDOR")
+- if f.text:
+- d = f.text[0]
+- if d.year and "TORY" not in self:
+- self.add(TORY(encoding=f.encoding, text="%04d" % d.year))
+-
+- # TDRC -> TYER, TDAT, TIME
+- if "TDRC" in self:
+- f = self.pop("TDRC")
+- if f.text:
+- d = f.text[0]
+- if d.year and "TYER" not in self:
+- self.add(TYER(encoding=f.encoding, text="%04d" % d.year))
+- if d.month and d.day and "TDAT" not in self:
+- self.add(TDAT(encoding=f.encoding, text="%02d%02d" % (d.day, d.month)))
+- if d.hour and d.minute and "TIME" not in self:
+- self.add(TIME(encoding=f.encoding, text="%02d%02d" % (d.hour, d.minute)))
+-
+- if "TCON" in self:
+- self["TCON"].genres = self["TCON"].genres
+-
+- if self.version < (2, 3):
+- # ID3v2.2 PIC frames are slightly different.
+- pics = self.getall("APIC")
+- mimes = {
+- "PNG": "image/png",
+- "JPG": "image/jpeg"
+- }
+- self.delall("APIC")
+- for pic in pics:
+- newpic = APIC(
+- encoding=pic.encoding, mime=mimes.get(pic.mime, pic.mime),
+- type=pic.type, desc=pic.desc, data=pic.data)
+- self.add(newpic)
+-
+- # ID3v2.2 LNK frames are just way too different to upgrade.
+- self.delall("LINK")
+-
++ def update_to_v23(self):
+ # leave TSOP, TSOA and TSOT even though they are officially defined
+ # only in ID3v2.4, because most applications use them also in ID3v2.3
+
+- # New frames added in v2.4.
+- for key in ["ASPI", "EQU2", "RVA2", "SEEK", "SIGN", "TDRL", "TDTG",
+- "TMOO", "TPRO"]:
+- if key in self:
+- del(self[key])
+-
+- for frame in self.values():
+- # ID3v2.3 doesn't support UTF-8 (and WMP can't read UTF-16 BE)
+- if hasattr(frame, "encoding"):
+- if frame.encoding > 1:
+- frame.encoding = 1
+- # ID3v2.3 doesn't support multiple values
+- if isinstance(frame, mutagen.id3.TextFrame):
+- try:
+- frame.text = [join_with.join(frame.text)]
+- except TypeError:
+- frame.text = frame.text[:1]
++ frames = []
++ for key in ["TSOP", "TSOA", "TSOT"]:
++ frames.extend(self.getall(key))
++ super(CompatID3, self).update_to_v23()
++ for frame in frames:
++ self.add(frame)
+--- a/test/test_compatid3.py
++++ b/test/test_compatid3.py
+@@ -3,23 +3,26 @@
+ import unittest
+ from mutagen import id3
+ from picard.formats.mutagenext import compatid3
++from picard.formats.id3 import id3text
+
+
+ class UpdateToV23Test(unittest.TestCase):
+
+- def test_multiple_text_values(self):
+- tags = compatid3.CompatID3()
+- tags.add(id3.TALB(encoding=0, text=["123", "abc"]))
+- tags.update_to_v23()
+- self.assertEqual(tags["TALB"].text, ["123/abc"])
+-
+- def test_encoding(self):
+- tags = compatid3.CompatID3()
+- tags.add(id3.TALB(encoding=2, text="abc"))
+- tags.add(id3.TIT2(encoding=3, text="abc"))
+- tags.update_to_v23()
+- self.assertEqual(tags["TALB"].encoding, 1)
+- self.assertEqual(tags["TIT2"].encoding, 1)
++ def test_id3text(self):
++ self.assertEqual(id3text(u"\u1234", 0), u"?")
++ self.assertEqual(id3text(u"\u1234", 1), u"\u1234")
++ self.assertEqual(id3text(u"\u1234", 2), u"\u1234")
++ self.assertEqual(id3text(u"\u1234", 3), u"\u1234")
++
++ def test_keep_some_v24_tag(self):
++ tags = compatid3.CompatID3()
++ tags.add(id3.TSOP(encoding=0, text=["foo"]))
++ tags.add(id3.TSOA(encoding=0, text=["foo"]))
++ tags.add(id3.TSOT(encoding=0, text=["foo"]))
++ tags.update_to_v23()
++ self.assertEqual(tags["TSOP"].text, ["foo"])
++ self.assertEqual(tags["TSOA"].text, ["foo"])
++ self.assertEqual(tags["TSOT"].text, ["foo"])
+
+ def test_tdrc(self):
+ tags = compatid3.CompatID3()
+@@ -39,22 +42,22 @@
+ tags = compatid3.CompatID3()
+ tags.add(id3.TCON(encoding=1, text=["4", "Rock"]))
+ tags.update_to_v23()
+- self.assertEqual(tags["TCON"].text, ["Disco/Rock"])
++ self.assertEqual(tags["TCON"].text, ["Disco", "Rock"])
+
+ def test_genre_from_v24_2(self):
+ tags = compatid3.CompatID3()
+ tags.add(id3.TCON(encoding=1, text=["RX", "3", "CR"]))
+ tags.update_to_v23()
+- self.assertEqual(tags["TCON"].text, ["Remix/Dance/Cover"])
++ self.assertEqual(tags["TCON"].text, ["Remix", "Dance", "Cover"])
+
+ def test_genre_from_v23_1(self):
+ tags = compatid3.CompatID3()
+ tags.add(id3.TCON(encoding=1, text=["(4)Rock"]))
+ tags.update_to_v23()
+- self.assertEqual(tags["TCON"].text, ["Disco/Rock"])
++ self.assertEqual(tags["TCON"].text, ["Disco", "Rock"])
+
+ def test_genre_from_v23_2(self):
+ tags = compatid3.CompatID3()
+ tags.add(id3.TCON(encoding=1, text=["(RX)(3)(CR)"]))
+ tags.update_to_v23()
+- self.assertEqual(tags["TCON"].text, ["Remix/Dance/Cover"])
++ self.assertEqual(tags["TCON"].text, ["Remix", "Dance", "Cover"])
Added: packages/picard/trunk/debian/patches/series
===================================================================
--- packages/picard/trunk/debian/patches/series (rev 0)
+++ packages/picard/trunk/debian/patches/series 2016-08-27 12:04:05 UTC (rev 13568)
@@ -0,0 +1 @@
+mutagen.patch
Modified: packages/picard/trunk/debian/rules
===================================================================
--- packages/picard/trunk/debian/rules 2016-08-26 21:44:07 UTC (rev 13567)
+++ packages/picard/trunk/debian/rules 2016-08-27 12:04:05 UTC (rev 13568)
@@ -7,6 +7,8 @@
--install-scripts=/usr/lib/picard \
--install-lib=/usr/lib/picard
+export LC_ALL=C.UTF-8
+
DESTDIR = $(CURDIR)/debian/picard
%:
More information about the Python-apps-commits
mailing list