Skip to content

feat: Spotify Canvas plugin — automatic per-track sourcing (slice 2 of #442) #473

Description

@InstaZDLL

Goal

Follow-up to #442 (slice 2). The manual-mp4 per-track Canvas shipped in #467 (core-only). This issue tracks the automatic sourcing path: a plugin that resolves the current track to a directly-playable loop and hands it to the existing Canvas pipeline — no manual drop.

A viable source exists: Spotify Canvas

Spotify serves Canvas clips as directly-playable mp4 from its CDN (https://canvaz.scdn.co/.../<hash>.cnvs.mp4) — no HLS, so it plays in the desktop webview via <video src> exactly like the manual Canvas and the Apple Motion Artwork overlay.

Resolution flow (reference: two local GPL-3.0 projects — a Python original and a clean Rust rewrite, spotify-canvas-downloader-rs v0.2.0, GET /api/canvas/{track_id}{canvas_url}):

  1. A Spotify track ID (22 chars) is turned into an access token derived from a logged-in session's sp_dc cookie (TOTP token dance — totp-rs).
  2. The private Canvas API (spclient.wg.spotify.com/canvaz-cache/) returns a protobuf pointing at the .cnvs.mp4 on canvaz.scdn.co.
  3. The core loops the mp4 through the existing CanvasStage / MotionCoverOverlay plumbing — slice 1 already proves the rendering works.

Why this stays a separate, non-signed plugin repo (not the core)

Same line #442 drew for YouTube. Spotify does not publish a Canvas API; this relies on private endpoints, and the token endpoint's own terms state its use is not permitted under Spotify's Developer Terms/Policy (quoted verbatim in the RS project's README). So:

  • Never in the signed core. Grey-area sourcing lives in its own plugin repo (liability isolation), exactly like the YT-plugin carve-out in feat: track Canvas — looping clip behind the now-playing view #442. The core only ever loops an mp4 URL a plugin returns.
  • License is fine (both reference projects are GPL-3.0-only, matching WaveFlow) — the constraint is Spotify's ToS, not code licensing.

Open problems (all real, none blocking-forever)

  1. Per-user sp_dc cookie. Only works for users with a Spotify account willing to paste their cookie; it's their account carrying the risk. Needs a plugin-options field + clear consent copy.
  2. Local track → Spotify track ID matching. Local files have no Spotify ID; the plugin must search by artist+title (or ISRC when present) first, then fetch the Canvas. Fuzzy, may mismatch.
  3. Private API fragility. Can break without notice; the plugin must fail soft (fall back to motion cover → slideshow → static cover, the existing precedence).

Prerequisites (blocked)

  • feat: Release Radar plugin + waveflow:ui/v1 plugin UI surface #443's plugin.wasm CI-rebuild prerequisite — same brick every plugin slice waits on.
  • Metadata world extended to per-track Canvas (the current motion field is album-keyed).
  • Authenticated HTTP + protobuf decode reachable from the plugin host — verify waveflow:host/* can carry the sp_dc token flow, or extend it.

Related

Metadata

Metadata

Assignees

Labels

scope: pluginsPlugin runtime, SDK, store, and bundled pluginstype: featNew feature

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions