Topic pages (#ai, #music, #tech, #science) that show only new uploads from channels I trust. The low-effort stuff is left out by construction: it can't show up if it never came from a channel I picked.
How it works
channels.jsonis the catalog: topics, the allowlist, a blacklist and the searches used to find new candidates.- A build step fetches each allowed channel's public RSS feed on the server (no CORS, no API quota) and bakes it into one JSON file the page reads. It runs every 30 minutes.
- Explore shows videos from channels I haven't ruled on yet. Judging one video rules on its whole channel, which is how the catalog grows. It refreshes six times a day.
- A Google Takeout import seeds the allowlist from my subscriptions, keeping only channels that actually post long-form. After that, a job checks my YouTube subscriptions twice a day and files any new channel under a
substag, so subscribing on YouTube is enough to add a channel here. - Tags belong to the channel, not the video, and a channel can carry several. I retag from a menu on any card.
Interesting problems
- Shorts have no marker in RSS. The build probes
youtube.com/shorts/<id>: a real Short answers 200, a normal video redirects. The probes run concurrently, about 8 seconds for 180 videos. - Live streams appear twice. A scheduled stream leaves an unwatchable placeholder in the feed for days. The build asks each video what it is (scheduled, live, ended, ordinary) and drops placeholders, which also removes the duplicates. Settled answers are cached, so a rebuild only pays for new videos.
- Videos open on YouTube in a new tab rather than in an embedded player. It sidesteps the embed's cross-origin limits and keeps the app small.
- A quota budget. RSS is the default source and costs nothing. The YouTube Data API is the fallback, and its daily quota is shared by the feed build and Explore. Only one Explore run a day may spend any, so the feed build always has what it needs. A run that finds nothing leaves the last good results in place.
- The catalog has more than one writer. The page's server and the feed build both edit one JSON file. Every write takes the same file lock, the build merges only what it learned into the current file, and its write is atomic.
This was the first version of the video room that now lives inside home.