## Overview This PR introduces HLS playback support, improves the player experience, and refactors documentation for better usability and maintainability. ## Key Features ### HLS Playback Support - Add HLS integration via new JavaScript assets: - `hls.min.js` - `plyr.hls.start.js` - `watch.hls.js` - Separate DASH and HLS logic: - `plyr-start.js` → `plyr.dash.start.js` - `watch.js` → `watch.dash.js` - Update templates (`embed.html`, `watch.html`) for conditional player loading ### Native Storyboard Preview - Add `native_player_storyboard` setting in `settings.py` - Implement hover thumbnail preview for native player modes - Add `storyboard-preview.js` ### UI and Player Adjustments - Update templates and styles (`custom_plyr.css`) - Modify backend modules to support new player modes: - `watch.py`, `channel.py`, `util.py`, and related components ### Internationalization - Update translation files: - `messages.po` - `messages.pot` ### Testing and CI - Add and update tests: - `test_shorts.py` - `test_util.py` - Minor CI and release script improvements ## Documentation ### OpenRC Service Guide Rewrite - Restructure `docs/basic-script-openrc/README.md` into: - Prerequisites - Installation - Service Management - Verification - Troubleshooting - Add admonition blocks: - `[!NOTE]`, `[!TIP]`, `[!IMPORTANT]`, `[!WARNING]`, `[!CAUTION]` - Fix log inspection command: ```bash doas tail -f /var/log/ytlocal.log ```` * Add path placeholders and clarify permission requirements * Remove legacy and duplicate content Reviewed-on: #1 Co-authored-by: Astounds <kirito@disroot.org> Co-committed-by: Astounds <kirito@disroot.org>
314 lines
12 KiB
Markdown
314 lines
12 KiB
Markdown
# yt-local
|
||
|
||
[](https://www.gnu.org/licenses/agpl-3.0)
|
||
[](https://www.python.org/downloads/)
|
||
[](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 |
|
||
|:-----------------------------------------------------:|:----------------------------------------------------:|:----------------------------------------------------:|
|
||
|  |  |  |
|
||
|
||
| Channel View | Playlist View |
|
||
|:-------------------------------------------------------:|:---------------------:|
|
||
|  | *(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
|