Albumize

Spotify's Discover Weekly and Release Radar are great at finding artists and terrible at how I actually listen: full albums, not algorithmic singles. Years ago I built a small web app that expanded a playlist into the albums behind its tracks. It worked, but it had three problems I could never fix as a website: expansion was manual (I wanted Discover Weekly albumized every Monday without thinking about it), the ignored-keywords list lived in localStorage behind a modal that discarded edits if you pressed Esc, and… it was a website. No tray, no autostart, no log of what happened while I wasn't looking.

Albumize is the rebuild as a proper desktop app: Tauri 2, the whole Spotify engine in Rust so scheduling, token refresh and keyring access run headless with no window open, and a thin React frontend that just renders events. Built in the same agentic setup as Switchboard — the scaffold-to-working-app sprint took two days, and a good chunk of the UI (User Interface) was ported straight from Switchboard's components.

Idempotency without a database

The design I'm happiest with is also the simplest: the playlist name is the idempotency key. An automation renders a target name like ALB-202634-Discover Weekly — prefix, date, source playlist — and "has this week's run already happened?" is answered by checking whether that exact name exists. No server, no state file, nothing to back up. The scheduler, manual runs, and the "albumized" badge in the UI (User Interface) all call the same Rust function to render and match names.

That simplicity had to survive three silent failure modes, all found and fixed the hard way:

  1. The partial-playlist hole. If the app died mid-run, the half-filled playlist already carried the final name — so next week's check said "done" and skipped it. Fix: create as [albumizing] work name, add all tracks, rename last. A crash can now never produce a playlist that counts.
  2. The year-boundary collision. The original default date format was YYYYWW — calendar year + ISO (International Organization for Standardization) week. December 29th, 2025 is ISO (International Organization for Standardization) week 1, so it renders 202501… the same as January. The last week of every year silently matched the first. The default is now GGGGWWISO (International Organization for Standardization) week-year — which is collision-free by construction.
  3. The consumed occurrence. A failed run at boot (locked keyring, network down) used to burn the week's slot. Now there's a pre-flight check that defers instead of failing, and catch-up after sleep is bounded to the current period so a laptop that was off for three weeks doesn't replay them.

The date tokenizer behind all this is a longest-match parser over moment.js-style formats, implemented twice: Rust for the real thing, TypeScript for live preview in the settings UI (User Interface). Both consume the same JSON (JavaScript Object Notation) test-vector filecargo test via include_str!, Vitest directly — so the mirror can't drift without a red build.

Assorted scar tissue

Spotify requires PKCE (Proof Key for Code Exchange) loopback on 127.0.0.1 with an exact port — and a fixed port on Linux turns out to be contested territory: if it sits in the ephemeral range, any process's outbound connection can randomly grab it as a source port. The engine also deliberately avoids fetching albums with an unbounded Promise.all-style fan-out; a bounded-concurrency queue keeps the thundering herd away from the rate limiter (token bucket, 10 req/s, honoring Retry-After on 429s).

On macOS, an unsigned app pays one keychain password prompt per stored item — so there all secrets live in a single keychain item as a JSON (JavaScript Object Notation) vault. Windows would happily do the same, except Credential Manager caps blobs at 2560 bytes, so it keeps per-key entries. Cross-platform parity is a policy, not a property.

And one honest lesson from working with agents and secrets: the updater's private signing key once leaked into a chat paste. Nothing had been released under that key, so rotation was free — but only because the leak was noticed before the first release. Treat signing keys like they will eventually end up in a transcript, because one did.

Status

Functionally complete and in personal use: PKCE (Proof Key for Code Exchange) auth, the expand engine, flexible schedules (daily/weekly/monthly with weekday sets), config export/import with rollback, self-updater, telemetry opt-out — all shipped. The remaining milestone is end-to-end verification against a real Spotify account. Repository: gitlab.com/KirboDev/agentic-coding/albumize.