Merge branch '189-use-supported-schemas'

This commit is contained in:
Sumner Evans
2020-07-25 12:12:39 -06:00
17 changed files with 215 additions and 160 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,18 +445,19 @@ class Adapter(abc.ABC):
"""
Whether or not the adapter supports :class:`get_cover_art_uri`.
"""
return False
@property
def can_stream(self) -> bool:
def can_get_song_file_uri(self) -> bool:
"""
Whether or not the adapter can provide a stream URI.
Whether or not the adapter supports :class:`get_song_file_uri`.
"""
return False
@property
def can_get_song_uri(self) -> bool:
def can_get_song_stream_uri(self) -> bool:
"""
Whether or not the adapter supports :class:`get_song_uri`.
Whether or not the adapter supports :class:`get_song_stream_uri`.
"""
return False
@@ -645,20 +645,26 @@ class Adapter(abc.ABC):
"""
raise self._check_can_error("get_cover_art_uri")
def get_song_uri(self, song_id: str, scheme: str, stream: bool = False) -> str:
def get_song_file_uri(self, song_id: str, schemes: Iterable[str]) -> str:
"""
Get a URI for a given song.
Get a URI for a given song. This URI must give the full file.
:param song_id: The ID of the song to get a URI for.
:param scheme: The URI scheme that should be returned. It is guaranteed that
``scheme`` will be one of the schemes returned by
:param schemes: A set of URI schemes that can be returned. It is guaranteed that
all of the items in ``schemes`` will be one of the schemes returned by
:class:`supported_schemes`.
:param stream: Whether or not the URI returned should be a stream URI. This will
only be ``True`` if :class:`supports_streaming` returns ``True``.
:returns: The URI for the given song.
"""
# TODO (#189)
raise self._check_can_error("get_song_uri")
raise self._check_can_error("get_song_file_uri")
def get_song_stream_uri(self, song_id: str) -> str:
"""
Get a URI for streaming the given song.
:param song_id: The ID of the song to get the stream URI for.
:returns: the stream URI for the given song.
"""
raise self._check_can_error("get_song_stream_uri")
def get_song_details(self, song_id: str) -> Song:
"""

View File

@@ -101,7 +101,7 @@ class FilesystemAdapter(CachingAdapter):
# TODO (#200) make these dependent on cache state. Need to do this kinda efficiently
can_get_cover_art_uri = True
can_get_song_uri = True
can_get_song_file_uri = True
can_get_song_details = True
can_get_artist = True
can_get_albums = True
@@ -286,7 +286,7 @@ class FilesystemAdapter(CachingAdapter):
raise CacheMissError()
def get_song_uri(self, song_id: str, scheme: str, stream: bool = False) -> str:
def get_song_file_uri(self, song_id: str, schemes: Iterable[str]) -> str:
song = models.Song.get_or_none(models.Song.id == song_id)
if not song:
if self.is_cache:

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
@@ -666,13 +655,17 @@ class AdapterManager:
return AdapterManager._ground_truth_can_do("delete_playlist")
@staticmethod
def can_get_song_filename_or_stream() -> bool:
return AdapterManager._ground_truth_can_do("get_song_uri")
def can_get_song_file_uri() -> bool:
return AdapterManager._ground_truth_can_do("get_song_file_uri")
@staticmethod
def can_get_song_stream_uri() -> bool:
return AdapterManager._ground_truth_can_do("get_song_stream_uri")
@staticmethod
def can_batch_download_songs() -> bool:
# We can only download from the ground truth adapter.
return AdapterManager._ground_truth_can_do("get_song_uri")
return AdapterManager._ground_truth_can_do("get_song_file_uri")
@staticmethod
def can_get_genres() -> bool:
@@ -805,122 +798,133 @@ 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("Cache Miss on get_cover_art_uri.")
except Exception:
logging.exception(
"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
def get_song_filename_or_stream(
song: Song, format: str = None, force_stream: bool = False
) -> str:
def get_song_file_uri(song: Song) -> str:
assert AdapterManager._instance
cached_song_filename = None
if AdapterManager._can_use_cache(force_stream, "get_song_uri"):
assert AdapterManager._instance.caching_adapter
if AdapterManager._can_use_cache(False, "get_song_file_uri"):
assert (caching_adapter := AdapterManager._instance.caching_adapter)
try:
return AdapterManager._instance.caching_adapter.get_song_uri(
song.id, "file"
)
if "file" not in caching_adapter.supported_schemes:
raise Exception("file not a supported scheme")
return caching_adapter.get_song_file_uri(song.id, "file")
except CacheMissError as e:
if e.partial_data is not None:
cached_song_filename = cast(str, e.partial_data)
logging.info(f'Cache Miss on {"get_song_filename_or_stream"}.')
logging.info("Cache Miss on get_song_file_uri.")
except Exception:
logging.exception(
f'Error on {"get_song_filename_or_stream"} retrieving from cache.'
)
logging.exception("Error on get_song_file_uri retrieving from cache.")
ground_truth_adapter = AdapterManager._instance.ground_truth_adapter
if (
not AdapterManager._ground_truth_can_do("stream")
or not AdapterManager._ground_truth_can_do("get_song_uri")
or (
AdapterManager._instance.ground_truth_adapter.is_networked
and AdapterManager._offline_mode
)
not AdapterManager._ground_truth_can_do("get_song_file_uri")
or (ground_truth_adapter.is_networked and AdapterManager._offline_mode)
or ("file" not in ground_truth_adapter.supported_schemes)
):
raise CacheMissError(partial_data=cached_song_filename)
return AdapterManager._instance.ground_truth_adapter.get_song_uri(
song.id, AdapterManager._get_scheme(), stream=True,
return ground_truth_adapter.get_song_file_uri(song.id, "file")
@staticmethod
def get_song_stream_uri(song: Song) -> str:
assert AdapterManager._instance
# TODO
return AdapterManager._instance.ground_truth_adapter.get_song_stream_uri(
song.id
)
@staticmethod
@@ -968,7 +972,9 @@ class AdapterManager:
# Download the actual song file.
try:
# If the song file is already cached, just indicate done immediately.
AdapterManager._instance.caching_adapter.get_song_uri(song_id, "file")
AdapterManager._instance.caching_adapter.get_song_file_uri(
song_id, "file"
)
AdapterManager._instance.download_limiter_semaphore.release()
AdapterManager._instance.song_download_progress(
song_id, DownloadProgress(DownloadProgress.Type.DONE),
@@ -984,8 +990,8 @@ class AdapterManager:
song_tmp_filename_result: Result[
str
] = AdapterManager._create_download_result(
AdapterManager._instance.ground_truth_adapter.get_song_uri(
song_id, AdapterManager._get_scheme()
AdapterManager._instance.ground_truth_adapter.get_song_file_uri(
song_id, AdapterManager._get_networked_scheme()
),
song_id,
lambda: before_download(song_id),

View File

@@ -281,7 +281,8 @@ class SubsonicAdapter(Adapter):
can_get_playlist_details = True
can_get_playlists = True
can_get_song_details = True
can_get_song_uri = True
can_get_song_file_uri = True
can_get_song_stream_uri = True
can_scrobble_song = True
can_search = True
can_stream = True
@@ -537,10 +538,14 @@ class SubsonicAdapter(Adapter):
params = {"id": cover_art_id, "size": size, **self._get_params()}
return self._make_url("getCoverArt") + "?" + urlencode(params)
def get_song_uri(self, song_id: str, scheme: str, stream: bool = False) -> str:
def get_song_file_uri(self, song_id: str, schemes: Iterable[str]) -> str:
assert any(s in schemes for s in self.supported_schemes)
params = {"id": song_id, **self._get_params()}
endpoint = "stream" if stream else "download"
return self._make_url(endpoint) + "?" + urlencode(params)
return self._make_url("download") + "?" + urlencode(params)
def get_song_stream_uri(self, song_id: str) -> str:
params = {"id": song_id, **self._get_params()}
return self._make_url("stream") + "?" + urlencode(params)
def get_song_details(self, song_id: str) -> API.Song:
song = self._get_json(self._make_url("getSong"), id=song_id).song

View File

@@ -7,6 +7,7 @@ from datetime import timedelta
from functools import partial
from pathlib import Path
from typing import Any, Callable, Dict, Iterable, List, Optional, Set, Tuple
from urllib.parse import urlparse
try:
import osxmmkeys
@@ -35,6 +36,7 @@ except Exception:
from .adapters import (
AdapterManager,
AlbumSearchQuery,
CacheMissError,
DownloadProgress,
Result,
SongCacheStatus,
@@ -469,8 +471,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 "")
@@ -1112,9 +1114,27 @@ class SublimeMusicApp(Gtk.Application):
if order_token != self.song_playing_order_token:
return
# TODO (#189): make this actually use the player's allowed list of schemes
# to play.
uri = AdapterManager.get_song_filename_or_stream(song)
uri = None
try:
if "file" in self.player_manager.supported_schemes:
uri = AdapterManager.get_song_file_uri(song)
except CacheMissError:
logging.debug("Couldn't find the file, will attempt to stream.")
if not uri:
try:
uri = AdapterManager.get_song_stream_uri(song)
except Exception:
pass
if (
not uri
or urlparse(uri).scheme not in self.player_manager.supported_schemes
):
self.app_config.state.current_notification = UIState.UINotification(
markup=f"<b>Unable to play {song.title}.</b>",
icon="dialog-error",
)
return
# Prevent it from doing the thing where it continually loads
# songs when it has to download.
@@ -1165,8 +1185,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())
@@ -1190,7 +1210,7 @@ class SublimeMusicApp(Gtk.Application):
os.system(f"osascript -e '{' '.join(osascript_command)}'")
except Exception:
logging.exception(
logging.warning(
"Unable to display notification. Is a notification daemon running?" # noqa: E501
)
@@ -1215,7 +1235,7 @@ class SublimeMusicApp(Gtk.Application):
assert self.player_manager
if self.player_manager.can_start_playing_with_no_latency:
self.player_manager.play_media(
AdapterManager.get_song_filename_or_stream(song),
AdapterManager.get_song_file_uri(song),
self.app_config.state.song_progress,
song,
)

View File

@@ -111,7 +111,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

@@ -237,8 +237,7 @@ class ChromecastPlayer(Player):
song = AdapterManager.get_song_details(
self._serving_song_id.value.decode()
).result()
filename = AdapterManager.get_song_filename_or_stream(song)
assert filename.startswith("file://")
filename = AdapterManager.get_song_file_uri(song)
with open(filename[7:], "rb") as fin:
song_buffer = io.BytesIO(fin.read())
@@ -300,7 +299,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

@@ -1,6 +1,6 @@
import logging
from datetime import timedelta
from typing import Any, Callable, Dict, List, Optional, Tuple, Type, Union
from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Type, Union
from sublime.adapters.api_objects import Song
@@ -89,6 +89,12 @@ class PlayerManager:
if current_player_type := self._get_current_player_type():
return self.players.get(current_player_type)
@property
def supported_schemes(self) -> Set[str]:
if cp := self._get_current_player():
return cp.supported_schemes
return set()
@property
def can_start_playing_with_no_latency(self) -> bool:
if self._current_device_id:

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

View File

@@ -371,13 +371,13 @@ def test_invalidate_song_file(cache_adapter: FilesystemAdapter):
cache_adapter.invalidate_data(KEYS.COVER_ART_FILE, "s1")
with pytest.raises(CacheMissError):
cache_adapter.get_song_uri("1", "file")
cache_adapter.get_song_file_uri("1", "file")
with pytest.raises(CacheMissError):
cache_adapter.get_cover_art_uri("s1", "file", size=300)
# Make sure it didn't delete the other song.
assert cache_adapter.get_song_uri("2", "file").endswith("song2.mp3")
assert cache_adapter.get_song_file_uri("2", "file").endswith("song2.mp3")
def test_malformed_song_path(cache_adapter: FilesystemAdapter):
@@ -390,10 +390,10 @@ def test_malformed_song_path(cache_adapter: FilesystemAdapter):
KEYS.SONG_FILE, "2", ("fine/path/song2.mp3", MOCK_SONG_FILE2, None)
)
song_uri = cache_adapter.get_song_uri("1", "file")
song_uri = cache_adapter.get_song_file_uri("1", "file")
assert song_uri.endswith(f"/music/{MOCK_SONG_FILE_HASH}")
song_uri2 = cache_adapter.get_song_uri("2", "file")
song_uri2 = cache_adapter.get_song_file_uri("2", "file")
assert song_uri2.endswith("fine/path/song2.mp3")
@@ -467,7 +467,7 @@ def test_delete_song_data(cache_adapter: FilesystemAdapter):
KEYS.COVER_ART_FILE, "s1", MOCK_ALBUM_ART,
)
music_file_path = cache_adapter.get_song_uri("1", "file")
music_file_path = cache_adapter.get_song_file_uri("1", "file")
cover_art_path = cache_adapter.get_cover_art_uri("s1", "file", size=300)
cache_adapter.delete_data(KEYS.SONG_FILE, "1")
@@ -477,7 +477,7 @@ def test_delete_song_data(cache_adapter: FilesystemAdapter):
assert not Path(cover_art_path).exists()
try:
cache_adapter.get_song_uri("1", "file")
cache_adapter.get_song_file_uri("1", "file")
assert 0, "DID NOT raise CacheMissError"
except CacheMissError as e:
assert e.partial_data is None