summaryrefslogtreecommitdiff
path: root/gnomemusic/storeart.py
diff options
context:
space:
mode:
Diffstat (limited to 'gnomemusic/storeart.py')
-rw-r--r--gnomemusic/storeart.py162
1 files changed, 162 insertions, 0 deletions
diff --git a/gnomemusic/storeart.py b/gnomemusic/storeart.py
new file mode 100644
index 00000000..368d61b2
--- /dev/null
+++ b/gnomemusic/storeart.py
@@ -0,0 +1,162 @@
+# Copyright 2020 The GNOME Music developers
+#
+# GNOME Music is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GNOME Music is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with GNOME Music; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# The GNOME Music authors hereby grant permission for non-GPL compatible
+# GStreamer plugins to be used and distributed together with GStreamer
+# and GNOME Music. This permission is above and beyond the permissions
+# granted by the GPL license by which GNOME Music is covered. If you
+# modify this code, you may extend this exception to your version of the
+# code, but you are not obligated to do so. If you do not wish to do so,
+# delete this exception statement from your version.
+
+import gi
+gi.require_versions({"MediaArt": "2.0", "Soup": "2.4"})
+from gi.repository import Gio, GLib, GObject, MediaArt, Soup
+
+from gnomemusic.musiclogger import MusicLogger
+from gnomemusic.coreartist import CoreArtist
+from gnomemusic.corealbum import CoreAlbum
+from gnomemusic.coresong import CoreSong
+
+
+class StoreArt(GObject.Object):
+ """Stores Art in the MediaArt cache.
+ """
+
+ def __init__(self, coreobject, uri):
+ """Initialize StoreArtistArt
+
+ :param coreobject: The CoreArtist or CoreAlbum to store art for
+ :param string uri: The art uri
+ """
+ self._coreobject = coreobject
+
+ self._log = MusicLogger()
+ self._soup_session = Soup.Session.new()
+
+ if (uri is None
+ or uri == ""):
+ self._coreobject.props.thumbnail = "generic"
+ return
+
+ cache_dir = GLib.build_filenamev(
+ [GLib.get_user_cache_dir(), "media-art"])
+ cache_dir_file = Gio.File.new_for_path(cache_dir)
+ cache_dir_file.query_info_async(
+ Gio.FILE_ATTRIBUTE_ACCESS_CAN_READ, Gio.FileQueryInfoFlags.NONE,
+ GLib.PRIORITY_LOW, None, self._cache_dir_info_read, uri)
+
+ def _cache_dir_info_read(self, cache_dir_file, res, uri):
+ try:
+ cache_dir_file.query_info_finish(res)
+ except GLib.Error:
+ # directory does not exist yet
+ try:
+ cache_dir_file.make_directory(None)
+ except GLib.Error as error:
+ self._log.warning(
+ "Error: {}, {}".format(error.domain, error.message))
+ self._coreobject.props.thumbnail = "generic"
+ return
+
+ msg = Soup.Message.new("GET", uri)
+ self._soup_session.queue_message(msg, self._read_callback, None)
+
+ def _read_callback(self, src, result, data):
+ if result.props.status_code != 200:
+ self._log.debug(
+ "Failed to get remote art: {}".format(
+ result.props.reason_phrase))
+ return
+
+ try:
+ [tmp_file, iostream] = Gio.File.new_tmp()
+ except GLib.Error as error:
+ self._log.warning(
+ "Error: {}, {}".format(error.domain, error.message))
+ self._coreobject.props.thumbnail = "generic"
+ return
+
+ istream = Gio.MemoryInputStream.new_from_bytes(
+ result.props.response_body_data)
+ ostream = iostream.get_output_stream()
+ # FIXME: Passing the iostream here, otherwise it gets
+ # closed. PyGI specific issue?
+ ostream.splice_async(
+ istream, Gio.OutputStreamSpliceFlags.CLOSE_SOURCE
+ | Gio.OutputStreamSpliceFlags.CLOSE_TARGET, GLib.PRIORITY_LOW,
+ None, self._splice_callback, [tmp_file, iostream])
+
+ def _delete_callback(self, src, result, data):
+ try:
+ src.delete_finish(result)
+ except GLib.Error as error:
+ self._log.warning(
+ "Error: {}, {}".format(error.domain, error.message))
+
+ def _splice_callback(self, src, result, data):
+ tmp_file, iostream = data
+
+ iostream.close_async(
+ GLib.PRIORITY_LOW, None, self._close_iostream_callback, None)
+
+ try:
+ src.splice_finish(result)
+ except GLib.Error as error:
+ self._log.warning(
+ "Error: {}, {}".format(error.domain, error.message))
+ self._coreobject.props.thumbnail = "generic"
+ return
+
+ if isinstance(self._coreobject, CoreArtist):
+ success, cache_file = MediaArt.get_file(
+ self._coreobject.props.artist, None, "artist")
+ elif isinstance(self._coreobject, CoreAlbum):
+ success, cache_file = MediaArt.get_file(
+ self._coreobject.props.artist, self._coreobject.props.title,
+ "album")
+ elif isinstance(self._coreobject, CoreSong):
+ success, cache_file = MediaArt.get_file(
+ self._coreobject.props.artist, self._coreobject.props.album,
+ "album")
+ else:
+ success = False
+
+ if not success:
+ self._coreobject.props.thumbnail = "generic"
+ return
+
+ try:
+ # FIXME: I/O blocking
+ MediaArt.file_to_jpeg(tmp_file.get_path(), cache_file.get_path())
+ except GLib.Error as error:
+ self._log.warning(
+ "Error: {}, {}".format(error.domain, error.message))
+ self._coreobject.props.thumbnail = "generic"
+ return
+
+ self._coreobject.props.media.set_thumbnail(cache_file.get_uri())
+ self._coreobject.props.thumbnail = cache_file.get_uri()
+
+ tmp_file.delete_async(
+ GLib.PRIORITY_LOW, None, self._delete_callback, None)
+
+ def _close_iostream_callback(self, src, result, data):
+ try:
+ src.close_finish(result)
+ except GLib.Error as error:
+ self._log.warning(
+ "Error: {}, {}".format(error.domain, error.message))