[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#989500: marked as done (unblock eyed3/0.8.10-4)



Your message dated Mon, 28 Jun 2021 21:41:28 +0200
with message-id <52fb74b4-9ac3-f16b-6b34-8f131e55135d@debian.org>
and subject line Re: unblock eyed3/0.8.10-4
has caused the Debian Bug report #989500,
regarding unblock eyed3/0.8.10-4
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
989500: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=989500
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Subject: unblock: eyed3/0.8.10-4
Package: release.debian.org
User: release.debian.org@packages.debian.org
Usertags: unblock
Severity: normal

Please unblock package eyed3

Package is not blocked, but it is marked for removal from
testing on 16 Jun and the auto migration period expires on 22 Jun.

There are no other excuses preventing the migration:
https://qa.debian.org/excuses.php?package=eyed3

[ Reason ]
New version in sid fixes the RC bug which is causing the autoremoval.

[ Impact ]
eyed3 would be removed from testing and so from bullseye.

[ Tests ]
It was manually tested that the fix for the RC bug effectly works.
Existing autopkgtests ensure general package functionality.

[ Other info ]
The fix is to completely remove a file with a debian patch (a plugin
which needs a library not packaged in debian).

The patch to remove the plugin was already packaged but it broke
during an upstream version update.

The plugin is already not working in testing.

[ Checklist ]
  [x] all changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in testing


unblock eyed3/0.8.10-4

Gaetano Guerriero
diff -Nru eyed3-0.8.10/debian/changelog eyed3-0.8.10/debian/changelog
--- eyed3-0.8.10/debian/changelog	2020-03-18 21:02:56.000000000 +0100
+++ eyed3-0.8.10/debian/changelog	2021-06-02 07:13:19.000000000 +0200
@@ -1,3 +1,32 @@
+eyed3 (0.8.10-4) unstable; urgency=medium
+
+  * Source only upload, to recover from previous binary upload.
+
+  * Upload sponsored by Petter Reinholdtsen.
+
+ -- Gaetano Guerriero <x.guerriero@tin.it>  Wed, 02 Jun 2021 07:13:19 +0200
+
+eyed3 (0.8.10-3) unstable; urgency=medium
+
+  * Fix autopkgtest generating sometimes output on stderr (Closes: #989356)
+
+  * Upload sponsored by Petter Reinholdtsen.
+
+ -- Gaetano Guerriero <x.guerriero@tin.it>  Tue, 01 Jun 2021 18:04:57 +0200
+
+eyed3 (0.8.10-2) unstable; urgency=medium
+
+  * Add patch to support pylast 3, backported from upstream
+    (Closes: #945371)
+  * Fix patch remove-display-plugin to really disable the plugin
+    (Closes: #988738)
+  * Add more autopkgtests and flag the original ones
+    with Restrictions: superficial (Closes: #974444)
+
+  * Upload sponsored by Petter Reinholdtsen.
+
+ -- Gaetano Guerriero <x.guerriero@tin.it>  Mon, 31 May 2021 15:02:53 +0200
+
 eyed3 (0.8.10-1.1) unstable; urgency=medium
 
   * Non-maintainer upload.
diff -Nru eyed3-0.8.10/debian/patches/remove-display-plugin eyed3-0.8.10/debian/patches/remove-display-plugin
--- eyed3-0.8.10/debian/patches/remove-display-plugin	2019-01-02 14:59:00.000000000 +0100
+++ eyed3-0.8.10/debian/patches/remove-display-plugin	2021-05-31 15:10:57.000000000 +0200
@@ -267,3 +267,1152 @@
 -        whitespace=args.whitespace,
 -        nameguard=not args.no_nameguard
 -    )
+--- a/src/eyed3/plugins/display.py
++++ /dev/null
+@@ -1,1146 +0,0 @@
+-# -*- coding: utf-8 -*-
+-################################################################################
+-#  Copyright (C) 2014-2016  Sebastian Patschorke <physicspatschi@gmx.de>
+-#
+-#  This program is free software; you can redistribute it and/or modify
+-#  it under the terms of the GNU General Public License as published by
+-#  the Free Software Foundation; either version 2 of the License, or
+-#  (at your option) any later version.
+-#
+-#  This program is distributed in the hope that it will be useful,
+-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-#  GNU General Public License for more details.
+-#
+-#  You should have received a copy of the GNU General Public License
+-#  along with this program; if not, see <http://www.gnu.org/licenses/>.
+-#
+-################################################################################
+-from __future__ import print_function
+-import os
+-import re
+-import abc
+-
+-from argparse import ArgumentTypeError
+-
+-from eyed3 import id3, compat
+-from eyed3.utils import console, formatSize, formatTime
+-from eyed3.plugins import LoaderPlugin
+-try:
+-    from eyed3.plugins._display_parser import DisplayPatternParser
+-    _have_grako = True
+-except ImportError:
+-    _have_grako = False
+-
+-
+-class Pattern(object):
+-
+-    def __init__(self, text=None, sub_patterns=None):
+-        self.__text = text
+-        self.__sub_patterns = sub_patterns
+-
+-    def output_for(self, audio_file):
+-        output = u""
+-        for sub_pattern in self.sub_patterns or []:
+-            output += sub_pattern.output_for(audio_file)
+-        return output
+-
+-    def __get_sub_patterns(self):
+-        if self.__sub_patterns is None and self.__text is not None:
+-            self.__compile()
+-        return self.__sub_patterns
+-
+-    def __set_sub_patterns(self, sub_patterns):
+-        self.__sub_patterns = sub_patterns
+-
+-    sub_patterns = property(__get_sub_patterns, __set_sub_patterns)
+-
+-    def __compile(self):
+-        # TODO: add support for comments in pattern
+-        parser = DisplayPatternParser(whitespace='')
+-        try:
+-            asts = parser.parse(self.__text, rule_name='start')
+-            self.sub_patterns = self.__compile_asts(asts)
+-            self.__text = None
+-        except BaseException as parsing_error:
+-            raise PatternCompileException(compat.unicode(parsing_error))
+-
+-    def __compile_asts(self, asts):
+-        patterns = []
+-        for ast in asts:
+-            patterns.append(self.__compile_ast(ast))
+-        return patterns
+-
+-    def __compile_ast(self, ast):
+-        if ast is None:
+-            return None
+-        if "text" in ast:
+-            return TextPattern(ast["text"])
+-        if "tag" in ast:
+-            parameters = self.__compile_parameters(ast["parameters"])
+-            return self.__create_complex_pattern(TagPattern, ast["name"],
+-                                                 parameters)
+-        if "function" in ast:
+-            parameters = self.__compile_parameters(ast["parameters"])
+-            if len(parameters) == 1 and parameters[0][0] is None and len(
+-                    parameters[0][1].sub_patterns) == 0:
+-                parameters = []
+-            return self.__create_complex_pattern(FunctionPattern, ast["name"],
+-                                                 parameters)
+-
+-    def __compile_parameters(self, parameter_asts):
+-        parameters = []
+-        for parameter_ast in parameter_asts:
+-            sub_patterns = self.__compile_asts(parameter_ast["value"])
+-            parameters.append((parameter_ast["name"],
+-                               Pattern(sub_patterns=sub_patterns)))
+-        return parameters
+-
+-    def __create_complex_pattern(self, base_class, class_name, parameters):
+-        pattern_class = self.__find_pattern_class(base_class, class_name)
+-        if pattern_class is not None:
+-            return pattern_class(class_name, parameters)
+-        raise PatternCompileException("Unknown " + base_class.TYPE + " '" +
+-                                      class_name + "'")
+-
+-    def __find_pattern_class(self, base_class, class_name):
+-        for pattern_class in Pattern.sub_pattern_classes(base_class):
+-            if class_name in pattern_class.NAMES:
+-                return pattern_class
+-
+-    @staticmethod
+-    def sub_pattern_classes(base_class):
+-        sub_classes = []
+-        for pattern_class in base_class.__subclasses__():
+-            if len(pattern_class.__subclasses__()) > 0:
+-                sub_classes.extend(Pattern.sub_pattern_classes(pattern_class))
+-                continue
+-            sub_classes.append(pattern_class)
+-        return sub_classes
+-
+-    @staticmethod
+-    def pattern_class_parameters(pattern_class):
+-        try:
+-            return pattern_class.PARAMETERS
+-        except AttributeError:
+-            return []
+-
+-    def __repr__(self):
+-        return self.__str__()
+-
+-    def __str__(self):
+-        return str(self.__sub_patterns)
+-
+-
+-class TextPattern(Pattern):
+-    SPECIAL_CHARACTERS = list("\\%$,()=nt")
+-    SPECIAL_CHARACTERS_DESCRIPTIONS = list("\\%$,()=") + ["New line", "Tab"]
+-
+-    def __init__(self, text):
+-        super(TextPattern, self).__init__(text)
+-        self.__text = text
+-        self.__replace_escapes()
+-
+-    def __replace_escapes(self):
+-        escape_matches = list(re.compile('\\\\.').finditer(self.__text))
+-        escape_matches.reverse()
+-        for escape_match in escape_matches:
+-            character = self.__text[escape_match.end() - 1]
+-            if character not in TextPattern.SPECIAL_CHARACTERS:
+-                raise PatternCompileException("Unknown escape character '" +
+-                                              character + "'")
+-            if character == 'n':
+-                character = os.linesep
+-            if character == 't':
+-                character = '\t'
+-            self.__text = self.__text[:escape_match.start()] + character + \
+-                          self.__text[escape_match.end():]
+-
+-    def output_for(self, audio_file):
+-        return self.__text
+-
+-    def __str__(self):
+-        return "text:" + self.__text
+-
+-
+-class ComplexPattern(Pattern):
+-    __metaclass__ = abc.ABCMeta
+-
+-    TYPE = "unknown"
+-    NAMES = []
+-    DESCRIPTION = ""
+-    PARAMETERS = []
+-
+-    class ExpectedParameter(object):
+-        def __init__(self, name, **kwargs):
+-            self.name = name
+-            if "default" in kwargs:
+-                self.requried = False
+-                self.default = kwargs["default"]
+-            else:
+-                self.requried = True
+-
+-        def __repr__(self):
+-            return self.__str__()
+-
+-        def __str__(self):
+-            if self.requried:
+-                return self.name
+-            return self.name + "(" + str(self.default) + ")"
+-
+-    class Parameter(object):
+-        def __init__(self, value, provided):
+-            self.value = value
+-            self.provided = provided
+-
+-        def __repr__(self):
+-            return self.__str__()
+-
+-        def __str__(self):
+-            return str(self.value) + "(" + str(self.provided) + ")"
+-
+-    def __init__(self, name, parameters):
+-        super(ComplexPattern, self).__init__()
+-        self.__name = name
+-        self.__import_parameters(parameters)
+-
+-    def output_for(self, audio_file):
+-        output = self._get_output_for(audio_file)
+-        return output or ""
+-
+-    @abc.abstractmethod
+-    def _get_output_for(self, audio_file):
+-        pass
+-
+-    def __import_parameters(self, parameters):
+-        expected_parameters = Pattern.pattern_class_parameters(self.__class__)
+-        self.__parameters = {}
+-        for expected_parameter in expected_parameters:
+-            found = False
+-            for parameter in parameters:
+-                if (parameter[0] is None or
+-                        parameter[0] == expected_parameter.name):
+-                    self.__parameters[expected_parameter.name] = \
+-                        ComplexPattern.Parameter(parameter[1], True)
+-                    parameters.remove(parameter)
+-                    found = True
+-                    break
+-                if parameter[0] is not None:
+-                    break
+-                if not expected_parameter.requried:
+-                    self.__parameters[expected_parameter.name] = \
+-                        ComplexPattern.Parameter(
+-                            Pattern(text=expected_parameter.default), True)
+-                    found = True
+-                    break
+-                raise PatternCompileException(
+-                    self._error_message("Unexpected parameter"))
+-            if not found:
+-                if expected_parameter.requried:
+-                    raise PatternCompileException(self._error_message(
+-                        "Missing required parameter '" +
+-                        expected_parameter.name + "'"))
+-                self.__parameters[expected_parameter.name] = \
+-                    ComplexPattern.Parameter(
+-                                Pattern(text=expected_parameter.default), False)
+-        if len(parameters) > 0:
+-            raise PatternCompileException(
+-                    self._error_message("Unexpected parameter"))
+-
+-    def __get_parameters(self):
+-        return self.__parameters
+-
+-    parameters = property(__get_parameters)
+-
+-    def _parameter_value(self, name, audio_file):
+-        return self.parameters[name].value.output_for(audio_file)
+-
+-    def _parameter_bool(self, name, audio_file):
+-        value = self._parameter_value(name, audio_file)
+-        return value.lower() in ("yes", "true", "y", "t", "1", "on")
+-
+-    def __get_name(self):
+-        return self.__name
+-
+-    name = property(__get_name)
+-
+-    def _error_message(self, message):
+-        return self.TYPE.capitalize() + " " + self.__name + ": " + message
+-
+-    def __str__(self):
+-        return self.TYPE + ":" + self.name + str(self.parameters)
+-
+-
+-class PlaceholderUsagePattern(object):
+-    __metaclass__ = abc.ABCMeta
+-
+-    def _replace_placeholders(self, text, replacements):
+-        if len(replacements) == 0:
+-            return text
+-
+-        replacement = replacements.pop(0)
+-        subtexts = []
+-        for subtext in text.split(replacement[0]):
+-            subtexts.append(
+-                    self._replace_placeholders(subtext, list(replacements)))
+-        return (str(replacement[1]) or "").join(subtexts)
+-
+-
+-class TagPattern(ComplexPattern):
+-    __metaclass__ = abc.ABCMeta
+-    TYPE = "tag"
+-
+-
+-class ArtistTagPattern(TagPattern):
+-    NAMES = ["a", "artist"]
+-    DESCRIPTION = "Artist"
+-
+-    def _get_output_for(self, audio_file):
+-        return audio_file.tag.artist
+-
+-
+-class AlbumTagPattern(TagPattern):
+-    NAMES = ["A", "album"]
+-    DESCRIPTION = "Album"
+-
+-    def _get_output_for(self, audio_file):
+-        return audio_file.tag.album
+-
+-
+-class AlbumArtistTagPattern(TagPattern):
+-    NAMES = ["b", "album-artist"]
+-    DESCRIPTION = "Album artist"
+-
+-    def _get_output_for(self, audio_file):
+-        return audio_file.tag.album_artist
+-
+-
+-class ComposerTagPattern(TagPattern):
+-    NAMES = ["C", "composer"]
+-    DESCRIPTION = "Composer"
+-
+-    def _get_output_for(self, audio_file):
+-        return audio_file.tag.composer
+-
+-
+-class TitleTagPattern(TagPattern):
+-    NAMES = ["t", "title"]
+-    DESCRIPTION = "Title"
+-
+-    def _get_output_for(self, audio_file):
+-        return audio_file.tag.title
+-
+-
+-class TrackTagPattern(TagPattern):
+-    NAMES = ["n", "track"]
+-    DESCRIPTION = "Track number"
+-
+-    def _get_output_for(self, audio_file):
+-        n = audio_file.tag.track_num[0]
+-        return str(n or "")
+-
+-
+-class TrackTotalTagPattern(TagPattern):
+-    NAMES = ["N", "track-total"]
+-    DESCRIPTION = "Total track number"
+-
+-    def _get_output_for(self, audio_file):
+-        n = audio_file.tag.track_num[1]
+-        return str(n or "")
+-
+-
+-class DiscTagPattern(TagPattern):
+-    NAMES = ["d", "disc", "disc-num"]
+-    DESCRIPTION = "Disc number"
+-
+-    def _get_output_for(self, audio_file):
+-        n = audio_file.tag.disc_num[0]
+-        return str(n or "")
+-
+-
+-class DiscTotalTagPattern(TagPattern):
+-    NAMES = ["D", "disc-total"]
+-    DESCRIPTION = "Total disc number"
+-
+-    def _get_output_for(self, audio_file):
+-        n = audio_file.tag.disc_num[1]
+-        return str(n or "")
+-
+-
+-class GenreTagPattern(TagPattern):
+-    NAMES = ["G", "genre"]
+-    DESCRIPTION = "Genre"
+-
+-    def _get_output_for(self, audio_file):
+-        return audio_file.tag.genre.name
+-
+-
+-class GenreIdTagPattern(TagPattern):
+-    NAMES = ["genre-id"]
+-    DESCRIPTION = "Genre ID"
+-
+-    def _get_output_for(self, audio_file):
+-        return str(audio_file.tag.genre.id) if audio_file.tag.genre else None
+-
+-
+-class YearTagPattern(TagPattern):
+-    NAMES = ["Y", "year"]
+-    DESCRIPTION = "Release year"
+-
+-    def _get_output_for(self, audio_file):
+-        return audio_file.tag.release_date.year
+-
+-
+-class DescriptableTagPattern(TagPattern):
+-    __metaclass__ = abc.ABCMeta
+-
+-    PARAMETERS = [ComplexPattern.ExpectedParameter("description", default=None),
+-                  ComplexPattern.ExpectedParameter("language", default=None)]
+-
+-    def _get_matching_elements(self, elements, audio_file):
+-        matching_elements = []
+-        for element in elements:
+-            if (self.__matches("description", element.description,
+-                               audio_file) and
+-                    self.__matches("language", element.lang, audio_file)):
+-                matching_elements.append(element)
+-        return matching_elements
+-
+-    def __matches(self, parameter_name, comment_attribute_value, audio_file):
+-        if not self.parameters[parameter_name].provided:
+-            return True
+-        if self.parameters[parameter_name].value is None:
+-            return (comment_attribute_value is None or
+-                    comment_attribute_value == "")
+-        return (self._parameter_value(parameter_name, audio_file) ==
+-                comment_attribute_value)
+-
+-
+-class CommentTagPattern(DescriptableTagPattern):
+-    NAMES = ["c", "comment"]
+-    PARAMETERS = DescriptableTagPattern.PARAMETERS
+-    DESCRIPTION = "First comment that matches description and language."
+-
+-    def _get_output_for(self, audio_file):
+-        matching_comments = self._get_matching_elements(audio_file.tag.comments,
+-                                                        audio_file)
+-        return matching_comments[0].text if len(matching_comments) > 0 else None
+-
+-
+-class AllCommentsTagPattern(DescriptableTagPattern, PlaceholderUsagePattern):
+-    NAMES = ["comments"]
+-    PARAMETERS = DescriptableTagPattern.PARAMETERS + \
+-                 [ComplexPattern.ExpectedParameter("output",
+-                        default="Comment: [Description: #d] [Lang: #l]: #t"),
+-                  ComplexPattern.ExpectedParameter("separation", default="\\n")]
+-    DESCRIPTION = "All comments that are matching description and language " \
+-                  "(with output placeholders #d as description, #l as " \
+-                  " language & #t as text)."
+-
+-    def _get_output_for(self, audio_file):
+-        output_pattern = self._parameter_value("output", audio_file)
+-        separation = self._parameter_value("separation", audio_file)
+-        outputs = []
+-        for comment in self._get_matching_elements(audio_file.tag.comments,
+-                                                   audio_file):
+-            replacements = [["#d", comment.description],
+-                            ["#l", comment.lang.decode("ascii")],
+-                            ["#t", comment.text]]
+-            outputs.append(self._replace_placeholders(output_pattern,
+-                                                      replacements))
+-        return separation.join(outputs)
+-
+-
+-class AbstractDateTagPattern(TagPattern):
+-    __metaclass__ = abc.ABCMeta
+-
+-    def _get_output_for(self, audio_file):
+-        return str(self._get_date(audio_file) or "")
+-
+-    @abc.abstractmethod
+-    def _get_date(self, audio_file):
+-        pass
+-
+-
+-class ReleaseDateTagPattern(AbstractDateTagPattern):
+-    NAMES = ["release-date"]
+-    DESCRIPTION = "Relase date"
+-
+-    def _get_date(self, audio_file):
+-        return audio_file.tag.release_date
+-
+-
+-class OriginalReleaseDateTagPattern(AbstractDateTagPattern):
+-    NAMES = ["original-release-date"]
+-    DESCRIPTION = "Original Relase date"
+-
+-    def _get_date(self, audio_file):
+-        return audio_file.tag.original_release_date
+-
+-
+-class RecordingDateTagPattern(AbstractDateTagPattern):
+-    NAMES = ["recording-date"]
+-    DESCRIPTION = "Recording date"
+-
+-    def _get_date(self, audio_file):
+-        return audio_file.tag.recording_date
+-
+-
+-class EncodingDateTagPattern(AbstractDateTagPattern):
+-    NAMES = ["encoding-date"]
+-    DESCRIPTION = "Encoding date"
+-
+-    def _get_date(self, audio_file):
+-        return audio_file.tag.encoding_date
+-
+-
+-class TaggingDateTagPattern(AbstractDateTagPattern):
+-    NAMES = ["tagging-date"]
+-    DESCRIPTION = "Tagging date"
+-
+-    def _get_date(self, audio_file):
+-        return audio_file.tag.tagging_date
+-
+-
+-class PlayCountTagPattern(TagPattern):
+-    NAMES = ["play-count"]
+-    DESCRIPTION = "Play count"
+-
+-    def _get_output_for(self, audio_file):
+-        return audio_file.tag.play_count
+-
+-
+-class PopularitiesTagPattern(TagPattern, PlaceholderUsagePattern):
+-    NAMES = ["popm", "popularities"]
+-    PARAMETERS = [ComplexPattern.ExpectedParameter("output",
+-            default="Popularity: [email: #e] [rating: #r] [play count: #c]"),
+-                  ComplexPattern.ExpectedParameter("separation", default="\\n")]
+-    DESCRIPTION = "Popularities (with output placeholders #e as email, "\
+-                  "#r as rating & #c as count)"
+-
+-    def _get_output_for(self, audio_file):
+-        output_pattern = self._parameter_value("output", audio_file)
+-        separation = self._parameter_value("separation", audio_file)
+-
+-        outputs = []
+-        for popularity in audio_file.tag.popularities:
+-            replacements = [["#e", popularity.email],
+-                            ["#r", popularity.rating],
+-                            ["#c", popularity.count]]
+-            outputs.append(self._replace_placeholders(output_pattern,
+-                                                      replacements))
+-        return separation.join(outputs)
+-
+-
+-class BPMTagPattern(TagPattern):
+-    NAMES = ["bpm"]
+-    DESCRIPTION = "BPM"
+-
+-    def _get_output_for(self, audio_file):
+-        return audio_file.tag.bpm
+-
+-
+-class PublisherTagPattern(TagPattern):
+-    NAMES = ["publisher"]
+-    DESCRIPTION = "Publisher"
+-
+-    def _get_output_for(self, audio_file):
+-        return audio_file.tag.publisher
+-
+-
+-class UniqueFileIDTagPattern(TagPattern, PlaceholderUsagePattern):
+-    NAMES = ["ufids", "unique-file-ids"]
+-    PARAMETERS = [ComplexPattern.ExpectedParameter("output",
+-                                        default="Unique File ID: [#o] : #i"),
+-                  ComplexPattern.ExpectedParameter("separation", default="\\n")]
+-    DESCRIPTION = "Unique File IDs (with output placeholders #o as owner & #i "\
+-                  " as unique id)"
+-
+-    def _get_output_for(self, audio_file):
+-        output_pattern = self._parameter_value("output", audio_file)
+-        separation = self._parameter_value("separation", audio_file)
+-
+-        outputs = []
+-        for ufid in audio_file.tag.unique_file_ids:
+-            replacements = [["#o", ufid.owner_id],
+-                            ["#i", ufid.uniq_id.encode("string_escape")]]
+-            outputs.append(self._replace_placeholders(output_pattern,
+-                                                      replacements))
+-        return separation.join(outputs)
+-
+-
+-class LyricsTagPattern(DescriptableTagPattern, PlaceholderUsagePattern):
+-    NAMES = ["lyrics"]
+-    PARAMETERS = DescriptableTagPattern.PARAMETERS + \
+-                 [ComplexPattern.ExpectedParameter(
+-                     "output",
+-                     default="Lyrics: [Description: #d] [Lang: #l]: #t"),
+-                  ComplexPattern.ExpectedParameter("separation", default="\\n")]
+-    DESCRIPTION = "All lyrics that are matching description and language " + \
+-                  "(with output placeholders #d as description, #l as "\
+-                  "language & #t as text)."
+-
+-    def _get_output_for(self, audio_file):
+-        output_pattern = self._parameter_value("output", audio_file)
+-        separation = self._parameter_value("separation", audio_file)
+-
+-        outputs = []
+-        for l in self._get_matching_elements(audio_file.tag.lyrics, audio_file):
+-            replacements = [["#d", l.description],
+-                            ["#l", l.lang.decode("ascii")],
+-                            ["#t", l.text]]
+-            outputs.append(self._replace_placeholders(output_pattern,
+-                                                      replacements))
+-        return separation.join(outputs)
+-
+-
+-class TextsTagPattern(TagPattern, PlaceholderUsagePattern):
+-    NAMES = ["txxx", "texts"]
+-    PARAMETERS = [
+-        ComplexPattern.ExpectedParameter(
+-            "output", default="UserTextFrame: [Description: #d] #t"),
+-        ComplexPattern.ExpectedParameter("separation", default="\\n")]
+-    DESCRIPTION = "User text frames (with output placeholders #d as "\
+-                  "description & #t as text)"
+-
+-    def _get_output_for(self, audio_file):
+-        output_pattern = self._parameter_value("output", audio_file)
+-        separation = self._parameter_value("separation", audio_file)
+-
+-        outputs = []
+-        for frame in audio_file.tag.user_text_frames:
+-            replacements = [["#d", frame.description],
+-                            ["#t", frame.text]]
+-            outputs.append(self._replace_placeholders(output_pattern,
+-                                                      replacements))
+-        return separation.join(outputs)
+-
+-
+-class ArtistURLTagPattern(TagPattern):
+-    NAMES = ["artist-url"]
+-    DESCRIPTION = "Artist URL"
+-
+-    def _get_output_for(self, audio_file):
+-        return audio_file.tag.artist_url
+-
+-
+-class AudioSourceURLTagPattern(TagPattern):
+-    NAMES = ["audio-source-url"]
+-    DESCRIPTION = "Audio source URL"
+-
+-    def _get_output_for(self, audio_file):
+-        return audio_file.tag.audio_source_url
+-
+-
+-class AudioFileURLTagPattern(TagPattern):
+-    NAMES = ["audio-file-url"]
+-    DESCRIPTION = "Audio file URL"
+-
+-    def _get_output_for(self, audio_file):
+-        return audio_file.tag.audio_file_url
+-
+-
+-class InternetRadioURLTagPattern(TagPattern):
+-    NAMES = ["internet-radio-url"]
+-    DESCRIPTION = "Internet radio URL"
+-
+-    def _get_output_for(self, audio_file):
+-        return audio_file.tag.internet_radio_url
+-
+-
+-class CommercialURLTagPattern(TagPattern):
+-    NAMES = ["commercial-url"]
+-    DESCRIPTION = "Comercial URL"
+-
+-    def _get_output_for(self, audio_file):
+-        return audio_file.tag.copyright_url
+-
+-
+-class PaymentURLTagPattern(TagPattern):
+-    NAMES = ["payment-url"]
+-    DESCRIPTION = "Payment URL"
+-
+-    def _get_output_for(self, audio_file):
+-        return audio_file.tag.payment_url
+-
+-
+-class PublisherURLTagPattern(TagPattern):
+-    NAMES = ["publisher-url"]
+-    DESCRIPTION = "Publisher URL"
+-
+-    def _get_output_for(self, audio_file):
+-        return audio_file.tag.publisher_url
+-
+-
+-class CopyrightTagPattern(TagPattern):
+-    NAMES = ["copyright-url"]
+-    DESCRIPTION = "Copyright URL"
+-
+-    def _get_output_for(self, audio_file):
+-        return audio_file.tag.copyright_url
+-
+-
+-class UserURLsTagPattern(TagPattern, PlaceholderUsagePattern):
+-    NAMES = ["user-urls"]
+-    PARAMETERS = [ComplexPattern.ExpectedParameter("output",
+-                                            default="#i [Description: #d]: #u"),
+-                  ComplexPattern.ExpectedParameter("separation", default="\\n")]
+-    DESCRIPTION = "User URL frames (with output placeholders #i as frame id, "\
+-                  "#d as description & #u as url)"
+-
+-    def _get_output_for(self, audio_file):
+-        output_pattern = self._parameter_value("output", audio_file)
+-        separation = self._parameter_value("separation", audio_file)
+-
+-        outputs = []
+-        for frame in audio_file.tag.user_url_frames:
+-            replacements = [["#i", frame.id],
+-                            ["#d", frame.description],
+-                            ["#u", frame.url]]
+-            outputs.append(self._replace_placeholders(output_pattern,
+-                                                      replacements))
+-        return separation.join(outputs)
+-
+-
+-class ImagesTagPattern(TagPattern, PlaceholderUsagePattern):
+-    NAMES = ["images", "apic"]
+-    PARAMETERS = [ComplexPattern.ExpectedParameter(
+-                    "output",
+-                    default="#t Image: [Type: #m] [Size: #s bytes] #d"),
+-                  ComplexPattern.ExpectedParameter("separation", default="\\n")]
+-    DESCRIPTION = "Attached pictures (APIC)" \
+-                  "(with output placeholders #t as image type, "\
+-                  "#m as mime type, #s as size in bytes & #d as description)"
+-
+-    def _get_output_for(self, audio_file):
+-        output_pattern = self._parameter_value("output", audio_file)
+-        separation = self._parameter_value("separation", audio_file)
+-
+-        outputs = []
+-        for img in audio_file.tag.images:
+-            if img.mime_type not in id3.frames.ImageFrame.URL_MIME_TYPE_VALUES:
+-                replacements = [["#t", img.picTypeToString(img.picture_type)],
+-                                ["#m", img.mime_type],
+-                                ["#s", len(img.image_data)],
+-                                ["#d", img.description]]
+-                outputs.append(self._replace_placeholders(output_pattern,
+-                                                          replacements))
+-        return separation.join(outputs)
+-
+-
+-class ImageURLsTagPattern(TagPattern, PlaceholderUsagePattern):
+-    NAMES = ["image-urls"]
+-    PARAMETERS = [ComplexPattern.ExpectedParameter(
+-        "output", default="#t Image: [Type: #m] [URL: #u] #d"),
+-                  ComplexPattern.ExpectedParameter("separation", default="\\n")]
+-    DESCRIPTION = "Attached pictures URLs" \
+-                  "(with output placeholders #t as image type, "\
+-                  "#m as mime type, #u as URL & #d as description)"
+-
+-    def _get_output_for(self, audio_file):
+-        output_pattern = self._parameter_value("output", audio_file)
+-        separation = self._parameter_value("separation", audio_file)
+-
+-        outputs = []
+-        for img in audio_file.tag.images:
+-            if img.mime_type in id3.frames.ImageFrame.URL_MIME_TYPE_VALUES:
+-                replacements = [["#t", img.picTypeToString(img.picture_type)],
+-                                ["#m", img.mime_type],
+-                                ["#u", img.image_url],
+-                                ["#d", img.description]]
+-                outputs.append(self._replace_placeholders(output_pattern,
+-                                                          replacements))
+-        return separation.join(outputs)
+-
+-
+-class ObjectsTagPattern(TagPattern, PlaceholderUsagePattern):
+-    NAMES = ["objects", "gobj"]
+-    PARAMETERS = [ComplexPattern.ExpectedParameter("output",
+-                                    default="GEOB: [Size: #s bytes] [Type: #t] "
+-                                            "Description: #d | Filename: #f"),
+-                  ComplexPattern.ExpectedParameter("separation", default="\\n")]
+-    DESCRIPTION = "Objects (GOBJ)" \
+-                  "(with output placeholders #s as size, #m as mime type, "\
+-                  "#d as description and #f as file name)"
+-
+-    def _get_output_for(self, audio_file):
+-        output_pattern = self._parameter_value("output", audio_file)
+-        separation = self._parameter_value("separation", audio_file)
+-
+-        outputs = []
+-        for obj in audio_file.tag.objects:
+-            replacements = [["#s", len(obj.object_data)],
+-                            ["#m", obj.mime_type],
+-                            ["#d", obj.description],
+-                            ["#f", obj.filename]]
+-            outputs.append(self._replace_placeholders(output_pattern,
+-                                                      replacements))
+-        return separation.join(outputs)
+-
+-
+-class PrivatesTagPattern(TagPattern, PlaceholderUsagePattern):
+-    NAMES = ["privates", "priv"]
+-    PARAMETERS = [ComplexPattern.ExpectedParameter("output",
+-                                default="PRIV-Content: #b bytes | Owner: #o"),
+-                  ComplexPattern.ExpectedParameter("separation", default="\\n")]
+-    DESCRIPTION = "Privates (APIC) (with output placeholders #c as content, "\
+-                  "#b as number of bytes & #o as owner)"
+-
+-    def _get_output_for(self, audio_file):
+-        output_pattern = self._parameter_value("output", audio_file)
+-        separation = self._parameter_value("separation", audio_file)
+-
+-        outputs = []
+-        for private in audio_file.tag.privates:
+-            replacements = [["#b", "%i" % len(private.data)],
+-                            ["#c", private.data.decode("ascii")],
+-                            ["#o", private.owner_id.decode("ascii")]]
+-            outputs.append(self._replace_placeholders(output_pattern,
+-                                                      replacements))
+-        return separation.join(outputs)
+-
+-
+-class MusicCDIdTagPattern(TagPattern):
+-    NAMES = ["music-cd-id", "mcdi"]
+-    DESCRIPTION = "Music CD Identification"
+-
+-    def _get_output_for(self, audio_file):
+-        if audio_file.tag.cd_id is not None:
+-            return audio_file.tag.cd_id.decode("ascii")
+-        else:
+-            return None
+-
+-
+-class TermsOfUseTagPattern(TagPattern):
+-    NAMES = ["terms-of-use"]
+-    DESCRIPTION = "Terms of use"
+-
+-    def _get_output_for(self, audio_file):
+-        return audio_file.tag.terms_of_use
+-
+-
+-class FunctionPattern(ComplexPattern):
+-    __metaclass__ = abc.ABCMeta
+-    TYPE = "function"
+-
+-
+-class FunctionFormatPattern(FunctionPattern):
+-    NAMES = ["format"]
+-    PARAMETERS = [ComplexPattern.ExpectedParameter("text"),
+-                  ComplexPattern.ExpectedParameter("bold", default=None),
+-                  ComplexPattern.ExpectedParameter("color", default=None)]
+-    DESCRIPTION = "Formats text bold and colored (grey, red, green, yellow, "\
+-                  "blue, magenta, cyan or white)"
+-
+-    def _get_output_for(self, audio_file):
+-        text = self._parameter_value("text", audio_file)
+-        bold = self._parameter_bool("bold", audio_file)
+-        color_name = self._parameter_value("color", audio_file)
+-        return console.formatText(text, b=bold, c=self.__color(color_name))
+-
+-    def __color(self, color_name):
+-        return {"GREY": console.Fore.GREY,
+-                "RED": console.Fore.RED,
+-                "GREEN": console.Fore.GREEN,
+-                "YELLOW": console.Fore.YELLOW,
+-                "BLUE": console.Fore.BLUE,
+-                "MAGENTA": console.Fore.MAGENTA,
+-                "CYAN": console.Fore.CYAN,
+-                "WHITE": console.Fore.WHITE}.get(color_name.upper(), None)
+-
+-
+-class FunctionNumberPattern(FunctionPattern):
+-    NAMES = ["num", "number-format"]
+-    PARAMETERS = [ComplexPattern.ExpectedParameter("number"),
+-                  ComplexPattern.ExpectedParameter("digits")]
+-    DESCRIPTION = "Appends leading zeros"
+-
+-    def _get_output_for(self, audio_file):
+-        number = self._parameter_value("number", audio_file)
+-        digits = self._parameter_value("digits", audio_file)
+-        try:
+-            number = int(number)
+-        except ValueError:
+-            raise DisplayException(self._error_message("'" + number +
+-                                                       "' is not a number."))
+-        try:
+-            digits = int(digits)
+-        except ValueError:
+-            raise DisplayException(self._error_message("'" + digits +
+-                                                       "' is not a number."))
+-
+-        output = str(number)
+-        return ("0" * max(0, digits - len(output))) + output
+-
+-
+-class FunctionFilenamePattern(FunctionPattern):
+-    NAMES = ["filename", "fn"]
+-    PARAMETERS = [ComplexPattern.ExpectedParameter("basename", default=None)]
+-    DESCRIPTION = "File name"
+-
+-    def _get_output_for(self, audio_file):
+-        if self._parameter_bool("basename", audio_file):
+-            return os.path.basename(audio_file.path)
+-        return audio_file.path
+-
+-
+-class FunctionFilesizePattern(FunctionPattern):
+-    NAMES = ["filesize"]
+-    DESCRIPTION = "Size of file"
+-
+-    def _get_output_for(self, audio_file):
+-        from stat import ST_SIZE
+-        file_size = os.stat(audio_file.path)[ST_SIZE]
+-        return formatSize(file_size)
+-
+-
+-class FunctionTagVersionPattern(FunctionPattern):
+-    NAMES = ["tag-version"]
+-    DESCRIPTION = "Tag version"
+-
+-    def _get_output_for(self, audio_file):
+-        return id3.versionToString(audio_file.tag.version)
+-
+-
+-class FunctionLengthPattern(FunctionPattern):
+-    NAMES = ["length"]
+-    DESCRIPTION = "Length of aufio file"
+-
+-    def _get_output_for(self, audio_file):
+-        return formatTime(audio_file.info.time_secs)
+-
+-
+-class FunctionMPEGVersionPattern(FunctionPattern, PlaceholderUsagePattern):
+-    NAMES = ["mpeg-version"]
+-    PARAMETERS = [ComplexPattern.ExpectedParameter("output",
+-                                                   default=r"MPEG#v\, Layer #l")]
+-    DESCRIPTION = "MPEG version (with output placeholders #v as version & "\
+-                  "#l as layer)"
+-
+-    def _get_output_for(self, audio_file):
+-        output = self._parameter_value("output", audio_file)
+-        replacements = [["#v", str(audio_file.info.mp3_header.version)],
+-                        ["#l", "I" * audio_file.info.mp3_header.layer]]
+-        return self._replace_placeholders(output, replacements)
+-
+-
+-class FunctionBitRatePattern(FunctionPattern):
+-    NAMES = ["bit-rate"]
+-    DESCRIPTION = "Bit rate of aufio file"
+-
+-    def _get_output_for(self, audio_file):
+-        return audio_file.info.bit_rate_str
+-
+-
+-class FunctionSampleFrequencePattern(FunctionPattern):
+-    NAMES = ["sample-freq"]
+-    DESCRIPTION = "Sample frequence of aufio file in Hz"
+-
+-    def _get_output_for(self, audio_file):
+-        return str(audio_file.info.mp3_header.sample_freq)
+-
+-
+-class FunctionAudioModePattern(FunctionPattern):
+-    NAMES = ["audio-mode"]
+-    DESCRIPTION = "Mode of aufio file: mono/stereo"
+-
+-    def _get_output_for(self, audio_file):
+-        return audio_file.info.mp3_header.mode
+-
+-
+-class FunctionNotEmptyPattern(FunctionPattern, PlaceholderUsagePattern):
+-    NAMES = ["not-empty"]
+-    PARAMETERS = [ComplexPattern.ExpectedParameter("text"),
+-                  ComplexPattern.ExpectedParameter("output", default="#t"),
+-                  ComplexPattern.ExpectedParameter("empty", default=None)]
+-    DESCRIPTION = "If condition is not empty (with output placeholder #t as "\
+-                  "text)"
+-
+-    def _get_output_for(self, audio_file):
+-        text = self._parameter_value("text", audio_file)
+-        if len(text) > 0:
+-            output = self._parameter_value("output", audio_file)
+-            return self._replace_placeholders(output, [["#t", text]])
+-            return output.replace("#t", text)
+-        else:
+-            return self._parameter_value("empty", audio_file)
+-
+-
+-class FunctionRepeatPattern(FunctionPattern):
+-    NAMES = ["repeat"]
+-    PARAMETERS = [ComplexPattern.ExpectedParameter("text"),
+-                  ComplexPattern.ExpectedParameter("count")]
+-    DESCRIPTION = "Repeats text"
+-
+-    def _get_output_for(self, audio_file):
+-        output = u""
+-        content = self._parameter_value("text", audio_file)
+-        count = self._parameter_value("count", audio_file)
+-        try:
+-            count = int(count)
+-        except ValueError:
+-            raise DisplayException(self._error_message("'" + count +
+-                                                       "' is not a number."))
+-        for i in range(count):
+-            output += content
+-        return output
+-
+-
+-class DisplayPlugin(LoaderPlugin):
+-    NAMES = ["display"]
+-    SUMMARY = u"Tag Display"
+-    DESCRIPTION = ""u"""
+-Prints specific tag information.
+-"""
+-
+-    def __init__(self, arg_parser):
+-        super(DisplayPlugin, self).__init__(arg_parser)
+-
+-        def filename(fn):
+-            if not os.path.exists(fn):
+-                raise ArgumentTypeError("The file %s does not exist!" % fn)
+-            return fn
+-
+-        pattern_group = \
+-            self.arg_group.add_mutually_exclusive_group(required=True)
+-        pattern_group.add_argument("--pattern-help", action="store_true",
+-                                   dest="pattern_help",
+-                                   help=ARGS_HELP["--pattern-help"])
+-        pattern_group.add_argument("-p", "--pattern", dest="pattern_string",
+-                                   metavar="STRING",
+-                                   help=ARGS_HELP["--pattern"])
+-        pattern_group.add_argument("-f", "--pattern-file", dest="pattern_file",
+-                                   metavar="FILE", type=filename,
+-                                   help=ARGS_HELP["--pattern-file"])
+-        self.arg_group.add_argument("--no-newline", action="store_true",
+-                                    dest="no_newline",
+-                                    help=ARGS_HELP["--no-newline"])
+-
+-        self.__pattern = None
+-        self.__return_code = 0
+-
+-    def start(self, args, config):
+-        super(DisplayPlugin, self).start(args, config)
+-
+-        if args.pattern_help:
+-            self.__print_pattern_help()
+-            return
+-
+-        if not _have_grako:
+-            console.printError(u"Unknown module 'grako'" + os.linesep +
+-                               u"Please install grako! " +
+-                               u"E.g. $ pip install grako")
+-            self.__return_code = 2
+-            return
+-
+-        if args.pattern_string is not None:
+-            self.__pattern = Pattern(args.pattern_string)
+-        if args.pattern_file is not None:
+-            pfile = open(args.pattern_file, "r")
+-            self.__pattern = Pattern(''.join(pfile.read().splitlines()))
+-            pfile.close()
+-        self.__output_ending = "" if args.no_newline else os.linesep
+-
+-    def handleFile(self, f, *args, **kwargs):
+-        if self.args.pattern_help:
+-            return
+-        if self.__return_code != 0:
+-            return
+-
+-        super(DisplayPlugin, self).handleFile(f)
+-        if not self.audio_file:
+-            return
+-
+-        try:
+-            print(self.__pattern.output_for(self.audio_file),
+-                  end=self.__output_ending)
+-        except PatternCompileException as e:
+-            self.__return_code = 1
+-            console.printError(e.message)
+-        except DisplayException as e:
+-            self.__return_code = 1
+-            console.printError(e.message)
+-
+-    def handleDone(self):
+-        return self.__return_code
+-
+-    def __print_pattern_help(self):
+-        # FIXME: Force some order
+-        print(console.formatText("ID3 Tags:", b=True))
+-        self.__print_complex_pattern_help(TagPattern)
+-        print(os.linesep)
+-
+-        print(console.formatText("Functions:", b=True))
+-        self.__print_complex_pattern_help(FunctionPattern)
+-        print(os.linesep)
+-
+-        print(console.formatText("Special characters:", b=True))
+-        print(console.formatText("\tescape seq.   character"))
+-        for i in range(len(TextPattern.SPECIAL_CHARACTERS)):
+-            print(("\t\\%s" + (" " * 12) + "%s") %
+-                  (TextPattern.SPECIAL_CHARACTERS[i],
+-                   TextPattern.SPECIAL_CHARACTERS_DESCRIPTIONS[i]))
+-
+-    def __print_complex_pattern_help(self, base_class):
+-        rows = []
+-        # TODO line wrap for description
+-        for pattern_class in Pattern.sub_pattern_classes(base_class):
+-            rows.append([", ".join(pattern_class.NAMES),
+-                         pattern_class.DESCRIPTION])
+-            parameters = Pattern.pattern_class_parameters(pattern_class)
+-            if len(parameters) > 0:
+-                rows.append(["", "Parameter" +
+-                                 ("s:" if len(parameters) > 1 else ":")])
+-            for parameter in parameters:
+-                parameter_desc = parameter.name
+-                if not parameter.requried:
+-                    default = ", default='" + parameter.default + \
+-                              "'" if parameter.default else ""
+-                    parameter_desc += " (optional" + default + ")"
+-                rows.append(["", "   " + parameter_desc])
+-        self.__print_rows(rows, "\t", "  ")
+-
+-    def __print_rows(self, rows, indent, spacing):
+-        row_widths = []
+-        for row in rows:
+-            for n in range(len(row)):
+-                width = len(row[n])
+-                if len(row_widths) <= n:
+-                    row_widths.append(width)
+-                else:
+-                    row_widths[n] = max(row_widths[n], width)
+-        for row in rows:
+-            out = indent
+-            for n in range(len(row)):
+-                out += row[n]
+-                if n < len(row) - 1:
+-                    out += (" " * (row_widths[n] - len(row[n]))) + spacing
+-            print(out)
+-
+-
+-class DisplayException(Exception):
+-    def __init__(self, message):
+-        self.__message = message
+-
+-    def __get_message(self):
+-        return self.__message
+-
+-    message = property(__get_message)
+-
+-
+-class PatternCompileException(Exception):
+-    def __init__(self, message):
+-        self.__message = message
+-
+-    def __get_message(self):
+-        return self.__message
+-
+-    message = property(__get_message)
+-
+-
+-ARGS_HELP = {
+-    "--pattern-help": "Detailed pattern help",
+-    "--pattern": "Pattern string",
+-    "--pattern-file": "Pattern file",
+-    "--no-newline": "Print no newline after each output"
+-}
diff -Nru eyed3-0.8.10/debian/patches/series eyed3-0.8.10/debian/patches/series
--- eyed3-0.8.10/debian/patches/series	2019-01-02 14:59:00.000000000 +0100
+++ eyed3-0.8.10/debian/patches/series	2021-05-31 15:18:00.000000000 +0200
@@ -1,2 +1,3 @@
 support-debian-python-magic
 remove-display-plugin
+support-pylast-3
diff -Nru eyed3-0.8.10/debian/patches/support-pylast-3 eyed3-0.8.10/debian/patches/support-pylast-3
--- eyed3-0.8.10/debian/patches/support-pylast-3	1970-01-01 01:00:00.000000000 +0100
+++ eyed3-0.8.10/debian/patches/support-pylast-3	2021-05-31 15:18:00.000000000 +0200
@@ -0,0 +1,45 @@
+--- a/src/eyed3/plugins/lastfm.py
++++ b/src/eyed3/plugins/lastfm.py
+@@ -1,5 +1,4 @@
+-from pylast import (COVER_EXTRA_LARGE, COVER_LARGE, COVER_MEDIUM, COVER_MEGA,
+-                    COVER_SMALL)
++from pylast import SIZE_EXTRA_LARGE, SIZE_LARGE, SIZE_MEDIUM, SIZE_MEGA, SIZE_SMALL
+ from pylast import LastFMNetwork, WSError
+ 
+ api_k = "a5f0ac61e7db2481b054ba52ff9a654f"
+@@ -23,15 +22,15 @@
+     return Client().get_album(artist, title)
+ 
+ 
+-def getAlbumArt(artist, title, size=COVER_EXTRA_LARGE):
++def getAlbumArt(artist, title, size=SIZE_EXTRA_LARGE):
+     return _getArt(getAlbum(artist, title), size=size)
+ 
+ 
+-def getArtistArt(artist, size=COVER_EXTRA_LARGE):
++def getArtistArt(artist, size=SIZE_EXTRA_LARGE):
+     return _getArt(getArtist(artist), size=size)
+ 
+ 
+-def _getArt(obj, size=COVER_EXTRA_LARGE):
++def _getArt(obj, size=SIZE_EXTRA_LARGE):
+     try:
+         return obj.get_cover_image(size)
+     except WSError:
+@@ -40,12 +39,12 @@
+ 
+ if __name__ == "__main__":
+     album = getAlbum("Melvins", "Houdini")
+-    for sz in (COVER_SMALL, COVER_MEGA, COVER_MEDIUM, COVER_LARGE,
+-               COVER_EXTRA_LARGE):
++    for sz in (SIZE_SMALL, SIZE_MEGA, SIZE_MEDIUM, SIZE_LARGE,
++               SIZE_EXTRA_LARGE):
+         print(album.get_cover_image(sz))
+ 
+     melvins = getArtist("Melvins")
+     print(melvins)
+-    for sz in (COVER_SMALL, COVER_MEGA, COVER_MEDIUM, COVER_LARGE,
+-               COVER_EXTRA_LARGE):
++    for sz in (SIZE_SMALL, SIZE_MEGA, SIZE_MEDIUM, SIZE_LARGE,
++               SIZE_EXTRA_LARGE):
+         print(melvins.get_cover_image(sz))
diff -Nru eyed3-0.8.10/debian/tests/cmd-id3-file-input-output eyed3-0.8.10/debian/tests/cmd-id3-file-input-output
--- eyed3-0.8.10/debian/tests/cmd-id3-file-input-output	1970-01-01 01:00:00.000000000 +0100
+++ eyed3-0.8.10/debian/tests/cmd-id3-file-input-output	2021-06-01 18:02:48.000000000 +0200
@@ -0,0 +1,28 @@
+#!/bin/sh
+# autopkgtest check: Generate an .id3 file and read it back using eyed3 program
+set -e
+
+# create an empty .id3 file
+tmpdir="${AUTOPKGTEST_TMP:-/tmp}"
+id3file="$tmpdir"/cmd-id3-file-input-output.id3
+> "$id3file"
+
+# write some ID3 tags into the file
+eyeD3 >/dev/null 2>&1 -Q\
+      -a artist \
+      -A album \
+      -t title \
+      -Y 2021 \
+      -n 42 "$id3file" 
+
+# read back written tags
+output=$(eyeD3 2>/dev/null "$id3file")
+
+# test tags are found inoutput
+test "${output#*artist: artist}" != "$output" || (echo 'ERROR: artist not found in written tags'; exit 1)
+test "${output#*album: album}" != "$output" || (echo 'ERROR: album not found in written tags'; exit 1)
+test "${output#*title: title}" != "$output" || (echo 'ERROR: title not found in written tags'; exit 1)
+test "${output#*release date: 2021}" != "$output" || (echo 'ERROR: year not found in written tags'; exit 1)
+test "${output#*track: 42}" != "$output" || (echo 'ERROR: track not found in written tags'; exit 1)
+
+
diff -Nru eyed3-0.8.10/debian/tests/control eyed3-0.8.10/debian/tests/control
--- eyed3-0.8.10/debian/tests/control	2020-03-18 21:02:45.000000000 +0100
+++ eyed3-0.8.10/debian/tests/control	2021-06-01 18:01:32.000000000 +0200
@@ -1,5 +1,13 @@
 Tests: base-script
 Depends: eyed3
+Restrictions: superficial
 
 Test-Command: set -e ; for py in $(py3versions -r 2>/dev/null) ; do cd "$ADTTMP" ; echo "Testing with $py:" ; $py -c "import eyed3; print(eyed3)" ; done
 Depends: python3-all, python3-eyed3
+Restrictions: superficial
+
+Tests: cmd-id3-file-input-output
+Depends: eyed3
+
+Tests: lib-id3-file-input-output
+Depends: eyed3
\ Manca newline alla fine del file
diff -Nru eyed3-0.8.10/debian/tests/lib-id3-file-input-output eyed3-0.8.10/debian/tests/lib-id3-file-input-output
--- eyed3-0.8.10/debian/tests/lib-id3-file-input-output	1970-01-01 01:00:00.000000000 +0100
+++ eyed3-0.8.10/debian/tests/lib-id3-file-input-output	2021-05-31 16:21:38.000000000 +0200
@@ -0,0 +1,42 @@
+#!/usr/bin/python3
+# autopkgtest check: Generate an .id3 file and read it back using python-eyed3 library
+
+import os
+import datetime
+import pathlib
+
+import eyed3
+import eyed3.id3
+import eyed3.core
+
+tmpdir = os.environ.get("AUTOPKGTEST_TMP") or "/tmp"
+tmpf = pathlib.Path(tmpdir) / "lib-id3-file-input-output.id3"
+
+
+def generate_id3_file(path):
+    with open(path, "wb"):
+        pass
+    f = eyed3.load(path)
+    f.initTag()
+
+    f.tag.artist = "artist"
+    f.tag.album = "album"
+    f.tag.title = "title"
+    f.tag.release_date = eyed3.core.Date(2021)
+    f.tag.track_num = (42, None)
+
+    f.tag.save()
+
+
+def test_id3_file(path):
+    f = eyed3.load(path)
+    assert f.tag.artist == "artist"
+    assert f.tag.album == "album"
+    assert f.tag.title == "title"
+    assert f.tag.release_date == eyed3.core.Date(2021)
+    assert f.tag.track_num == (42, None)
+
+
+if __name__ == "__main__":
+    generate_id3_file(tmpf)
+    test_id3_file(tmpf)

--- End Message ---
--- Begin Message ---
Hi,

On 08-06-2021 22:20, Paul Gevers wrote:
> On Sat, 5 Jun 2021 15:06:31 +0200 Gaetano Guerriero <x.guerriero@tin.it>
> wrote:
>> Package is not blocked, but it is marked for removal from
>> testing on 16 Jun and the auto migration period expires on 22 Jun.
> 
> I have pinged the RC bug. That should reset the autoremoval timer, so
> the package should migrate on its own.
> 
> Don't hesitate to remove the moreinfo tag if you're seeing issues.

paul@mulciber ~ $ rmadison eyed3 --suite testing
eyed3      | 0.8.10-4      | testing    | source, all

Paul

Attachment: OpenPGP_signature
Description: OpenPGP digital signature


--- End Message ---

Reply to: