示例#1
0
文件: art.py 项目: aembleton/cinamp
 def add_artwork_to_cache(self, name, surface, prefix):
     """
         Add artwork to cache
         @param name as str
         @param surface as cairo.Surface
         @param prefix as str
         @thread safe
     """
     try:
         encoded = md5(name.encode("utf-8")).hexdigest()
         width = surface.get_width()
         height = surface.get_height()
         cache_path_jpg = "%s/@%s@%s_%s_%s.jpg" % (CACHE_PATH, prefix,
                                                   encoded, width, height)
         pixbuf = Gdk.pixbuf_get_from_surface(surface, 0, 0, width, height)
         pixbuf.savev(
             cache_path_jpg, "jpeg", ["quality"],
             [str(App().settings.get_value("cover-quality").get_int32())])
     except Exception as e:
         Logger.error("Art::add_artwork_to_cache(): %s" % e)
示例#2
0
 def __get_duckduck_name(self, string):
     """
         Get wikipedia duck duck name for string
         @param string as str
         @return str
     """
     name = None
     try:
         uri = "https://api.duckduckgo.com/?q=%s&format=json&pretty=1"\
             % string
         (status, data) = App().task_helper.load_uri_content_sync(uri)
         if status:
             import json
             decode = json.loads(data.decode("utf-8"))
             uri = decode["AbstractURL"]
             if uri:
                 name = uri.split("/")[-1]
     except Exception as e:
         Logger.error("Wikipedia::__get_duckduck_name(): %s", e)
     return name
示例#3
0
 def __on_request_send_async(self, source, result, callback, cancellable,
                             uri, *args):
     """
         Get stream and start reading from it
         @param source as Soup.Session
         @param result as Gio.AsyncResult
         @param cancellable as Gio.Cancellable
         @param callback as a function
         @param uri as str
     """
     try:
         stream = source.send_finish(result)
         # We use a bytearray here as seems that bytes += is really slow
         stream.read_bytes_async(4096, GLib.PRIORITY_LOW,
                                 cancellable, self.__on_read_bytes_async,
                                 bytearray(0), cancellable, callback, uri,
                                 *args)
     except Exception as e:
         Logger.error("TaskHelper::__on_soup_msg_finished(): %s" % e)
         callback(uri, False, b"", *args)
示例#4
0
 def remove_disc(self, disc, album_id):
     """
         Remove disc for album_id
         @param disc as Disc
         @param album_id as int
     """
     try:
         removed = []
         for album in self._albums:
             if album.id == album_id:
                 for track in list(album.tracks):
                     if track.id in disc.track_ids:
                         empty = album.remove_track(track)
                         if empty:
                             removed.append(album)
         for album in removed:
             self._albums.remove(album)
         self.emit("playlist-changed")
     except Exception as e:
         Logger.error("Player::remove_disc(): %s" % e)
示例#5
0
 def load_tracks(self, album, cancellable):
     """
         Load tracks for album
         @param album as Album
         @param cancellable as Gio.Cancellable
     """
     try:
         mbid = album.uri.replace("mb:", "")
         tracks = self.get_tracks_payload(mbid, cancellable)
         # We want to share the same item as lp_album_id may change
         album_item = album.collection_item
         for track in tracks:
             lollypop_payload = self.lollypop_track_payload(track)
             self.save_track_payload_to_db(lollypop_payload,
                                           album_item,
                                           album.storage_type,
                                           False,
                                           cancellable)
     except Exception as e:
         Logger.error("MusicBrainzSearch::load_tracks(): %s", e)
示例#6
0
 def _get_lastfm_album_artwork(self, artist, album):
     """
         Get album artwork from lastfm
         @param artist as string
         @param album as string
         @return data as bytes
         @tread safe
     """
     image = None
     if App().lastfm is not None:
         try:
             helper = TaskHelper()
             last_album = App().lastfm.get_album(artist, album)
             uri = last_album.get_cover_image(4)
             if uri is not None:
                 (status, image) = helper.load_uri_content_sync(uri, None)
         except Exception as e:
             Logger.error("Downloader::_get_album_art_lastfm: %s [%s/%s]" %
                          (e, artist, album))
     return image
示例#7
0
 def __on_uri_content(self, uri, status, data):
     """
         Save artwork to cache and set artist artwork
         @param uri as str
         @param status as bool
         @param data as bytes
     """
     try:
         if not status:
             return
         self.__cover_data = data
         scale_factor = self.get_scale_factor()
         App().art.add_artist_artwork(self.__artist_name, data,
                                      StorageType.EPHEMERAL)
         App().art_helper.set_artist_artwork(
             self.__artist_name, ArtSize.SMALL, ArtSize.SMALL, scale_factor,
             ArtBehaviour.CROP | ArtBehaviour.CACHE | ArtBehaviour.ROUNDED,
             self.__on_artist_artwork)
     except Exception as e:
         Logger.error("ArtistRow::__on_uri_content(): %s", e)
示例#8
0
文件: mpris.py 项目: aembleton/cinamp
 def __on_current_changed(self, player):
     if App().player.current_track.id is None:
         self.__lollypop_id = 0
     else:
         self.__lollypop_id = App().player.current_track.id
     # We only need to recalculate a new trackId at song changes.
     self.__track_id = self.__get_media_id(self.__lollypop_id)
     self.__rating = None
     self.__update_metadata()
     properties = {
         "Metadata": GLib.Variant("a{sv}", self.__metadata),
         "CanPlay": GLib.Variant("b", True),
         "CanPause": GLib.Variant("b", True),
         "CanGoNext": GLib.Variant("b", True),
         "CanGoPrevious": GLib.Variant("b", True)
     }
     try:
         self.PropertiesChanged(self.__MPRIS_PLAYER_IFACE, properties, [])
     except Exception as e:
         Logger.error("MPRIS::__on_current_changed(): %s" % e)
示例#9
0
    def set_prev(self):
        """
            Set previous track
        """
        if self.current_track.id == Type.RADIOS:
            return
        try:
            prev_track = ShufflePlayer.prev(self)

            # Look at user playlist then
            if prev_track.id is None:
                prev_track = PlaylistPlayer.prev(self)

            # Get a linear track then
            if prev_track.id is None:
                prev_track = LinearPlayer.prev(self)
            self._prev_track = prev_track
            self.emit("prev-changed")
        except Exception as e:
            Logger.error("Player::set_prev(): %s" % e)
 def _get_lastfm_album_artwork_uri(self, artist, album, cancellable=None):
     """
         Get album artwork uri from lastfm
         @param artist as str
         @param album as str
         @param cancellable as Gio.Cancellable
         @return uri as str
         @tread safe
     """
     if not get_network_available("LASTFM"):
         return None
     if App().lastfm is not None:
         try:
             last_album = App().lastfm.get_album(artist, album)
             uri = last_album.get_cover_image(4)
             return uri
         except Exception as e:
             Logger.error("ArtDownloader::_get_album_art_lastfm_uri: %s" %
                          e)
     return None
示例#11
0
 def populate(self):
     """
         Populate view
     """
     try:
         ArtworkSearchWidget.populate(self)
         # First load local files
         uris = App().art.get_album_artworks(self.__album)
         # Direct load, not using loopback because not many items
         for uri in uris:
             child = ArtworkSearchChild(_("Local"))
             child.show()
             f = Gio.File.new_for_uri(uri)
             (status, content, tag) = f.load_contents()
             if status:
                 status = child.populate(content)
             if status:
                 self._flowbox.add(child)
     except Exception as e:
         Logger.error("AlbumArtworkSearchWidget::populate(): %s", e)
示例#12
0
 def clean_album_cache(self, album, width=-1, height=-1):
     """
         Remove cover from cache for album id
         @param album as Album
         @param width as int
         @param height as int
     """
     try:
         from pathlib import Path
         if width == -1 or height == -1:
             for p in Path(CACHE_PATH).glob("%s*.jpg" % album.lp_album_id):
                 p.unlink()
         else:
             filename = "%s/%s_%s_%s.jpg" % (CACHE_PATH, album.lp_album_id,
                                             width, height)
             f = Gio.File.new_for_path(filename)
             if f.query_exists():
                 f.delete()
     except Exception as e:
         Logger.error("AlbumArt::clean_album_cache(): %s" % e)
示例#13
0
 def __populate_loved_tracks(self):
     """
         Populate loved tracks playlist
     """
     if not self.available:
         return
     try:
         user = self.get_user(self.__login)
         for loved in user.get_loved_tracks(limit=None):
             artist = str(loved.track.artist)
             title = str(loved.track.title)
             track_id = App().tracks.search_track(artist, title)
             if track_id is None:
                 Logger.warning(
                     "LastFM::__populate_loved_tracks(): %s, %s" %
                     (artist, title))
             else:
                 Track(track_id).set_loved(1)
     except Exception as e:
         Logger.error("LastFM::__populate_loved_tracks: %s" % e)
示例#14
0
 def uncache_radio_artwork(self, name):
     """
         Remove radio artwork from cache
         @param name as string
     """
     cache_name = self.__get_radio_cache_name(name)
     try:
         f = Gio.File.new_for_path(self._CACHE_PATH)
         infos = f.enumerate_children(
             "standard::name",
             Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS,
             None)
         for info in infos:
             f = infos.get_child(info)
             basename = f.get_basename()
             if re.search(r"%s_.*\.png" % re.escape(cache_name), basename):
                 f.delete()
     except Exception as e:
         Logger.error("RadioArt::clean_radio_cache(): %s, %s" %
                      (e, cache_name))
示例#15
0
 def search_similar_artists(self, artist, cancellable):
     """
         Search similar artists
         @param artist as str
         @param cancellable as Gio.Cancellable
     """
     try:
         found = False
         artist_item = self.get_artist(artist)
         for similar_item in artist_item.get_similar():
             if cancellable.is_cancelled():
                 raise Exception("cancelled")
             found = True
             artist_name = similar_item.item.name
             cover_uri = similar_item.item.get_cover_image()
             GLib.idle_add(self.emit, "new-artist", artist_name, cover_uri)
     except Exception as e:
         Logger.error("LastFM::search_similar_artists(): %s", e)
     if not found:
         GLib.idle_add(self.emit, "new-artist", None, None)
    def _get_spotify_album_artwork_uri(self, artist, album, cancellable=None):
        """
            Get album artwork uri from spotify
            @param artist as str
            @param album as str
            @param cancellable as Gio.Cancellable
            @return uri as str
            @tread safe
        """
        if not get_network_available("SPOTIFY"):
            return None
        artists_spotify_ids = []
        try:
            token = self.__get_spotify_token(cancellable)
            artist_formated = GLib.uri_escape_string(artist, None,
                                                     True).replace(" ", "+")
            uri = "https://api.spotify.com/v1/search?q=%s" % artist_formated +\
                  "&type=artist"
            token = "Bearer %s" % token
            helper = TaskHelper()
            helper.add_header("Authorization", token)
            (status, data) = helper.load_uri_content_sync(uri, cancellable)
            if status:
                decode = json.loads(data.decode("utf-8"))
                for item in decode["artists"]["items"]:
                    artists_spotify_ids.append(item["id"])

            for artist_spotify_id in artists_spotify_ids:
                uri = "https://api.spotify.com/v1/artists/" +\
                      "%s/albums" % artist_spotify_id
                (status, data) = helper.load_uri_content_sync(uri, cancellable)
                if status:
                    decode = json.loads(data.decode("utf-8"))
                    uri = None
                    for item in decode["items"]:
                        if noaccents(item["name"].lower()) ==\
                                noaccents(album.lower()):
                            return item["images"][0]["url"]
        except Exception as e:
            Logger.error("ArtDownloader::_get_album_art_spotify_uri: %s" % e)
        return None
示例#17
0
 def populate(self):
     """
         Setup an initial widget based on current request
     """
     sql = App().playlists.get_smart_sql(self.__playlist_id)
     if sql is None:
         return
     try:
         if sql.find(" UNION ") != -1:
             operand = "OR"
         else:
             operand = "AND"
         self.__operand_combobox.set_active_id(operand)
     except Exception as e:
         self.__operand_combobox.set_active(0)
         Logger.warning("SmartPlaylistView::populate: %s", e)
     # Setup rows
     for line in sql.split("((")[1:]:
         widget = SmartPlaylistRow(self.__size_group)
         try:
             widget.set(line.split("))")[0])
         except Exception as e:
             Logger.error("SmartPlaylistView::populate: %s", e)
         widget.show()
         self.__listbox.add(widget)
     try:
         split_limit = sql.split("LIMIT")
         limit = int(split_limit[1].split(" ")[1])
         self.__limit_spin.set_value(limit)
     except Exception as e:
         Logger.warning("SmartPlaylistView::populate: %s", e)
     try:
         split_order = sql.split("ORDER BY")
         split_spaces = split_order[1].split(" ")
         orderby = split_spaces[1]
         if split_spaces[2] in ["ASC", "DESC"]:
             orderby += " %s" % split_spaces[2]
         self.__select_combobox.set_active_id(orderby)
     except Exception as e:
         self.__select_combobox.set_active(0)
         Logger.warning("SmartPlaylistView::populate: %s", e)
示例#18
0
 def get_album_cache_path(self, album, width, height):
     """
         get artwork cache path for album_id
         @param album as Album
         @param width as int
         @param height as int
         @return cover path as string or None if no cover
     """
     try:
         cache_filepath = "%s/%s_%s_%s.%s" % (CACHE_PATH, album.lp_album_id,
                                              width, height, self._ext)
         f = Gio.File.new_for_path(cache_filepath)
         if f.query_exists():
             return cache_filepath
         else:
             self.get_album_artwork(album, width, height, 1)
             if f.query_exists():
                 return cache_filepath
     except Exception as e:
         Logger.error("Art::get_album_cache_path(): %s" % e)
     return None
示例#19
0
 def __edit_tag(self, action, variant):
     """
         Run tag editor
         @param Gio.SimpleAction
         @param GLib.Variant
     """
     path = GLib.filename_from_uri(self._object.uri)[0]
     if GLib.find_program_in_path("flatpak-spawn") is not None:
         argv = ["flatpak-spawn", "--host", App().art.tag_editor, path]
     else:
         argv = [App().art.tag_editor, path]
     try:
         (pid, stdin, stdout, stderr) = GLib.spawn_async(
             argv, flags=GLib.SpawnFlags.SEARCH_PATH |
             GLib.SpawnFlags.STDOUT_TO_DEV_NULL,
             standard_input=False,
             standard_output=False,
             standard_error=False
         )
     except Exception as e:
         Logger.error("MenuPopover::__edit_tag(): %s" % e)
 def __on_edit_button_clicked(self, button):
     """
         Run tags editor
         @param button as Gtk.Button
     """
     path = GLib.filename_from_uri(self.__object.uri)[0]
     if GLib.find_program_in_path("flatpak-spawn") is not None:
         argv = ["flatpak-spawn", "--host", App().art.tag_editor, path]
     else:
         argv = [App().art.tag_editor, path]
     try:
         (pid, stdin, stdout,
          stderr) = GLib.spawn_async(argv,
                                     flags=GLib.SpawnFlags.SEARCH_PATH
                                     | GLib.SpawnFlags.STDOUT_TO_DEV_NULL,
                                     standard_input=False,
                                     standard_output=False,
                                     standard_error=False)
     except Exception as e:
         Logger.error("ContextWidget::__on_edit_button_clicked(): %s" % e)
     self.hide()
示例#21
0
def remove_oldest(path, timestamp):
    """
        Remove oldest files at path
        @param path as str
        @param timestamp as int
    """
    SCAN_QUERY_INFO = "%s" % FILE_ATTRIBUTE_TIME_ACCESS
    try:
        d = Gio.File.new_for_path(path)
        infos = d.enumerate_children(SCAN_QUERY_INFO,
                                     Gio.FileQueryInfoFlags.NONE, None)
        for info in infos:
            f = infos.get_child(info)
            if info.get_file_type() == Gio.FileType.REGULAR:
                atime = int(
                    info.get_attribute_as_string(FILE_ATTRIBUTE_TIME_ACCESS))
                # File not used since one year
                if time() - atime > timestamp:
                    f.delete(None)
    except Exception as e:
        Logger.error("remove_oldest(): %s", e)
 def __on_load_google_content(self, uri, loaded, content):
     """
         Extract uris from content
         @param uri as str
         @param loaded as bool
         @param content as bytes
     """
     try:
         if not loaded:
             self.emit("uri-artwork-found", [])
             return
         decode = json.loads(content.decode("utf-8"))
         results = []
         for item in decode["items"]:
             if item["link"] is not None:
                 results.append((item["link"], "Google"))
         self.emit("uri-artwork-found", results)
     except Exception as e:
         self.emit("uri-artwork-found", [])
         Logger.error("ArtDownloader::__on_load_google_content(): %s: %s" %
                      (e, content))
示例#23
0
 def __playing_now(self, artist, album, title, duration, mb_track_id):
     """
         Now playing track
         @param artist as str
         @param title as str
         @param album as str
         @param duration as int
         @thread safe
     """
     try:
         self.update_now_playing(artist=artist,
                                 album=album,
                                 title=title,
                                 duration=duration,
                                 mbid=mb_track_id)
         Logger.debug("LastFM::__playing_now(): %s, %s, %s, %s, %s" %
                      (artist, album, title, duration, mb_track_id))
     except WSError:
         pass
     except Exception as e:
         Logger.error("LastFM::__playing_now(): %s" % e)
示例#24
0
 def get_album_payload(self, album, artist, cancellable):
     """
         Get album payload for mbid
         @param album as str
         @param artist as str
         @param cancellable as Gio.Cancellable
         @return {}/None
     """
     artist = GLib.uri_escape_string(artist, None, True)
     album = GLib.uri_escape_string(album, None, True)
     try:
         uri = "http://ws.audioscrobbler.com/2.0/"
         uri += "?method=album.getInfo"
         uri += "&album=%s&artist=%s&api_key=%s&format=json" % (
             album, artist, LASTFM_API_KEY)
         (status, data) = App().task_helper.load_uri_content_sync(uri, None)
         if status:
             return json.loads(data.decode("utf-8"))["album"]
     except:
         Logger.error("LastFMWebHelper::get_album_payload(): %s", uri)
     return None
示例#25
0
 def install(self):
     """
         Install missing plugins
     """
     if not GstPbutils.install_plugins_supported():
         return
     try:
         context = GstPbutils.InstallPluginsContext.new()
         try:
             context.set_desktop_id("org.gnome.Lollypop.desktop")
         except:
             pass  # Not supported by Ubuntu VIVID
         details = []
         for message in self._messages:
             detail = \
                 GstPbutils.missing_plugin_message_get_installer_detail(
                     message)
             details.append(detail)
         GstPbutils.install_plugins_async(details, context, self.__null)
     except Exception as e:
         Logger.error("Codecs::__init__(): %s" % e)
示例#26
0
 def __get_cover_art_uri(self, mbid, cancellable):
     """
         Get cover art URI for mbid
         @param mbid as str
         @param cancellable as Gio.Cancellable
         @return str/None
     """
     try:
         uri = "http://coverartarchive.org/release/%s" % mbid
         (status, data) = App().task_helper.load_uri_content_sync(uri, None)
         if status:
             decode = json.loads(data.decode("utf-8"))
             for image in decode["images"]:
                 if not image["front"]:
                     continue
                 return image["image"]
     except Exception as e:
         Logger.error(e)
         Logger.error(
             "SaveWebHelper::__get_cover_art_uri(): %s", data)
     return None
示例#27
0
 def skip_album(self):
     """
         Skip current album
     """
     try:
         # In party or shuffle, just update next track
         if self.is_party or\
                 App().settings.get_enum("shuffle") == Shuffle.TRACKS:
             self.set_next()
             # We send this signal to update next popover
             self.emit("queue-changed")
         elif self._current_track.id is not None:
             index = self.album_ids.index(
                 App().player._current_playback_track.album.id)
             if index + 1 >= len(self._albums):
                 next_album = self._albums[0]
             else:
                 next_album = self._albums[index + 1]
             self.load(next_album.tracks[0])
     except Exception as e:
         Logger.error("Player::skip_album(): %s" % e)
示例#28
0
 def execute(self, request):
     """
         Execute SQL request (only smart one)
         @param request as str
         @return list
     """
     try:
         with SqlCursor(App().db) as sql:
             result = sql.execute(request)
             # Special case for OR request
             if request.find("ORDER BY random()") == -1 and\
                     request.find("UNION") != -1:
                 ids = []
                 for (id, other) in list(result):
                     ids.append(id)
                 return ids
             else:
                 return list(itertools.chain(*result))
     except Exception as e:
         Logger.error("Database::execute(): %s -> %s", e, request)
     return []
示例#29
0
 def pop(self, index=-1):
     """
         Pop last view from history
         @param index as int
         @return View
     """
     try:
         if not self.__items:
             return None
         (view, _class, args, sidebar_id,
          selection_ids, position) = self.__items.pop(index)
         # View is offloaded, create a new one
         if view is None:
             view = self.__get_view_from_class(_class, args)
             view.set_sidebar_id(sidebar_id)
             view.set_selection_ids(selection_ids)
             view.set_populated_scrolled_position(position)
         return view
     except Exception as e:
         Logger.error("AdaptiveHistory::pop(): %s" % e)
         self.__items = []
示例#30
0
 def get_token(self, service):
     """
         Get token for service
         @param service as str
     """
     try:
         secret = Secret.Service.get_sync(Secret.ServiceFlags.NONE)
         SecretSchema = {"service": Secret.SchemaAttributeType.STRING}
         SecretAttributes = {"service": service}
         schema = Secret.Schema.new("org.gnome.Lollypop",
                                    Secret.SchemaFlags.NONE, SecretSchema)
         items = secret.search_sync(schema, SecretAttributes,
                                    Secret.SearchFlags.ALL, None)
         if items:
             items[0].load_secret_sync(None)
             value = items[0].get_secret()
             if value is not None:
                 return value.get_text()
     except Exception as e:
         Logger.error("PasswordsHelper::get_sync(): %s" % e)
     return None