Skip to content

Add multi-provider album art and harden Spotify auth/polling - #1

Open
crithitstudio wants to merge 2 commits into
tnarla:mainfrom
crithitstudio:crithitstudio-fix-repo-audit-issues
Open

Add multi-provider album art and harden Spotify auth/polling#1
crithitstudio wants to merge 2 commits into
tnarla:mainfrom
crithitstudio:crithitstudio-fix-repo-audit-issues

Conversation

@crithitstudio

@crithitstudio crithitstudio commented Jun 26, 2026

Copy link
Copy Markdown

Summary

Two related improvements to the now-playing matrix:

  1. Reliability/security hardening of the Spotify polling and OAuth token cache.
  2. Multi-provider support — abstract playback behind a single PlaybackProvider interface so the matrix can be driven by more than just Spotify.

Providers

  • spotify (default) — live currently-playing via the Spotify Web API. Exact and real-time.
  • lastfm — universal best-effort provider. Reads the Last.fm "now scrobbling" track, so any service that scrobbles (Spotify, Apple Music, Tidal, Deezer, YouTube Music, …) can drive the display from one free, headless, cloud-pollable endpoint.
  • youtube-music — most-recent history via ytmusicapi (unofficial, best-effort).

Why no Apple Music provider

A direct Apple Music provider isn't feasible for a hands-off, headless wall display:

  1. No live now-playing endpoint — the Apple Music cloud API exposes catalog, library, and recently played, but no "currently playing." Real-time state lives only in MusicKit on the device that's actually playing, which a remote Pi can't query.
  2. Paid credentials — even recently-played needs a developer token signed with a MusicKit .p8 key, which requires a paid Apple Developer Program membership (~$99/€99/yr).

Workaround (documented): scrobble Apple Music to Last.fm and run --provider lastfm.

Changes

Hardening

  • Replace recursive 401 retry with a bounded retry flow.
  • Handle 429 rate limits without clearing current playback art state.
  • Add OAuth callback timeout via --auth-timeout-seconds.
  • Save token cache atomically and enforce stricter cache permissions.
  • Recover from corrupt token cache JSON by moving it aside and re-authorizing.
  • Cache album-art disk prep work to reduce per-frame rendering overhead.

Multi-provider

  • New PlaybackProvider protocol; SpotifyClient, LastFmClient, YouTubeMusicClient implement get_playback_art().
  • Generalized poller (poll_provider) and rate-limit error (ProviderRateLimitError) across providers.
  • New --provider {spotify,youtube-music,lastfm} flag and per-provider env/config (LASTFM_API_KEY, LASTFM_USER, YTMUSIC_AUTH_HEADERS_PATH).
  • Last.fm only spins on a live nowplaying scrobble; historical scrobbles render idle (no stale art).
  • README: setup per provider + a "Music provider support" section documenting feasibility (incl. Tidal/Deezer → use Last.fm). .env.example updated; Apple Music env vars removed.

Verification

  • python -m py_compile spotify_matrix.py passes.
  • python spotify_matrix.py --preview-frames /tmp/spotify-matrix-preview renders sample frames.
  • LastFmClient parsing unit-tested against now-playing, historical-only, empty, bad-key, and single-object payloads.
  • Missing-credential runs exit cleanly with a clear message.
  • Not yet run against the live Last.fm API (needs a real API key).

Improve robustness for auth callback timeouts, token cache handling, rate limiting behavior, and rendering performance.

- Bound currently-playing retry flow on 401 responses
- Preserve playback state on 429 rate limits
- Add configurable OAuth callback timeout
- Save token cache atomically with stricter permissions
- Recover from corrupt token cache files
- Cache album-art disk prep work across frames
- Document live smoke-test commands in README
Abstract playback behind a PlaybackProvider protocol and support
multiple sources for the spinning album art:

- Spotify (default): live currently-playing via the Web API.
- Last.fm: universal best-effort provider that reads the "now
  scrobbling" track, so any service that scrobbles (Spotify, Apple
  Music, Tidal, Deezer, ...) can drive the display from one free,
  headless, cloud-pollable endpoint.
- YouTube Music: most-recent history via ytmusicapi.

Apple Music has no native provider: its cloud API exposes no live
now-playing endpoint and its credentials require a paid Apple
Developer Program membership, neither of which fits a headless wall
display. Documented this (and the Last.fm scrobble workaround) in the
README provider-support section.

Generalize the poller and rate-limit error across providers and add
--provider plus the matching env/config for each.
@crithitstudio
crithitstudio force-pushed the crithitstudio-fix-repo-audit-issues branch from ae0f9d4 to 6253dd4 Compare June 26, 2026 20:49
@crithitstudio crithitstudio changed the title Harden Spotify auth, polling, and token cache behavior Add multi-provider album art (Last.fm, YouTube Music) + auth/polling hardening Jun 26, 2026
@crithitstudio crithitstudio changed the title Add multi-provider album art (Last.fm, YouTube Music) + auth/polling hardening Add multi-provider album art and harden Spotify auth/polling Jun 26, 2026
@tnarla

tnarla commented Jun 29, 2026

Copy link
Copy Markdown
Owner

Oh nice!!! I'll take a look at this this week :)!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants