A terminal-based YouTube subscription manager.
Three packages in a monorepo: api is a NestJS backend backed by PostgreSQL that fetches videos from YouTube RSS feeds. cli is a React Ink terminal UI compiled to a standalone binary. contracts holds the shared ts-rest API types used by both.
- Copy
packages/api/.env.exampletopackages/api/.envand setDATABASE_URL - Install dependencies:
bun install - Generate the Prisma client:
bun run --filter api generate - Start the API:
bun run --filter api dev
Requires a PostgreSQL database.
docker run \
-e DATABASE_URL="postgresql://user:pass@host/db" \
-p 3000:3000 \
ghcr.io/frankmarazita/subs:latestThe container runs migrations automatically on startup.
Download the subs binary from the latest CI artifact, or build it yourself:
bun run --filter cli build
# outputs: packages/cli/subsRun it:
./subsBy default it connects to the API at http://localhost:3000. Override via config (see below).
| Key | Action |
|---|---|
↑ / ↓ or j / k |
Navigate videos |
PgUp / PgDn |
Jump by page |
Enter / o |
Open in browser (marks as watched) |
v |
Open in built-in HTML viewer (marks as watched) |
w |
Toggle watch-later |
m |
Toggle watched/unwatched |
l |
Filter to watch-later only |
s |
Show QR code for current video |
r |
Refresh videos |
p |
Toggle thumbnail preview |
q / Esc |
Quit |
Config is stored at ~/.config/subs/config.json:
{
"userPreferences": {
"thumbnailPreview": true,
"autoRefresh": true
},
"apiUrl": "http://localhost:3000",
"viewerUrl": "http://localhost:3000/watch?v={videoId}"
}viewerUrl sets where the v key opens videos. The {videoId} placeholder is
replaced with the URL-encoded video ID, so any player or proxy path shape works.
When omitted, videos open at <apiUrl>/watch?v=<videoId>.
The CLI watches this file for live changes.
Via the API:
# Add a channel (any YouTube URL format)
curl -X POST http://localhost:3000/subscriptions \
-H "Content-Type: application/json" \
-d '{"url": "https://www.youtube.com/@channelname"}'
# Import from Google Takeout CSV
curl -X POST http://localhost:3000/subscriptions/import-csv \
-H "Content-Type: text/csv" \
--data-binary @subscriptions.csv
# Export to CSV
curl http://localhost:3000/subscriptions/export-csv