nixamp 0.9: a server that names itself, and a CNN feed that stopped talking
A day of nixamp releases, 0.7.36 through 0.9.3. It started with a bug report ("I see CNN but get no audio or video, and the graph is moving") and ended with servers that get their own DNS name and certificate without anyone touching a registrar.
The frozen channel
CNN had been on the air for twelve hours and showed nobody anything. The graph moved because it was the server's own player mirrored over SSE, not the channel. On the box, the ffmpeg was alive, its byte count frozen, and its stderr socket had 131 KB queued that nothing had ever read. Node only reads a piped stream that is flowing. An IPTV transport stream logs a line for every corrupt packet, the 64 KB pipe filled, and ffmpeg blocked on its next write with every thread waiting on the one that was stuck. It never exited, so nothing redialled.
Every ffmpeg a channel spawns now has its stderr drained. Remote pulls get a read timeout and a watchdog, and a redial resets the stream header instead of appending a second one mid-picture.
Then the channel "looped." A late joiner was handed only future bytes, so it started on the live edge with nothing buffered and stalled on every hiccup. A newcomer now gets the last six seconds first, from a fragment boundary. Measured in Chrome: six stalls in thirty seconds before, zero after.
Catalogs
An m3u with three thousand IPTV entries used to become three thousand flat rows in the playlist. A server now keeps named catalogs, reads group-title and logos, and sorts entries into live and on demand. Anyone with the link browses by group and plays. A live entry becomes a channel started on the first click and stopped a minute after the last viewer leaves, capped at four at once.
Names and certificates
server2 came up as http://152.53.47.37:4321. The only reason server1 had a name was that someone typed an A record into Porkbun and copied a wildcard certificate onto the box by hand.
Now a signed-in server asks nixamp.com for a name and gets label.handle.nixamp.com with A and AAAA records, written with keys only nixamp.com holds. It asks for the handle's certificate and gets one Let's Encrypt wildcard per handle, issued by DNS-01 and renewed on nixamp.com, cached on the box and swapped into the running listener once a day. The API is account-gated and metered with @profullstack/throttle. nixamp dns manages names by hand, and it is 2026, so v6 is not an afterthought.
The one that mattered most
A daemon restarted from a home directory served the home directory, under a public listing. That default is gone. The library is a saved setting, asked for at sign-in or first start, and the whole filesystem, the home directory, anything above it, and anything under a hidden folder in home are refused however they are asked for.
Smaller things
The installer restarts a running daemon with its saved flags, and pulled channels survive a restart. The directory shows what is on each server and offers Viewer and Admin, with Admin greyed unless the server is yours. Favourites are a heart. The tab says what is playing.
Install: curl -fsSL https://nixamp.com/install.sh | sh, then nixamp login, nixamp library ~/Music, nixamp daemon start.
Drafted with Claude Code from the session that did the work.
Top comments (1)
The frozen ffmpeg via an unread stderr pipe is a classic I've hit too — Node only drains a piped stream that's flowing, so a chatty child process fills the 64 KB buffer and blocks on write while every thread waits on the one stuck on the socket. A child that looks alive but never exits until you read its stderr is exactly the failure that gets misdiagnosed as an upstream outage. Draining stderr and adding a watchdog is the right fix.
One thing I'd push on: the six-seconds-of-buffer-on-join trade-off. You trade startup latency for stall avoidance on the live edge, but if a viewer seeks immediately after joining, the initial buffer doesn't cover the jump and you're likely back to a stall. Did you measure seeks-just-after-join separately, or does the redial path reset the buffer to handle it?