0.6.2: Bypass sldl's Spotify client -- fetch the playlist ourselves, feed sldl a CSV
sldl's vendored Spotify client still calls GET /playlists/{id}/tracks, which
Spotify removed in its February 2026 API changes. Grandfathered apps still get
a pass; apps created after the change get a hard 403 there no matter how they
authenticate (client-credentials or a correctly-scoped OAuth user token), so
sldl can never load a playlist for a new app regardless of what we hand it.
Instead of depending on sldl's Spotify client at all, run-playlist.sh now reads
the playlist itself via the still-working /items endpoint (new
spotify-playlist-csv.py, creds sourced from _spotify.env) and invokes sldl with
the CSV + --input-type csv, which override the conf's input lines while -c still
supplies Soulseek login, paths, and quality settings (verified live). The same
CSV format upgrade-mp3-to-flac.sh already feeds sldl. All artists are
comma-joined in the CSV so multi-artist tracks search no worse than before, and
a 403/404 on the fetch prints the account-visibility hint instead of a bare
traceback.
Since sldl no longer talks to Spotify, playlist .confs no longer carry
spotify-id/spotify-secret/spotify-refresh: _template.conf drops them,
render_playlist_confs stops injecting them, and a Spotify credential save no
longer re-renders confs (only _spotify.env). The retag step in run-playlist.sh
reuses the sourced _spotify.env creds instead of scraping the conf lines that
no longer exist. Confs are also re-rendered once at app startup so
already-deployed confs converge on upgrade (and shed the stale secret lines)
without waiting for a playlist or credential change. Playlist delete now also
removes the generated .csv.
Tests updated: conf rendering must NOT contain Spotify creds but must keep the
input URL line; new coverage for _spotify.env rendering (quoting, refresh-token
presence/blank, 0600).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+20
-1
@@ -8,7 +8,7 @@ from fastapi.templating import Jinja2Templates
|
||||
from starlette.exceptions import HTTPException as StarletteHTTPException
|
||||
from starlette.middleware.sessions import SessionMiddleware
|
||||
|
||||
from app.db import enable_beets_db_wal, init_db, mark_interrupted_runs
|
||||
from app.db import SessionLocal, enable_beets_db_wal, init_db, mark_interrupted_runs
|
||||
from app.routers import artist_casing, auth, connect, credentials, dashboard, dedup, genres, health, import_, jobs, library, playlists
|
||||
from app.security.session import resolve_session_secret
|
||||
from app.services import scheduler_service
|
||||
@@ -48,12 +48,31 @@ def _warn_if_key_colocated_with_config() -> None:
|
||||
)
|
||||
|
||||
|
||||
def _render_confs_on_startup() -> None:
|
||||
"""Re-render every playlist .conf from the current template once per boot,
|
||||
so confs rendered by an older version converge on upgrade without waiting
|
||||
for a playlist or credential change. Concretely: 0.6.2 dropped the Spotify
|
||||
credential lines from confs (sldl no longer talks to Spotify), and this is
|
||||
what scrubs those secrets from already-deployed confs. Best-effort -- a
|
||||
render failure shouldn't stop the app from starting."""
|
||||
from app.services import credential_service
|
||||
|
||||
db = SessionLocal()
|
||||
try:
|
||||
credential_service.render_playlist_confs(db)
|
||||
except Exception:
|
||||
log.exception("Startup playlist .conf render failed; continuing")
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(_app: FastAPI):
|
||||
_warn_if_key_colocated_with_config()
|
||||
init_db()
|
||||
mark_interrupted_runs()
|
||||
enable_beets_db_wal()
|
||||
_render_confs_on_startup()
|
||||
|
||||
scheduler = scheduler_service.create_scheduler()
|
||||
scheduler_service.register_all_jobs(scheduler)
|
||||
|
||||
Reference in New Issue
Block a user