UnTube β Self-Hosted YouTube Channel Downloader & Viewer
π For Local Network Use Only
This application is not designed or intended to be run on a public-facing URL. There is no authentication, no user management, and no security hardening. Run it exclusively on your local network or behind a VPN. Do not expose it to the internet.
β οΈ Disclaimer
This project was built entirely through AI prompting using Claude β no manual code was written by the author. AI can and does make mistakes, and this application is not perfect. Bugs should be expected.
The author does not take any credit for the features and technologies that make UnTube function β all credit goes to the open-source projects this app is built on: yt-dlp, Flask, React, and others.
You are free to modify, improve, and adapt this project in any way you like. Use at your own risk.
A Docker-based web application that lets you follow YouTube channels, automatically download their videos, and watch them in a clean, ad-free interface β all on your own hardware.

Features
- Channel Management β Add channels by URL,
@handle, or channel ID - Auto Downloads β Background scheduler polls for new videos at a configurable interval
- Quality Control β Per-channel quality overrides (360p to 4K or best available)
- Skip Shorts β Optionally skip YouTube Shorts (videos under 60 seconds)
- Auto-Delete β Automatically remove videos older than X days (global or per-channel)
- Built-in Player β HTML5 video player with HLS/transcoded stream support and CC subtitles
- Feed View β All videos sorted by newest first, filterable by channel
- Push Notifications β Optional Apprise-based notifications on new downloads
- Mobile-Friendly β Responsive layout optimised for phone/tablet use
- Persistent Storage β Everything saved to local Docker volumes
Quick Start
Prerequisites
- Docker and Docker Compose
Option 1 β Pull from Docker Hub (fastest)
docker pull tomfriart/untube:latest
Then create a docker-compose.yml:
services:
untube:
image: tomfriart/untube:latest
container_name: untube
ports:
- "3987:80"
volumes:
- ./data:/app/data
- ./downloads:/app/downloads
restart: unless-stopped
docker compose up -d
# Open in your browser
open http://localhost:3987
Option 2 β Build from source
git clone https://github.com/tomfriart/untube.git
cd untube
docker compose up -d --build
# Open in your browser
open http://localhost:3987
Stop
docker compose down
Architecture
UnTube runs as a single Docker container combining the frontend and backend, managed by supervisord.
untube/
βββ Dockerfile # Single image: React build β Python + nginx + supervisord
βββ nginx.conf # Serves frontend, proxies /api/* to Flask on localhost:5000
βββ supervisord.conf # Runs Flask + nginx together in one container
βββ docker-compose.yml
βββ backend/
β βββ requirements.txt
β βββ app.py # Flask API + yt-dlp + APScheduler
βββ frontend/
β βββ package.json
β βββ vite.config.js
β βββ index.html
β βββ src/
β βββ main.jsx
β βββ App.jsx
β βββ icons.jsx
β βββ styles.js
β βββ utils.js
β βββ components/
βββ data/ # Auto-created: SQLite database + thumb cache
βββ downloads/ # Auto-created: downloaded video files
βββ ChannelName1/
β βββ videoId1.mp4
β βββ videoId2.mp4
βββ ChannelName2/
βββ videoId3.mp4
Configuration
All settings are adjustable from the Settings panel in the UI:
| Setting | Default | Description |
|---|---|---|
| Quality | 720p | Video download resolution (360pβ4K or best) |
| Skip Shorts | On | Don't download videos under 60 seconds |
| Check Interval | 180 min | How often to poll channels for new uploads |
| Auto-Delete | Off | Remove videos older than N days |
| Notifications | Off | Apprise URL for push notifications on new downloads |
Per-channel overrides for quality and auto-delete are available from each channel's settings.
Custom Downloads Path
By default videos are saved to ./downloads/ next to the docker-compose.yml. To point at an existing media library, edit the backend volume in docker-compose.yml:
volumes:
- /your/media/path:/app/downloads
API Endpoints
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/channels |
List all followed channels |
| POST | /api/channels |
Add a channel { url: "..." } |
| DELETE | /api/channels/:id |
Remove a channel + its videos |
| GET | /api/videos |
List all videos (newest first) |
| GET | /api/videos?channel_id=X |
Filter by channel |
| GET | /api/settings |
Get current settings |
| PUT | /api/settings |
Update settings |
| POST | /api/check-now |
Trigger immediate check |
| GET | /media/:filepath |
Serve a downloaded video file |
| GET | /api/stream/:video_id |
HLS transcode stream |
Troubleshooting
- Videos not downloading? Check logs:
docker compose logs untube - yt-dlp errors? YouTube frequently changes its internals, which breaks yt-dlp. This is the most common source of issues and is outside this project's control. When it happens, rebuild the image to get the latest yt-dlp:
docker compose build --no-cache(ordocker pull tomfriart/untube:latestif using Docker Hub). Expect this to be needed every few weeks. - Disk space? Monitor
./downloads/β higher quality = bigger files; enable auto-delete in Settings
Tech Stack
- Backend β Python, Flask, yt-dlp, APScheduler, SQLite
- Frontend β React 18, Vite, hls.js
- Serving β nginx (reverse proxy + static files)
- Packaging β Docker Compose
License
MIT