feat: cover-first radio — LLM album planner, source acquisition, Sources UI #2
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feature/radio-cover-first"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What
The autonomous radio becomes cover-first: instead of generating all-new music, most album tracks are now ACE
coverrenders of real popular songs, reimagined into one cohesive album genre.This branch also carries the groundwork it builds on: the Reimagine page (re-render a song/URL in a new style via ACE cover), ACE generation tuning, provider cleanup (Anthropic/ComfyUI removal, codex consolidation), raw oneshot, and the radio ops console polish.
Album composition (configurable via settings)
Per 12-track album: 8 covers + 1 brand-new + 1 cover-of-cover + 2 random fill, shuffled. Keys:
radioCoversPerAlbum,radioNewPerAlbum,radioCoverOfCoverPerAlbum,radioRandomFill,radioSearchRatio(0.75),radioSourceLibraryDir,radioCoverNoiseStrength.LLM album planner (
services/album-planner.ts)One
callLlmObjectcall designs the album (target genre/era/vibe, band name, title) plus 12 track specs: real popularsearchTargetsongs for covers, per-covervariation(genre / lyrics / both), full lyrics, captions, vocal casting.normalizeAlbumPlanTracksforces the LLM output back onto the requested slot plan. Planner failure → deterministic template fallback, so the radio never stalls.Source acquisition (
services/cover-source-service.ts)Priority per cover slot:
cover_sourcestable, atomic claim, genre-tag aware)Worker (
worker/song-worker.ts)sourceUrl(direct URL orytsearch…query) is resolved to a local file before taking an ACE audio slot — downloads parallelize across songs. Download failure demotes the track to text2music so albums always complete; persistence failures propagate normally.Downloader hardening (
external/youtube-audio.ts)--use-extractors "youtube.*,soundcloud.*,bandcamp.*"— kills the arbitrary-URL SSRF/redirect vector at the source (public-IP DNS pre-check kept as defense in depth)UI
New
/autoplayer/sourcespage: seed URLs (+optional genre tag), queue status (pending/used/failed), NAS dir status incl. scan errors, album mix + ratio + fidelity settings. Nav links on the radio home page.Data model
songs.source_url(additive, mirrored in schema/migrate/test-db/shared types)cover_sourcestableVerified live
Forced an album end-to-end: planner produced "Midnight Firmware Soul" (soft circuit neo soul) with 8 genre-cohesive covers (Sweet Dreams, No Scrubs, Toxic, Passionfruit, Blinding Lights, Running Up That Hill, Fast Car, Levitating); all reference audio downloaded via search through the extractor allowlist, cached, and queued into ACE cover tasks. Planner-failure fallback also observed live (albums complete without covers).
Testing
pnpm --filter @infinitune/server test); newcover-first-radio.test.tscovers track-mix composition, plan normalization, source-resolution priority, seeded-pool lifecycle, SSRF guard, search-target sanitation,createRadioAlbumplanner→fallback wiring, and demotion persistencepnpm typecheckand Biome clean (pre-existing warnings unchanged)Notes
POST /api/radio/sourcesis unauthenticated, matching the existing radio mutation surface (force-generate-album,feedback,requests)usedat claim time; if its song dies before the audio phase the row staysusedwith noresolvedAudioPath— reconciliation pass is a possible follow-upSomewhere a GPU is overheating so I don't have to think.
Node's Happy Eyeballs connection path calls the custom lookup with { all: true } and expects an array of LookupAddress objects; the old (err, address, family) reply left the address undefined and every pinned public-http request (inference.sh cover downloads) failed with ERR_INVALID_IP_ADDRESS. Answer the array form when all=true. Powered by human calories and mass GPU cycles.