Unify get_cover_art_uri and get_cover_art_filename
This commit is contained in:
@@ -19,6 +19,8 @@ v0.11.1
|
||||
* Fixed issue where users couldn't log in to LMS due to Sublime Music always
|
||||
sending version number "1.15.0" instead of figuring out what version of the
|
||||
API the server actually reports.
|
||||
* Fixed issue where edits to the music provider configurations were applied even
|
||||
if ESC was pressed. (#247)
|
||||
|
||||
v0.11.0
|
||||
=======
|
||||
|
@@ -438,7 +438,6 @@ class Adapter(abc.ABC):
|
||||
Examples of values that could be provided include ``http``, ``https``, ``file``,
|
||||
or ``ftp``.
|
||||
"""
|
||||
# TODO (#189) actually use this
|
||||
return ()
|
||||
|
||||
@property
|
||||
@@ -446,6 +445,7 @@ class Adapter(abc.ABC):
|
||||
"""
|
||||
Whether or not the adapter supports :class:`get_cover_art_uri`.
|
||||
"""
|
||||
return False
|
||||
|
||||
@property
|
||||
def can_stream(self) -> bool:
|
||||
|
@@ -539,17 +539,6 @@ class AdapterManager:
|
||||
|
||||
return future_finished
|
||||
|
||||
@staticmethod
|
||||
def _get_scheme() -> str:
|
||||
# TODO (#189): eventually this will come from the players
|
||||
assert AdapterManager._instance
|
||||
scheme_priority = ("https", "http")
|
||||
schemes = sorted(
|
||||
AdapterManager._instance.ground_truth_adapter.supported_schemes,
|
||||
key=scheme_priority.index,
|
||||
)
|
||||
return list(schemes)[0]
|
||||
|
||||
@staticmethod
|
||||
def get_supported_artist_query_types() -> Set[AlbumSearchQuery.Type]:
|
||||
assert AdapterManager._instance
|
||||
@@ -805,87 +794,98 @@ class AdapterManager:
|
||||
CachingAdapter.CachedDataKey.PLAYLIST_DETAILS, playlist_id
|
||||
)
|
||||
|
||||
# TODO (#189): allow this to take a set of schemes and unify with
|
||||
# get_cover_art_filename
|
||||
@staticmethod
|
||||
def get_cover_art_uri(cover_art_id: str = None, size: int = 300) -> str:
|
||||
def _get_networked_scheme() -> str:
|
||||
assert AdapterManager._instance
|
||||
networked_scheme_priority = ("https", "http")
|
||||
return sorted(
|
||||
AdapterManager._instance.ground_truth_adapter.supported_schemes,
|
||||
key=lambda s: networked_scheme_priority.index(s),
|
||||
)[0]
|
||||
|
||||
@staticmethod
|
||||
def get_cover_art_uri(
|
||||
cover_art_id: Optional[str],
|
||||
scheme: str,
|
||||
size: int = 300,
|
||||
before_download: Callable[[], None] = None,
|
||||
force: bool = False,
|
||||
allow_download: bool = True,
|
||||
) -> Result[str]:
|
||||
existing_filename = str(
|
||||
Path(__file__).parent.joinpath("images/default-album-art.png")
|
||||
)
|
||||
if (
|
||||
not AdapterManager._ground_truth_can_do("get_cover_art_uri")
|
||||
or not cover_art_id
|
||||
):
|
||||
return ""
|
||||
|
||||
return AdapterManager._instance.ground_truth_adapter.get_cover_art_uri(
|
||||
cover_art_id, AdapterManager._get_scheme(), size=size
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_cover_art_filename(
|
||||
cover_art_id: str = None,
|
||||
before_download: Callable[[], None] = None,
|
||||
force: bool = False, # TODO (#202): rename to use_ground_truth_adapter?
|
||||
allow_download: bool = True,
|
||||
) -> Result[str]:
|
||||
existing_cover_art_filename = str(
|
||||
Path(__file__).parent.joinpath("images/default-album-art.png")
|
||||
)
|
||||
if cover_art_id is None:
|
||||
return Result(existing_cover_art_filename)
|
||||
return Result(existing_filename if scheme == "file" else "")
|
||||
|
||||
assert AdapterManager._instance
|
||||
|
||||
# If the ground truth adapter can't provide cover art, just give up immediately.
|
||||
if not AdapterManager._ground_truth_can_do("get_cover_art_uri"):
|
||||
return Result(existing_cover_art_filename)
|
||||
|
||||
# There could be partial data if the cover art exists, but for some reason was
|
||||
# marked out-of-date.
|
||||
if AdapterManager._can_use_cache(force, "get_cover_art_uri"):
|
||||
assert AdapterManager._instance.caching_adapter
|
||||
try:
|
||||
return Result(
|
||||
AdapterManager._instance.caching_adapter.get_cover_art_uri(
|
||||
cover_art_id, "file", size=300
|
||||
)
|
||||
)
|
||||
except CacheMissError as e:
|
||||
if e.partial_data is not None:
|
||||
existing_cover_art_filename = cast(str, e.partial_data)
|
||||
logging.info(f'Cache Miss on {"get_cover_art_uri"}.')
|
||||
except Exception:
|
||||
logging.exception(
|
||||
f'Error on {"get_cover_art_uri"} retrieving from cache.'
|
||||
)
|
||||
|
||||
if AdapterManager._instance.caching_adapter and force:
|
||||
AdapterManager._instance.caching_adapter.invalidate_data(
|
||||
CachingAdapter.CachedDataKey.COVER_ART_FILE, cover_art_id
|
||||
)
|
||||
|
||||
if not allow_download or (
|
||||
AdapterManager._offline_mode
|
||||
and AdapterManager._instance.ground_truth_adapter.is_networked
|
||||
):
|
||||
return Result(existing_cover_art_filename)
|
||||
|
||||
future: Result[str] = AdapterManager._create_download_result(
|
||||
AdapterManager._instance.ground_truth_adapter.get_cover_art_uri(
|
||||
cover_art_id, AdapterManager._get_scheme(), size=300
|
||||
),
|
||||
cover_art_id,
|
||||
before_download,
|
||||
default_value=existing_cover_art_filename,
|
||||
supported_schemes = (
|
||||
AdapterManager._instance.ground_truth_adapter.supported_schemes
|
||||
)
|
||||
|
||||
if AdapterManager._instance.caching_adapter:
|
||||
future.add_done_callback(
|
||||
AdapterManager._create_caching_done_callback(
|
||||
# If the scheme is supported natively, then return it.
|
||||
if scheme in supported_schemes:
|
||||
uri = AdapterManager._instance.ground_truth_adapter.get_cover_art_uri(
|
||||
cover_art_id, scheme, size=size
|
||||
)
|
||||
return Result(uri)
|
||||
|
||||
# If the scheme is "file", then we may need to try to download.
|
||||
if scheme == "file" and (
|
||||
"http" in supported_schemes or "https" in supported_schemes
|
||||
):
|
||||
if AdapterManager._can_use_cache(force, "get_cover_art_uri"):
|
||||
assert AdapterManager._instance.caching_adapter
|
||||
try:
|
||||
return Result(
|
||||
AdapterManager._instance.caching_adapter.get_cover_art_uri(
|
||||
cover_art_id, "file", size=size
|
||||
)
|
||||
)
|
||||
except CacheMissError as e:
|
||||
if e.partial_data is not None:
|
||||
existing_filename = cast(str, e.partial_data)
|
||||
logging.info(f'Cache Miss on {"get_cover_art_uri"}.')
|
||||
except Exception:
|
||||
logging.exception(
|
||||
f'Error on {"get_cover_art_uri"} retrieving from cache.'
|
||||
)
|
||||
|
||||
# If we are forcing, invalidate the existing cached data.
|
||||
if AdapterManager._instance.caching_adapter and force:
|
||||
AdapterManager._instance.caching_adapter.invalidate_data(
|
||||
CachingAdapter.CachedDataKey.COVER_ART_FILE, cover_art_id
|
||||
)
|
||||
|
||||
if not allow_download or (
|
||||
AdapterManager._offline_mode
|
||||
and AdapterManager._instance.ground_truth_adapter.is_networked
|
||||
):
|
||||
return Result(existing_filename)
|
||||
|
||||
# Create a download result.
|
||||
future = AdapterManager._create_download_result(
|
||||
AdapterManager._instance.ground_truth_adapter.get_cover_art_uri(
|
||||
cover_art_id, AdapterManager._get_networked_scheme(), size=size,
|
||||
),
|
||||
cover_art_id,
|
||||
before_download,
|
||||
default_value=existing_filename,
|
||||
)
|
||||
|
||||
return future
|
||||
if AdapterManager._instance.caching_adapter:
|
||||
future.add_done_callback(
|
||||
AdapterManager._create_caching_done_callback(
|
||||
CachingAdapter.CachedDataKey.COVER_ART_FILE, cover_art_id
|
||||
)
|
||||
)
|
||||
|
||||
return future
|
||||
|
||||
return Result("")
|
||||
|
||||
# TODO (#189): allow this to take a set of schemes
|
||||
@staticmethod
|
||||
@@ -920,7 +920,7 @@ class AdapterManager:
|
||||
raise CacheMissError(partial_data=cached_song_filename)
|
||||
|
||||
return AdapterManager._instance.ground_truth_adapter.get_song_uri(
|
||||
song.id, AdapterManager._get_scheme(), stream=True,
|
||||
song.id, AdapterManager._get_networked_scheme(), stream=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@@ -985,7 +985,7 @@ class AdapterManager:
|
||||
str
|
||||
] = AdapterManager._create_download_result(
|
||||
AdapterManager._instance.ground_truth_adapter.get_song_uri(
|
||||
song_id, AdapterManager._get_scheme()
|
||||
song_id, AdapterManager._get_networked_scheme()
|
||||
),
|
||||
song_id,
|
||||
lambda: before_download(song_id),
|
||||
|
@@ -29,15 +29,11 @@ encoder_functions = {
|
||||
|
||||
for type_, translation_function in decoder_functions.items():
|
||||
dataclasses_json.cfg.global_config.decoders[type_] = translation_function
|
||||
dataclasses_json.cfg.global_config.decoders[
|
||||
Optional[type_] # type: ignore
|
||||
] = translation_function
|
||||
dataclasses_json.cfg.global_config.decoders[Optional[type_]] = translation_function
|
||||
|
||||
for type_, translation_function in encoder_functions.items():
|
||||
dataclasses_json.cfg.global_config.encoders[type_] = translation_function
|
||||
dataclasses_json.cfg.global_config.encoders[
|
||||
Optional[type_] # type: ignore
|
||||
] = translation_function
|
||||
dataclasses_json.cfg.global_config.encoders[Optional[type_]] = translation_function
|
||||
|
||||
|
||||
@dataclass_json(letter_case=LetterCase.CAMEL)
|
||||
|
@@ -469,8 +469,8 @@ class SublimeMusicApp(Gtk.Application):
|
||||
)
|
||||
|
||||
def make_playlist_tuple(p: Playlist) -> GLib.Variant:
|
||||
cover_art_filename = AdapterManager.get_cover_art_filename(
|
||||
p.cover_art, allow_download=False,
|
||||
cover_art_filename = AdapterManager.get_cover_art_uri(
|
||||
p.cover_art, "file", allow_download=False,
|
||||
).result()
|
||||
return (f"/playlist/{p.id}", p.name, cover_art_filename or "")
|
||||
|
||||
@@ -1165,8 +1165,8 @@ class SublimeMusicApp(Gtk.Application):
|
||||
)
|
||||
song_notification.show()
|
||||
|
||||
cover_art_result = AdapterManager.get_cover_art_filename(
|
||||
song.cover_art
|
||||
cover_art_result = AdapterManager.get_cover_art_uri(
|
||||
song.cover_art, "file"
|
||||
)
|
||||
cover_art_result.add_done_callback(
|
||||
lambda f: on_cover_art_download_complete(f.result())
|
||||
|
@@ -18,9 +18,7 @@ def encode_path(path: Path) -> str:
|
||||
|
||||
|
||||
dataclasses_json.cfg.global_config.decoders[Path] = Path
|
||||
dataclasses_json.cfg.global_config.decoders[
|
||||
Optional[Path] # type: ignore
|
||||
] = (
|
||||
dataclasses_json.cfg.global_config.decoders[Optional[Path]] = (
|
||||
lambda p: Path(p) if p else None
|
||||
)
|
||||
|
||||
@@ -111,7 +109,7 @@ def decode_providers(
|
||||
else None
|
||||
),
|
||||
caching_adapter_config=(
|
||||
ConfigurationStore(**config.get("caching_adapter_config", {}))
|
||||
ConfigurationStore(**(config.get("caching_adapter_config") or {}))
|
||||
),
|
||||
)
|
||||
for id_, config in providers_dict.items()
|
||||
|
@@ -277,8 +277,8 @@ class DBusManager:
|
||||
).result()
|
||||
|
||||
try:
|
||||
cover_art = AdapterManager.get_cover_art_filename(
|
||||
playlist.cover_art, allow_download=False
|
||||
cover_art = AdapterManager.get_cover_art_uri(
|
||||
playlist.cover_art, "file", allow_download=False
|
||||
).result()
|
||||
except CacheMissError:
|
||||
cover_art = ""
|
||||
@@ -319,8 +319,8 @@ class DBusManager:
|
||||
)
|
||||
|
||||
try:
|
||||
cover_art = AdapterManager.get_cover_art_filename(
|
||||
song.cover_art, allow_download=False
|
||||
cover_art = AdapterManager.get_cover_art_uri(
|
||||
song.cover_art, "file", allow_download=False
|
||||
).result()
|
||||
except CacheMissError:
|
||||
cover_art = ""
|
||||
|
@@ -300,7 +300,15 @@ class ChromecastPlayer(Player):
|
||||
uri = f"http://{host_ip}:{self.config.get(LAN_PORT_KEY)}/s/{token.decode()}"
|
||||
logging.info("Serving {song.name} at {uri}")
|
||||
|
||||
cover_art_url = AdapterManager.get_cover_art_uri(song.cover_art, size=1000)
|
||||
assert AdapterManager._instance
|
||||
networked_scheme_priority = ("https", "http")
|
||||
scheme = sorted(
|
||||
AdapterManager._instance.ground_truth_adapter.supported_schemes,
|
||||
key=lambda s: networked_scheme_priority.index(s),
|
||||
)[0]
|
||||
cover_art_url = AdapterManager.get_cover_art_uri(
|
||||
song.cover_art, scheme, size=1000
|
||||
)
|
||||
self._current_chromecast.media_controller.play_media(
|
||||
uri,
|
||||
# Just pretend that whatever we send it is mp3, even if it isn't.
|
||||
|
@@ -839,8 +839,8 @@ class AlbumsGrid(Gtk.Overlay):
|
||||
artwork.set_from_file(filename.result())
|
||||
artwork.set_loading(False)
|
||||
|
||||
cover_art_filename_future = AdapterManager.get_cover_art_filename(
|
||||
item.album.cover_art
|
||||
cover_art_filename_future = AdapterManager.get_cover_art_uri(
|
||||
item.album.cover_art, "file"
|
||||
)
|
||||
if cover_art_filename_future.data_is_available:
|
||||
on_artwork_downloaded(cover_art_filename_future)
|
||||
|
@@ -1,4 +1,5 @@
|
||||
from datetime import timedelta
|
||||
from functools import partial
|
||||
from random import randint
|
||||
from typing import cast, List, Sequence
|
||||
|
||||
@@ -462,7 +463,7 @@ class ArtistDetailPanel(Gtk.Box):
|
||||
self.albums_list.update(artist, app_config, force=force)
|
||||
|
||||
@util.async_callback(
|
||||
AdapterManager.get_cover_art_filename,
|
||||
partial(AdapterManager.get_cover_art_uri, scheme="file"),
|
||||
before_download=lambda self: self.artist_artwork.set_loading(True),
|
||||
on_failure=lambda self, e: self.artist_artwork.set_loading(False),
|
||||
)
|
||||
|
@@ -51,8 +51,10 @@ class AlbumWithSongs(Gtk.Box):
|
||||
artist_artwork.set_from_file(f.result())
|
||||
artist_artwork.set_loading(False)
|
||||
|
||||
cover_art_filename_future = AdapterManager.get_cover_art_filename(
|
||||
album.cover_art, before_download=lambda: artist_artwork.set_loading(True),
|
||||
cover_art_filename_future = AdapterManager.get_cover_art_uri(
|
||||
album.cover_art,
|
||||
"file",
|
||||
before_download=lambda: artist_artwork.set_loading(True),
|
||||
)
|
||||
cover_art_filename_future.add_done_callback(
|
||||
lambda f: GLib.idle_add(cover_art_future_done, f)
|
||||
|
@@ -1065,7 +1065,7 @@ class MainWindow(Gtk.ApplicationWindow):
|
||||
image.set_loading(False)
|
||||
image.set_from_file(f.result())
|
||||
|
||||
artwork_future = AdapterManager.get_cover_art_filename(cover_art_id)
|
||||
artwork_future = AdapterManager.get_cover_art_uri(cover_art_id, "file")
|
||||
artwork_future.add_done_callback(lambda f: GLib.idle_add(image_callback, f))
|
||||
|
||||
return row
|
||||
@@ -1196,7 +1196,7 @@ class DownloadStatusBox(Gtk.Box):
|
||||
image.set_loading(False)
|
||||
image.set_from_file(f.result())
|
||||
|
||||
artwork_future = AdapterManager.get_cover_art_filename(self.song.cover_art)
|
||||
artwork_future = AdapterManager.get_cover_art_uri(self.song.cover_art, "file")
|
||||
artwork_future.add_done_callback(lambda f: GLib.idle_add(image_callback, f))
|
||||
|
||||
def update_progress(self, progress_fraction: float):
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import copy
|
||||
import math
|
||||
|
||||
from datetime import timedelta
|
||||
from functools import partial
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable, Dict, Optional, Set, Tuple
|
||||
|
||||
@@ -246,7 +246,7 @@ class PlayerControls(Gtk.ActionBar):
|
||||
def get_cover_art_filename_or_create_future(
|
||||
cover_art_id: Optional[str], idx: int, order_token: int
|
||||
) -> Optional[str]:
|
||||
cover_art_result = AdapterManager.get_cover_art_filename(cover_art_id)
|
||||
cover_art_result = AdapterManager.get_cover_art_uri(cover_art_id, "file")
|
||||
if not cover_art_result.data_is_available:
|
||||
cover_art_result.add_done_callback(
|
||||
make_idle_index_capturing_function(
|
||||
@@ -331,7 +331,7 @@ class PlayerControls(Gtk.ActionBar):
|
||||
self.editing_play_queue_song_list = False
|
||||
|
||||
@util.async_callback(
|
||||
AdapterManager.get_cover_art_filename,
|
||||
partial(AdapterManager.get_cover_art_uri, scheme="file"),
|
||||
before_download=lambda self: self.album_art.set_loading(True),
|
||||
on_failure=lambda self, e: self.album_art.set_loading(False),
|
||||
)
|
||||
|
@@ -1,4 +1,4 @@
|
||||
from functools import lru_cache
|
||||
from functools import lru_cache, partial
|
||||
from random import randint
|
||||
from typing import Any, cast, Dict, Iterable, List, Tuple
|
||||
|
||||
@@ -679,7 +679,7 @@ class PlaylistDetailPanel(Gtk.Overlay):
|
||||
self.playlist_action_buttons.show_all()
|
||||
|
||||
@util.async_callback(
|
||||
AdapterManager.get_cover_art_filename,
|
||||
partial(AdapterManager.get_cover_art_uri, scheme="file"),
|
||||
before_download=lambda self: self.playlist_artwork.set_loading(True),
|
||||
on_failure=lambda self, e: self.playlist_artwork.set_loading(False),
|
||||
)
|
||||
|
Reference in New Issue
Block a user