# 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
