Hello community, here is the log from the commit of package lollypop for openSUSE:Factory checked in at 2019-02-01 11:45:51 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/lollypop (Old) and /work/SRC/openSUSE:Factory/.lollypop.new.28833 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "lollypop" Fri Feb 1 11:45:51 2019 rev:66 rq:669975 version:0.9.916 Changes: -------- --- /work/SRC/openSUSE:Factory/lollypop/lollypop.changes 2019-01-25 22:45:14.135089864 +0100 +++ /work/SRC/openSUSE:Factory/.lollypop.new.28833/lollypop.changes 2019-02-01 11:45:51.632526904 +0100 @@ -1,0 +2,16 @@ +Tue Jan 29 19:57:41 UTC 2019 - antoine.belv...@opensuse.org + +- Update to version 0.9.916: + * Fix inotify code. + * Faster collection scanner. + +------------------------------------------------------------------- +Sat Jan 26 13:14:00 UTC 2019 - antoine.belv...@opensuse.org + +- Update to version 0.9.915: + * Fix an issue with artist playback (glgo#World/lollypop#1611). + * Fix an issue with lyrics (glgo#World/lollypop#1606). + * Fix an issue in collection scanner. + * Fix an issue with collection history. + +------------------------------------------------------------------- Old: ---- lollypop-0.9.914.tar.xz New: ---- lollypop-0.9.916.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ lollypop.spec ++++++ --- /var/tmp/diff_new_pack.nStfcX/_old 2019-02-01 11:45:52.164526357 +0100 +++ /var/tmp/diff_new_pack.nStfcX/_new 2019-02-01 11:45:52.164526357 +0100 @@ -17,7 +17,7 @@ Name: lollypop -Version: 0.9.914 +Version: 0.9.916 Release: 0 Summary: GNOME music playing application License: GPL-3.0-or-later ++++++ _service ++++++ --- /var/tmp/diff_new_pack.nStfcX/_old 2019-02-01 11:45:52.192526329 +0100 +++ /var/tmp/diff_new_pack.nStfcX/_new 2019-02-01 11:45:52.192526329 +0100 @@ -1,7 +1,7 @@ <services> <service mode="disabled" name="tar_scm"> <param name="changesgenerate">enable</param> - <param name="revision">0.9.914</param> + <param name="revision">0.9.916</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.nStfcX/_old 2019-02-01 11:45:52.204526316 +0100 +++ /var/tmp/diff_new_pack.nStfcX/_new 2019-02-01 11:45:52.208526312 +0100 @@ -1,4 +1,4 @@ <servicedata> <service name="tar_scm"> <param name="url">https://gitlab.gnome.org/World/lollypop.git</param> - <param name="changesrevision">ddb232d9eb8d91917e3eb12192f1006d1f498990</param></service></servicedata> \ No newline at end of file + <param name="changesrevision">8a6b84f0bd565d1d764aadc29de3fa61a78df335</param></service></servicedata> \ No newline at end of file ++++++ lollypop-0.9.914.tar.xz -> lollypop-0.9.916.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-0.9.914/data/application.css new/lollypop-0.9.916/data/application.css --- old/lollypop-0.9.914/data/application.css 2019-01-23 19:00:51.000000000 +0100 +++ new/lollypop-0.9.916/data/application.css 2019-01-29 07:05:19.000000000 +0100 @@ -57,6 +57,7 @@ .progress-bottom { border: none; + border-radius: 0px; background-color: transparent; background-image: none; padding-top: 0px; @@ -69,11 +70,13 @@ background-color: @theme_selected_bg_color; background-image: none; border: none; + border-radius: 0px; min-height: 6px; } .progress-bottom trough { border: none; + border-radius: 0px; background-color: transparent; background-image: none; min-height: 6px; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-0.9.914/data/org.gnome.Lollypop.appdata.xml.in new/lollypop-0.9.916/data/org.gnome.Lollypop.appdata.xml.in --- old/lollypop-0.9.914/data/org.gnome.Lollypop.appdata.xml.in 2019-01-23 19:00:51.000000000 +0100 +++ new/lollypop-0.9.916/data/org.gnome.Lollypop.appdata.xml.in 2019-01-29 07:05:19.000000000 +0100 @@ -27,9 +27,10 @@ </ul> </description> <releases> - <release version="0.9.913" date="2019-01-23"> + <release version="0.9.916" date="2019-01-28"> <description> - <ul>Fix issues in collection scanner</ul> + <ul>Fix inotify code</ul> + <ul>Faster collection scanner</ul> </description> </release> </releases> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-0.9.914/lollypop/application.py new/lollypop-0.9.916/lollypop/application.py --- old/lollypop-0.9.914/lollypop/application.py 2019-01-23 19:00:51.000000000 +0100 +++ new/lollypop-0.9.916/lollypop/application.py 2019-01-29 07:05:19.000000000 +0100 @@ -38,7 +38,7 @@ from lollypop.utils import set_proxy_from_gnome from lollypop.application_actions import ApplicationActions from lollypop.utils import is_audio, is_pls -from lollypop.define import Type, LOLLYPOP_DATA_PATH +from lollypop.define import Type, LOLLYPOP_DATA_PATH, ScanType from lollypop.window import Window from lollypop.database import Database from lollypop.player import Player @@ -472,7 +472,7 @@ """ def scanner_update(): self.__scanner_timeout_id = None - self.scanner.update(self.__scanner_uris, False) + self.scanner.update(ScanType.EPHEMERAL, self.__scanner_uris) self.__scanner_uris = [] if self.__scanner_timeout_id is not None: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-0.9.914/lollypop/application_actions.py new/lollypop-0.9.916/lollypop/application_actions.py --- old/lollypop-0.9.914/lollypop/application_actions.py 2019-01-23 19:00:51.000000000 +0100 +++ new/lollypop-0.9.916/lollypop/application_actions.py 2019-01-29 07:05:19.000000000 +0100 @@ -12,7 +12,7 @@ from gi.repository import Gio, GLib, Gtk -from lollypop.define import App +from lollypop.define import App, ScanType from lollypop.settings import SettingsDialog @@ -72,7 +72,7 @@ """ if App().window: App().task_helper.run(App().art.clean_all_cache) - App().scanner.update() + App().scanner.update(ScanType.FULL) def __on_about_activate_response(self, dialog, response_id): """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-0.9.914/lollypop/collectionscanner.py new/lollypop-0.9.916/lollypop/collectionscanner.py --- old/lollypop-0.9.914/lollypop/collectionscanner.py 2019-01-23 19:00:51.000000000 +0100 +++ new/lollypop-0.9.916/lollypop/collectionscanner.py 2019-01-29 07:05:19.000000000 +0100 @@ -24,7 +24,7 @@ from time import time from lollypop.inotify import Inotify -from lollypop.define import App, Type +from lollypop.define import App, Type, ScanType from lollypop.objects import Track, Album from lollypop.sqlcursor import SqlCursor from lollypop.tagreader import TagReader @@ -67,30 +67,31 @@ self.__inotify = None App().albums.update_max_count() - def update(self, uris=[], saved=True): + def update(self, scan_type, uris=[]): """ Update database + @param scan_type as ScanType @param uris as [str] - @param saved as bool """ + App().lookup_action("update_db").set_enabled(False) # Stop previous scan - if self.is_locked(): + if self.is_locked() and scan_type != ScanType.EPHEMERAL: self.stop() - GLib.timeout_add(250, self.update, uris, saved) + GLib.timeout_add(250, self.update, scan_type, uris) else: self.__disable_compilations = not App().settings.get_value( "show-compilations") - if not uris: + if scan_type == ScanType.FULL: uris = App().settings.get_music_uris() - if not uris: - return - + if not uris: + return # Register to progressbar - App().window.container.progress.add(self) - App().window.container.progress.set_fraction(0, self) + if scan_type != ScanType.EPHEMERAL: + App().window.container.progress.add(self) + App().window.container.progress.set_fraction(0, self) # Launch scan in a separate thread - self.__thread = Thread(target=self.__scan, args=(uris, saved)) + self.__thread = Thread(target=self.__scan, args=(scan_type, uris)) self.__thread.daemon = True self.__thread.start() @@ -114,13 +115,16 @@ Update progress bar status @param scanned items as int, total items as int """ - App().window.container.progress.set_fraction(current / total, self) + GLib.idle_add(App().window.container.progress.set_fraction, + current / total, + self) def __finish(self, modifications): """ Notify from main thread when scan finished @param modifications as bool """ + App().lookup_action("update_db").set_enabled(True) App().window.container.progress.set_fraction(1.0, self) self.stop() self.emit("scan-finished", modifications) @@ -145,11 +149,12 @@ self.__inotify.add_monitor(d) @profile - def __get_objects_for_uris(self, uris): + def __get_objects_for_uris(self, scan_type, uris): """ Get all tracks and dirs in uris + @param scan_type as ScanType @param uris as string - @return (tracks as [mtime: int, uri: str], dirs as [uri: str]) + @return (tracks [mtimes: int, uri: str], dirs as [uri: str]) """ files = [] dirs = [] @@ -178,6 +183,7 @@ else: mtime = get_mtime(info) files.append((mtime, child_uri)) + # Only happens if files passed as args else: mtime = get_mtime(info) files.append((mtime, uri)) @@ -188,36 +194,43 @@ return (files, dirs) @profile - def __scan(self, uris, saved): + def __scan(self, scan_type, uris): """ Scan music collection for music files + @param scan_type as ScanType @param uris as [str] - @param saved as bool @thread safe """ - if self.__history is None: + if scan_type != ScanType.EPHEMERAL and self.__history is None: self.__history = History() - (files, dirs) = self.__get_objects_for_uris(uris) + (files, dirs) = self.__get_objects_for_uris(scan_type, uris) - new_tracks = self.__scan_files(files, saved) - self.__add_monitor(dirs) + if scan_type == ScanType.NEW_FILES: + db_uris = App().tracks.get_uris(uris) + else: + db_uris = App().tracks.get_uris() + new_tracks = self.__scan_files(files, db_uris, scan_type) - GLib.idle_add(self.__finish, new_tracks and saved) + if scan_type != ScanType.EPHEMERAL: + self.__add_monitor(dirs) + GLib.idle_add(self.__finish, new_tracks) - if not saved and self.__thread is not None: + if scan_type == ScanType.EPHEMERAL: self.__play_new_tracks(new_tracks) - del self.__history - self.__history = None + if scan_type != ScanType.EPHEMERAL: + del self.__history + self.__history = None - def __scan_to_handle(self, f): + def __scan_to_handle(self, uri): """ Check if file has to be handle by scanner @param f as Gio.File @return bool """ try: + f = Gio.File.new_for_uri(uri) # Scan file if is_pls(f): # Handle playlist @@ -230,77 +243,57 @@ Logger.error("CollectionScanner::__scan_to_handle(): %s" % e) return False - def __scan_add(self, uri, mtime): - """ - Add audio file to database - @param uri as str - @param mtime as float - """ - try: - Logger.debug("Adding file: %s" % uri) - self.__add2db(uri, mtime) - SqlCursor.allow_thread_execution(App().db) - except Exception as e: - Logger.error("CollectionScanner::__scan_add(add): " - "%s, %s" % (e, uri)) - - def __scan_del(self, uri): - """ - Delete file from DB - @param uri as str - """ - try: - self.__del_from_db(uri) - SqlCursor.allow_thread_execution(App().db) - except Exception as e: - Logger.error("CollectionScanner::__scan_del: %s" % e) - @profile - def __scan_files(self, files, saved): + def __scan_files(self, files, db_uris, scan_type): """ Scan music collection for new audio files - @param files as [(int, str)] + @param files as [str] + @param db_uris as [str] + @param scan_type as ScanType @return new track uris as [str] @thread safe """ + SqlCursor.add(App().db) + i = 0 + # New tracks present in collection new_tracks = [] # Get mtime of all tracks to detect which has to be updated - mtimes = App().tracks.get_mtimes() - # Get uris of all tracks to detect which has to be deleted - to_delete = App().tracks.get_uris() - SqlCursor.add(App().db) + db_mtimes = App().tracks.get_mtimes() + count = len(files) + 1 try: - count = len(files) - i = 0 - while files: + # Scan new files + for (mtime, uri) in files: # Handle a stop request - if self.__thread is None: - raise Exception("Scan cancelled") + if self.__thread is None and scan_type != ScanType.EPHEMERAL: + raise Exception("Scan add cancelled") try: - (mtime, uri) = files.pop(0) - f = Gio.File.new_for_uri(uri) - already_in_db = uri in to_delete - if already_in_db: - to_delete.remove(uri) - if mtime > mtimes.get(uri, 0): - handled = self.__scan_to_handle(f) - if handled: - # On first scan, we want file mtime - mtime = int(time()) if mtimes else mtime - # If not saved, use 0 as mtime, easy delete on quit - if already_in_db: - self.__scan_del(uri) - self.__scan_add(uri, mtime if saved else 0) - new_tracks.append(uri) + if not self.__scan_to_handle(uri): + continue + if mtime > db_mtimes.get(uri, 0): + # If not saved, use 0 as mtime, easy delete on quit + if scan_type == ScanType.EPHEMERAL: + mtime = 0 + # Do not use mtime if not intial scan + elif db_mtimes: + mtime = int(time()) + Logger.debug("Adding file: %s" % uri) + self.__add2db(uri, mtime) + SqlCursor.allow_thread_execution(App().db) + new_tracks.append(uri) except Exception as e: Logger.error( - "CollectionScanner:: __scan_files: % s" % e) + "CollectionScanner:: __scan_add_files: % s" % e) i += 1 - GLib.idle_add(self.__update_progress, i, count) - # This files are not in collection anymore - if saved: - for uri in to_delete: - self.__scan_del(uri) + self.__update_progress(i, count) + if scan_type != ScanType.EPHEMERAL and self.__thread is not None: + for uri in db_uris: + # Handle a stop request + if self.__thread is None: + raise Exception("Scan del cancelled") + f = Gio.File.new_for_uri(uri) + if not f.query_exists(): + self.__del_from_db(uri) + SqlCursor.allow_thread_execution(App().db) except Exception as e: Logger.warning("CollectionScanner:: __scan_files: % s" % e) SqlCursor.commit(App().db) @@ -358,9 +351,25 @@ Logger.debug("CollectionScanner::add2db(): Restore stats") # Restore stats - (track_pop, track_rate, track_ltime, album_mtime, - track_loved, album_loved, album_pop, album_rate) = self.__history.get( - name, duration) + track_id = App().tracks.get_id_by_uri(uri) + if track_id is None: + basename = f.get_basename() + track_id = App().tracks.get_id_by_basename_duration(basename, + duration) + # Restore from history + if self.__history is None: + (track_pop, track_rate, track_ltime, + album_mtime, track_loved, album_loved, + album_pop, album_rate) = (0, 0, 0, 0, False, False, 0, 0) + elif track_id is None: + (track_pop, track_rate, track_ltime, + album_mtime, track_loved, album_loved, + album_pop, album_rate) = self.__history.get(name, duration) + # Delete track and restore from it + else: + (track_pop, track_rate, track_ltime, + album_mtime, track_loved, album_loved, + album_pop, album_rate) = self.__del_from_db(uri) # If nothing in stats, use track mtime if album_mtime == 0: album_mtime = mtime @@ -414,28 +423,24 @@ """ Delete track from db @param uri as str + @return (popularity, ltime, mtime, + loved album, album_popularity) """ try: - f = Gio.File.new_for_uri(uri) - name = f.get_basename() track_id = App().tracks.get_id_by_uri(uri) album_id = App().tracks.get_album_id(track_id) genre_ids = App().tracks.get_genre_ids(track_id) album_artist_ids = App().albums.get_artist_ids(album_id) artist_ids = App().tracks.get_artist_ids(track_id) - popularity = App().tracks.get_popularity(track_id) - rate = App().tracks.get_rate(track_id) - ltime = App().tracks.get_ltime(track_id) - mtime = App().tracks.get_mtime(track_id) - loved_track = App().tracks.get_loved(track_id) - duration = App().tracks.get_duration(track_id) - album_popularity = App().albums.get_popularity(album_id) + track_pop = App().tracks.get_popularity(track_id) + track_rate = App().tracks.get_rate(track_id) + track_ltime = App().tracks.get_ltime(track_id) + album_mtime = App().tracks.get_mtime(track_id) + track_loved = App().tracks.get_loved(track_id) + album_pop = App().albums.get_popularity(album_id) album_rate = App().albums.get_rate(album_id) - loved_album = App().albums.get_loved(album_id) + album_loved = App().albums.get_loved(album_id) uri = App().tracks.get_uri(track_id) - self.__history.add(name, duration, popularity, rate, - ltime, mtime, loved_track, loved_album, - album_popularity, album_rate) App().tracks.remove(track_id) App().tracks.clean(track_id) cleaned = App().albums.clean(album_id) @@ -445,16 +450,17 @@ album_id, True) for artist_id in album_artist_ids + artist_ids: cleaned = App().artists.clean(artist_id) - # Force update even if not cleaned as artist may - # have been removed from a selected genre - GLib.idle_add(self.emit, "artist-updated", - artist_id, False) + if cleaned: + GLib.idle_add(self.emit, "artist-updated", + artist_id, False) for genre_id in genre_ids: cleaned = App().genres.clean(genre_id) if cleaned: SqlCursor.commit(App().db) GLib.idle_add(self.emit, "genre-updated", genre_id, False) + return (track_pop, track_rate, track_ltime, album_mtime, + track_loved, album_loved, album_pop, album_rate) except Exception as e: Logger.error("CollectionScanner::__del_from_db: %s" % e) @@ -485,8 +491,9 @@ album_artist_ids = new_artist_ids App().albums.set_artist_ids(album_id, new_artist_ids) # Update UI based on previous artist calculation - for artist_id in album_artist_ids: - GLib.idle_add(self.emit, "artist-updated", artist_id, add) + if App().albums.get_tracks_count(album_id) > 1: + for artist_id in album_artist_ids: + GLib.idle_add(self.emit, "artist-updated", artist_id, add) # Update album genres for genre_id in genre_ids: App().albums.add_genre(album_id, genre_id) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-0.9.914/lollypop/database_tracks.py new/lollypop-0.9.916/lollypop/database_tracks.py --- old/lollypop-0.9.914/lollypop/database_tracks.py 2019-01-23 19:00:51.000000000 +0100 +++ new/lollypop-0.9.916/lollypop/database_tracks.py 2019-01-29 07:05:19.000000000 +0100 @@ -144,6 +144,22 @@ return v[0] return None + def get_id_by_basename_duration(self, basename, duration): + """ + Get track id by basename + @param basename as str + @param duration as int + @return track_id as int + """ + with SqlCursor(App().db) as sql: + result = sql.execute("SELECT rowid FROM tracks\ + WHERE uri like ? AND duration=?", + ("%" + basename, duration)) + v = result.fetchone() + if v is not None: + return v[0] + return None + def get_id_by(self, name, album_id, artist_ids): """ Return track id for name/album/artists @@ -432,14 +448,24 @@ WHERE mtime=0") return list(itertools.chain(*result)) - def get_uris(self): + def get_uris(self, uris_concerned=None): """ Get all tracks uri + @param uris_concerned as [uri as str] @return [str] """ with SqlCursor(App().db) as sql: - result = sql.execute("SELECT uri FROM tracks") - return list(itertools.chain(*result)) + uris = [] + if uris_concerned: + for uri in uris_concerned: + result = sql.execute("SELECT uri\ + FROM tracks\ + WHERE uri LIKE ?", (uri + "%",)) + uris += list(itertools.chain(*result)) + else: + result = sql.execute("SELECT uri FROM tracks") + uris = list(itertools.chain(*result)) + return uris def get_number(self, track_id): """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-0.9.914/lollypop/define.py new/lollypop-0.9.916/lollypop/define.py --- old/lollypop-0.9.914/lollypop/define.py 2019-01-23 19:00:51.000000000 +0100 +++ new/lollypop-0.9.916/lollypop/define.py 2019-01-29 07:05:19.000000000 +0100 @@ -62,6 +62,12 @@ MAX = 4000 +class ScanType: + EPHEMERAL = 0 + NEW_FILES = 1 + FULL = 2 + + class SelectionListMask: LIST_ONE = 1 << 1 LIST_TWO = 1 << 2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-0.9.914/lollypop/inotify.py new/lollypop-0.9.916/lollypop/inotify.py --- old/lollypop-0.9.914/lollypop/inotify.py 2019-01-23 19:00:51.000000000 +0100 +++ new/lollypop-0.9.916/lollypop/inotify.py 2019-01-29 07:05:19.000000000 +0100 @@ -12,7 +12,7 @@ from gi.repository import Gio, GLib -from lollypop.define import App +from lollypop.define import App, ScanType from lollypop.utils import is_audio from lollypop.logger import Logger @@ -21,15 +21,15 @@ """ Inotify support """ - # 10 second before updating database - __TIMEOUT = 10000 + # 2 seconds before updating database + __TIMEOUT = 2000 def __init__(self): """ Init inode notification """ self.__monitors = {} - self.__timeout = None + self.__timeout_id = None def add_monitor(self, uri): """ @@ -61,7 +61,18 @@ @param other_file as Gio.File/None @param event as Gio.FileMonitorEvent """ - update = False + changed_uri = changed_file.get_uri() + # Do not monitor our self + if changed_uri in self.__monitors.keys() and\ + self.__monitors[changed_uri] == monitor: + return + # Ignore non audio/dir + if changed_file.query_exists() and\ + not is_audio(changed_file) and\ + changed_file.query_file_type(Gio.FileQueryInfoFlags.NONE, + None) != Gio.FileType.DIRECTORY: + return + # Stop collection scanner and wait if App().scanner.is_locked(): App().scanner.stop() @@ -73,40 +84,20 @@ event) # Run update delayed else: - uri = changed_file.get_uri() - d = Gio.File.new_for_uri(uri) - is_dir = False - if d.query_exists(): - # If a directory, monitor it - if changed_file.query_file_type( - Gio.FileQueryInfoFlags.NONE, - None) == Gio.FileType.DIRECTORY: - self.add_monitor(uri) - is_dir = True - # If not an audio file, exit - elif is_audio(changed_file): - update = True + if self.__timeout_id is not None: + GLib.source_remove(self.__timeout_id) + if changed_file.has_parent(): + uris = [changed_file.get_parent().get_uri()] else: - update = True - if update: - if self.__timeout is not None: - GLib.source_remove(self.__timeout) - self.__timeout = None - # Launch collection update from this directory - # (and not the entire collection) - uris = None - if is_dir: - uris = [uri] - elif changed_file.has_parent(): - uris = [changed_file.get_parent().get_uri()] - self.__timeout = GLib.timeout_add(self.__TIMEOUT, - self.__run_collection_update, - uris) + uris = [changed_uri] + self.__timeout_id = GLib.timeout_add(self.__TIMEOUT, + self.__run_collection_update, + uris) - def __run_collection_update(self, uris=None): + def __run_collection_update(self, uris=[]): """ Run a collection update @param uris as [str] """ - self.__timeout = None - App().scanner.update(uris) + self.__timeout_id = None + App().scanner.update(ScanType.NEW_FILES, uris) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-0.9.914/lollypop/mpris.py new/lollypop-0.9.916/lollypop/mpris.py --- old/lollypop-0.9.914/lollypop/mpris.py 2019-01-23 19:00:51.000000000 +0100 +++ new/lollypop-0.9.916/lollypop/mpris.py 2019-01-29 07:05:19.000000000 +0100 @@ -54,7 +54,7 @@ args = list(parameters.unpack()) for i, sig in enumerate(self.method_inargs[method_name]): - if sig is "h": + if sig == "h": msg = invocation.get_message() fd_list = msg.get_unix_fd_list() args[i] = fd_list.get(args[i]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-0.9.914/lollypop/objects.py new/lollypop-0.9.916/lollypop/objects.py --- old/lollypop-0.9.914/lollypop/objects.py 2019-01-23 19:00:51.000000000 +0100 +++ new/lollypop-0.9.916/lollypop/objects.py 2019-01-29 07:05:19.000000000 +0100 @@ -326,12 +326,12 @@ """ Get track @param track_id as int - @return Track/None + @return Track """ for track in self.tracks: if track.id == track_id: return track - return None + return Track() @property def title(self): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-0.9.914/lollypop/player.py new/lollypop-0.9.916/lollypop/player.py --- old/lollypop-0.9.914/lollypop/player.py 2019-01-23 19:00:51.000000000 +0100 +++ new/lollypop-0.9.916/lollypop/player.py 2019-01-29 07:05:19.000000000 +0100 @@ -257,37 +257,25 @@ else: album_ids += App().albums.get_ids([], filter1_ids, True) - shuffle_setting = App().settings.get_enum("shuffle") if not album_ids: return - elif shuffle_setting == Shuffle.ALBUMS: - if album_id is None: - shuffle(album_ids) - album = Album(album_id, filter1_ids, filter2_ids, True) - else: - album = Album(album_id, filter1_ids, filter2_ids, True) - shuffle(album_ids) - else: - album = Album(album_id, filter1_ids, filter2_ids, True) - # Select a track and start playback - track = None - if shuffle_setting == Shuffle.ALBUMS: - self._albums = [album] - album_ids.remove(album_id) - if shuffle_setting == Shuffle.TRACKS: - track = choice(album.tracks) - elif shuffle_setting == Shuffle.ALBUMS: - if self._albums and self._albums[0].tracks: - track = self._albums[0].tracks[0] - elif album.tracks: - track = album.tracks[0] # Create album objects + albums = [] + album = None for _album_id in album_ids: - album = Album(_album_id, filter1_ids, filter2_ids, True) - self._albums.append(album) - if track is not None: - self.load(track) + _album = Album(_album_id, filter1_ids, filter2_ids, True) + if album_id == _album_id: + album = _album + albums.append(_album) + + shuffle_setting = App().settings.get_enum("shuffle") + if shuffle_setting == Shuffle.ALBUMS: + self.__play_shuffle_albums(album, albums) + elif shuffle_setting == Shuffle.TRACKS: + self.__play_shuffle_tracks(album, albums) + else: + self.__play_albums(album, albums) self.emit("playlist-changed") def clear_albums(self): @@ -539,6 +527,57 @@ ####################### # PRIVATE # ####################### + def __play_shuffle_albums(self, album, albums): + """ + Start shuffle albums playback. Prepend album if not None + @param album as Album + @param albums as [albums] + """ + track = None + if album is None: + album = choice(albums) + else: + self._albums = [album] + albums.remove(album) + shuffle(albums) + self._albums += albums + if album.tracks: + track = album.tracks[0] + if track is not None: + self.load(track) + + def __play_shuffle_tracks(self, album, albums): + """ + Start shuffle tracks playback. + @param album as Album + @param albums as [albums] + """ + if album is None: + album = choice(albums) + if album.tracks: + track = choice(album.tracks) + else: + track = None + self._albums = albums + if track is not None: + self.load(track) + + def __play_albums(self, album, albums): + """ + Start albums playback. + @param album as Album + @param albums as [albums] + """ + if album is None: + album = albums[0] + if album.tracks: + track = album.tracks[0] + else: + track = None + self._albums = albums + if track is not None: + self.load(track) + def __on_playback_changed(self, settings, value): """ reset next/prev diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-0.9.914/lollypop/progressbar.py new/lollypop-0.9.916/lollypop/progressbar.py --- old/lollypop-0.9.914/lollypop/progressbar.py 2019-01-23 19:00:51.000000000 +0100 +++ new/lollypop-0.9.916/lollypop/progressbar.py 2019-01-29 07:05:19.000000000 +0100 @@ -51,7 +51,9 @@ if caller == self.__callers[0]: self.show() self.__fraction = fraction - if not self.__progress_running: + if fraction == 0: + Gtk.ProgressBar.set_fraction(self, 0.0) + elif not self.__progress_running: self.__progress_running = True self.__progress_update(caller) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-0.9.914/lollypop/settings.py new/lollypop-0.9.916/lollypop/settings.py --- old/lollypop-0.9.914/lollypop/settings.py 2019-01-23 19:00:51.000000000 +0100 +++ new/lollypop-0.9.916/lollypop/settings.py 2019-01-29 07:05:19.000000000 +0100 @@ -15,7 +15,7 @@ from gettext import gettext as _ from gettext import ngettext as ngettext -from lollypop.define import App +from lollypop.define import App, ScanType from lollypop.logger import Logger from lollypop.database import Database from lollypop.database_history import History @@ -668,7 +668,15 @@ self.__settings_dialog.hide() self.__settings_dialog.destroy() if set(previous) != set(uris): - App().scanner.update() + to_delete = [uri for uri in previous if uri not in uris] + if to_delete: + # We need to do a full scan + App().scanner.update(ScanType.FULL) + else: + # Only scan new folders + to_scan = [uri for uri in uris if uri not in previous] + if to_scan: + App().scanner.update(ScanType.NEW_FILES, to_scan) def __test_lastfm_connection(self, result, fm): """ @@ -806,7 +814,7 @@ App().db = Database() App().window.container.show_genres( App().settings.get_value("show-genres")) - App().scanner.update() + App().scanner.update(ScanType.FULL) self.__progress.get_toplevel().set_deletable(True) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-0.9.914/lollypop/tagreader.py new/lollypop-0.9.916/lollypop/tagreader.py --- old/lollypop-0.9.914/lollypop/tagreader.py 2019-01-23 19:00:51.000000000 +0100 +++ new/lollypop-0.9.916/lollypop/tagreader.py 2019-01-29 07:05:19.000000000 +0100 @@ -375,6 +375,7 @@ def get_lyrics(self, tags): """ Return lyrics for tags + All this code sucks @parma tags as Gst.TagList @return lyrics as str """ @@ -387,9 +388,11 @@ else: return None elif bytes[0:4] == b"USLT": - # This code sucks, if someone know how to handle this - # UTF8 - lyrics = bytes.split(b"\x00")[-1] + # Search for lyrics (more than 10 chars) + for value in bytes.split(b"\x00"): + if len(value) > 10: + lyrics = value + break # UTF-16 if not lyrics: lyrics = bytes.split( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-0.9.914/lollypop/view_information.py new/lollypop-0.9.916/lollypop/view_information.py --- old/lollypop-0.9.914/lollypop/view_information.py 2019-01-23 19:00:51.000000000 +0100 +++ new/lollypop-0.9.916/lollypop/view_information.py 2019-01-29 07:05:19.000000000 +0100 @@ -158,6 +158,8 @@ albums = [] for album_id in App().albums.get_ids([artist_id], []): albums.append(Album(album_id)) + if not albums: + albums = [App().player.current_track.album] albums_view.populate(albums) App().task_helper.run(InformationStore.get_bio, self.__artist_name, callback=(self.__on_get_bio,)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-0.9.914/lollypop/window.py new/lollypop-0.9.916/lollypop/window.py --- old/lollypop-0.9.914/lollypop/window.py 2019-01-23 19:00:51.000000000 +0100 +++ new/lollypop-0.9.916/lollypop/window.py 2019-01-29 07:05:19.000000000 +0100 @@ -15,7 +15,7 @@ from gettext import gettext as _ from lollypop.container import Container -from lollypop.define import App, Sizing, Type +from lollypop.define import App, Sizing, Type, ScanType from lollypop.toolbar import Toolbar from lollypop.logger import Logger from lollypop.adaptive import AdaptiveWindow @@ -523,7 +523,7 @@ # Delayed, make python segfault on sys.exit() otherwise # No idea why, maybe scanner using Gstpbutils before Gstreamer # initialisation is finished... - GLib.timeout_add(2000, App().scanner.update) + GLib.timeout_add(1000, App().scanner.update, ScanType.FULL) # Here we ignore initial configure events self.__toolbar.set_content_width(self.get_size()[0]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lollypop-0.9.914/meson.build new/lollypop-0.9.916/meson.build --- old/lollypop-0.9.914/meson.build 2019-01-23 19:00:51.000000000 +0100 +++ new/lollypop-0.9.916/meson.build 2019-01-29 07:05:19.000000000 +0100 @@ -1,5 +1,5 @@ project('lollypop', - version: '0.9.914', + version: '0.9.916', meson_version: '>= 0.40.0' ) i18n = import('i18n')