# yt-local [![License: AGPL v3](https://img.shields.io/badge/License-AGPL_v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0) [![Python 3.7+](https://img.shields.io/badge/python-3.7+-blue.svg)](https://www.python.org/downloads/) [![Tests](https://img.shields.io/badge/tests-passing-brightgreen.svg)](https://github.com/user234683/youtube-local) A privacy-focused, browser-based YouTube client that routes requests through Tor for anonymous viewing—**without compromising on speed or features**. [Features](#features) • [Install](#install) • [Usage](#usage) • [Screenshots](#screenshots) --- > [!NOTE] > How it works: yt-local mirrors YouTube's web requests (using the same Invidious/InnerTube endpoints as yt-dlp and Invidious) but strips JavaScript and serves a lightweight HTML frontend. No API keys needed. ## Overview yt-local is a lightweight, self-hosted YouTube client written in Python that gives you: - **Privacy-first**: All requests route through Tor by default (video optional), keeping you anonymous. - **Fast page loads**: No lazy-loading, no layout reflows, instant comment rendering. - **Full control**: Customize subtitles, related videos, comments, and playback speed. - **High quality**: Supports all YouTube video qualities (144p–2160p) via DASH muxing. - **Zero ads**: Clean interface, no tracking, no sponsored content. - **Self-hosted**: You control the instance—no third-party trust required. ## Features | Category | Features | |---------------|----------------------------------------------------------------------------------------| | Core | Search, channels, playlists, watch pages, comments, subtitles (auto/manual) | | Privacy | Optional Tor routing (including video), automatic circuit rotation on 429 errors | | Local | Local playlists (durable against YouTube deletions), thumbnail caching | | UI | 3 themes (Light/Gray/Dark), theater mode, custom font selection | | Config | Fine-grained settings: subtitle mode, comment visibility, sponsorblock integration | | Performance | No JavaScript required, instant page rendering, rate limiting with exponential backoff | | Subscriptions | Import from YouTube Takeout (CSV/JSON), tag organization, mute channels | ### Advanced Capabilities - SponsorBlock integration — skip sponsored segments automatically - Custom video speeds — 0.25x to 4x playback rate - Video transcripts — accessible via transcript button - Video quality muxing — combine separate video/audio streams for non-360p/720p resolutions - Tor circuit rotation — automatic new identity on rate limiting (429) - File downloading — download videos/audio (disabled by default, configurable) ## Screenshots | Light Theme | Gray Theme | Dark Theme | |:-----------------------------------------------------:|:----------------------------------------------------:|:----------------------------------------------------:| | ![Light](https://pic.infini.fr/l7WINjzS/0Ru6MrhA.png) | ![Gray](https://pic.infini.fr/znnQXWNc/hL78CRzo.png) | ![Dark](https://pic.infini.fr/iXwFtTWv/mt2kS5bv.png) | | Channel View | Playlist View | |:-------------------------------------------------------:|:---------------------:| | ![Channel](https://pic.infini.fr/JsenWVYe/SbdIQlS6.png) | *(similar structure)* | --- ## Install ### Windows 1. Download the latest [release ZIP](https://github.com/user234683/yt-local/releases) 2. Extract to any folder 3. Run `run.bat` to start ### GNU/Linux / macOS ```bash # 1. Clone or extract the release git clone https://github.com/user234683/yt-local.git cd yt-local # 2. Create and activate virtual environment python3 -m venv venv source venv/bin/activate # or `venv\Scripts\activate` on Windows # 3. Install dependencies pip install -r requirements.txt # 4. Run the server python3 server.py ``` > [!TIP] > If `pip` isn't installed, use your distro's package manager (e.g., `sudo apt install python3-pip` on Debian/Ubuntu). ### Portable Mode To keep settings and data in the same directory as the app: ```bash # Create an empty settings.txt in the project root touch settings.txt python3 server.py # Data now stored in ./data/ instead of ~/.yt-local/ ``` --- ## Usage ### Basic Access 1. Start the server: ```bash python3 server.py # Server runs on http://127.0.0.1:9010 (configurable in /settings) ``` 2. Access YouTube via proxy: ```bash http://localhost:9010/https://www.youtube.com/watch?v=vBgulDeV2RU ``` All YouTube URLs must be prefixed with `http://localhost:9010/https://`. 3. (Optional) Use Redirector to auto-redirect YouTube URLs: - **Firefox**: [Redirector addon](https://addons.mozilla.org/firefox/addon/redirector/) - **Chrome**: [Redirector addon](https://chrome.google.com/webstore/detail/redirector/ocgpenflpmgnfapjedencafcfakcekcd) - **Pattern**: `^(https?://(?:[a-zA-Z0-9_-]*\.)?(?:youtube\.com|youtu\.be|youtube-nocookie\.com)/.*)` - **Redirect to**: `http://localhost:9010/$1` > [!NOTE] > To use embeds on web pages, make sure "Iframes" is checked under advanced options in your redirector rule. ### Tor Routing > [!IMPORTANT] > Recommended for privacy. In `/settings`, set **Route Tor** to `"On, except video"` (or `"On, including video"`), then save. #### Running Tor Option A: Tor Browser (easiest) - Launch Tor Browser and leave it running - yt-local uses port `9150` (Tor Browser default) Option B: Standalone Tor ```bash # Linux (Debian/Ubuntu) sudo apt install tor sudo systemctl enable --now tor # Configure yt-local ports (if using default Tor ports): # Tor port: 9150 # Tor control port: 9151 ``` > [!WARNING] > Video over Tor is bandwidth-intensive. Consider donating to [Tor node operators](https://torservers.net/donate.html) to sustain the network. ### Import Subscriptions 1. Go to [Google Takeout](https://takeout.google.com/takeout/custom/youtube) 2. Deselect all → select only **Subscriptions** → create export 3. Download and extract `subscriptions.csv` (path: `YouTube and YouTube Music/subscriptions/subscriptions.csv`) 4. In yt-local: **Subscriptions** → **Import** → upload CSV > [!IMPORTANT] > The CSV file must contain columns: `channel_id,channel_name,channel_url` ## Supported formats - Google Takeout CSV - Google Takeout JSON (legacy) - NewPipe JSON export - OPML (from YouTube's old subscription manager) --- ## Configuration Visit `http://localhost:9010/settings` to configure: | Setting | Description | |--------------------|-------------------------------------------------| | Route Tor | Off / On (except video) / On (including video) | | Default subtitles | Off / Manual only / Auto + Manual | | Comments mode | Shown by default / Hidden by default / Never | | Related videos | Same options as comments | | Theme | Light / Gray / Dark | | Font | Browser default / Serif / Sans-serif | | Default resolution | Auto / 144p–2160p | | SponsorBlock | Enable Sponsored segments skipping | | Proxy images | Route thumbnails through yt-local (for privacy) | --- ## Troubleshooting | Issue | Solution | |------------------------------|----------------------------------------------------------------------------------------------| | Port already in use | Change `port_number` in `/settings` or kill existing process: `pkill -f "python3 server.py"` | | 429 Too Many Requests | Enable Tor routing for automatic IP rotation, or wait 5-10 minutes | | Failed to connect to Tor | Verify Tor is running: `tor --version` or launch Tor Browser | | Subscriptions not importing | Ensure CSV has columns: `channel_id,channel_name,channel_url` | | Settings persist across runs | Check `~/.yt-local/settings.txt` (non-portable) or `./settings.txt` (portable) | --- ## Development ### Running Tests ```bash source venv/bin/activate # if not already in venv make test ``` ### Project Structure ```bash yt-local/ ├── youtube/ # Core application logic │ ├── __init__.py # Flask app entry point │ ├── util.py # HTTP utilities, Tor manager, fetch_url │ ├── watch.py # Video/playlist page handlers │ ├── channel.py # Channel page handlers │ ├── playlist.py # Playlist handlers │ ├── search.py # Search handlers │ ├── comments.py # Comment extraction/rendering │ ├── subscriptions.py # Subscription management + SQLite │ ├── local_playlist.py # Local playlist CRUD │ ├── proto.py # YouTube protobuf token generation │ ├── yt_data_extract/ # Polymer JSON parsing abstractions │ └── hls_cache.py # HLS audio/video streaming proxy ├── templates/ # Jinja2 HTML templates ├── static/ # CSS/JS assets ├── translations/ # i18n files (Babel) ├── tests/ # pytest test suite ├── server.py # WSGI entry point ├── settings.py # Settings parser + admin page ├── generate_release.py # Windows release builder └── manage_translations.py # i18n maintenance script ``` > [!NOTE] > For detailed architecture guidance, see [`docs/HACKING.md`](docs/HACKING.md). ### Contributing Contributions welcome! Please: 1. Read [`docs/HACKING.md`](docs/HACKING.md) for coding guidelines 2. Follow [PEP 8](https://peps.python.org/pep-0008/) style (use `ruff format`) 3. Run tests before submitting: `pytest` 4. Ensure no security issues: `bandit -r .` 5. Update docs for new features --- ## Security Notes - **No API keys required** — uses same endpoints as public YouTube web interface - **Tor is optional** — disable in `/settings` if you prefer performance over anonymity - **Rate limiting handled** — exponential backoff (max 5 retries) with automatic Tor circuit rotation - **Path traversal protected** — user input validated against regex whitelists (CWE-22) - **Subprocess calls secure** — build scripts use `subprocess.run([...])` instead of shell (CWE-78) > [!NOTE] > GPG key for release verification: `72CFB264DFC43F63E098F926E607CE7149F4D71C` --- ## Public Instances yt-local is designed for self-hosting. --- ## Donate This project is 100% free and open-source. If you'd like to support development: - **Bitcoin**: `1JrC3iqs3PP5Ge1m1vu7WE8LEf4S85eo7y` - **Tor node donation**: https://torservers.net/donate --- ## License GNU Affero General Public License v3.0+ See [`LICENSE`](LICENSE) for full text. ### Exception for youtube-dl Permission is granted to relicense code portions into youtube-dl's license (currently GPL) for direct inclusion into the [official youtube-dl repository](https://github.com/ytdl-org/youtube-dl). This exception **does not apply** to forks or other uses—those remain under AGPLv3. --- ## Similar Projects | Project | Type | Notes | |--------------------------------------------------------------|----------|--------------------------------------| | [invidious](https://github.com/iv-org/invidious) | Server | Multi-user instance, REST API | | [Yotter](https://github.com/ytorg/Yotter) | Server | YouTube + Twitter integration | | [FreeTube](https://github.com/FreeTubeApp/FreeTube) | Desktop | Electron-based client | | [NewPipe](https://newpipe.schabi.org/) | Mobile | Android-only, no JavaScript | | [mps-youtube](https://github.com/mps-youtube/mps-youtube) | Terminal | CLI-based, text UI | | [youtube-local](https://github.com/user234683/youtube-local) | Browser | Original project (base for yt-local) | --- Made for privacy-conscious users Last updated: 2026-04-19