Skip to content

feat(play): queue YouTube radio links and start playback faster - #10

Merged
Nxssie merged 3 commits into
fix/queue-reset-on-leavefrom
feat/youtube-radio-fast-start
Oct 18, 2026
Merged

Nxssie merged 3 commits into
fix/queue-reset-on-leavefrom
feat/youtube-radio-fast-start

Conversation

@Nxssie

@Nxssie Nxssie commented Oct 18, 2026

Copy link
Copy Markdown
Owner

Summary

  • A YouTube radio ("Mix") link (watch?v=…&list=RD…) now queues the radio's first 25 songs as a playlist. Before, the v= parameter made it play only the seed video.
  • /play no longer runs two full yt-dlp extractions back to back. Resolution extracts once (yt-dlp -J), caches the info JSON in memory, and the stream starts from it through --load-info-json -. Measured first audio byte: 0.67 s cached vs 4.99 s fresh.

Changes

File Change
packages/server/src/lib/youtube.ts isRadioUrl and RADIO_TRACK_LIMIT = 25
packages/server/src/lib/infoCache.ts Bounded TTL cache of yt-dlp info JSON (10 min, 20 entries), consumed once per stream
packages/server/src/index.ts Radios take the playlist path with --playlist-end 25; getVideoInfo extracts with -J and caches; createAudioStream streams from the cache and falls back to a fresh extraction
README.md Lists radio links among the supported inputs
odd/tasks/youtube-radio-fast-start.md Feature document with specs, measurements and evidence

Design notes

  • Why 25 songs: a radio is endless. Unlimited, yt-dlp returned 360 songs in 15.4 s; capped at 25 it resolves in ~1.3–1.8 s.
  • Why the cache is safe: the 10-minute TTL is far below the ~6 h lifetime of YouTube's signed media URLs, so a cached entry never streams from an expired URL. A missing, expired or already-used entry falls back to today's extraction.
  • Memory bound: info JSON measured 86–660 KB per video, so 20 entries cap the cache at ~13 MB.
  • watch?v=X&list=PL… still plays the single video; playlist?list=RD… is rejected by YouTube ("This playlist type is unviewable"), so only the watch form counts as a radio.

Test plan

  • bun test: 84 pass, 0 fail (new isRadioUrl and infoCache cases)
  • bun build src/index.ts --target bun: exit 0
  • Live yt-dlp: radio with --playlist-end 25 → 25 entries in 1.8 s; first audio byte 0.67 s cached vs 4.99 s fresh
  • Live Discord smoke test (no interaction harness in this repo): /play with a single YouTube link, /play with a radio link

Known limitations

  • The first song of a YouTube playlist or radio still extracts while starting: those entries arrivewith a title, so they skip the cached resolution. Prefetching the next song during playback would
    cover them and the gap between songs.
  • A generic HLS/DASH stream with no audio-only format now shows its URL as the title; such streams
    already failed to play with the same format selector.

Stacked on fix/queue-reset-on-leave; merge that one first.

@Nxssie
Nxssie merged commit c1df390 into fix/queue-reset-on-leave Oct 18, 2026
2 checks passed
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.

1 participant