## Daveo Radio Just a litle page on the intrawebs where I can broadcast and chat with friends. > **Note:** the password prompt is *not* authentication — it gates a modal and > nothing else. The socket connection and the Icecast stream are both reachable > without it. See "Auth" below before putting this anywhere public. --- #### Built With: - Icecast - https://icecast.org - Node - https://nodejs.org - Express - https://expressjs.com - Socket.io - https://socket.io - Redis - https://redis.io (optional) - Amplitude.js - https://github.com/serversideup/amplitudejs - Last.fm API - https://www.last.fm/api --- #### Running it Needs Node 20+. ```sh npm install cp .env.example .env # then edit npm run build # src/ -> app/ npm start ``` `npm run dev` rebuilds on change and reloads the server. Config is all environment variables (see `.env.example`) — there are no `config.js` / `config-dev.js` files anymore. Nothing renders until `npm run build` has run: Express serves `app/`, which is generated from `src/` and is not in git. #### Serving under davidawindham.com/radio Set `BASE_PATH=/radio` and `TRUST_PROXY=1`, then point nginx at it. `proxy_pass` deliberately has **no** trailing path, so the `/radio` prefix is passed through intact — the app expects to see it. ```nginx location = /radio { return 301 /radio/; } location /radio/ { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; # websockets proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } ``` Leave `BASE_PATH` empty to serve at a domain root instead; the client works out where it's mounted at runtime, so the same build covers both. #### Site chrome The header and footer come from the main site's shared web components — the same ones `/rtc` uses: ```html ``` `chrome.js` renders into a shadow root, so the site's styles stay sealed off from this page's Bootstrap 3 and the two can't collide. Nothing is copied into this repo — the chrome is maintained in the main site and can't drift out of sync here. That script tag is root-relative on purpose: in production Apache serves `/embed` from the docroot alongside `/radio`. Locally there's no Apache in front, so set `DAW_ORIGIN=http://daw.stu` and the app proxies `/embed` to it. **Leave `DAW_ORIGIN` unset in production.** #### Routes | Route | Purpose | |---|---| | `/` | the page | | `/health` | ok, room count, socket count | | `/api/status` | now-playing + listeners, proxied from Icecast | | `/api/lastfm` | sidebar data, proxied so the API key stays server-side | | `/api/broadcast` | POST `{msg}` — sends to every room | | `/other` | the modal's password check (not auth) | All are relative to `BASE_PATH`. #### Icecast The player streams from `$STREAM_URL` and gets now-playing from `$STREAM_STATUS_URL`. Both must be **https** — the page is served over TLS, so an `http://` stream is blocked as mixed content. Status is read from Icecast's stock `status-json.xsl` and proxied through `/api/status` rather than being fetched from the browser. The old code called a hand-customized `status2.xsl` over JSONP; Icecast upgrades overwrite those XSL files (see the 2021 note below — it 404s today). The stock endpoint survives upgrades, and proxying keeps the page same-origin. #### Redis Optional. Unset `REDIS_URL` and it runs single-process, keeping per-connection state in memory. Set it and socket.io uses the Redis adapter so rooms and presence work across multiple processes. #### Auth There isn't any, despite appearances. `ROOM_PASSWORD` is checked client-side via the modal's `data-remote` hook; passing it just closes the modal. `/api/broadcast` is unauthenticated, the socket handshake is unauthenticated, and the Icecast stream can be opened directly. Doing this properly means a server-verified session that covers the socket handshake and the stream, not only the page. --- #### Notes: - Feb 2016 - built and published @ http://radio.davidawindham.com - stream running from http://stream.davidawindham.com (8008) - 2021 - Icecast updated overwrote Icecast XML files - see: https://davidawindham.com/til/docs/host/Icecast - May 2022 - Migrate to new server, reinstall Icecast, add SSL to stream, updated packages, and secure Redis. - Jul 2026 - Modernized. Server rewritten on Express 5 / socket.io 4; gulp (dead on Node 12+) replaced with esbuild; config moved to env vars; stream status proxied server-side over https; mountable under a subpath. - Jul 2026 - Trimmed for the davidawindham.com/radio rebuild. Dropped the Facebook comments tab (third-party JS for a widget on the long-dead Graph v2.5) and the Call/Video tabs (WebRTC sample code with no signaling — it could only call itself). Last.fm moved behind a server-side proxy so the key no longer ships to the browser.