def __update_for_url(self, url): """ Update charts for url @param url as str """ if not get_network_available(): return debug("SpotifyCharts::__update_for_url(): %s" % (url)) ids = self.__get_ids(url) web = Web() search = SpotifySearch() position = len(ids) while ids: sleep(10) track_id = ids.pop(0) album = search.get_track(track_id) if self.__stop: return if album is None or not album.subitems: position -= 1 continue for item in album.subitems: item.mtime = self.__time + position debug("SpotifyCharts::__update_for_url(): %s - %s - %s" % ( album.name, album.artists, track_id)) web.save_album_thread(album, DbPersistent.CHARTS, [Type.SPOTIFY]) position -= 1
def __scrobble(self, artist, album, title, timestamp, first=True): """ Scrobble track @param artist as str @param title as str @param album_title as str @param timestamp as int @param duration as int @param first is internal @thread safe """ debug("LastFM::__scrobble(): %s, %s, %s, %s" % (artist, album, title, timestamp)) try: self.scrobble(artist=artist, album=album, title=title, timestamp=timestamp) except BadAuthenticationError as e: pass except Exception as e: print("Lastfm::scrobble():", e) # Scrobble sometimes fails if first: self.__connect(self.__username, self.__password) self.__scrobble(artist, album, title, timestamp, False)
def __connect(self, username, password, populate_loved=False): """ Connect lastfm @param username as str @param password as str @thread safe """ self.__username = username if self.__goa is not None or (password != '' and username != ''): self.__is_auth = True else: self.__is_auth = False try: self.session_key = "" self.__check_for_proxy() if self.__goa is not None: self.session_key = self.__goa.call_get_access_token_sync( None)[0] else: skg = SessionKeyGenerator(self) self.session_key = skg.get_session_key( username=self.__username, password_hash=md5(password)) if populate_loved: self.__populate_loved_tracks() except Exception as e: debug("Lastfm::__connect(): %s" % e) self.__is_auth = False
def __now_playing(self, artist, album, title, duration, first=True): """ Now playing track @param artist as str @param title as str @param album as str @param duration as int @param first is internal @thread safe """ try: self.update_now_playing(artist=artist, album=album, title=title, duration=duration) debug("LastFM::__now_playing(): %s, %s, %s, %s" % (artist, album, title, duration)) except BadAuthenticationError: if Lp().notify is not None: GLib.idle_add(Lp().notify.send, _("Wrong Last.fm credentials")) except Exception as e: print("Lastfm::scrobble():", e) # now playing sometimes fails if first: self.__connect(self.__username, self.__password) self.__now_playing(artist, album, title, duration, False)
def __on_stream_about_to_finish(self, playbin): """ When stream is about to finish, switch to next track without gap @param playbin as Gst bin """ debug("Player::__on_stream_about_to_finish(): %s" % playbin) # Don't do anything if crossfade on, track already changed if self._crossfading: return if self.current_track.id == Type.RADIOS: return self._scrobble(self.current_track, self._start_time) # Increment popularity if not Lp().scanner.is_locked(): Lp().tracks.set_more_popular(self.current_track.id) # In party mode, linear popularity if self.is_party: pop_to_add = 1 # In normal mode, based on tracks count else: pop_to_add = int( Lp().albums.max_count / Lp().albums.get_tracks_count(self.current_track.album_id)) Lp().albums.set_more_popular(self.current_track.album_id, pop_to_add) if self._next_track.id is not None: self._load_track(self._next_track)
def _load_track(self, track, init_volume=True): """ Load track @param track as Track @param init volume as bool @return False if track not loaded """ if self._need_to_stop(): return False if init_volume: self._plugins.volume.props.volume = 1.0 debug("BinPlayer::_load_track(): %s" % track.uri) try: if track.id in self._queue: self._queue_track = track self._queue.remove(track.id) self.emit('queue-changed') self._playbin.set_property('uri', self._queue_track.uri) else: self._current_track = track self._queue_track = None self._playbin.set_property('uri', self.current_track.uri) except Exception as e: # Gstreamer error print("BinPlayer::_load_track(): ", e) self._queue_track = None return False return True
def _connect(self, username, password, populate_loved=False): """ Connect lastfm @param username as str @param password as str @thread safe """ self._username = username if self._goa is not None or (password != '' and username != ''): self._is_auth = True else: self._is_auth = False try: self._check_for_proxy() if self._goa is None: LastFMNetwork.__init__( self, api_key=self._API_KEY, api_secret=self._API_SECRET, username=self._username, password_hash=md5(password)) else: LastFMNetwork.__init__( self, api_key=self._API_KEY, api_secret=self._API_SECRET, session_key=self._goa.call_get_access_token_sync(None)[0]) if populate_loved: self._populate_loved_tracks() except Exception as e: debug("Lastfm::_connect(): %s" % e) self._is_auth = False
def _add(self, files): GLib.idle_add(self._progress.show) sql = Objects.db.get_cursor() tracks = Objects.tracks.get_paths(sql) count = len(files) i = 0 GLib.idle_add(self._update_progress, i, count) for f in files: track_id = None if not self._in_thread: sql.close() self._is_locked = False return if f not in tracks: infos = Objects.player.get_infos(f) if infos is not None: debug("Adding file: %s" % f) track_id = self._add2db(f, 0, infos, True, sql) else: print("Can't get infos for ", f) else: track_id = Objects.tracks.get_id_by_path(f, sql) if track_id is not None: if i == 0: sql.commit() GLib.idle_add(self.emit, "added", track_id, i==0) i += 1 GLib.idle_add(self._update_progress, i, count) Objects.albums.search_compilations(True, sql) sql.commit() sql.close() GLib.idle_add(self._progress.hide) self._in_thread = False self._is_locked = False
def __now_playing(self, artist, album, title, duration, first=True): """ Now playing track @param artist as str @param title as str @param album as str @param duration as int @param first is internal @thread safe """ try: self.update_now_playing(artist=artist, album=album, title=title, duration=duration) debug("LastFM::__now_playing(): %s, %s, %s, %s" % (artist, album, title, duration)) except WSError: pass except Exception as e: print("LastFM::__now_playing():", e) # now playing sometimes fails if first: self.__connect() self.__now_playing(artist, album, title, duration, False)
def _on_stream_start(self, bus, message): """ On stream start Emit "current-changed" to notify others components @param bus as Gst.Bus @param message as Gst.Message """ self._start_time = time() self._gst_duration = self._playbin.query_duration( Gst.Format.TIME)[1] / 1000 debug("Player::_on_stream_start(): %s" % self.current_track.uri) self.emit('current-changed') # Update now playing on lastfm if Lp().lastfm is not None and self.current_track.id >= 0: if self.current_track.album_artist_id == Type.COMPILATIONS: artist = self.current_track.artist else: artist = self.current_track.album_artist Lp().lastfm.now_playing(artist, self.current_track.album_name, self.current_track.title, int(self.current_track.duration)) if not Lp().scanner.is_locked(): Lp().tracks.set_listened_at(self.current_track.id, int(time())) self._handled_error = None
def _load_track(self, track, init_volume=True): """ Load track @param track as Track @param init volume as bool @return False if track not loaded """ if self.__need_to_stop(): return False if init_volume: self._plugins.volume.props.volume = 1.0 debug("BinPlayer::_load_track(): %s" % track.uri) try: self._current_track = track if track.is_web: loaded = self._load_web(track) # If track not loaded, go next if not loaded: self.set_next() GLib.timeout_add(500, self.__load, self.next_track, init_volume) return False # Return not loaded as handled by load_web() else: self._playbin.set_property("uri", track.uri) except Exception as e: # Gstreamer error print("BinPlayer::_load_track(): ", e) return False return True
def _load_track(self, track, init_volume=True): """ Load track @param track as Track @param init volume as bool @return False if track not loaded """ if self.__need_to_stop(): return False if init_volume: self._plugins.volume.props.volume = 1.0 debug("BinPlayer::_load_track(): %s" % track.uri) try: if track.id in self._queue: self._queue_track = track self._queue.remove(track.id) self.emit('queue-changed') else: self._current_track = track self._queue_track = None if track.is_youtube: loaded = self._load_youtube(track) # If track not loaded, go next if not loaded: self.set_next() GLib.timeout_add(500, self.__load, self.next_track, init_volume) return False # Return not loaded as handled by load_youtube() else: self._playbin.set_property('uri', track.uri) except Exception as e: # Gstreamer error print("BinPlayer::_load_track(): ", e) self._queue_track = None return False return True
def __connect(self, full_sync=False): """ Connect service @param full_sync as bool @thread safe """ if self.__goa is not None or (self.__password != "" and self.__login != ""): self.__is_auth = True else: self.__is_auth = False try: self.session_key = "" self.__check_for_proxy() if self.__goa is not None: self.session_key = self.__goa.call_get_access_token_sync( None)[0] else: skg = SessionKeyGenerator(self) self.session_key = skg.get_session_key(username=self.__login, password_hash=md5( self.__password)) if full_sync: self.__populate_loved_tracks() except Exception as e: debug("LastFM::__connect(): %s" % e) self.__is_auth = False
def __delayedclean_view(self, view): """ Clean view @param valid view as View """ debug("ViewContainer::__delayedclean_view(): %s" % view) view.destroy()
def __on_stream_about_to_finish(self, playbin): """ When stream is about to finish, switch to next track without gap @param playbin as Gst bin """ debug("Player::__on_stream_about_to_finish(): %s" % playbin) # Don"t do anything if crossfade on, track already changed if self._crossfading: return if self._current_track.id == Type.RADIOS: return self._scrobble(self._current_track, self._start_time) # Increment popularity if not Lp().scanner.is_locked() and self._current_track.id >= 0: Lp().tracks.set_more_popular(self._current_track.id) # In party mode, linear popularity if self.is_party: pop_to_add = 1 # In normal mode, based on tracks count else: # Some users report an issue where get_tracks_count() return 0 # See issue #886 # Don"t understand how this can happen! count = Lp().albums.get_tracks_count( self._current_track.album_id) if count: pop_to_add = int(Lp().albums.max_count / count) else: pop_to_add = 1 Lp().albums.set_more_popular(self._current_track.album_id, pop_to_add) if self._next_track.id is not None: self._load_track(self._next_track)
def _now_playing(self, artist, album, title, duration, first=True): """ Now playing track @param artist as str @param title as str @param album as str @param duration as int @param first is internal @thread safe """ debug("LastFM::_now_playing(): %s, %s, %s, %s" % (artist, album, title, duration)) try: LastFMNetwork.update_now_playing(self, artist=artist, album=album, title=title, duration=duration) except BadAuthenticationError: if Lp.notify is not None: GLib.idle_add(Lp.notify.send, _("Wrong Last.fm credentials")) except: # now playing sometimes fails if first: self._connect(self._username, self._password) self._now_playing(artist, album, title, duration, False)
def get_token(cancellable): """ Get a new auth token @param cancellable as Gio.Cancellable @return str """ # Remove 60 seconds to be sure if int(time()) + 60 < SpotifySearch.__EXPIRES and\ SpotifySearch.__TOKEN is not None: debug("Use spotify token: %s" % SpotifySearch.__TOKEN) return SpotifySearch.__TOKEN try: token_uri = "https://accounts.spotify.com/api/token" credentials = "%s:%s" % (SPOTIFY_CLIENT_ID, SPOTIFY_SECRET) encoded = b64encode(credentials.encode("utf-8")) credentials = encoded.decode("utf-8") session = Soup.Session.new() data = {"grant_type": "client_credentials"} msg = Soup.form_request_new_from_hash("POST", token_uri, data) msg.request_headers.append("Authorization", "Basic %s" % credentials) status = session.send_message(msg) if status == 200: body = msg.get_property("response-body") data = body.flatten().get_data() decode = json.loads(data.decode("utf-8")) SpotifySearch.__EXPIRES = int(time()) +\ int(decode["expires_in"]) SpotifySearch.__TOKEN = decode["access_token"] return SpotifySearch.__TOKEN except: return ""
def _scrobble(self, artist, album, title, timestamp, duration, first=True): """ Scrobble track @param artist as str @param title as str @param album_title as str @param timestamp as int @param duration as int @param first is internal @thread safe """ debug("LastFM::_scrobble(): %s, %s, %s, %s, %s" % (artist, album, title, timestamp, duration)) try: LastFMNetwork.scrobble(self, artist=artist, album=album, title=title, timestamp=timestamp) except BadAuthenticationError as e: pass except Exception as e: print("Lastfm::scrobble():", e) # Scrobble sometimes fails if first: self._connect(self._username, self._password)
def _get_objects_for_paths(self, paths): """ Return all tracks/dirs for paths @param paths as string @return ([tracks path], [dirs path], track count) """ tracks = [] track_dirs = list(paths) count = 0 for path in paths: for root, dirs, files in os.walk(path): # Add dirs for d in dirs: track_dirs.append(os.path.join(root, d)) # Add files for name in files: filepath = os.path.join(root, name) try: f = Gio.File.new_for_path(filepath) if is_pls(f): pass elif is_audio(f): tracks.append(filepath) count += 1 else: debug("%s not detected as a music file" % filepath) except Exception as e: print("CollectionScanner::_get_objects_for_paths: %s" % e) return (tracks, track_dirs, count)
def __update_for_url(self, url): """ Update charts for url @param url as str """ if not Gio.NetworkMonitor.get_default().get_network_available(): return debug("SpotifyCharts::__update_for_url(): %s => %s" % (url, self.__count)) ids = self.__get_ids(url) yt = Youtube() search = SpotifySearch() while ids: sleep(10) track_id = ids.pop(0) album_id = search.get_album_id(track_id) album = search.get_album(album_id) if album is None or album.exists_in_db(): continue if self._stop: return Lp().db.del_tracks(Lp().tracks.get_old_from_charts(self.__count)) debug("SpotifyCharts::__update_for_url(): %s - %s - %s" % (album.name, album.artists, album_id)) yt.save_album(album, DbPersistent.CHARTS)
def __get_objects_for_paths(self, paths): """ Return all tracks/dirs for paths @param paths as string @return ([tracks path], [dirs path], track count) """ tracks = [] track_dirs = list(paths) for path in paths: for root, dirs, files in os.walk(path, followlinks=True): # Add dirs for d in dirs: track_dirs.append(os.path.join(root, d)) # Add files for name in files: path = os.path.join(root, name) uri = GLib.filename_to_uri(path) try: f = Gio.File.new_for_uri(uri) if is_pls(f): pass elif is_audio(f): tracks.append(uri) else: debug("%s not detected as a music file" % uri) except Exception as e: print( "CollectionScanner::__get_objects_for_paths: %s" % e) return (tracks, track_dirs)
def __update_for_url(self, url): """ Update charts for url @param url as str """ if not get_network_available(): return debug("ItunesCharts::__update_for_url(): %s => %s" % (url, self.__LIMIT)) web = Web() ids = self.__get_ids(url) position = len(ids) while ids: sleep(10) (itunes_id, itunes_genre) = ids.pop(0) album = self.__get_album(itunes_id) if self.__stop: return if album is None or not album.subitems: position -= 1 continue album.mtime = self.__time + position for item in album.subitems: item.mtime = self.__time debug("ItunesCharts::__update_for_url(): %s - %s" % (album.name, album.artists)) t = TagReader() with SqlCursor(Lp().db) as sql: genre_ids = t.add_genres(itunes_genre) sql.commit() genre_ids.append(Type.ITUNES) web.save_album_thread(album, DbPersistent.CHARTS, genre_ids) position -= 1
def _on_stream_start(self, bus, message): """ On stream start Emit "current-changed" to notify others components @param bus as Gst.Bus @param message as Gst.Message """ self._start_time = time() debug("Player::_on_stream_start(): %s" % self._current_track.uri) self.emit("current-changed") # Update now playing on lastfm # Not supported by librefm if Lp().lastfm is not None and\ Lp().lastfm.session_key and\ self._current_track.id >= 0: artists = ", ".join(self._current_track.artists) Lp().lastfm.now_playing(artists, self._current_track.album_name, self._current_track.title, int(self._current_track.duration)) try: if not Lp().scanner.is_locked(): Lp().tracks.set_listened_at(self._current_track.id, int(time())) except: # Locked database pass
def __update_for_url(self, url): """ Update charts for url @param url as str """ if not get_network_available(): return debug("SpotifyCharts::__update_for_url(): %s => %s" % (url, self.__count)) ids = self.__get_ids(url) web = Web() search = SpotifySearch() while ids: sleep(10) track_id = ids.pop(0) album_id = search.get_album_id(track_id) album = search.get_album(album_id) if album is None or album.exists_in_db(): continue if self._stop: return Lp().db.del_tracks(Lp().tracks.get_old_from_charts(self.__count)) debug("SpotifyCharts::__update_for_url(): %s - %s - %s" % ( album.name, album.artists, album_id)) web.save_album(album, DbPersistent.CHARTS)
def _scrobble(self, artist, album, title, timestamp, duration): """ Scrobble track @param artist as str @param title as str @param album_title as str @param timestamp as int @param duration as int @thread safe """ debug("LastFM::_scrobble(): %s, %s, %s, %s, %s" % (artist, album, title, timestamp, duration)) try: LastFMNetwork.scrobble(self, artist=artist, album=album, title=title, timestamp=timestamp) except BadAuthenticationError: pass except: self._connect(self._username, self._password)
def __connect(self, username, password, populate_loved=False): """ Connect lastfm @param username as str @param password as str @thread safe """ self.__username = username if self.__goa is not None or (password != '' and username != ''): self.__is_auth = True else: self.__is_auth = False try: self.__check_for_proxy() if self.__goa is None: LastFMNetwork.__init__(self, api_key=self.__API_KEY, api_secret=self.__API_SECRET, username=self.__username, password_hash=md5(password)) else: LastFMNetwork.__init__( self, api_key=self.__API_KEY, api_secret=self.__API_SECRET, session_key=self.__goa.call_get_access_token_sync(None)[0]) if populate_loved: self.__populate_loved_tracks() except Exception as e: debug("Lastfm::__connect(): %s" % e) self.__is_auth = False
def __update_for_url(self, url): """ Update charts for url @param url as str """ if not get_network_available(): return debug("ItunesCharts::__update_for_url(): %s => %s" % (url, self.__LIMIT)) web = Web() ids = self.__get_ids(url) position = len(ids) while ids: sleep(10) (itunes_id, itunes_genre) = ids.pop(0) album = self.__get_album(itunes_id) if self.__stop: return if album is None or not album.subitems: position -= 1 continue album.mtime = self.__time + position for item in album.subitems: item.mtime = self.__time debug("ItunesCharts::__update_for_url(): %s - %s" % ( album.name, album.artists)) t = TagReader() with SqlCursor(Lp().db) as sql: genre_ids = t.add_genres(itunes_genre) sql.commit() genre_ids.append(Type.ITUNES) web.save_album_thread(album, DbPersistent.CHARTS, genre_ids) position -= 1
def __on_stream_about_to_finish(self, playbin): """ When stream is about to finish, switch to next track without gap @param playbin as Gst bin """ debug("Player::__on_stream_about_to_finish(): %s" % playbin) # Don't do anything if crossfade on, track already changed if self._crossfading: return if self.current_track.id == Type.RADIOS: return self._scrobble(self.current_track, self._start_time) # Increment popularity if not Lp().scanner.is_locked(): Lp().tracks.set_more_popular(self.current_track.id) # In party mode, linear popularity if self.is_party: pop_to_add = 1 # In normal mode, based on tracks count else: pop_to_add = int(Lp().albums.max_count / Lp().albums.get_tracks_count( self.current_track.album_id)) Lp().albums.set_more_popular(self.current_track.album_id, pop_to_add) if self._next_track.id is not None: self._load_track(self._next_track)
def _load_track(self, track, init_volume=True): """ Load track @param track as Track @param init volume as bool @return False if track not loaded """ if self.__need_to_stop(): return False if init_volume: self._plugins.volume.props.volume = 1.0 debug("BinPlayer::_load_track(): %s" % track.uri) try: if track.id in self._queue: self._queue_track = track self._queue.remove(track.id) self.emit('queue-changed') else: self._current_track = track self._queue_track = None if track.is_web: loaded = self._load_web(track) # If track not loaded, go next if not loaded: self.set_next() GLib.timeout_add(500, self.__load, self.next_track, init_volume) return False # Return not loaded as handled by load_web() else: self._playbin.set_property('uri', track.uri) except Exception as e: # Gstreamer error print("BinPlayer::_load_track(): ", e) self._queue_track = None return False return True
def __on_bus_message_tag(self, bus, message): """ Read tags from stream @param bus as Gst.Bus @param message as Gst.Message """ # Some radio streams send message tag every seconds! changed = False if (self.current_track.persistent == DbPersistent.INTERNAL or self.current_track.mtime != 0) and\ (self.current_track.id >= 0 or self.current_track.duration > 0.0): return debug("Player::__on_bus_message_tag(): %s" % self.current_track.uri) reader = TagReader() # Update duration of non internals if self.current_track.persistent != DbPersistent.INTERNAL: t = Thread(target=self.__update_current_duration, args=(reader, self.current_track)) t.daemon = True t.start() return tags = message.parse_tag() title = reader.get_title(tags, '') if title != '' and self.current_track.name != title: self.current_track.name = title changed = True if self.current_track.name == '': self.current_track.name = self.current_track.uri changed = True artists = reader.get_artists(tags) if artists != '' and self.current_track.artists != artists: self.current_track.artists = artists.split(',') changed = True if not self.current_track.artists: self.current_track.artists = self.current_track.album_artists changed = True if self.current_track.id == Type.EXTERNALS: (b, duration) = self._playbin.query_duration(Gst.Format.TIME) if b: self.current_track.duration = duration / 1000000000 # We do not use tagreader as we need to check if value is None self.current_track.album_name = tags.get_string_index('album', 0)[1] if self.current_track.album_name is None: self.current_track.album_name = '' self.current_track.artists = reader.get_artists(tags).split(',') self.current_track.set_album_artists( reader.get_album_artist(tags).split(',')) if self.current_track.album_artist == '': self.current_track.set_album_artists( self.current_track.artists) self.current_track.genres = reader.get_genres(tags).split(',') changed = True if changed: self.emit('current-changed')
def _on_bus_eos(self, bus, message): debug("Player::_on_bus_eos(): %s" % self.current_track.uri) if self.context.next != NextContext.NONE: self.context.next = NextContext.NONE self._set_next() self.next() else: self.load(self.current_track)
def __on_current_changed(self, player): """ Update toolbar @param player as Player """ debug("Toolbar::_on_current_changed") self.__toolbar_playback.on_current_changed(player) self.__toolbar_info.on_current_changed(player) self.__toolbar_title.on_current_changed(player)
def _on_bus_error(self, bus, message): debug("Error playing: %s" % self.current_track.uri) if self._handled_error != self.current_track.uri: self._handled_error = self.current_track.uri Lp.notify.send(_("File doesn't exist: %s") % self.current_track.uri) self._set_next() self.next() return False
def _on_current_changed(self, player): """ Update toolbar @param player as Player """ debug("Toolbar::_on_current_changed") self._toolbar_playback.on_current_changed(player) self._toolbar_info.on_current_changed(player) self._toolbar_title.on_current_changed(player)
def __on_get_secret(self, source, result): """ Store secret proxy @param source as GObject.Object @param result as Gio.AsyncResult """ try: self.__secret = Secret.Service.get_finish(result) except Exception as e: self.__secret = -1 debug("PasswordsHelper::__on_get_secret(): %s" % e)
def _cache_artists_art(self): """ Cache artwork for all artists """ # We create cache if needed InfoCache.init() # Then cache artwork for lastfm/wikipedia/spotify # We cache content as the same time # TODO Make this code more generic for (artist_id, artist) in Lp().artists.get([]): debug("ArtDownloader::_cache_artists_art(): %s" % artist) artwork_set = False if not Gio.NetworkMonitor.get_default().get_network_available() or\ InfoCache.exists_in_cache(artist): continue if Lp().lastfm is not None: try: (url, content) = Lp().lastfm.get_artist_infos(artist) if url is not None: s = Gio.File.new_for_uri(url) (status, data, tag) = s.load_contents() if status: artwork_set = True InfoCache.cache(artist, content, data, "lastfm") else: InfoCache.cache(artist, None, None, "lastfm") except: InfoCache.cache(artist, None, None, "lastfm") if ArtDownloader.Wikipedia is not None: try: wp = ArtDownloader.Wikipedia() (url, content) = wp.get_page_infos(artist) if url is not None: s = Gio.File.new_for_uri(url) (status, data, tag) = s.load_contents() if status: artwork_set = True InfoCache.cache(artist, content, data, "wikipedia") else: InfoCache.cache(artist, None, None, "wikipedia") except: InfoCache.cache(artist, None, None, "wikipedia") url = self._get_spotify_artist_artwork(artist) if url is not None: s = Gio.File.new_for_uri(url) (status, data, tag) = s.load_contents() if status: artwork_set = True InfoCache.cache(artist, None, data, "spotify") else: InfoCache.cache(artist, None, None, "spotify") if artwork_set: Lp().art.emit('artist-artwork-changed', artist) self._cache_artists_running = False
def _scan(self, paths): sql = Lp.db.get_cursor() orig_tracks = Lp.tracks.get_paths(sql) self._is_empty = len(orig_tracks) == 0 # Add monitors on dirs (new_tracks, new_dirs, count) = self._get_objects_for_paths(paths) if self._inotify is not None: for d in new_dirs: self._inotify.add_monitor(d) i = 0 for filepath in new_tracks: if not self._in_thread: sql.close() self._is_locked = False return GLib.idle_add(self._update_progress, i, count) try: mtime = int(os.path.getmtime(filepath)) if filepath not in orig_tracks: infos = self.get_infos(filepath) if infos is not None: debug("Adding file: %s" % filepath) self._add2db(filepath, mtime, infos, sql) else: print("Can't get infos for ", filepath) else: # Update tags by removing song and readd it if mtime != self._mtimes[filepath]: self._del_from_db(filepath, sql) infos = self.get_infos(filepath) if infos is not None: debug("Adding file: %s" % filepath) self._add2db(filepath, mtime, infos, sql) else: print("Can't get infos for ", filepath) orig_tracks.remove(filepath) except Exception as e: print(ascii(filepath)) print("CollectionScanner::_scan(): %s" % e) i += 1 # Clean deleted files if i > 0: for filepath in orig_tracks: self._del_from_db(filepath, sql) self._restore_popularities(sql) self._restore_mtimes(sql) sql.commit() sql.close() GLib.idle_add(self._finish)
def _on_bus_eos(self, bus, message): debug("Player::_on_bus_eos(): %s" % self.current_track.uri) if self.context.next not in [NextContext.NONE, NextContext.START_NEW_ALBUM]: self.stop() self.context.next = NextContext.NONE if self.next_track.id is not None: self._load_track(self.next_track) self.emit('current-changed') else: self._playbin.set_state(Gst.State.NULL) self._playbin.set_state(Gst.State.PLAYING)
def __on_bus_message_tag(self, bus, message): """ Read tags from stream @param bus as Gst.Bus @param message as Gst.Message """ # Some radio streams send message tag every seconds! changed = False if (self.current_track.persistent == DbPersistent.INTERNAL or self.current_track.mtime != 0) and\ (self.current_track.id >= 0 or self.current_track.duration > 0.0): return debug("Player::__on_bus_message_tag(): %s" % self.current_track.uri) reader = TagReader() # Update duration of non internals if self.current_track.persistent != DbPersistent.INTERNAL: t = Thread(target=self.__update_current_duration, args=(reader, self.current_track)) t.daemon = True t.start() return tags = message.parse_tag() title = reader.get_title(tags, '') if title != '' and self.current_track.name != title: self.current_track.name = title changed = True if self.current_track.name == '': self.current_track.name = self.current_track.uri changed = True artists = reader.get_artists(tags) if artists != '' and self.current_track.artists != artists: self.current_track.artists = artists.split(',') changed = True if not self.current_track.artists: self.current_track.artists = self.current_track.album_artists changed = True if self.current_track.id == Type.EXTERNALS: (b, duration) = self._playbin.query_duration(Gst.Format.TIME) if b: self.current_track.duration = duration/1000000000 # We do not use tagreader as we need to check if value is None self.current_track.album_name = tags.get_string_index('album', 0)[1] if self.current_track.album_name is None: self.current_track.album_name = '' self.current_track.genres = reader.get_genres(tags).split(',') changed = True if changed: self.emit('current-changed')
def __on_bus_eos(self, bus, message): """ On end of stream, stop playback go next otherwise """ debug("Player::__on_bus_eos(): %s" % self.current_track.uri) if self._playbin.get_bus() == bus: self.stop() self._next_context = NextContext.NONE if self._next_track.id is not None: self._load_track(self._next_track) self.emit('current-changed')
def __on_bus_eos(self, bus, message): """ On end of stream, stop playback go next otherwise """ debug("Player::__on_bus_eos(): %s" % self._current_track.uri) if self._playbin.get_bus() == bus: self.stop() self._next_context = NextContext.NONE if self._next_track.id is not None: self._load_track(self._next_track) self.emit("current-changed")
def __get_objects_for_uris(self, uris): """ Return all tracks/dirs for uris @param uris as string @return (track uri as [str], track dirs as [str], ignore dirs as [str]) """ tracks = [] ignore_dirs = [] track_dirs = list(uris) walk_uris = list(uris) while walk_uris: uri = walk_uris.pop(0) empty = True try: d = Gio.File.new_for_uri(uri) infos = d.enumerate_children( "standard::name,standard::type,standard::is-hidden", Gio.FileQueryInfoFlags.NONE, None) except Exception as e: print("CollectionScanner::__get_objects_for_uris():", e) ignore_dirs.append(uri) continue for info in infos: f = infos.get_child(info) child_uri = f.get_uri() empty = False if info.get_is_hidden(): continue elif info.get_file_type() == Gio.FileType.DIRECTORY: track_dirs.append(child_uri) walk_uris.append(child_uri) else: try: f = Gio.File.new_for_uri(child_uri) if is_pls(f): pass elif is_audio(f): tracks.append(child_uri) else: debug("%s not detected as a music file" % child_uri) except Exception as e: print( "CollectionScanner::" "__get_objects_for_uris():", e) # If a root uri is empty # Ensure user is not doing something bad if empty and uri in uris: ignore_dirs.append(uri) return (tracks, track_dirs, ignore_dirs)
def _on_bus_eos(self, bus, message): """ On end of stream, stop playing if user ask for, go next otherwise """ debug("Player::_on_bus_eos(): %s" % self.current_track.uri) if self.context.next not in [NextContext.NONE, NextContext.START_NEW_ALBUM]: self.stop() self.context.next = NextContext.NONE if self.next_track.id is not None: self._load_track(self.next_track) self.emit("current-changed") else: self.next()
def _on_bus_error(self, bus, message): """ Try a codec install and update current track @param bus as Gst.Bus @param message as Gst.Message """ debug("Error playing: %s" % self._current_track.uri) Lp().window.pulse(False) if self.__codecs.is_missing_codec(message): self.__codecs.install() Lp().scanner.stop() elif Lp().notify is not None: Lp().notify.send(message.parse_error()[0].message) self.stop()
def __get_objects_for_uris(self, uris): """ Return all tracks/dirs for uris @param uris as string @return (track uri as [str], track dirs as [str], ignore dirs as [str]) """ tracks = [] ignore_dirs = [] track_dirs = list(uris) walk_uris = list(uris) while walk_uris: uri = walk_uris.pop(0) empty = True try: d = Lio.File.new_for_uri(uri) infos = d.enumerate_children( 'standard::name,standard::type,standard::is-hidden', Gio.FileQueryInfoFlags.NONE, None) except Exception as e: print("CollectionScanner::__get_objects_for_uris():", e) continue for info in infos: f = infos.get_child(info) child_uri = f.get_uri() empty = False if info.get_is_hidden(): continue elif info.get_file_type() == Gio.FileType.DIRECTORY: track_dirs.append(child_uri) walk_uris.append(child_uri) else: try: f = Lio.File.new_for_uri(child_uri) if is_pls(f): pass elif is_audio(f): tracks.append(child_uri) else: debug("%s not detected as a music file" % uri) except Exception as e: print("CollectionScanner::" "__get_objects_for_uris():", e) # If a root uri is empty # Ensure user is not doing something bad if empty and uri in uris: ignore_dirs.append(uri) return (tracks, track_dirs, ignore_dirs)
def _on_bus_error(self, bus, message): debug("Error playing: %s" % self.current_track.uri) if self._codecs.is_missing_codec(message): self._codecs.install() self.stop() Lp.scanner.stop() return True if self._handled_error != self.current_track.uri: self._handled_error = self.current_track.uri if Lp.notify is not None: Lp.notify.send(_("File doesn't exist: %s") % self.current_track.uri) self.set_next() self.next() return False
def __on_clear_search(self, source, result, callback=None, *args): """ Clear passwords @param source as GObject.Object @param result as Gio.AsyncResult """ try: if result is not None: items = source.search_finish(result) for item in items: item.delete(None, None) if callback is not None: callback(*args) except Exception as e: debug("PasswordsHelper::__on_clear_search(): %s" % e)
def __on_bus_error(self, bus, message): """ Handle first bus error, ignore others @param bus as Gst.Bus @param message as Gst.Message """ debug("Error playing: %s" % self.current_track.uri) Lp().window.pulse(False) if self.__codecs.is_missing_codec(message): self.__codecs.install() Lp().scanner.stop() elif Lp().notify is not None: Lp().notify.send(message.parse_error()[0].message) self.emit('current-changed') return True
def __on_bus_error(self, bus, message): """ Handle first bus error, ignore others @param bus as Gst.Bus @param message as Gst.Message """ debug("Error playing: %s" % self._current_track.uri) Lp().window.pulse(False) if self.__codecs.is_missing_codec(message): self.__codecs.install() Lp().scanner.stop() elif Lp().notify is not None: Lp().notify.send(message.parse_error()[0].message) self.emit("current-changed") return True
def _on_bus_eos(self, bus, message): """ On end of stream, stop playing if user ask for, go next otherwise """ debug("Player::_on_bus_eos(): %s" % self.current_track.uri) if self.context.next not in [ NextContext.NONE, NextContext.START_NEW_ALBUM ]: self.stop() self.context.next = NextContext.NONE if self.next_track.id is not None: self._load_track(self.next_track) self.emit('current-changed') else: self.next()
def __on_bus_eos(self, bus, message): """ On end of stream, stop playback go next otherwise """ debug("Player::__on_bus_eos(): %s" % self.current_track.uri) if self._playbin.get_bus() == bus: self.stop() self._finished = NextContext.NONE if Lp().settings.get_value('repeat'): self._context.next = NextContext.NONE else: self._context.next = NextContext.STOP_ALL if self._next_track.id is not None: self._load_track(self._next_track) self.emit('current-changed')
def _on_bus_eos(self, bus, message): """ On end of stream, stop playback go next otherwise """ debug("Player::_on_bus_eos(): %s" % self.current_track.uri) if self._playbin.get_bus() == bus: self.stop() self._finished = NextContext.NONE if Lp().settings.get_value('repeat'): self._context.next = NextContext.NONE else: self._context.next = NextContext.STOP_ALL if self._next_track.id is not None: self._load_track(self._next_track) self.emit('current-changed')
def _on_stream_about_to_finish(self, playbin): """ When stream is about to finish, switch to next track without gap @param playbin as Gst bin """ debug("Player::_on_stream_about_to_finish(): %s" % playbin) # Don't do anything if crossfade on if self._crossfading: return if self.current_track.id == Type.RADIOS: return finished = self.current_track finished_start_time = self._start_time if self._next_track.id is not None: self._load_track(self._next_track) self._track_finished(finished, finished_start_time)
def _on_bus_error(self, bus, message): """ Handle first bus error, ignore others @param bus as Gst.Bus @param message as Gst.Message """ debug("Error playing: %s" % self.current_track.uri) if self._codecs.is_missing_codec(message): self._codecs.install() Lp.scanner.stop() elif Lp.notify is not None: Lp.notify.send(_("File doesn't exist: %s") % self.current_track.uri) self.stop() self.emit('current-changed') return True