Andromeda: a public TV channel with a schedule and a chat
A livestream page for my media library. Anyone with the link can see what's on, what's next, and chat about it. The whole thing runs in one container.
ErsatzTV takes a media library and turns it into a TV channel. It picks what plays next and just keeps going, so there's always something on. I liked that a lot, and I wanted other people to be able to watch it with me. But a raw stream is missing two things you need for that: a schedule, so you know if it's worth sticking around, and a chat, so you can talk about what's on.
Andromeda adds both. When you open the page, the channel is already playing. Next to the player you can see what's on now and what's coming up, with the chat right under it.
Everything runs in one process
The whole app is one Node process on one origin:
/ the page
/api/chat/* chat, with a server-sent-events stream for live messages
/api/schedule the schedule, normalized
/iptv/* a reverse proxy to ErsatzTVHonestly, that layout is most of why I built this. The player, schedule, chat, and stream proxy all fit in one container, so deploying it is a single compose service, and if you want to know how requests get routed, you can just read one file.
The schedule comes from ErsatzTV's guide, and the server cleans it up before sending it to the browser. If you give it a Jellyfin key, it adds release years and air dates too. The IPTV proxy rewrites the playlist as it passes through, so the stream still works behind any public hostname, as long as PUBLIC_APP_ORIGIN is set.
The chat doesn't stick around
Accounts are just a nickname and a password. Messages max out at 500 characters, and the server only keeps the last 100. That's intentional. TV doesn't have scrollback, so I didn't think the chat next to it should either. There's also a small admin side for warning people, deleting messages, and banning.
The frontend is React, TypeScript, Vite, and Tailwind. The backend is a small Express app with SQLite and its own tests. I use Bun for development and Node 24 in production. It's been running for months now, and people I know drop in when something good is on the schedule.