[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