Closes #253: fixed ingestion of search results; restricted search results to just ones that won't blow up
This commit is contained in:
@@ -26,7 +26,7 @@ v0.11.1
|
||||
* Fixed issue where pressing next/previous would start playing even if the
|
||||
player was paused. (#131)
|
||||
* Fixed issue where using DBUS to go next/previous ignored when no song was
|
||||
playing (#185)
|
||||
playing. (#185)
|
||||
|
||||
**Under the Hood**
|
||||
|
||||
|
@@ -147,11 +147,19 @@ class SearchResult:
|
||||
|
||||
def __init__(self, query: str = None):
|
||||
self.query = query
|
||||
self.similiarity_partial = partial(
|
||||
similarity_ratio, self.query.lower() if self.query else ""
|
||||
)
|
||||
self._artists: Dict[str, Artist] = {}
|
||||
self._albums: Dict[str, Album] = {}
|
||||
self._songs: Dict[str, Song] = {}
|
||||
self._playlists: Dict[str, Playlist] = {}
|
||||
|
||||
def __repr__(self) -> str:
|
||||
fields = ("query", "_artists", "_albums", "_songs", "_playlists")
|
||||
formatted_fields = map(lambda f: f"{f}={getattr(self, f)}", fields)
|
||||
return f"<SearchResult {' '.join(formatted_fields)}>"
|
||||
|
||||
def add_results(self, result_type: str, results: Iterable):
|
||||
"""Adds the ``results`` to the ``_result_type`` set."""
|
||||
if results is None:
|
||||
@@ -177,7 +185,7 @@ class SearchResult:
|
||||
(
|
||||
(
|
||||
max(
|
||||
partial(similarity_ratio, self.query.lower())(t.lower())
|
||||
self.similiarity_partial(t.lower())
|
||||
for t in transform(x)
|
||||
if t is not None
|
||||
),
|
||||
|
@@ -386,7 +386,10 @@ class FilesystemAdapter(CachingAdapter):
|
||||
models.Album,
|
||||
CachingAdapter.CachedDataKey.ALBUMS,
|
||||
ignore_cache_miss=True,
|
||||
where_clauses=(~(models.Album.id.startswith("invalid:")),),
|
||||
where_clauses=(
|
||||
~(models.Album.id.startswith("invalid:")),
|
||||
models.Album.artist.is_null(False),
|
||||
),
|
||||
)
|
||||
|
||||
def get_album(self, album_id: str) -> API.Album:
|
||||
@@ -419,11 +422,14 @@ class FilesystemAdapter(CachingAdapter):
|
||||
search_result.add_results(
|
||||
"songs",
|
||||
self._get_list(
|
||||
models.Song, CachingAdapter.CachedDataKey.SONG, ignore_cache_miss=True
|
||||
models.Song,
|
||||
CachingAdapter.CachedDataKey.SONG,
|
||||
ignore_cache_miss=True,
|
||||
where_clauses=(models.Song.artist.is_null(False),),
|
||||
),
|
||||
)
|
||||
search_result.add_results(
|
||||
"playlists", self.get_playlists(ignore_cache_miss=True)
|
||||
"playlists", self.get_playlists(ignore_cache_miss=True),
|
||||
)
|
||||
return search_result
|
||||
|
||||
@@ -786,38 +792,37 @@ class FilesystemAdapter(CachingAdapter):
|
||||
song_data = getattrs(
|
||||
api_song, ["id", "title", "track", "year", "duration", "parent_id"]
|
||||
)
|
||||
if not partial:
|
||||
song_data["genre"] = (
|
||||
self._do_ingest_new_data(KEYS.GENRE, None, g)
|
||||
if (g := api_song.genre)
|
||||
else None
|
||||
song_data["genre"] = (
|
||||
self._do_ingest_new_data(KEYS.GENRE, None, g)
|
||||
if (g := api_song.genre)
|
||||
else None
|
||||
)
|
||||
song_data["artist"] = (
|
||||
self._do_ingest_new_data(KEYS.ARTIST, ar.id, ar, partial=True)
|
||||
if (ar := api_song.artist)
|
||||
else None
|
||||
)
|
||||
song_data["album"] = (
|
||||
self._do_ingest_new_data(KEYS.ALBUM, al.id, al, partial=True)
|
||||
if (al := api_song.album)
|
||||
else None
|
||||
)
|
||||
song_data["_cover_art"] = (
|
||||
self._do_ingest_new_data(
|
||||
KEYS.COVER_ART_FILE, api_song.cover_art, data=None,
|
||||
)
|
||||
song_data["artist"] = (
|
||||
self._do_ingest_new_data(KEYS.ARTIST, ar.id, ar, partial=True)
|
||||
if (ar := api_song.artist) and not partial
|
||||
else None
|
||||
)
|
||||
song_data["album"] = (
|
||||
self._do_ingest_new_data(KEYS.ALBUM, al.id, al, partial=True)
|
||||
if (al := api_song.album)
|
||||
else None
|
||||
)
|
||||
song_data["_cover_art"] = (
|
||||
self._do_ingest_new_data(
|
||||
KEYS.COVER_ART_FILE, api_song.cover_art, data=None,
|
||||
)
|
||||
if api_song.cover_art
|
||||
else None
|
||||
)
|
||||
song_data["file"] = (
|
||||
self._do_ingest_new_data(
|
||||
KEYS.SONG_FILE,
|
||||
api_song.id,
|
||||
data=(api_song.path, None, api_song.size),
|
||||
)
|
||||
if api_song.path
|
||||
else None
|
||||
if api_song.cover_art
|
||||
else None
|
||||
)
|
||||
song_data["file"] = (
|
||||
self._do_ingest_new_data(
|
||||
KEYS.SONG_FILE,
|
||||
api_song.id,
|
||||
data=(api_song.path, None, api_song.size),
|
||||
)
|
||||
if api_song.path
|
||||
else None
|
||||
)
|
||||
|
||||
song, created = models.Song.get_or_create(
|
||||
id=song_data["id"], defaults=song_data
|
||||
|
@@ -220,6 +220,8 @@ class AppConfiguration(DataClassJsonMixin):
|
||||
# Just ignore any errors, it is only UI state.
|
||||
self._state = UIState()
|
||||
|
||||
self._state.__init_available_players__()
|
||||
|
||||
@property
|
||||
def _state_file_location(self) -> Optional[Path]:
|
||||
if not (provider := self.provider):
|
||||
|
@@ -105,6 +105,7 @@ class UIState:
|
||||
self.current_notification = None
|
||||
self.playing = False
|
||||
|
||||
def __init_available_players__(self):
|
||||
from sublime.players import PlayerManager
|
||||
|
||||
self.available_players = {
|
||||
|
@@ -983,10 +983,18 @@ def test_search(cache_adapter: FilesystemAdapter):
|
||||
"albums",
|
||||
[
|
||||
SubsonicAPI.Album(
|
||||
id="album1", name="Foo", artist_id="artist1", cover_art="cal1"
|
||||
id="album1",
|
||||
name="Foo",
|
||||
artist_id="artist1",
|
||||
_artist="foo",
|
||||
cover_art="cal1",
|
||||
),
|
||||
SubsonicAPI.Album(
|
||||
id="album2", name="Boo", artist_id="artist1", cover_art="cal2"
|
||||
id="album2",
|
||||
name="Boo",
|
||||
artist_id="artist1",
|
||||
_artist="foo",
|
||||
cover_art="cal2",
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -1002,13 +1010,27 @@ def test_search(cache_adapter: FilesystemAdapter):
|
||||
search_result.add_results(
|
||||
"songs",
|
||||
[
|
||||
SubsonicAPI.Song("s1", "amazing boo", cover_art="s1"),
|
||||
SubsonicAPI.Song("s2", "foo of all foo", cover_art="s2"),
|
||||
SubsonicAPI.Song(
|
||||
"s1",
|
||||
"amazing boo",
|
||||
cover_art="s1",
|
||||
_artist="artist3",
|
||||
artist_id="ohea1",
|
||||
),
|
||||
SubsonicAPI.Song(
|
||||
"s2",
|
||||
"foo of all foo",
|
||||
cover_art="s2",
|
||||
_artist="artist4",
|
||||
artist_id="ohea2",
|
||||
),
|
||||
],
|
||||
)
|
||||
cache_adapter.ingest_new_data(KEYS.SEARCH_RESULTS, None, search_result)
|
||||
|
||||
search_result = cache_adapter.search("foo")
|
||||
assert [s.title for s in search_result.songs] == ["foo of all foo", "amazing boo"]
|
||||
assert [
|
||||
(s.title, s.artist.name if s.artist else None) for s in search_result.songs
|
||||
] == [("foo of all foo", "artist4"), ("amazing boo", "artist3")]
|
||||
assert [a.name for a in search_result.artists] == ["foo", "better boo"]
|
||||
assert [a.name for a in search_result.albums] == ["Foo", "Boo"]
|
||||
|
253
tests/adapter_tests/mock_data/search3-navidrome.json
Normal file
253
tests/adapter_tests/mock_data/search3-navidrome.json
Normal file
@@ -0,0 +1,253 @@
|
||||
{
|
||||
"subsonic-response": {
|
||||
"status": "ok",
|
||||
"version": "1.10.2",
|
||||
"type": "navidrome",
|
||||
"serverVersion": "0.27.0 (ddb30ce)",
|
||||
"searchResult3": {
|
||||
"artist": [
|
||||
{
|
||||
"id": "28d3ba2dd29c49d79276780ffdd55657",
|
||||
"name": "NC帝国 (USAO \u0026 Massive New Krew)",
|
||||
"albumCount": 1
|
||||
},
|
||||
{
|
||||
"id": "4e94cea7827e99bad4aa9d09924cb1ad",
|
||||
"name": "UOM Records (USAO)",
|
||||
"albumCount": 7
|
||||
}
|
||||
],
|
||||
"album": [
|
||||
{
|
||||
"id": "09817e6dd2537db90e7e249722e746d1",
|
||||
"isDir": true,
|
||||
"name": "AD:Drum'n Bass 3",
|
||||
"artist": "Diverse System",
|
||||
"year": 2017,
|
||||
"coverArt": "al-09817e6dd2537db90e7e249722e746d1",
|
||||
"duration": 4015,
|
||||
"created": "2020-05-01T17:26:54.508020396Z",
|
||||
"artistId": "ea7fe36e30ad44d86d80b8c098b1b354",
|
||||
"songCount": 14,
|
||||
"isVideo": false
|
||||
},
|
||||
{
|
||||
"id": "122b175790eeba47d5dd8703a5b9ec62",
|
||||
"isDir": true,
|
||||
"name": "ALTERNA",
|
||||
"artist": "Massive CircleZ (Massive New Krew)",
|
||||
"year": 2016,
|
||||
"coverArt": "al-122b175790eeba47d5dd8703a5b9ec62",
|
||||
"duration": 2525,
|
||||
"created": "2020-05-01T17:42:46.46328879Z",
|
||||
"artistId": "7b128e7593a9007576b8c944aa1e34be",
|
||||
"songCount": 11,
|
||||
"isVideo": false
|
||||
},
|
||||
{
|
||||
"id": "a048955fc533aaa658cb08f560b45bc2",
|
||||
"isDir": true,
|
||||
"name": "BASTARD ARCHIVE+",
|
||||
"artist": "M.P.T.",
|
||||
"year": 2008,
|
||||
"coverArt": "al-a048955fc533aaa658cb08f560b45bc2",
|
||||
"duration": 4634,
|
||||
"created": "2020-05-01T17:37:05.609815622Z",
|
||||
"artistId": "b80e98a2145430a326ec3e21261a813b",
|
||||
"songCount": 12,
|
||||
"isVideo": false
|
||||
},
|
||||
{
|
||||
"id": "9b7b52fae8b919b9de6e752c76f3ff00",
|
||||
"isDir": true,
|
||||
"name": "BREAK OUT BLACK",
|
||||
"artist": "Massive CircleZ (Massive New Krew)",
|
||||
"year": 2014,
|
||||
"coverArt": "al-9b7b52fae8b919b9de6e752c76f3ff00",
|
||||
"duration": 2928,
|
||||
"created": "2020-05-01T17:42:46.430711977Z",
|
||||
"artistId": "7b128e7593a9007576b8c944aa1e34be",
|
||||
"songCount": 11,
|
||||
"isVideo": false
|
||||
}
|
||||
],
|
||||
"song": [
|
||||
{
|
||||
"id": "2b62a4c1070a6e7747b439041fddbca3",
|
||||
"parent": "149884cddb190c8b150ed43ffc3617bb",
|
||||
"isDir": false,
|
||||
"title": "260",
|
||||
"album": "Kick's For Liberation",
|
||||
"artist": "USAO",
|
||||
"track": 11,
|
||||
"year": 2009,
|
||||
"coverArt": "al-149884cddb190c8b150ed43ffc3617bb",
|
||||
"size": 30208885,
|
||||
"contentType": "audio/flac",
|
||||
"suffix": "flac",
|
||||
"transcodedContentType": "audio/ogg",
|
||||
"transcodedSuffix": "oga",
|
||||
"duration": 232,
|
||||
"bitRate": 1039,
|
||||
"path": "UOM Records/Kick's For Liberation/260.flac",
|
||||
"discNumber": 1,
|
||||
"created": "2019-07-26T15:44:34.1975208Z",
|
||||
"albumId": "149884cddb190c8b150ed43ffc3617bb",
|
||||
"artistId": "923fe3977eec9a949f817e6da59ecc13",
|
||||
"type": "music",
|
||||
"isVideo": false
|
||||
},
|
||||
{
|
||||
"id": "f08997ac88302e8422033ed5f3c82478",
|
||||
"parent": "2a3a19a69ed681d7212a7f3ea8a6a61d",
|
||||
"isDir": false,
|
||||
"title": "50000DPS",
|
||||
"album": "Kick's For Liberation 5",
|
||||
"artist": "USAO",
|
||||
"track": 4,
|
||||
"year": 2015,
|
||||
"coverArt": "al-2a3a19a69ed681d7212a7f3ea8a6a61d",
|
||||
"size": 42064165,
|
||||
"contentType": "audio/flac",
|
||||
"suffix": "flac",
|
||||
"transcodedContentType": "audio/ogg",
|
||||
"transcodedSuffix": "oga",
|
||||
"duration": 293,
|
||||
"bitRate": 1146,
|
||||
"path": "UOM Records (USAO)/Kick's For Liberation 5/50000DPS.flac",
|
||||
"discNumber": 1,
|
||||
"created": "2019-07-26T18:57:32.0111078Z",
|
||||
"albumId": "2a3a19a69ed681d7212a7f3ea8a6a61d",
|
||||
"artistId": "923fe3977eec9a949f817e6da59ecc13",
|
||||
"type": "music",
|
||||
"isVideo": false
|
||||
},
|
||||
{
|
||||
"id": "287d1b10a7e0e7269c3fc24f89d2fe7d",
|
||||
"parent": "149884cddb190c8b150ed43ffc3617bb",
|
||||
"isDir": false,
|
||||
"title": "5ymphoTEK",
|
||||
"album": "Kick's For Liberation",
|
||||
"artist": "USAO",
|
||||
"track": 8,
|
||||
"year": 2009,
|
||||
"coverArt": "al-149884cddb190c8b150ed43ffc3617bb",
|
||||
"size": 45426359,
|
||||
"contentType": "audio/flac",
|
||||
"suffix": "flac",
|
||||
"transcodedContentType": "audio/ogg",
|
||||
"transcodedSuffix": "oga",
|
||||
"duration": 344,
|
||||
"bitRate": 1055,
|
||||
"path": "UOM Records/Kick's For Liberation/5ymphoTEK.flac",
|
||||
"discNumber": 1,
|
||||
"created": "2019-07-26T17:22:02.059486Z",
|
||||
"albumId": "149884cddb190c8b150ed43ffc3617bb",
|
||||
"artistId": "923fe3977eec9a949f817e6da59ecc13",
|
||||
"type": "music",
|
||||
"isVideo": false
|
||||
},
|
||||
{
|
||||
"id": "513daf633bffc7cf3faa5a0a3337ed6f",
|
||||
"parent": "09e23675867dc64d8563035ec9df96e0",
|
||||
"isDir": false,
|
||||
"title": "ARENARemix2008",
|
||||
"album": "ほっちぽっち4beat",
|
||||
"artist": "USAO",
|
||||
"track": 2,
|
||||
"year": 2008,
|
||||
"coverArt": "al-09e23675867dc64d8563035ec9df96e0",
|
||||
"size": 46553211,
|
||||
"contentType": "audio/flac",
|
||||
"suffix": "flac",
|
||||
"transcodedContentType": "audio/ogg",
|
||||
"transcodedSuffix": "oga",
|
||||
"duration": 361,
|
||||
"bitRate": 1031,
|
||||
"path": "UTY/UOM Records/ほっちぽっち4beat/ARENARemix2008.flac",
|
||||
"discNumber": 1,
|
||||
"created": "2019-08-02T17:13:07.3348309Z",
|
||||
"albumId": "09e23675867dc64d8563035ec9df96e0",
|
||||
"artistId": "923fe3977eec9a949f817e6da59ecc13",
|
||||
"type": "music",
|
||||
"isVideo": false
|
||||
},
|
||||
{
|
||||
"id": "dac4aa78ff6cebcb79082c2301f317e8",
|
||||
"parent": "5e761a69c8218c24245a64baf499cdee",
|
||||
"isDir": false,
|
||||
"title": "Acid Virus",
|
||||
"album": "S2TB Files7: Battle Royale Disc 2",
|
||||
"artist": "kors k vs USAO",
|
||||
"track": 7,
|
||||
"year": 2017,
|
||||
"coverArt": "al-5e761a69c8218c24245a64baf499cdee",
|
||||
"size": 41790587,
|
||||
"contentType": "audio/flac",
|
||||
"suffix": "flac",
|
||||
"transcodedContentType": "audio/ogg",
|
||||
"transcodedSuffix": "oga",
|
||||
"duration": 290,
|
||||
"bitRate": 1151,
|
||||
"path": "S2TB Recording/S2TB Files7: Battle Royale Disc 2/Acid Virus.flac",
|
||||
"discNumber": 2,
|
||||
"created": "2019-08-01T20:23:28.8786968Z",
|
||||
"albumId": "5e761a69c8218c24245a64baf499cdee",
|
||||
"artistId": "86c4404190b692e82cf215544099c204",
|
||||
"type": "music",
|
||||
"isVideo": false
|
||||
},
|
||||
{
|
||||
"id": "bd67969a42d00992c1428e0d1cee1a06",
|
||||
"parent": "149884cddb190c8b150ed43ffc3617bb",
|
||||
"isDir": false,
|
||||
"title": "Add Insult To Injury",
|
||||
"album": "Kick's For Liberation",
|
||||
"artist": "USAO",
|
||||
"track": 6,
|
||||
"year": 2009,
|
||||
"coverArt": "al-149884cddb190c8b150ed43ffc3617bb",
|
||||
"size": 37176906,
|
||||
"contentType": "audio/flac",
|
||||
"suffix": "flac",
|
||||
"transcodedContentType": "audio/ogg",
|
||||
"transcodedSuffix": "oga",
|
||||
"duration": 268,
|
||||
"bitRate": 1109,
|
||||
"path": "UOM Records/Kick's For Liberation/Add Insult To Injury.flac",
|
||||
"discNumber": 1,
|
||||
"created": "2019-07-26T19:26:27.2135649Z",
|
||||
"albumId": "149884cddb190c8b150ed43ffc3617bb",
|
||||
"artistId": "923fe3977eec9a949f817e6da59ecc13",
|
||||
"type": "music",
|
||||
"isVideo": false
|
||||
},
|
||||
{
|
||||
"id": "9f4dba1188c2d772fb82947dd60fdd74",
|
||||
"parent": "2a3a19a69ed681d7212a7f3ea8a6a61d",
|
||||
"isDir": false,
|
||||
"title": "Aeropolis",
|
||||
"album": "Kick's For Liberation 5",
|
||||
"artist": "USAO",
|
||||
"track": 8,
|
||||
"year": 2015,
|
||||
"coverArt": "al-2a3a19a69ed681d7212a7f3ea8a6a61d",
|
||||
"size": 40838681,
|
||||
"contentType": "audio/flac",
|
||||
"suffix": "flac",
|
||||
"transcodedContentType": "audio/ogg",
|
||||
"transcodedSuffix": "oga",
|
||||
"duration": 302,
|
||||
"bitRate": 1080,
|
||||
"path": "UOM Records (USAO)/Kick's For Liberation 5/Aeropolis.flac",
|
||||
"discNumber": 1,
|
||||
"created": "2019-07-26T19:08:21.8450483Z",
|
||||
"albumId": "2a3a19a69ed681d7212a7f3ea8a6a61d",
|
||||
"artistId": "923fe3977eec9a949f817e6da59ecc13",
|
||||
"type": "music",
|
||||
"isVideo": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@@ -38,10 +38,10 @@ def test_server_property(tmp_path: Path):
|
||||
config.current_provider_id = "1"
|
||||
assert config.provider == provider
|
||||
|
||||
assert config._state_file_location == tmp_path.joinpath("1", "state.pickle",)
|
||||
assert config._state_file_location == tmp_path.joinpath("1", "state.pickle")
|
||||
|
||||
|
||||
def test_json_load_unload(config_filename: Path):
|
||||
def test_json_load_unload(config_filename: Path, tmp_path: Path):
|
||||
ConfigurationStore.MOCK = True
|
||||
subsonic_config_store = ConfigurationStore(username="test")
|
||||
subsonic_config_store.set_secret("password", "testpass")
|
||||
@@ -59,6 +59,7 @@ def test_json_load_unload(config_filename: Path):
|
||||
current_provider_id="1",
|
||||
filename=config_filename,
|
||||
)
|
||||
original_config.cache_location = tmp_path
|
||||
|
||||
original_config.save()
|
||||
|
||||
|
Reference in New Issue
Block a user