Add ad-free YouTube player built on zero-native
Desktop YouTube player with no login and no ads. Extracts direct video/audio streams with yt-dlp and plays them in a native window via zero-native (Zig + system WebView) for a tiny footprint vs Electron. - Dual-stream engine: muted video synced with separate audio track for high quality without ffmpeg muxing; progressive fallback - On-device playlists, watch history, audio-only mode - Full custom controls: seek, volume, speed, quality, fullscreen, queue - Zig bridge handlers spawn yt-dlp and return slimmed JSON to the web UI - Cinematic dark UI: Bricolage/Hanken/JetBrains Mono, vermilion accent
This commit is contained in:
97
README.md
Normal file
97
README.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# YT Player
|
||||
|
||||
A lightweight, **ad-free YouTube player** with on-device playlists. No login, no
|
||||
tracking, no ads — it extracts direct video/audio streams with `yt-dlp` and plays
|
||||
them in a native window.
|
||||
|
||||
Built on [**zero-native**](https://github.com/vercel-labs/zero-native) (Zig + the
|
||||
system WebView) instead of Electron, so the binary is tiny — no bundled Chromium
|
||||
or Node runtime.
|
||||
|
||||
## Features
|
||||
|
||||
- 🔍 **Search** YouTube without an account
|
||||
- 🚫 **No ads** — plays the raw stream, never the YouTube player
|
||||
- 📺 **High quality** via a dual-stream engine: a muted video track synced with a
|
||||
separate audio track (1080p+) with no `ffmpeg` muxing required; progressive
|
||||
formats are used as a fallback
|
||||
- 🎵 **Audio-only mode** — great for music, saves bandwidth
|
||||
- 📂 **On-device playlists** — create, rename, delete, add/remove videos. Stored
|
||||
locally as JSON; nothing leaves your machine
|
||||
- 🕘 **Watch history**
|
||||
- ⏯ Full controls: seek, volume, playback speed, quality switching, fullscreen,
|
||||
next/prev, and keyboard shortcuts (`space`, `←/→`, `f`, `m`)
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
frontend/ Static web UI (no framework, no build step)
|
||||
index.html
|
||||
styles.css
|
||||
app.js Player engine + UI; calls window.zero.invoke(...)
|
||||
src/
|
||||
main.zig App definition + bridge handler registration
|
||||
bridge.zig Native handlers: spawn yt-dlp, slim its JSON, local store
|
||||
scripts/
|
||||
setup-ytdlp.js Downloads the standalone yt-dlp binary into ./bin
|
||||
bin/ yt-dlp lands here (gitignored)
|
||||
app.zon App manifest (window, engine, permissions, frontend dir)
|
||||
```
|
||||
|
||||
The web UI talks to the Zig side over the zero-native bridge:
|
||||
|
||||
| `window.zero.invoke(...)` | Native handler | Returns |
|
||||
|---|---|---|
|
||||
| `yt.search { query }` | `ytSearch` | `{ ok, results:[…] }` |
|
||||
| `yt.streams { videoId }` | `ytStreams` | `{ ok, data:{ meta, audioUrl, qualities[] } }` |
|
||||
| `store.load {}` | `storeLoad` | playlists / history / settings |
|
||||
| `store.save { data }` | `storeSave` | `{ ok }` |
|
||||
|
||||
Because the bridge is size-limited, the Zig handlers parse `yt-dlp`'s large JSON
|
||||
and return only the compact fields the UI needs.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- **Zig** (0.14.x recommended) — <https://ziglang.org/download/>
|
||||
- **zero-native** CLI: `npm install -g zero-native`
|
||||
- **Node.js** (only to run the yt-dlp downloader script)
|
||||
- No system `yt-dlp` needed — the setup script bundles it. (On Linux/macOS the
|
||||
bundled build is self-contained; Python is not required.)
|
||||
|
||||
## Setup & run
|
||||
|
||||
```bash
|
||||
# 1. Download the yt-dlp binary into ./bin
|
||||
npm run setup # or: node scripts/setup-ytdlp.js
|
||||
|
||||
# 2. Generate the zero-native build files for your installed version
|
||||
# (build.zig, build.zig.zon, src/runner.zig). Run this in a scratch dir and
|
||||
# copy the generated build.zig / build.zig.zon next to this project, OR run
|
||||
# init here and keep your files:
|
||||
zero-native init ytplayer --frontend none
|
||||
|
||||
# 3. Merge: keep THIS repo's frontend/, src/main.zig, src/bridge.zig and app.zon.
|
||||
# (src/main.zig shows exactly how the handlers are registered — fold that into
|
||||
# the generated App if the scaffold differs.)
|
||||
|
||||
# 4. Build & launch the native window
|
||||
zig build run
|
||||
```
|
||||
|
||||
To refresh yt-dlp later (YouTube changes often): `npm run update-ytdlp`.
|
||||
|
||||
## Notes & caveats
|
||||
|
||||
- **zero-native is pre-1.0.** The bridge handler signature used here follows its
|
||||
documented contract (`fn(context, invocation, output) anyerror![]const u8`).
|
||||
If your installed version exposes the `Invocation` type or `BridgeDispatcher`
|
||||
fields slightly differently, only the wiring in `src/main.zig` and the
|
||||
`payloadField` helper need adjusting — the handler logic is self-contained.
|
||||
- Stream URLs from `yt-dlp` are IP-locked and expire after a few hours; the app
|
||||
re-fetches them each time you play a video, so this is transparent.
|
||||
- This is for **personal use**. Respect YouTube's Terms of Service and the
|
||||
rights of content creators.
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
Reference in New Issue
Block a user