[gnome-music/wip/mschraal/file-exists-async: 9/12] storeart: Replace blocking MediaArt call
- From: Marinus Schraal <mschraal src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-music/wip/mschraal/file-exists-async: 9/12] storeart: Replace blocking MediaArt call
- Date: Sat, 4 Sep 2021 22:20:28 +0000 (UTC)
commit b55a50c18bc1cbb8750ede02e3cee733fa76e645
Author: Marinus Schraal <mschraal gnome org>
Date: Fri Aug 20 01:02:08 2021 +0200
storeart: Replace blocking MediaArt call
MediaArt.file_to_jpeg is a blocking call.
Replace it with async Gio + GdkPixbuf based calls, also removing the
need to use a temporary file.
gnomemusic/storeart.py | 129 ++++++++++++++++++++++---------------------------
1 file changed, 59 insertions(+), 70 deletions(-)
---
diff --git a/gnomemusic/storeart.py b/gnomemusic/storeart.py
index a1ff57664..75dd47eaf 100644
--- a/gnomemusic/storeart.py
+++ b/gnomemusic/storeart.py
@@ -24,7 +24,7 @@
import gi
gi.require_versions({"MediaArt": "2.0", "Soup": "2.4"})
-from gi.repository import Gio, GLib, GObject, MediaArt, Soup
+from gi.repository import Gio, GLib, GObject, MediaArt, Soup, GdkPixbuf
from gnomemusic.musiclogger import MusicLogger
from gnomemusic.coreartist import CoreArtist
@@ -50,6 +50,7 @@ class StoreArt(GObject.Object):
self._coreobject = None
+ self._file = None
self._log = MusicLogger()
self._soup_session = Soup.Session.new()
@@ -62,6 +63,25 @@ class StoreArt(GObject.Object):
self.emit("finished")
return
+ if isinstance(self._coreobject, CoreArtist):
+ success, self._file = MediaArt.get_file(
+ self._coreobject.props.artist, None, "artist")
+ elif isinstance(self._coreobject, CoreAlbum):
+ success, self._file = MediaArt.get_file(
+ self._coreobject.props.artist, self._coreobject.props.title,
+ "album")
+ elif isinstance(self._coreobject, CoreSong):
+ success, self._file = MediaArt.get_file(
+ self._coreobject.props.artist, self._coreobject.props.album,
+ "album")
+ else:
+ success = False
+
+ if not success:
+ self._coreobject.props.thumbnail = "generic"
+ self.emit("finished")
+ return
+
cache_dir = GLib.build_filenamev(
[GLib.get_user_cache_dir(), "media-art"])
cache_dir_file = Gio.File.new_for_path(cache_dir)
@@ -91,89 +111,58 @@ class StoreArt(GObject.Object):
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"
self.emit("finished")
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)
+ GdkPixbuf.Pixbuf.new_from_stream_async(
+ istream, None, self._pixbuf_from_stream_finished)
+ def _pixbuf_from_stream_finished(
+ self, stream: Gio.MemoryInputStream,
+ result: Gio.AsyncResult) -> None:
try:
- src.splice_finish(result)
+ pixbuf = GdkPixbuf.Pixbuf.new_from_stream_finish(result)
except GLib.Error as error:
- self._log.warning(
- "Error: {}, {}".format(error.domain, error.message))
- self._coreobject.props.thumbnail = "generic"
+ self._log.warning(f"Error: {error.domain}, {error.message}")
self.emit("finished")
- 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"
- self.emit("finished")
- return
+ self._file.create_async(
+ Gio.FileCreateFlags.NONE, GLib.PRIORITY_LOW, None,
+ self._output_stream_created, pixbuf)
+ finally:
+ stream.close_async(GLib.PRIORITY_LOW, None, self._stream_closed)
+
+ def _output_stream_created(
+ self, stream: Gio.FileOutputStream, result: Gio.AsyncResult,
+ pixbuf: GdkPixbuf.Pixbuf) -> None:
+ try:
+ output_stream = stream.create_finish(result)
+ except GLib.Error as error:
+ # File already exists.
+ self._log.info(f"Error: {error.domain}, {error.message}")
+ else:
+ pixbuf.save_to_streamv_async(
+ output_stream, "jpeg", None, None, None,
+ self._output_stream_saved, output_stream)
+ def _output_stream_saved(
+ self, pixbuf: GdkPixbuf.Pixbuf, result: Gio.AsyncResult,
+ output_stream: Gio.FileOutputStream) -> None:
try:
- # FIXME: I/O blocking
- MediaArt.file_to_jpeg(tmp_file.get_path(), cache_file.get_path())
+ pixbuf.save_to_stream_finish(result)
except GLib.Error as error:
- self._log.warning(
- "Error: {}, {}".format(error.domain, error.message))
- self._coreobject.props.thumbnail = "generic"
+ self._log.warning(f"Error: {error.domain}, {error.message}")
+ else:
self.emit("finished")
- return
+ finally:
+ output_stream.close_async(
+ GLib.PRIORITY_LOW, None, self._stream_closed)
- 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):
+ def _stream_closed(
+ self, stream: Gio.OutputStream, result: Gio.AsyncResult) -> None:
try:
- src.close_finish(result)
+ stream.close_finish(result)
except GLib.Error as error:
- self._log.warning(
- "Error: {}, {}".format(error.domain, error.message))
-
- self.emit("finished")
+ self._log.warning(f"Error: {error.domain}, {error.message}")
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]