def __reset_database(self):
        """
            Reset database
        """
        def update_ui():
            App().window.container.go_home()
            App().scanner.update(ScanType.FULL)

        App().player.stop()
        if App().ws_director.collection_ws is not None:
            App().ws_director.collection_ws.stop()
        uris = App().tracks.get_uris()
        i = 0
        SqlCursor.add(App().db)
        SqlCursor.add(self.__history)
        count = len(uris)
        for uri in uris:
            self.del_from_db(uri, True)
            self.__update_progress(i, count, 0.01)
            i += 1
        App().tracks.del_persistent(False)
        App().tracks.clean(False)
        App().albums.clean(False)
        App().artists.clean(False)
        App().genres.clean(False)
        App().cache.clear_table("duration")
        SqlCursor.commit(App().db)
        SqlCursor.remove(App().db)
        SqlCursor.commit(self.__history)
        SqlCursor.remove(self.__history)
        GLib.idle_add(update_ui)
Ejemplo n.º 2
0
 def clean_old_albums(self, storage_types):
     """
         Clean old albums from DB
         @param storage_types as [StorageType]
     """
     SqlCursor.add(App().db)
     # Remove older albums
     for storage_type in storage_types:
         # If too many albums, do some cleanup
         count = App().albums.get_count_for_storage_type(storage_type)
         diff = count - self.MAX_ITEMS_PER_STORAGE_TYPE
         if diff > 0:
             album_ids = App().albums.get_oldest_for_storage_type(
                 storage_type, diff)
             for album_id in album_ids:
                 # EPHEMERAL with not tracks will be cleaned below
                 App().albums.set_storage_type(album_id,
                                               StorageType.EPHEMERAL)
                 App().tracks.remove_album(album_id, False)
     # On cancel, clean not needed, done in Application::quit()
     if not self.__cancellable.is_cancelled():
         App().tracks.clean(False)
         App().albums.clean(False)
         App().artists.clean(False)
     SqlCursor.remove(App().db)
Ejemplo n.º 3
0
 def del_tracks(self, track_ids):
     """
         Delete tracks from db
         @param track_ids as [int]
     """
     SqlCursor.add(Lp().playlists)
     with SqlCursor(self) as sql:
         all_album_ids = []
         all_artist_ids = []
         all_genre_ids = []
         for track_id in track_ids:
             album_id = Lp().tracks.get_album_id(track_id)
             art_file = Lp().art.get_album_cache_name(Album(album_id))
             genre_ids = Lp().tracks.get_genre_ids(track_id)
             album_artist_ids = Lp().albums.get_artist_ids(album_id)
             artist_ids = Lp().tracks.get_artist_ids(track_id)
             uri = Lp().tracks.get_uri(track_id)
             Lp().playlists.remove(uri)
             Lp().tracks.remove(track_id)
             Lp().tracks.clean(track_id)
             all_album_ids.append(album_id)
             all_artist_ids += album_artist_ids + artist_ids
             all_genre_ids += genre_ids
         for album_id in list(set(all_album_ids)):
             if Lp().albums.clean(album_id):
                 Lp().art.clean_store(art_file)
         for artist_id in list(set(all_artist_ids)):
             Lp().artists.clean(artist_id)
         for genre_id in list(set(all_genre_ids)):
             Lp().genres.clean(genre_id)
         sql.commit()
     SqlCursor.remove(Lp().playlists)
Ejemplo n.º 4
0
    def __vacuum(self):
        """
            VACUUM DB
        """
        try:
            if self.scanner.is_locked():
                self.scanner.stop()
                GLib.idle_add(self.__vacuum)
                return
            SqlCursor.add(self.db)
            self.tracks.del_non_persistent(False)
            self.tracks.clean(False)
            self.albums.clean(False)
            self.artists.clean(False)
            self.genres.clean(False)
            SqlCursor.remove(self.db)
            self.cache.clean(True)

            with SqlCursor(self.db) as sql:
                sql.isolation_level = None
                sql.execute("VACUUM")
                sql.isolation_level = ""
            with SqlCursor(self.playlists) as sql:
                sql.isolation_level = None
                sql.execute("VACUUM")
                sql.isolation_level = ""
        except Exception as e:
            Logger.error("Application::__vacuum(): %s" % e)
Ejemplo n.º 5
0
    def init(self):
        """
            Init main application
        """
        self.settings = Settings.new()
        # Mount enclosing volume as soon as possible
        uris = self.settings.get_music_uris()
        try:
            for uri in uris:
                if uri.startswith("file:/"):
                    continue
                f = Gio.File.new_for_uri(uri)
                f.mount_enclosing_volume(Gio.MountMountFlags.NONE, None, None,
                                         None)
        except Exception as e:
            print("Application::init():", e)
        self.__is_fs = False

        cssProviderFile = Lio.File.new_for_uri(
            "resource:///org/gnome/Lollypop/application.css")
        cssProvider = Gtk.CssProvider()
        cssProvider.load_from_file(cssProviderFile)
        screen = Gdk.Screen.get_default()
        styleContext = Gtk.StyleContext()
        styleContext.add_provider_for_screen(screen, cssProvider,
                                             Gtk.STYLE_PROVIDER_PRIORITY_USER)
        self.db = Database()
        self.playlists = Playlists()
        # We store cursors for main thread
        SqlCursor.add(self.db)
        SqlCursor.add(self.playlists)
        self.albums = AlbumsDatabase()
        self.artists = ArtistsDatabase()
        self.genres = GenresDatabase()
        self.tracks = TracksDatabase()
        self.player = Player()
        self.scanner = CollectionScanner()
        self.art = Art()
        self.notify = NotificationManager()
        self.art.update_art_size()
        if self.settings.get_value("artist-artwork"):
            GLib.timeout_add(5000, self.art.cache_artists_info)
        if LastFM is not None:
            self.lastfm = LastFM()
        if not self.settings.get_value("disable-mpris"):
            from lollypop.mpris import MPRIS
            MPRIS(self)

        settings = Gtk.Settings.get_default()
        self.__gtk_dark = settings.get_property(
            "gtk-application-prefer-dark-theme")
        if not self.__gtk_dark:
            dark = self.settings.get_value("dark-ui")
            settings.set_property("gtk-application-prefer-dark-theme", dark)

        # Map some settings to actions
        self.add_action(self.settings.create_action("playback"))
        self.add_action(self.settings.create_action("shuffle"))

        self.db.upgrade()
Ejemplo n.º 6
0
 def upgrade(self, db):
     """
         Upgrade db
         @param db as Database
     """
     version = 0
     SqlCursor.add(db)
     with SqlCursor(db, True) as sql:
         result = sql.execute("PRAGMA user_version")
         v = result.fetchone()
         if v is not None:
             version = v[0]
         if version < self.version:
             for i in range(version + 1, self.version + 1):
                 try:
                     if isinstance(self._UPGRADES[i], str):
                         sql.execute(self._UPGRADES[i])
                         SqlCursor.commit(db)
                     else:
                         self._UPGRADES[i](db)
                         SqlCursor.commit(db)
                 except Exception as e:
                     Logger.error("DB upgrade %s failed: %s" % (i, e))
             sql.execute("PRAGMA user_version=%s" % self.version)
     SqlCursor.remove(db)
Ejemplo n.º 7
0
    def init(self):
        """
            Init main application
        """
        self.__is_fs = False
        if Gtk.get_minor_version() > 18:
            cssProviderFile = Gio.File.new_for_uri(
                'resource:///org/gnome/Lollypop/application.css')
        else:
            cssProviderFile = Gio.File.new_for_uri(
                'resource:///org/gnome/Lollypop/application-legacy.css')
        cssProvider = Gtk.CssProvider()
        cssProvider.load_from_file(cssProviderFile)
        screen = Gdk.Screen.get_default()
        styleContext = Gtk.StyleContext()
        styleContext.add_provider_for_screen(screen, cssProvider,
                                             Gtk.STYLE_PROVIDER_PRIORITY_USER)
        self.settings = Settings.new()
        self.db = Database()
        self.playlists = Playlists()
        # We store cursors for main thread
        SqlCursor.add(self.db)
        SqlCursor.add(self.playlists)
        self.albums = AlbumsDatabase()
        self.artists = ArtistsDatabase()
        self.genres = GenresDatabase()
        self.tracks = TracksDatabase()
        self.player = Player()
        self.scanner = CollectionScanner()
        self.art = Art()
        self.art.update_art_size()
        if self.settings.get_value('artist-artwork'):
            GLib.timeout_add(5000, self.art.cache_artists_info)
        if LastFM is not None:
            self.lastfm = LastFM()
        if not self.settings.get_value('disable-mpris'):
            # Ubuntu > 16.04
            if Gtk.get_minor_version() > 18:
                from lollypop.mpris import MPRIS
            # Ubuntu <= 16.04, Debian Jessie, ElementaryOS
            else:
                from lollypop.mpris_legacy import MPRIS
            MPRIS(self)
        if not self.settings.get_value('disable-notifications'):
            from lollypop.notification import NotificationManager
            self.notify = NotificationManager()

        settings = Gtk.Settings.get_default()
        dark = self.settings.get_value('dark-ui')
        settings.set_property('gtk-application-prefer-dark-theme', dark)

        self.__parser = TotemPlParser.Parser.new()
        self.__parser.connect('entry-parsed', self.__on_entry_parsed)

        self.add_action(self.settings.create_action('shuffle'))

        self.db.upgrade()
Ejemplo n.º 8
0
    def __upgrade_13(self):
        """
            Convert tracks filepath column to uri
        """
        with SqlCursor(self._db) as sql:
            sql.execute("ALTER TABLE tracks RENAME TO tmp_tracks")
            sql.execute('''CREATE TABLE tracks (id INTEGER PRIMARY KEY,
                                              name TEXT NOT NULL,
                                              uri TEXT NOT NULL,
                                              duration INT,
                                              tracknumber INT,
                                              discnumber INT,
                                              discname TEXT,
                                              album_id INT NOT NULL,
                                              year INT,
                                              popularity INT NOT NULL,
                                              ltime INT NOT NULL,
                                              mtime INT NOT NULL,
                                              persistent INT NOT NULL
                                              DEFAULT 1)''')

            sql.execute('''INSERT INTO tracks(id, name, uri, duration,
                        tracknumber, discnumber, discname, album_id,
                        year, popularity, ltime, mtime, persistent) SELECT
                            id, name, filepath, duration,
                            tracknumber, discnumber, discname, album_id,
                            year, popularity, ltime, mtime, persistent FROM
                          tmp_tracks''')
            sql.execute("DROP TABLE tmp_tracks")
            result = sql.execute("SELECT rowid FROM tracks")
            for track_id in list(itertools.chain(*result)):
                result = sql.execute("SELECT uri FROM tracks WHERE rowid=?",
                                     (track_id,))
                v = result.fetchone()
                if v is not None:
                    uri = v[0]
                    if uri.startswith("/"):
                        uri = GLib.filename_to_uri(uri)
                        sql.execute("UPDATE tracks set uri=? WHERE rowid=?",
                                    (uri, track_id))
            sql.commit()
        dumb = DumbPlaylists()
        SqlCursor.add(dumb)
        with SqlCursor(dumb) as sql:
            sql.execute("ALTER TABLE tracks RENAME TO tmp_tracks")
            sql.execute('''CREATE TABLE tracks (playlist_id INT NOT NULL,
                                                uri TEXT NOT NULL)''')
            sql.execute('''INSERT INTO tracks(playlist_id, uri) SELECT
                            playlist_id, filepath FROM tmp_tracks''')
            sql.execute("DROP TABLE tmp_tracks")
            result = sql.execute("SELECT uri FROM tracks")
            for path in list(itertools.chain(*result)):
                if path.startswith("/"):
                    uri = GLib.filename_to_uri(path)
                    sql.execute("UPDATE tracks set uri=? WHERE uri=?",
                                (uri, path))
            sql.commit()
Ejemplo n.º 9
0
    def init(self):
        """
            Init main application
        """
        self.__is_fs = False
        if Gtk.get_minor_version() > 18:
            cssProviderFile = Gio.File.new_for_uri(
                'resource:///org/gnome/Lollypop/application.css')
        else:
            cssProviderFile = Gio.File.new_for_uri(
                'resource:///org/gnome/Lollypop/application-legacy.css')
        cssProvider = Gtk.CssProvider()
        cssProvider.load_from_file(cssProviderFile)
        screen = Gdk.Screen.get_default()
        styleContext = Gtk.StyleContext()
        styleContext.add_provider_for_screen(screen, cssProvider,
                                             Gtk.STYLE_PROVIDER_PRIORITY_USER)
        self.settings = Settings.new()
        self.db = Database()
        self.playlists = Playlists()
        # We store cursors for main thread
        SqlCursor.add(self.db)
        SqlCursor.add(self.playlists)
        self.albums = AlbumsDatabase()
        self.artists = ArtistsDatabase()
        self.genres = GenresDatabase()
        self.tracks = TracksDatabase()
        self.player = Player()
        self.scanner = CollectionScanner()
        self.art = Art()
        self.art.update_art_size()
        if self.settings.get_value('artist-artwork'):
            GLib.timeout_add(5000, self.art.cache_artists_info)
        if LastFM is not None:
            self.lastfm = LastFM()
        if not self.settings.get_value('disable-mpris'):
            # Ubuntu > 16.04
            if Gtk.get_minor_version() > 18:
                from lollypop.mpris import MPRIS
            # Ubuntu <= 16.04, Debian Jessie, ElementaryOS
            else:
                from lollypop.mpris_legacy import MPRIS
            MPRIS(self)
        if not self.settings.get_value('disable-notifications'):
            from lollypop.notification import NotificationManager
            self.notify = NotificationManager()

        settings = Gtk.Settings.get_default()
        dark = self.settings.get_value('dark-ui')
        settings.set_property('gtk-application-prefer-dark-theme', dark)

        self.add_action(self.settings.create_action('playback'))
        self.add_action(self.settings.create_action('shuffle'))

        self.db.upgrade()
Ejemplo n.º 10
0
    def init(self):
        """
            Init main application
        """
        if Gtk.get_minor_version() > 18:
            cssProviderFile = Gio.File.new_for_uri(
                'resource:///org/gnome/Lollypop/application.css')
        else:
            cssProviderFile = Gio.File.new_for_uri(
                'resource:///org/gnome/Lollypop/application-legacy.css')
        cssProvider = Gtk.CssProvider()
        cssProvider.load_from_file(cssProviderFile)
        screen = Gdk.Screen.get_default()
        styleContext = Gtk.StyleContext()
        styleContext.add_provider_for_screen(screen, cssProvider,
                                             Gtk.STYLE_PROVIDER_PRIORITY_USER)
        self.settings = Settings.new()
        ArtSize.BIG = self.settings.get_value('cover-size').get_int32()
        # For a 200 album artwork, we want a 60 artist artwork
        ArtSize.ARTIST_SMALL = ArtSize.BIG * 60 / 200
        self.db = Database()
        self.playlists = Playlists()
        # We store cursors for main thread
        SqlCursor.add(self.db)
        SqlCursor.add(self.playlists)
        self.albums = AlbumsDatabase()
        self.artists = ArtistsDatabase()
        self.genres = GenresDatabase()
        self.tracks = TracksDatabase()
        self.player = Player()
        self.scanner = CollectionScanner()
        self.art = Art()
        if self.settings.get_value('artist-artwork'):
            GLib.timeout_add(5000, self.art.cache_artists_art)
        if LastFM is not None:
            self.lastfm = LastFM()
        if not self.settings.get_value('disable-mpris'):
            MPRIS(self)
        if not self.settings.get_value('disable-notifications'):
            self.notify = NotificationManager()

        settings = Gtk.Settings.get_default()
        dark = self.settings.get_value('dark-ui')
        settings.set_property('gtk-application-prefer-dark-theme', dark)

        self._parser = TotemPlParser.Parser.new()
        self._parser.connect('entry-parsed', self._on_entry_parsed)

        self.add_action(self.settings.create_action('shuffle'))

        self._is_fs = False
Ejemplo n.º 11
0
    def init(self):
        """
            Init main application
        """
        cssProviderFile = Gio.File.new_for_uri(
            'resource:///org/gnome/Lollypop/application.css')
        cssProvider = Gtk.CssProvider()
        cssProvider.load_from_file(cssProviderFile)
        screen = Gdk.Screen.get_default()
        styleContext = Gtk.StyleContext()
        styleContext.add_provider_for_screen(screen, cssProvider,
                                             Gtk.STYLE_PROVIDER_PRIORITY_USER)
        self.settings = Settings.new()
        ArtSize.BIG = self.settings.get_value('cover-size').get_int32()
        if LastFM is not None:
            self.lastfm = LastFM()
        self.db = Database()
        self.playlists = Playlists()
        # We store cursors for main thread
        SqlCursor.add(self.db)
        SqlCursor.add(self.playlists)
        self.albums = AlbumsDatabase()
        self.artists = ArtistsDatabase()
        self.genres = GenresDatabase()
        self.tracks = TracksDatabase()
        self.player = Player()
        self.scanner = CollectionScanner()
        self.art = Art()
        if not self.settings.get_value('disable-mpris'):
            MPRIS(self)
        if not self.settings.get_value('disable-mpd'):
            self.mpd = MpdServerDaemon(
                self.settings.get_value('mpd-eth').get_string(),
                self.settings.get_value('mpd-port').get_int32())
        if not self.settings.get_value('disable-notifications'):
            self.notify = NotificationManager()

        settings = Gtk.Settings.get_default()
        dark = self.settings.get_value('dark-ui')
        settings.set_property('gtk-application-prefer-dark-theme', dark)

        self._parser = TotemPlParser.Parser.new()
        self._parser.connect('entry-parsed', self._on_entry_parsed)

        self.add_action(self.settings.create_action('shuffle'))

        self._is_fs = False
Ejemplo n.º 12
0
    def init(self):
        """
            Init main application
        """
        cssProviderFile = Gio.File.new_for_uri(
            'resource:///org/gnome/Lollypop/application.css')
        cssProvider = Gtk.CssProvider()
        cssProvider.load_from_file(cssProviderFile)
        screen = Gdk.Screen.get_default()
        styleContext = Gtk.StyleContext()
        styleContext.add_provider_for_screen(screen, cssProvider,
                                             Gtk.STYLE_PROVIDER_PRIORITY_USER)
        self.settings = Settings.new()
        ArtSize.BIG = self.settings.get_value('cover-size').get_int32()
        if LastFM is not None:
            self.lastfm = LastFM()
        self.db = Database()
        self.playlists = Playlists()
        # We store cursors for main thread
        SqlCursor.add(self.db)
        SqlCursor.add(self.playlists)
        self.albums = AlbumsDatabase()
        self.artists = ArtistsDatabase()
        self.genres = GenresDatabase()
        self.tracks = TracksDatabase()
        self.player = Player()
        self.scanner = CollectionScanner()
        self.art = Art()
        if not self.settings.get_value('disable-mpris'):
            MPRIS(self)
        if not self.settings.get_value('disable-mpd'):
            self.mpd = MpdServerDaemon(
                               self.settings.get_value('mpd-eth').get_string(),
                               self.settings.get_value('mpd-port').get_int32())
        if not self.settings.get_value('disable-notifications'):
            self.notify = NotificationManager()

        settings = Gtk.Settings.get_default()
        dark = self.settings.get_value('dark-ui')
        settings.set_property('gtk-application-prefer-dark-theme', dark)

        self._parser = TotemPlParser.Parser.new()
        self._parser.connect('entry-parsed', self._on_entry_parsed)

        self.add_action(self.settings.create_action('shuffle'))

        self._is_fs = False
Ejemplo n.º 13
0
 def insert_track(self, playlist_id, track, position):
     """
         Insert track at position, will remove track first if exists
         @param playlist_id as int
         @param track as Track
         @param position as int
     """
     SqlCursor.add(self)
     track_ids = self.get_track_ids(playlist_id)
     if track.id in track_ids:
         index = track_ids.index(track.id)
         track_ids.remove(track.id)
         if index < position:
             position -= 1
     track_ids.insert(position, track.id)
     self.clear(playlist_id)
     tracks = [Track(track_id) for track_id in track_ids]
     self.add_tracks(playlist_id, tracks)
     SqlCursor.remove(self)
Ejemplo n.º 14
0
    def __scan(self, uris, saved):
        """
            Scan music collection for music files
            @param uris as [str]
            @param saved as bool
            @thread safe
        """
        modifications = False
        if self.__history is None:
            self.__history = History()
        mtimes = App().tracks.get_mtimes()
        (new_tracks, new_dirs) = self.__get_objects_for_uris(uris)
        orig_tracks = App().tracks.get_uris()
        was_empty = len(orig_tracks) == 0

        count = len(new_tracks) + len(orig_tracks)
        # Add monitors on dirs
        if self.__inotify is not None:
            for d in new_dirs:
                if d.startswith("file://"):
                    self.__inotify.add_monitor(d)

        i = 0
        # Look for new files/modified file
        SqlCursor.add(App().db)
        try:
            to_add = []
            for uri in new_tracks:
                if self.__thread is None:
                    SqlCursor.remove(App().db)
                    return
                try:
                    GLib.idle_add(self.__update_progress, i, count)
                    f = Gio.File.new_for_uri(uri)
                    # We do not use time::modified because many tag editors
                    # just preserve this setting
                    try:
                        info = f.query_info("time::changed",
                                            Gio.FileQueryInfoFlags.NONE, None)
                        mtime = int(
                            info.get_attribute_as_string("time::changed"))
                    except:  # Fallback for remote fs
                        info = f.query_info("time::modified",
                                            Gio.FileQueryInfoFlags.NONE, None)
                        mtime = int(
                            info.get_attribute_as_string("time::modified"))
                    # If songs exists and mtime unchanged, continue,
                    # else rescan
                    if uri in orig_tracks:
                        orig_tracks.remove(uri)
                        i += 1
                        if not saved or mtime <= mtimes.get(uri, mtime + 1):
                            i += 1
                            continue
                        else:
                            SqlCursor.allow_thread_execution(App().db)
                            self.__del_from_db(uri)
                    # If not saved, use 0 as mtime, easy delete on quit
                    if not saved:
                        mtime = 0
                    # On first scan, use modification time
                    # Else, use current time
                    elif not was_empty:
                        mtime = int(time())
                    to_add.append((uri, mtime))
                except Exception as e:
                    Logger.error("CollectionScanner::__scan(mtime): %s" % e)
            if to_add or orig_tracks:
                modifications = True
            # Clean deleted files
            # Now because we need to populate history
            # Only if we are saving
            if saved:
                for uri in orig_tracks:
                    i += 1
                    GLib.idle_add(self.__update_progress, i, count)
                    self.__del_from_db(uri)
                    SqlCursor.allow_thread_execution(App().db)
            # Add files to db
            for (uri, mtime) in to_add:
                try:
                    Logger.debug("Adding file: %s" % uri)
                    i += 1
                    GLib.idle_add(self.__update_progress, i, count)
                    self.__add2db(uri, mtime)
                    SqlCursor.allow_thread_execution(App().db)
                except Exception as e:
                    Logger.error("CollectionScanner::__scan(add): %s, %s" %
                                 (e, uri))
        except Exception as e:
            Logger.error("CollectionScanner::__scan(): %s" % e)
        SqlCursor.commit(App().db)
        SqlCursor.remove(App().db)
        GLib.idle_add(self.__finish, modifications and saved)
        if not saved:
            self.__play_new_tracks(new_tracks)
        del self.__history
        self.__history = None
    def __scan(self, scan_type, uris):
        """
            Scan music collection for music files
            @param scan_type as ScanType
            @param uris as [str]
            @thread safe
        """
        try:
            SqlCursor.add(App().db)
            App().art.clean_rounded()
            (files, dirs,
             streams) = self.__get_objects_for_uris(scan_type, uris)
            if not files:
                App().notify.send("Lollypop",
                                  _("Scan disabled, missing collection"))
                return
            if scan_type == ScanType.NEW_FILES:
                db_uris = App().tracks.get_uris(uris)
            else:
                db_uris = App().tracks.get_uris()

            # Get mtime of all tracks to detect which has to be updated
            db_mtimes = App().tracks.get_mtimes()
            # * 2 => Scan + Save
            self.__progress_total = len(files) * 2 + len(streams)
            self.__progress_count = 0
            self.__progress_fraction = 0
            # Min: 1 thread, Max: 5 threads
            count = max(1, min(5, cpu_count() // 2))
            split_files = split_list(files, count)
            self.__tags = {}
            self.__pending_new_artist_ids = []
            threads = []
            for files in split_files:
                thread = App().task_helper.run(self.__scan_files, files,
                                               db_mtimes, scan_type)
                threads.append(thread)

            if scan_type == ScanType.EXTERNAL:
                storage_type = StorageType.EXTERNAL
            else:
                storage_type = StorageType.COLLECTION
            # Start getting files and populating DB
            self.__items = []
            i = 0
            while threads:
                thread = threads[i]
                if not thread.is_alive():
                    threads.remove(thread)
                self.__items += self.__save_in_db(storage_type)
                if i >= len(threads) - 1:
                    i = 0
                else:
                    i += 1

            # Add streams to DB, only happening on command line/m3u files
            self.__items += self.__save_streams_in_db(streams, storage_type)

            self.__remove_old_tracks(db_uris, scan_type)

            if scan_type == ScanType.EXTERNAL:
                albums = tracks_to_albums(
                    [Track(item.track_id) for item in self.__items])
                App().player.play_albums(albums)
            else:
                self.__add_monitor(dirs)
                GLib.idle_add(self.__finish, self.__items)
            self.__tags = {}
            self.__items = []
            self.__pending_new_artist_ids = []
        except Exception as e:
            Logger.warning("CollectionScanner::__scan(): %s", e)
        SqlCursor.remove(App().db)
Ejemplo n.º 16
0
 def __scan_files(self, files, db_uris, scan_type):
     """
         Scan music collection for new audio files
         @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
     db_mtimes = App().tracks.get_mtimes()
     count = len(files) + 1
     try:
         # Scan new files
         for (mtime, uri) in files:
             # Handle a stop request
             if self.__thread is None and scan_type != ScanType.EPHEMERAL:
                 raise Exception("Scan add cancelled")
             try:
                 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_add_files: % s" %
                              e)
             i += 1
             self.__update_progress(i, count)
         if scan_type != ScanType.EPHEMERAL and self.__thread is not None:
             # We need to check files are always in collections
             if scan_type == ScanType.FULL:
                 collections = App().settings.get_music_uris()
             else:
                 collections = None
             for uri in db_uris:
                 # Handle a stop request
                 if self.__thread is None:
                     raise Exception("Scan del cancelled")
                 in_collection = True
                 if collections is not None:
                     in_collection = False
                     for collection in collections:
                         if collection in uri:
                             in_collection = True
                             break
                 f = Gio.File.new_for_uri(uri)
                 if not in_collection or not f.query_exists():
                     self.del_from_db(uri, True)
                     SqlCursor.allow_thread_execution(App().db)
     except Exception as e:
         Logger.warning("CollectionScanner:: __scan_files: % s" % e)
     SqlCursor.commit(App().db)
     SqlCursor.remove(App().db)
     return new_tracks