FeedrStream is a lightweight, locally hosted (Docker) YouTube subscription manager and player. It fetches channel updates via RSS feeds and plays videos directly using yt-dlp without pre-downloading them to disk.
- Cinema Mode: Distraction-free viewing experience without algorithms
- RSS Sync: Automatic background fetching of new videos (every 15 min)
- Video Proxy: Stream directly via backend
yt-dlpproxy (no ads, no tracking) - Subscription Management: Import subscriptions from Google Takeout
- HLS HEVC Transcoding: On-the-fly transcoding for Apple devices (iOS, Apple TV)
- M3U Playlist:
/api/m3uendpoint for Infuse, VLC, and other IPTV players - Copy Stream URL: Copy a direct stream URL for any video from the player page
- Health Monitoring:
/api/healthendpoint with yt-dlp status tracking - Resilient Streaming: Retry + format fallback when YouTube changes APIs
- Mobile-friendly UI: Responsive layout across all pages
Three Docker Compose services:
| Service | Description |
|---|---|
app |
FastAPI backend + Vite SPA + FFmpeg transcoding |
cron |
Scheduled video sync (15 min) + yt-dlp updates (daily 03:00) |
player |
yt-dlp web player (matszwe02/ytdlp_web_player) |
This project heavily utilizes the excellent yt-dlp-web-player by Matszwe02 for its core video playback capabilities.
FeedrStream packages ytdlp_web_player as an independent Docker service and embeds its UI for playback. Due to this integration and in accordance with copyleft principles, FeedrStream is also licensed under the GNU General Public License v2.0 (GPL-2.0).
Requirements: Docker and Docker Compose.
-
Clone the repository and start via Docker Compose:
git clone https://github.com/jessepesse/FeedrStream.git cd FeedrStream docker compose up -d -
Open
http://localhost:8000
Security note: FeedrStream has no built-in authentication. It is intended for use on a local network or behind a VPN (e.g. Tailscale). Do not expose port 8000 directly to the internet without adding authentication (e.g. a reverse proxy with Basic Auth or Authelia).
All data is stored in the ./data directory (mounted as a Docker volume). To back up your subscriptions and watch history, back up this folder. To reset FeedrStream, delete ./data/feedrstream.db.
Environment variables (set in docker-compose.yml):
| Variable | Default | Description |
|---|---|---|
DATABASE_PATH |
/app/data/feedrstream.db |
SQLite database path |
PLAYER_URL |
http://player:5000 |
yt-dlp web player URL |
CLEANUP_WATCHED_DAYS |
3 |
Days before watched videos are removed |
CLEANUP_OLD_DAYS |
90 |
Days before old unwatched videos are removed |
SYNC_WINDOW_DAYS |
14 |
How many days back to sync from RSS feeds |
FEEDRSTREAM_BASE_URL |
(request host) | Base URL used in M3U stream entries (e.g. http://192.168.1.10:8000) |
Go to /channels and add channels in any of these formats:
- YouTube handle:
@veritasium - Full URL:
https://www.youtube.com/@veritasium - Channel ID:
UCHnyfMqiRRG1u-2MsSQLbXA
The channel name is resolved automatically when using a handle or URL.
- Download YouTube subscriptions from Google Takeout (
subscriptions.csvorsubscriptions.json) - Go to
/channelspage - Upload the file using the form
Videos sync automatically every 15 minutes. You can also trigger a sync manually:
- Click the Sync button on the Videos page
- Or via API:
curl -X POST http://localhost:8000/api/videos/sync
Point your IPTV player to:
http://<your-host>:8000/api/m3u
Optional filters:
?channel_id=UCxxxxxxx— limit to one channel?days=7— limit to videos published in the last N days
Tip: If accessing from another device (e.g. Apple TV), set
FEEDRSTREAM_BASE_URL=http://192.168.x.x:8000indocker-compose.ymlso the stream URLs in the playlist point to the correct host. Alternatively, just open the web UI via your IP address — the Copy Stream URL button in the player will automatically use the right host.
| Endpoint | Description |
|---|---|
GET /api/health |
System health + yt-dlp status |
GET /api/errors |
Recent errors for monitoring |
GET /api/channels |
List subscribed channels |
POST /api/channels |
Add a channel (ID, @handle, or URL) |
DELETE /api/channels/{id} |
Remove a channel |
GET /api/videos |
List videos (pagination, filters) |
POST /api/videos/sync |
Trigger video sync |
GET /api/stream?v=ID |
Resolve video stream |
GET /api/stream/mp4?v=ID |
Universal MP4 stream (remuxed) |
GET /api/m3u |
M3U playlist for IPTV players |
Requirements: Node.js 20+, Python 3.11+, Docker.
# Build Docker images locally
docker compose up -d --build
# Run natively (without Docker)
npm install
pip install -r backend/requirements.txt
# Run backend dev server (port 8000)
uvicorn backend.main:app --reload --port 8000
# Run frontend dev server (port 3000, proxies /api to 8000)
npm run dev
# Run backend tests
PYTHONPATH=. pytest backend/tests/ -v- Please see CONTRIBUTING.md for details on our code of conduct, and the process for submitting pull requests.
- For security vulnerabilities, please refer to SECURITY.md.