Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package lollypop for openSUSE:Factory checked in at 2021-01-18 11:28:42 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/lollypop (Old) and /work/SRC/openSUSE:Factory/.lollypop.new.28504 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "lollypop" Mon Jan 18 11:28:42 2021 rev:143 rq:863904 version:1.4.12 Changes: -------- --- /work/SRC/openSUSE:Factory/lollypop/lollypop.changes 2021-01-11 17:16:13.732606419 +0100 +++ /work/SRC/openSUSE:Factory/.lollypop.new.28504/lollypop.changes 2021-01-18 11:32:30.364693559 +0100 @@ -1,0 +2,26 @@ +Sun Jan 17 19:51:31 UTC 2021 - antoine.belv...@opensuse.org + +- Update to version 1.4.12: + * Fix a crash on init due to missing secret. + * Fix a crash on album widget reveal (glgo#World/lollypop#2679). + * Fix a playback issue (glgo#World/lollypop#2683). + * Fix content not being reloaded after resizing window + (glgo#World/lollypop#2673). + * Fix album artwork removal (glgo#World/lollypop#2680). + +------------------------------------------------------------------- +Sun Jan 17 12:25:41 UTC 2021 - antoine.belv...@opensuse.org + +- Update to version 1.4.11: + * Fix an issue with blacklisted songs (glgo#Wolrd/lollypop#2676). + * Fix an issue with loved songs (glgo#World/lollypop#2677). + +------------------------------------------------------------------- +Sat Jan 16 14:26:58 UTC 2021 - antoine.belv...@opensuse.org + +- Update to version 1.4.10: + * Fix crash when clicking "Play all" button for entire library + (glgo#World/lollypop#2674) + * Rework ReplayGain defaults (glgo#World/lollypop#2564). + +------------------------------------------------------------------- Old: ---- lollypop-1.4.9.tar.xz New: ---- lollypop-1.4.12.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ lollypop.spec ++++++ --- /var/tmp/diff_new_pack.CFGi6G/_old 2021-01-18 11:32:31.016694201 +0100 +++ /var/tmp/diff_new_pack.CFGi6G/_new 2021-01-18 11:32:31.016694201 +0100 @@ -17,7 +17,7 @@ Name: lollypop -Version: 1.4.9 +Version: 1.4.12 Release: 0 Summary: GNOME music playing application License: GPL-3.0-or-later ++++++ _service ++++++ --- /var/tmp/diff_new_pack.CFGi6G/_old 2021-01-18 11:32:31.048694233 +0100 +++ /var/tmp/diff_new_pack.CFGi6G/_new 2021-01-18 11:32:31.048694233 +0100 @@ -1,7 +1,7 @@ <services> <service mode="disabled" name="tar_scm"> <param name="changesgenerate">enable</param> - <param name="revision">1.4.9</param> + <param name="revision">1.4.12</param> <param name="scm">git</param> <param name="url">https://gitlab.gnome.org/World/lollypop.git</param> <param name="versionformat">@PARENT_TAG@</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.CFGi6G/_old 2021-01-18 11:32:31.068694253 +0100 +++ /var/tmp/diff_new_pack.CFGi6G/_new 2021-01-18 11:32:31.068694253 +0100 @@ -1,4 +1,4 @@ <servicedata> <service name="tar_scm"> <param name="url">https://gitlab.gnome.org/World/lollypop.git</param> - <param name="changesrevision">99d5aaf24c8b2cfe0c0cd81d0cdc0bbb2ed77d1c</param></service></servicedata> \ No newline at end of file + <param name="changesrevision">0b01adcdeb33ad3af86f2336dd067759cae9d4b8</param></service></servicedata> \ No newline at end of file ++++++ lollypop-1.4.9.tar.xz -> lollypop-1.4.12.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-1.4.9/data/org.gnome.Lollypop.gschema.xml new/lollypop-1.4.12/data/org.gnome.Lollypop.gschema.xml --- old/lollypop-1.4.9/data/org.gnome.Lollypop.gschema.xml 2021-01-10 20:27:35.000000000 +0100 +++ new/lollypop-1.4.12/data/org.gnome.Lollypop.gschema.xml 2021-01-17 20:48:13.000000000 +0100 @@ -365,17 +365,17 @@ <description></description> </key> <key enum="org.gnome.Lollypop.ReplayGain" name="replay-gain"> - <default>'album'</default> + <default>'none'</default> <summary>ReplayGain state</summary> <description></description> </key> <key type="d" name="replay-gain-db"> - <default>3.0</default> + <default>0</default> <summary>ReplayGain value in dB</summary> <description>Between -15 and 15</description> </key> <key type="b" name="replay-gain-limiter"> - <default>true</default> + <default>false</default> <summary>Applies signal compression/limiting to raw audio data</summary> <description>It performs strict hard limiting with soft-knee characteristics, using a threshold of -6 dB</description> </key> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-1.4.9/lollypop/artwork_album.py new/lollypop-1.4.12/lollypop/artwork_album.py --- old/lollypop-1.4.9/lollypop/artwork_album.py 2021-01-10 20:27:35.000000000 +0100 +++ new/lollypop-1.4.12/lollypop/artwork_album.py 2021-01-17 20:48:13.000000000 +0100 @@ -397,7 +397,7 @@ art_uri = "%s/%s" % (album.uri, self.__favorite) art_uri = self.add_extension(art_uri) # Save cover to tags - if save_to_tags: + if save_to_tags and data is not None: helper = TaskHelper() helper.run(self.__add_to_tags, album, data) # We need to remove favorite if exists diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-1.4.9/lollypop/collection_scanner.py new/lollypop-1.4.12/lollypop/collection_scanner.py --- old/lollypop-1.4.9/lollypop/collection_scanner.py 2021-01-10 20:27:35.000000000 +0100 +++ new/lollypop-1.4.12/lollypop/collection_scanner.py 2021-01-17 20:48:13.000000000 +0100 @@ -557,6 +557,8 @@ except Exception as e: Logger.warning("CollectionScanner::__scan(): %s", e) SqlCursor.remove(App().db) + App().settings.set_value("flatpak-access-migration", + GLib.Variant("b", True)) def __scan_to_handle(self, uri): """ @@ -870,5 +872,3 @@ assistant.set_position(Gtk.WindowPosition.CENTER_ON_PARENT) assistant.set_transient_for(App().window) GLib.timeout_add(1000, assistant.show) - App().settings.set_value("flatpak-access-migration", - GLib.Variant("b", True)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-1.4.9/lollypop/container.py new/lollypop-1.4.12/lollypop/container.py --- old/lollypop-1.4.9/lollypop/container.py 2021-01-10 20:27:35.000000000 +0100 +++ new/lollypop-1.4.12/lollypop/container.py 2021-01-17 20:48:13.000000000 +0100 @@ -58,6 +58,7 @@ """ self.__widget = Handy.Leaflet() self.__widget.show() + self.__widget.connect("notify::folded", self.__on_folded) self.__sub_widget = Handy.Leaflet() self.__sub_widget.show() self.__focused_view = None @@ -210,6 +211,13 @@ ############ # PRIVATE # ############ + def __on_folded(self, *ignore): + """ + Reload main view if needed + """ + if not App().window.folded and self.view is None: + self.show_view(self.sidebar.selected_ids) + def __on_search_activate(self, action, variant): """ @param action as Gio.SimpleAction diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-1.4.9/lollypop/database_albums.py new/lollypop-1.4.12/lollypop/database_albums.py --- old/lollypop-1.4.9/lollypop/database_albums.py 2021-01-10 20:27:35.000000000 +0100 +++ new/lollypop-1.4.12/lollypop/database_albums.py 2021-01-17 20:48:13.000000000 +0100 @@ -940,6 +940,7 @@ @param skipped as bool @return [int] """ + print("::", skipped) genre_ids = remove_static(genre_ids) artist_ids = remove_static(artist_ids) with SqlCursor(self.__db) as sql: @@ -1078,7 +1079,7 @@ request += " AND not albums.loved & ?" filters += (LovedFlags.SKIPPED,) request += order - result = sql.execute(request, (storage_type,)) + result = sql.execute(request, filters) # Get albums for genres elif not artist_ids: filters = (storage_type,) @@ -1268,7 +1269,7 @@ @return album ids as [int] """ with SqlCursor(self.__db) as sql: - filters = () + filters = (storage_type,) request = "SELECT album_id FROM tracks, albums\ WHERE albums.storage_type & ? AND albums.rowid=album_id" if not skipped: @@ -1276,7 +1277,7 @@ filters += (LovedFlags.SKIPPED,) request += " GROUP BY album_id\ ORDER BY SUM(ltime)/COUNT(ltime), random() LIMIT ?" - filters += (storage_type, limit) + filters += (limit,) result = sql.execute(request, filters) return list(itertools.chain(*result)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-1.4.9/lollypop/database_genres.py new/lollypop-1.4.12/lollypop/database_genres.py --- old/lollypop-1.4.9/lollypop/database_genres.py 2021-01-10 20:27:35.000000000 +0100 +++ new/lollypop-1.4.12/lollypop/database_genres.py 2021-01-17 20:48:13.000000000 +0100 @@ -13,7 +13,7 @@ import itertools from lollypop.sqlcursor import SqlCursor -from lollypop.define import App, Type, OrderBy +from lollypop.define import App, Type, OrderBy, LovedFlags from lollypop.utils import get_network_available, sql_escape @@ -104,6 +104,7 @@ albums.name\ COLLATE NOCASE COLLATE LOCALIZED" with SqlCursor(self.__db) as sql: + filters = () request = "SELECT albums.rowid\ FROM albums, album_genres, genres,\ album_artists, artists\ @@ -114,9 +115,10 @@ if not get_network_available(): request += " AND albums.synced!=%s" % Type.NONE if ignore: - request += " AND albums.loved != -1" + request += " AND not albums.loved & ?" + filters += (LovedFlags.SKIPPED,) request += order - result = sql.execute(request) + result = sql.execute(request, filters) return list(itertools.chain(*result)) def get(self): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-1.4.9/lollypop/database_tracks.py new/lollypop-1.4.12/lollypop/database_tracks.py --- old/lollypop-1.4.9/lollypop/database_tracks.py 2021-01-10 20:27:35.000000000 +0100 +++ new/lollypop-1.4.12/lollypop/database_tracks.py 2021-01-17 20:48:13.000000000 +0100 @@ -604,10 +604,10 @@ @return [int] """ with SqlCursor(self.__db) as sql: - filters = (storage_type,) + filters = (LovedFlags.LOVED, storage_type) request = "SELECT tracks.rowid\ FROM tracks, album_artists, artists\ - WHERE loved=1 AND\ + WHERE loved=? AND\ artists.rowid=album_artists.artist_id AND\ tracks.album_id=album_artists.album_id AND\ storage_type & ?" @@ -617,7 +617,7 @@ request += make_subrequest("album_artists.artist_id=?", "OR", len(artist_ids)) - request += "ORDER BY artists.name" + request += " ORDER BY artists.name" result = sql.execute(request, filters) return list(itertools.chain(*result)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-1.4.9/lollypop/dialog_settings.py new/lollypop-1.4.12/lollypop/dialog_settings.py --- old/lollypop-1.4.9/lollypop/dialog_settings.py 2021-01-10 20:27:35.000000000 +0100 +++ new/lollypop-1.4.12/lollypop/dialog_settings.py 2021-01-17 20:48:13.000000000 +0100 @@ -149,6 +149,10 @@ setting = widget.get_name() value = widget.get_active() App().settings.set_enum(setting, value) + if setting == "replay-gain": + for plugin in App().player.plugins: + plugin.build_audiofilter() + App().player.reload_track() def _on_clean_artwork_cache_clicked(self, button): """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-1.4.9/lollypop/helper_passwords.py new/lollypop-1.4.12/lollypop/helper_passwords.py --- old/lollypop-1.4.9/lollypop/helper_passwords.py 2021-01-10 20:27:35.000000000 +0100 +++ new/lollypop-1.4.12/lollypop/helper_passwords.py 2021-01-17 20:48:13.000000000 +0100 @@ -28,12 +28,7 @@ """ # Initial password lookup, prevent a lock issue in Flatpak backend if GLib.file_test("/app", GLib.FileTest.EXISTS): - SecretSchema = {"service": Secret.SchemaAttributeType.STRING} - SecretAttributes = {"service": "LASTFM"} - schema = Secret.Schema.new("org.gnome.Lollypop", - Secret.SchemaFlags.NONE, - SecretSchema) - Secret.password_lookup_sync(schema, SecretAttributes) + self.get_token("LASTFM") def get_token(self, service): """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-1.4.9/lollypop/objects_album.py new/lollypop-1.4.12/lollypop/objects_album.py --- old/lollypop-1.4.9/lollypop/objects_album.py 2021-01-10 20:27:35.000000000 +0100 +++ new/lollypop-1.4.12/lollypop/objects_album.py 2021-01-17 20:48:13.000000000 +0100 @@ -350,7 +350,8 @@ @return album """ album = Album(self.id, self.genre_ids, self.artist_ids, skipped) - album.set_tracks(self.tracks) + if skipped: + album.set_tracks(self.tracks) return album def set_storage_type(self, storage_type): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-1.4.9/lollypop/tagreader.py new/lollypop-1.4.12/lollypop/tagreader.py --- old/lollypop-1.4.9/lollypop/tagreader.py 2021-01-10 20:27:35.000000000 +0100 +++ new/lollypop-1.4.12/lollypop/tagreader.py 2021-01-17 20:48:13.000000000 +0100 @@ -32,12 +32,7 @@ """ Init tag reader """ - self.init_discoverer() - def init_discoverer(self): - """ - Init discover - """ self._discoverer = GstPbutils.Discoverer.new(10 * Gst.SECOND) def get_info(self, uri): @@ -56,6 +51,15 @@ Scanner tag reader """ + __STRING = ["title", "artist", "composer", "conductor", + "musicbrainz-albumid", "musicbrainz-trackid", + "musicbrainz-artistid", "musicbrainz-albumartistid", + "version", "performer", "artist-sortname", + "album-artist-sortname", "interpreted-by", "album-artist", + "album", "genre", "lyrics", "publisher"] + __INT = ["album-disc-number", "track-number"] + __DOUBLE = ["beats-per-minute"] + def __init__(self): """ Init tag reader @@ -71,9 +75,8 @@ """ if tags is None: return GLib.path_get_basename(filepath) - (exists, title) = tags.get_string_index("title", 0) - # We need to check tag is not just spaces - if not exists or not title.strip(" "): + title = self.__get(tags, ["title"]) + if not title: title = GLib.path_get_basename(filepath) return title @@ -85,13 +88,7 @@ """ if tags is None: return _("Unknown") - artists = [] - for i in range(tags.get_tag_size("artist")): - (exists, read) = tags.get_string_index("artist", i) - # We need to check tag is not just spaces - if exists and read.strip(" "): - artists.append(read) - return "; ".join(artists) + return self.__get(tags, ["artist"]) def get_composers(self, tags): """ @@ -101,13 +98,7 @@ """ if tags is None: return _("Unknown") - composers = [] - for i in range(tags.get_tag_size("composer")): - (exists, read) = tags.get_string_index("composer", i) - # We need to check tag is not just spaces - if exists and read.strip(" "): - composers.append(read) - return "; ".join(composers) + return self.__get(tags, ["composer"]) def get_conductors(self, tags): """ @@ -117,13 +108,7 @@ """ if tags is None: return _("Unknown") - conductors = [] - for i in range(tags.get_tag_size("conductor")): - (exists, read) = tags.get_string_index("conductor", i) - # We need to check tag is not just spaces - if exists and read.strip(" "): - conductors.append(read) - return "; ".join(conductors) + return self.__get(tags, ["conductor"]) def get_mb_id(self, tags, name): """ @@ -134,8 +119,7 @@ """ if tags is None or not name: return "" - (exists, mbid) = tags.get_string_index("musicbrainz-" + name, 0) - return mbid or "" + return self.__get(tags, ["musicbrainz-" + name]) def get_mb_album_id(self, tags): """ @@ -177,8 +161,7 @@ """ if tags is None: return "" - (exists, version) = tags.get_string_index("version", 0) - return version or "" + return self.__get(tags, ["version"]) def get_performers(self, tags): """ @@ -188,13 +171,7 @@ """ if tags is None: return _("Unknown") - performers = [] - for i in range(tags.get_tag_size("performer")): - (exists, read) = tags.get_string_index("performer", i) - # We need to check tag is not just spaces - if exists and read.strip(" "): - performers.append(read) - return "; ".join(performers) + return self.__get(tags, ["performer"]) def get_artist_sortnames(self, tags): """ @@ -204,13 +181,7 @@ """ if tags is None: return "" - sortnames = [] - for i in range(tags.get_tag_size("artist-sortname")): - (exists, read) = tags.get_string_index("artist-sortname", i) - # We need to check tag is not just spaces - if exists and read.strip(" "): - sortnames.append(read) - return "; ".join(sortnames) + return self.__get(tags, ["artist-sortname"]) def get_album_artist_sortnames(self, tags): """ @@ -220,13 +191,7 @@ """ if tags is None: return "" - sortnames = [] - for i in range(tags.get_tag_size("album-artist-sortname")): - (exists, read) = tags.get_string_index("album-artist-sortname", i) - # We need to check tag is not just spaces - if exists and read.strip(" "): - sortnames.append(read) - return "; ".join(sortnames) + return self.__get(tags, ["album-artist-sortname"]) def get_remixers(self, tags): """ @@ -236,19 +201,10 @@ """ if tags is None: return _("Unknown") - remixers = [] - for i in range(tags.get_tag_size("interpreted-by")): - (exists, read) = tags.get_string_index("interpreted-by", i) - # We need to check tag is not just spaces - if exists and read.strip(" "): - remixers.append(read) + remixers = self.__get(tags, ["interpreted-by"]) if not remixers: - for i in range(tags.get_tag_size("extended-comment")): - (exists, read) = tags.get_string_index("extended-comment", i) - if exists and read.startswith("REMIXER="): - remixer = read[8:] - remixers.append(remixer) - return "; ".join(remixers) + remixers = self.__get_extended(tags, ["REMIXER"]) + return remixers def get_album_artists(self, tags): """ @@ -258,13 +214,7 @@ """ if tags is None: return _("Unknown") - artists = [] - for i in range(tags.get_tag_size("album-artist")): - (exists, read) = tags.get_string_index("album-artist", i) - # We need to check tag is not just spaces - if exists and read.strip(" "): - artists.append(read) - return "; ".join(artists) + return self.__get(tags, ["album-artist"]) def get_album_name(self, tags): """ @@ -274,11 +224,10 @@ """ if tags is None: return _("Unknown") - (exists, album_name) = tags.get_string_index("album", 0) - # We need to check tag is not just spaces - if not exists or not album_name.strip(" "): - album_name = _("Unknown") - return album_name + album = self.__get(tags, ["album"]) + if not album: + album = _("Unknown") + return album def get_genres(self, tags): """ @@ -288,15 +237,10 @@ """ if tags is None: return _("Unknown") - genres = [] - for i in range(tags.get_tag_size("genre")): - (exists, read) = tags.get_string_index("genre", i) - # We need to check tag is not just spaces - if exists and read.strip(" "): - genres.append(read) + genres = self.__get(tags, ["genre"]) if not genres: - return _("Unknown") - return "; ".join(genres) + genres = _("Unknown") + return genres def get_discname(self, tags): """ @@ -304,18 +248,7 @@ @param tags as Gst.TagList @return disc name as str """ - if tags is None: - return "" - discname = "" - for i in range(tags.get_tag_size("extended-comment")): - (exists, read) = tags.get_string_index("extended-comment", i) - if exists and read.startswith("PART"): - discname = "=".join(read.split("=")[1:]) - break - if exists and read.startswith("DISCSUBTITLE"): - discname = "=".join(read.split("=")[1:]) - break - return discname + return self.__get_extended(tags, ['PART', 'DISCSUBTITLE']) def get_discnumber(self, tags): """ @@ -325,8 +258,8 @@ """ if tags is None: return 0 - (exists, discnumber) = tags.get_uint_index("album-disc-number", 0) - if not exists: + discnumber = self.__get(tags, ["album-disc-number"]) + if not discnumber: discnumber = 0 return discnumber @@ -338,35 +271,14 @@ """ if tags is None: return False - size = tags.get_tag_size("private-id3v2-frame") - for i in range(0, size): - (exists, sample) = tags.get_sample_index( - "private-id3v2-frame", - i) - if not exists: - continue - (exists, m) = sample.get_buffer().map(Gst.MapFlags.READ) - if not exists: - continue - # Gstreamer 1.18 API breakage - try: - bytes = m.data.tobytes() - except: - bytes = m.data - frame = FrameTextTag(bytes) - if frame.key == "TCMP": - string = frame.string - if not string: - Logger.debug(tags.to_string()) - return string and string[-1] == "1" - size = tags.get_tag_size("extended-comment") - for i in range(0, size): - (exists, sample) = tags.get_string_index( - "extended-comment", - i) - if not exists or not sample.startswith("COMPILATION="): - continue - return sample[12] + try: + compilation = self.__get_private_string(tags, "TCMP", False) + if not compilation: + compilation = self.__get_extended(tags, ["COMPILATION"]) + if compilation: + return bool(compilation) + except Exception as e: + Logger.error("TagReader::get_compilation(): %s" % e) return False def get_tracknumber(self, tags, filename): @@ -377,10 +289,10 @@ @return track number as int """ if tags is not None: - (exists, tracknumber) = tags.get_uint_index("track-number", 0) + tracknumber = self.__get(tags, ["track-number"]) else: - (exists, tracknumber) = (False, 0) - if not exists: + tracknumber = None + if not tracknumber: # Guess from filename m = match("^([0-9]*)[ ]*-", filename) if m: @@ -436,45 +348,21 @@ @return year and timestamp (int, int) """ def get_id3(): + date_string = self.__get_private_string(tags, "TDOR", False) try: - size = tags.get_tag_size("private-id3v2-frame") - for i in range(0, size): - (exists, sample) = tags.get_sample_index( - "private-id3v2-frame", - i) - if not exists: - continue - (exists, m) = sample.get_buffer().map(Gst.MapFlags.READ) - if not exists: - continue - # Gstreamer 1.18 API breakage - try: - bytes = m.data.tobytes() - except: - bytes = m.data - frame = FrameTextTag(bytes) - if frame.key == "TDOR": - if not frame.string: - Logger.debug(tags.to_string()) - date = get_iso_date_from_string(frame.string) - datetime = GLib.DateTime.new_from_iso8601(date, None) - return (datetime.get_year(), datetime.to_unix()) + date = get_iso_date_from_string(date_string) + datetime = GLib.DateTime.new_from_iso8601(date, None) + return (datetime.get_year(), datetime.to_unix()) except: pass return (None, None) def get_ogg(): try: - size = tags.get_tag_size("extended-comment") - for i in range(0, size): - (exists, sample) = tags.get_string_index( - "extended-comment", - i) - if not exists or not sample.startswith("ORIGINALDATE="): - continue - date = get_iso_date_from_string(sample[13:]) - datetime = GLib.DateTime.new_from_iso8601(date, None) - return (datetime.get_year(), datetime.to_unix()) + date_string = self.__get_extended(tags, ['ORIGINALDATE']) + date = get_iso_date_from_string(date_string) + datetime = GLib.DateTime.new_from_iso8601(date, None) + return (datetime.get_year(), datetime.to_unix()) except: pass return (None, None) @@ -492,14 +380,10 @@ @param tags as Gst.TagList @return int/None """ - try: - if tags is not None: - (exists, bpm) = tags.get_double_index("beats-per-minute", 0) - if exists: - return bpm - except: - pass - return None + bpm = self.__get(tags, ["beats-per-minute"]) + if not bpm: + bpm = None + return bpm def get_popm(self, tags): """ @@ -524,8 +408,12 @@ bytes = m.data.tobytes() except: bytes = m.data - if bytes[0:4] == b"POPM": - popm = bytes.split(b"\x00")[6][0] + + if len(bytes) > 4 and bytes[0:4] == b"POPM": + try: + popm = bytes.split(b"\x00")[6][0] + except: + popm = 0 if popm == 0: value = 0 elif popm >= 1 and popm < 64: @@ -551,61 +439,14 @@ @parma tags as Gst.TagList @return lyrics as str """ - def decode_lyrics(bytes): - try: - frame = FrameLangTag(bytes) - if frame.key == "USLT": - return frame.string - except Exception as e: - Logger.warning("TagReader::get_lyrics(): %s", e) - return None - def get_mp4(): - try: - (exists, sample) = tags.get_string_index("lyrics", 0) - if exists: - return sample - except Exception as e: - Logger.error("TagReader::get_mp4(): %s" % e) - return "" + return self.__get(tags, ["lyrics"]) def get_id3(): - try: - size = tags.get_tag_size("private-id3v2-frame") - for i in range(0, size): - (exists, sample) = tags.get_sample_index( - "private-id3v2-frame", - i) - if not exists: - continue - (exists, m) = sample.get_buffer().map(Gst.MapFlags.READ) - if not exists: - continue - # Gstreamer 1.18 API breakage - try: - bytes = m.data.tobytes() - except: - bytes = m.data - string = decode_lyrics(bytes) - if string is not None: - return string - except Exception as e: - Logger.error("TagReader::get_id3(): %s" % e) - return "" + return self.__get_private_string(tags, "USLT", True) def get_ogg(): - try: - size = tags.get_tag_size("extended-comment") - for i in range(0, size): - (exists, sample) = tags.get_string_index( - "extended-comment", - i) - if not exists or not sample.startswith("LYRICS="): - continue - return sample[7:] - except Exception as e: - Logger.error("TagReader::get_ogg(): %s" % e) - return "" + return self.__get_extended(tags, ["LYRICS"]) if tags is None: return "" @@ -631,36 +472,21 @@ lyrics.append((decodeUnicode(l, encoding), int.from_bytes(t[1:4], "big"))) except Exception as e: - Logger.warning("TagReader::get_synced_lyrics1(): %s", e) + Logger.warning( + "TagReader::get_synced_lyrics.decode_lyrics(): %s", e) return lyrics def get_id3(): try: - size = tags.get_tag_size("private-id3v2-frame") - for i in range(0, size): - (exists, sample) = tags.get_sample_index( - "private-id3v2-frame", - i) - if not exists: - continue - (exists, m) = sample.get_buffer().map(Gst.MapFlags.READ) - if not exists: - continue - # Gstreamer 1.18 API breakage - try: - bytes = m.data.tobytes() - except: - bytes = m.data - prefix = (bytes[0:4]) - if prefix not in [b"SYLT"]: - continue - frame = bytes[10:] + b = self.__get_private_bytes(tags, "SYLT") + if b: + frame = b[10:] encoding = frame[0:1] string = decode_lyrics(frame.split(b"\n"), encoding) if string is not None: return string except Exception as e: - Logger.error("TagReader::get_synced_lyrics2(): %s" % e) + Logger.warning("TagReader::get_synced_lyrics.get_id3(): %s", e) return "" if tags is None: @@ -784,3 +610,106 @@ ####################### # PRIVATE # ####################### + def __get_extended(self, tags, keys): + """ + Return tag from tags following keys + @param tags as Gst.TagList + @param keys as [str] + @return Tag as str + """ + if tags is None: + return "" + items = [] + try: + for i in range(tags.get_tag_size("extended-comment")): + (exists, read) = tags.get_string_index("extended-comment", i) + for key in keys: + if exists and read.startswith(key + "="): + items.append("".join(read.split("=")[1:])) + except Exception as e: + Logger.error("TagReader::__get_extended(): %s", e) + return ";".join(items) + + def __get(self, tags, keys): + """ + Return tag from tags following keys + Only handles string/uint/double + @param tags as Gst.TagList + @param keys as [str] + @return Tag as str/int/double. Empty string if does not exist + """ + if tags is None: + return "" + items = [] + try: + for key in keys: + for i in range(tags.get_tag_size(key)): + if key in self.__STRING: + (exists, read) = tags.get_string_index(key, i) + if exists and read.strip(" "): + items.append(read) + elif key in self.__INT: + (exists, read) = tags.get_uint_index(key, i) + if exists: + return read + elif key in self.__DOUBLE: + (exists, read) = tags.get_double_index(key, i) + if exists: + return read + else: + Logger.error("Missing key" % key) + except Exception as e: + Logger.error("TagReader::__get(): %s", e) + return ";".join(items) + + def __get_private_bytes(self, tags, key): + """ + Get key from private frame + @param tags as Gst.TagList + @param key as str + @return frame as bytes + """ + try: + size = tags.get_tag_size("private-id3v2-frame") + encoded_key = key.encode("utf-8") + for i in range(0, size): + (exists, sample) = tags.get_sample_index( + "private-id3v2-frame", + i) + if not exists: + continue + (exists, m) = sample.get_buffer().map(Gst.MapFlags.READ) + if not exists: + continue + # Gstreamer 1.18 API breakage + try: + b = m.data.tobytes() + except: + b = m.data + + if b[0:len(encoded_key)] != encoded_key: + continue + return b + except Exception as e: + Logger.error("TagReader::__get_private_bytes(): %s" % e) + return b"" + + def __get_private_string(self, tags, key, lang): + """ + Get key from private frame + @param tags as Gst.TagList + @param key as str + @param lang as bool + @return Tag as str + """ + try: + b = self.__get_private_bytes(tags, key) + if lang: + frame = FrameLangTag(b) + else: + frame = FrameTextTag(b) + if frame.key == key: + return frame.string + except Exception as e: + Logger.error("TagReader::__get_private(): %s" % e) + return "" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-1.4.9/lollypop/view_albums_box.py new/lollypop-1.4.12/lollypop/view_albums_box.py --- old/lollypop-1.4.9/lollypop/view_albums_box.py 2021-01-10 20:27:35.000000000 +0100 +++ new/lollypop-1.4.12/lollypop/view_albums_box.py 2021-01-17 20:48:13.000000000 +0100 @@ -263,11 +263,10 @@ def play_album(status, child): child.artwork.get_style_context().remove_class("load-animation") - child.data.reset_tracks() - App().player.play_album(child.data.clone(True)) + App().player.play_album(child.data.clone(False)) if child.data.storage_type & StorageType.COLLECTION: - App().player.play_album(child.data.clone(True)) + App().player.play_album(child.data.clone(False)) else: child.artwork.get_style_context().add_class("load-animation") cancellable = Gio.Cancellable.new() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-1.4.9/lollypop/view_current_albums.py new/lollypop-1.4.12/lollypop/view_current_albums.py --- old/lollypop-1.4.9/lollypop/view_current_albums.py 2021-01-10 20:27:35.000000000 +0100 +++ new/lollypop-1.4.12/lollypop/view_current_albums.py 2021-01-17 20:48:13.000000000 +0100 @@ -194,6 +194,7 @@ if App().player.next_track.id != track.id: App().player.next() row.album.remove_track(track) + App().player.update_next_prev() emit_signal(App().player, "playback-updated", row.album) if not row.children: row.destroy() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-1.4.9/lollypop/view_lazyloading.py new/lollypop-1.4.12/lollypop/view_lazyloading.py --- old/lollypop-1.4.9/lollypop/view_lazyloading.py 2021-01-10 20:27:35.000000000 +0100 +++ new/lollypop-1.4.12/lollypop/view_lazyloading.py 2021-01-17 20:48:13.000000000 +0100 @@ -13,7 +13,6 @@ from gi.repository import GLib, GObject from time import time -import gc from lollypop.define import LoadingState, App from lollypop.logger import Logger @@ -180,7 +179,6 @@ else: GLib.idle_add( App().window.container.type_ahead.entry.grab_focus) - gc.collect() Logger.debug("LazyLoadingView::lazy_loading(): %s", time() - self.__start_time) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-1.4.9/lollypop/view_tracks_album.py new/lollypop-1.4.12/lollypop/view_tracks_album.py --- old/lollypop-1.4.9/lollypop/view_tracks_album.py 2021-01-10 20:27:35.000000000 +0100 +++ new/lollypop-1.4.12/lollypop/view_tracks_album.py 2021-01-17 20:48:13.000000000 +0100 @@ -18,7 +18,7 @@ from lollypop.widgets_label import LabelWidget from lollypop.objects_album import Album from lollypop.utils import emit_signal -from lollypop.define import App, ViewType +from lollypop.define import App, ViewType, LovedFlags from lollypop.view_tracks import TracksView @@ -256,7 +256,8 @@ if self.view_type & (ViewType.ALBUM | ViewType.ARTIST): tracks = [] for child in self.children: - if child.track.loved != -1 or track.id == child.track.id: + if not child.track.loved & LovedFlags.SKIPPED or\ + track.id == child.track.id: tracks.append(child.track) child.set_state_flags(Gtk.StateFlags.NORMAL, True) # Do not update album list if in party or album already available @@ -365,6 +366,6 @@ @param label as LabelWidget @param disc_number as int """ - album = Album(self.__album.id) + album = self.__album.clone(False) album.set_disc_number(disc_number) App().player.play_album(album) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-1.4.9/lollypop/widgets_album.py new/lollypop-1.4.12/lollypop/widgets_album.py --- old/lollypop-1.4.9/lollypop/widgets_album.py 2021-01-10 20:27:35.000000000 +0100 +++ new/lollypop-1.4.12/lollypop/widgets_album.py 2021-01-17 20:48:13.000000000 +0100 @@ -38,6 +38,7 @@ Gtk.Grid.__init__(self) self.set_orientation(Gtk.Orientation.VERTICAL) self.__tracks_view = None + self.__revealer = None self.__view_type = view_type self.__storage_type = storage_type self.__album = album @@ -50,23 +51,25 @@ """ Populate widget """ - self.__revealer = Gtk.Revealer.new() - self.__revealer.show() - self.__banner = AlbumBannerWidget(self.__album, self.__storage_type, - self.__view_type) - self.__banner.show() - self.__banner.connect("populated", self.__on_banner_populated) - self.__banner.populate() - self.add(self.__banner) - self.add(self.__revealer) - self.__gesture = GesturesHelper(self.__banner, - primary_press_callback=self._on_press) - self.get_style_context().add_class("album-banner") - if App().settings.get_value("show-artist-tracks"): - self.__revealer.set_transition_type( - Gtk.RevealerTransitionType.NONE) - self.__populate() - self.set_selection() + if self.__revealer is None: + self.__revealer = Gtk.Revealer.new() + self.__revealer.show() + self.__banner = AlbumBannerWidget(self.__album, + self.__storage_type, + self.__view_type) + self.__banner.show() + self.__banner.connect("populated", self.__on_banner_populated) + self.__banner.populate() + self.add(self.__banner) + self.add(self.__revealer) + self.__gesture = GesturesHelper( + self.__banner, primary_press_callback=self._on_press) + self.get_style_context().add_class("album-banner") + if App().settings.get_value("show-artist-tracks"): + self.__revealer.set_transition_type( + Gtk.RevealerTransitionType.NONE) + self.__populate() + self.set_selection() def reveal_child(self): """ @@ -103,6 +106,8 @@ Get banner @return BannerWidget """ + if self.__revealer is None: + self.populate() return self.__banner @property diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-1.4.9/lollypop/widgets_banner_album.py new/lollypop-1.4.12/lollypop/widgets_banner_album.py --- old/lollypop-1.4.9/lollypop/widgets_banner_album.py 2021-01-10 20:27:35.000000000 +0100 +++ new/lollypop-1.4.12/lollypop/widgets_banner_album.py 2021-01-17 20:48:13.000000000 +0100 @@ -369,13 +369,15 @@ Play album @param button as Gtk.Button """ - App().player.play_album(self.__album.clone(False)) + selected = button.get_state_flags() & Gtk.StateFlags.SELECTED + App().player.play_album(self.__album.clone(selected)) def __on_add_button_clicked(self, button): """ Add/Remove album @param button as Gtk.Button """ + selected = button.get_state_flags() & Gtk.StateFlags.SELECTED add = self.__add_button.get_image().get_icon_name()[0] ==\ "list-add-symbolic" albums = App().player.get_albums_for_id(self.__album.id) @@ -393,7 +395,7 @@ break emit_signal(App().player, "playback-updated", album) else: - App().player.add_album(self.__album.clone(False)) + App().player.add_album(self.__album.clone(selected)) def __on_year_clicked(self, label): """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-1.4.9/meson.build new/lollypop-1.4.12/meson.build --- old/lollypop-1.4.9/meson.build 2021-01-10 20:27:35.000000000 +0100 +++ new/lollypop-1.4.12/meson.build 2021-01-17 20:48:13.000000000 +0100 @@ -1,5 +1,5 @@ project('lollypop', - version: '1.4.9', + version: '1.4.12', meson_version: '>= 0.46.0' ) revision = run_command('bin/revision.sh').stdout().strip()