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.
124 lines
4.5 KiB
124 lines
4.5 KiB
"""Batch library presence check for search results.
|
|
|
|
Given a list of `albums` and `tracks` from a metadata search, return per-row
|
|
booleans (and matched-row metadata for tracks) indicating whether each
|
|
result is already in the user's library or wishlist. Plex relative-path
|
|
thumb URLs are rewritten to absolute URLs with token.
|
|
|
|
Called async from the frontend after the main search renders, so the user
|
|
sees results immediately and "in library" badges fade in once the check
|
|
completes.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from typing import Optional
|
|
|
|
from core.wishlist.presence import load_wishlist_keys as _load_wishlist_keys_shared
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def _resolve_plex_thumb(thumb: str, plex_base: str, plex_token: str) -> str:
|
|
"""Rewrite a Plex relative thumb path to an absolute URL with token."""
|
|
if not thumb or thumb.startswith('http') or not plex_base or not thumb.startswith('/'):
|
|
return thumb
|
|
if plex_token:
|
|
return f"{plex_base}{thumb}?X-Plex-Token={plex_token}"
|
|
return f"{plex_base}{thumb}"
|
|
|
|
|
|
def _resolve_plex_credentials(plex_client, config_manager) -> tuple[str, str]:
|
|
"""Pull (base_url, token) for the active Plex server.
|
|
|
|
Prefers the live `plex_client.server` attrs; falls back to config_manager
|
|
if the live client isn't connected yet. Mirrors original web_server.py
|
|
inline logic byte-for-byte.
|
|
"""
|
|
base, token = '', ''
|
|
if plex_client and plex_client.server:
|
|
base = getattr(plex_client.server, '_baseurl', '') or ''
|
|
token = getattr(plex_client.server, '_token', '') or ''
|
|
if not base:
|
|
cfg = config_manager.get_plex_config()
|
|
base = (cfg.get('base_url', '') or '').rstrip('/')
|
|
token = token or cfg.get('token', '')
|
|
return base, token
|
|
|
|
|
|
def _load_wishlist_keys(cursor, profile_id: int) -> set[str]:
|
|
return _load_wishlist_keys_shared(cursor, profile_id)
|
|
|
|
|
|
def check_library_presence(
|
|
database,
|
|
plex_client,
|
|
config_manager,
|
|
profile_id: int,
|
|
albums: list[dict],
|
|
tracks: list[dict],
|
|
) -> dict:
|
|
"""Return `{albums: [bool], tracks: [{...}]}` for the given search results.
|
|
|
|
- `albums` returns one bool per input row.
|
|
- `tracks` returns one dict per input row. Matched rows get the full
|
|
track metadata + resolved thumb URL; unmatched rows get
|
|
`{in_library: False, in_wishlist: bool}`.
|
|
"""
|
|
conn = database._get_connection()
|
|
try:
|
|
cursor = conn.cursor()
|
|
|
|
cursor.execute(
|
|
"SELECT LOWER(al.title) || '|||' || LOWER(ar.name) "
|
|
"FROM albums al JOIN artists ar ON ar.id = al.artist_id"
|
|
)
|
|
owned_albums = {r[0] for r in cursor.fetchall()}
|
|
|
|
cursor.execute(
|
|
"""
|
|
SELECT LOWER(t.title) || '|||' || LOWER(a.name), t.id, t.file_path,
|
|
t.title, a.name, al.title, al.thumb_url
|
|
FROM tracks t
|
|
JOIN artists a ON a.id = t.artist_id
|
|
JOIN albums al ON al.id = t.album_id
|
|
"""
|
|
)
|
|
owned_tracks: dict[str, dict] = {}
|
|
for r in cursor.fetchall():
|
|
if r[0] not in owned_tracks: # keep first match only
|
|
owned_tracks[r[0]] = {
|
|
'track_id': r[1],
|
|
'file_path': r[2],
|
|
'title': r[3],
|
|
'artist_name': r[4],
|
|
'album_title': r[5],
|
|
'album_thumb_url': r[6],
|
|
}
|
|
|
|
wishlist_keys = _load_wishlist_keys(cursor, profile_id)
|
|
|
|
album_results: list[bool] = []
|
|
for a in albums:
|
|
key = (a.get('name', '').lower() + '|||' + a.get('artist', '').split(',')[0].strip().lower())
|
|
album_results.append(key in owned_albums)
|
|
|
|
plex_base, plex_token = _resolve_plex_credentials(plex_client, config_manager)
|
|
|
|
track_results: list[dict] = []
|
|
for t in tracks:
|
|
key = (t.get('name', '').lower() + '|||' + t.get('artist', '').split(',')[0].strip().lower())
|
|
in_wishlist = key in wishlist_keys
|
|
match = owned_tracks.get(key)
|
|
if match:
|
|
thumb = match.get('album_thumb_url') or ''
|
|
match['album_thumb_url'] = _resolve_plex_thumb(thumb, plex_base, plex_token)
|
|
track_results.append({'in_library': True, 'in_wishlist': in_wishlist, **match})
|
|
else:
|
|
track_results.append({'in_library': False, 'in_wishlist': in_wishlist})
|
|
finally:
|
|
conn.close()
|
|
|
|
return {'albums': album_results, 'tracks': track_results}
|