Automations: per-profile playlist source reads in auto-sync (part 2)
The playlist source registry built the Spotify/Tidal adapters with a client GETTER (resolved fresh on every read), but web_server passed `lambda: <global client>`. Swapped those to get_spotify_client_for_profile / get_tidal_client_for_profile. Combined with part 1 (the engine running each automation as its owner), an auto-sync pipeline now reads its source playlist through the OWNER's account: - interactive sync → the user's session profile, - background automation → the automation owner (via core.profile_context), - admin / profile 1 → the global client, so the admin's existing auto-sync pipelines pull exactly as before. The adapters re-resolve per read, so a singleton registry is fine. Deezer/Qobuz getters left global (their playlist login is tangled with downloads — deferred). Tests: the Spotify/Tidal source adapters resolve the global client under admin and re-resolve through the profile context per call (unconnected → safe global fallback). 27 endpoint/profile tests pass.
This commit is contained in:
parent
6980253a96
commit
783839349c
2 changed files with 34 additions and 2 deletions
|
|
@ -315,3 +315,29 @@ def test_real_session_still_wins_over_background(client, nonadmin_profile):
|
|||
assert body['is_admin'] is False # it's the non-admin session, not 999/admin
|
||||
finally:
|
||||
reset_background_profile(tok)
|
||||
|
||||
|
||||
# ── Part 2: the playlist SOURCE adapters read per-profile (sync handlers) ──────
|
||||
# bootstrap now passes get_*_client_for_profile as the source adapters'
|
||||
# client_getter; these prove that composition resolves per the current profile
|
||||
# context and stays on the global client for admin (the existing pipelines).
|
||||
|
||||
def test_spotify_source_adapter_resolves_per_profile():
|
||||
from core.playlists.sources.spotify import SpotifyPlaylistSource
|
||||
src = SpotifyPlaylistSource(web_server.get_spotify_client_for_profile)
|
||||
# admin / no override -> the global client (admin pipelines unchanged)
|
||||
assert src._client() is web_server.spotify_client
|
||||
# a background owner override flows through the resolver, re-resolved per
|
||||
# call (unconnected profile -> safe global fallback, never a frozen client)
|
||||
from core.profile_context import set_background_profile, reset_background_profile
|
||||
tok = set_background_profile(424242)
|
||||
try:
|
||||
assert src._client() is web_server.spotify_client
|
||||
finally:
|
||||
reset_background_profile(tok)
|
||||
|
||||
|
||||
def test_tidal_source_adapter_resolves_per_profile():
|
||||
from core.playlists.sources.tidal import TidalPlaylistSource
|
||||
src = TidalPlaylistSource(web_server.get_tidal_client_for_profile)
|
||||
assert src._client() is web_server.tidal_client # admin -> global, unchanged
|
||||
|
|
|
|||
|
|
@ -1138,8 +1138,14 @@ def _register_automation_handlers():
|
|||
return match_mb_tracks(tracks, _mb_match_deps)
|
||||
|
||||
_playlist_source_registry = build_playlist_source_registry(
|
||||
spotify_client_getter=lambda: spotify_client,
|
||||
tidal_client_getter=lambda: tidal_client,
|
||||
# Per-profile source reads: the adapter calls these fresh on every read,
|
||||
# so they resolve the CURRENT profile's account (their session
|
||||
# interactively, their automation's owner in the background — via
|
||||
# core.profile_context). Admin/profile 1 → the global client, so the
|
||||
# admin's existing auto-sync pipelines are unchanged. (Deezer/Qobuz stay
|
||||
# global for now — their playlist login is tangled with downloads.)
|
||||
spotify_client_getter=get_spotify_client_for_profile,
|
||||
tidal_client_getter=get_tidal_client_for_profile,
|
||||
qobuz_client_getter=_get_qobuz_client_for_sync,
|
||||
deezer_client_getter=_get_deezer_client,
|
||||
youtube_parser=parse_youtube_playlist,
|
||||
|
|
|
|||
Loading…
Reference in a new issue