Unify get_cover_art_uri and get_cover_art_filename

This commit is contained in:
Sumner Evans
2020-07-20 22:06:23 -06:00
parent e86ba55a7a
commit 2332925fcd
14 changed files with 119 additions and 112 deletions

View File

@@ -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
=======

View File

@@ -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:

View File

@@ -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),

View File

@@ -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)

View File

@@ -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())

View File

@@ -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()

View File

@@ -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 = ""

View File

@@ -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.

View File

@@ -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)

View File

@@ -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),
)

View File

@@ -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)

View File

@@ -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):

View File

@@ -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),
)

View File

@@ -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),
)