mirror of https://github.com/Nezreka/SoulSync.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
80 lines
2.8 KiB
80 lines
2.8 KiB
"""Basic download-source file search — flat list of file results sorted by quality.
|
|
|
|
Used by the basic search UI on the Search page and by ``/api/search``.
|
|
|
|
``run_basic_search`` replaced ``run_basic_soulseek_search`` so the caller
|
|
can target any active download source (not just slskd). The old name is
|
|
kept as a thin alias for backwards compat with any callers outside this
|
|
module.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from typing import Callable, Optional
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def run_basic_search(
|
|
query: str,
|
|
download_orchestrator,
|
|
run_async: Callable,
|
|
*,
|
|
source: Optional[str] = None,
|
|
) -> list[dict]:
|
|
"""Search ``source`` (or the active/first hybrid source) for ``query``.
|
|
|
|
Returns dicts with ``result_type`` set to ``"album"`` or ``"track"``
|
|
and sorted by ``quality_score`` descending. Empty list on any failure.
|
|
|
|
Parameters
|
|
----------
|
|
source:
|
|
Optional source name to override the orchestrator's default selection.
|
|
Must be a canonical name from ``DownloadPluginRegistry`` (e.g.
|
|
``"soulseek"``, ``"tidal"``, ``"qobuz"``). When ``None``, behaviour
|
|
is unchanged from before: orchestrator.search() picks the active
|
|
source (single mode) or the first in chain (hybrid).
|
|
"""
|
|
if source and download_orchestrator:
|
|
# Target a specific source: resolve the client and call search()
|
|
# directly instead of going through the orchestrator chain.
|
|
try:
|
|
client = download_orchestrator.client(source)
|
|
except Exception as exc:
|
|
logger.warning("basic search: could not resolve client for %r: %s", source, exc)
|
|
client = None
|
|
|
|
if client is None:
|
|
logger.warning("basic search: no client for source %r — falling back to orchestrator", source)
|
|
tracks, albums = run_async(download_orchestrator.search(query))
|
|
else:
|
|
logger.info("basic search: targeting %r for %r", source, query)
|
|
tracks, albums = run_async(client.search(query))
|
|
else:
|
|
tracks, albums = run_async(download_orchestrator.search(query))
|
|
|
|
processed_albums = []
|
|
for album in albums:
|
|
album_dict = album.__dict__.copy()
|
|
album_dict['tracks'] = [track.__dict__ for track in album.tracks]
|
|
album_dict['result_type'] = 'album'
|
|
processed_albums.append(album_dict)
|
|
|
|
processed_tracks = []
|
|
for track in tracks:
|
|
track_dict = track.__dict__.copy()
|
|
track_dict['result_type'] = 'track'
|
|
processed_tracks.append(track_dict)
|
|
|
|
return sorted(
|
|
processed_albums + processed_tracks,
|
|
key=lambda x: x.get('quality_score', 0),
|
|
reverse=True,
|
|
)
|
|
|
|
|
|
# Backwards-compat alias for any callers that haven't been updated yet.
|
|
run_basic_soulseek_search = run_basic_search
|