Skip to content

Play your own SiriusXM here: the radio rail beside the playlist one - #22

Merged
ralyodio merged 1 commit into
mainfrom
siriusxm
Sep 3, 2026
Merged

ralyodio merged 1 commit into
mainfrom
siriusxm

Conversation

@ralyodio

@ralyodio ralyodio commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

A reader connects their SiriusXM subscription in Settings → SiriusXM — the email on the account and the code SiriusXM emails them, the way its own app signs in; no password — and the sports and news lineups play on /radio (tabs, search, quality) and, looked up on request, in an On SiriusXM section on a fixture's page. Ported from media-streamer's radio rail; runs on Bun's fetch with a per-reader residential proxy instead of undici's dispatcher.

What leaves the server: nothing. The session is sealed with the playlist key (siriusxm_sessions, migration 0030). Tune URLs are minted server-side and held for their own lifetime; manifests are rewritten to root-relative /radio/proxy addresses; the AES key is decoded from SiriusXM's JSON into the sixteen bytes a player wants; and concurrent requests for one URL reach SiriusXM once (sharedFetch), which is what keeps two tabs from looking like two listeners on one subscription. The proxy checks the host before it fetches, so a bearer is never sent anywhere a reader chose. The browser never sees a siriusxm.com address.

The player is the house one. @profullstack/player 0.6.0 with its compact audio bar and hls.js engine — the audio: true option that lets an .m3u8 draw as audio rather than as a black 16:9 stage landed there as profullstack/player#7. Bundled as vendor-player.js (+ its stylesheet) with only hls.js's light build inside (400KB, 127KB gzipped — the first build was 900KB because the demuxer came along), fetched on the first press of Play. Verified in headless Chrome: the bar draws on an <audio>, LIVE badge on, and Stop tears it down. One stream per reader, across TV and radio: the teardown chains into __tipoffStopPlayer.

Knobs (README): SIRIUSXM (on by default for the tipoffwatch brand, off for genrewatch), SIRIUSXM_PROXY_URL (falls back to SPORTS_PROXY_URL), SIRIUSXM_PROXIES (a pool to pin each reader to one exit — SXM ties a session to the IP that authenticated it), SIRIUSXM_DEVICE_GRANT (the rare bootstrap token; the sign-in is tried without it first, and there is no puppeteer here).

Not verified against SiriusXM itself: this box has no SiriusXM account to sign in with, so the protocol layer is covered by a fake gateway that answers the way media-streamer observed the real one to, step by step. First production sign-in is the real test; the failure messages name what SXM said.

Tests: 8 new files (protocol against a fake gateway, HLS rewriting, key decoding, the upstream cache, pending sign-ins, config, views, route shape, schema). CSP gains blob: on worker-src for hls.js's demuxing worker.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Ac4GWmd6Nfd8JReX9u7kH1

A reader connects their SiriusXM subscription in settings -- the email on the
account and the code SiriusXM sends to it, the way its own app signs in -- and
the sports and news lineups play on /radio and, looked up on request, on a
fixture's page. Ported from media-streamer's radio rail; runs on Bun's fetch
with a per-reader residential proxy instead of undici.

The session is sealed with the playlist key and every byte is fetched by the
server as that reader: tune URLs are minted here, manifests are rewritten to
root-relative /radio/proxy addresses, the AES key is decoded from SiriusXM's
JSON into bytes, and concurrent requests for one URL reach SiriusXM once. The
browser never sees a siriusxm.com address or a bearer.

The player is @profullstack/player 0.6.0 with its audio bar (the option that
makes an HLS station draw as audio landed there as #7), bundled as
vendor-player.js with only the light HLS engine inside and fetched on the first
press of Play. One stream per reader, across TV and radio alike.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ac4GWmd6Nfd8JReX9u7kH1
@socket-security

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatednpm/​@​profullstack/​player@​0.5.0 ⏵ 0.6.078 +1100100 +193 +1100

View full report

@ralyodio
ralyodio merged commit dfb4c78 into main Sep 3, 2026
2 checks passed
@ralyodio
ralyodio deleted the siriusxm branch September 3, 2026 23:53
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