# torttube Kodi addon for YouTube via [RustyPipe](https://codeberg.org/ThetaDev/rustypipe) extraction + [SponsorBlock](https://sponsor.ajay.app/) segment skipping. Replaces the dead `plugin.video.youtube` on LibreELEC RPi TVs after Google required account-linking for the upstream addon. ## Architecture ``` Kodi (LibreELEC, RPi) └── plugin.video.torttube [Python addon — UI, browse, SponsorBlock] ├── torttube-sidecar [Rust binary — JSON-over-stdio] │ ├── rustypipe [Native Rust Innertube for browse] │ ├── yt-dlp subprocess [Fallback resolve] │ └── sponsorblock [REST client, SHA-256 prefix lookup] └── plugin.video.youtube [DEPENDENCY — handles HD playback] └── inputstream.adaptive [DASH demux + decode] ``` `plugin.video.youtube` is declared as a Kodi addon dependency in [addon.xml](addon/plugin.video.torttube/addon.xml). When a user installs torttube, Kodi auto-fetches pv.youtube from the official Kodi addon repository — user only manages torttube; the dep is transparent. torttube does what it's faster at: rustypipe-backed search/channel/playlist browse, SponsorBlock auto-skip via a tight `xbmc.Player()` monitor loop, JSON-RPC remote-control for share-to-TV. Playback hands off to pv.youtube via `plugin://plugin.video.youtube/play/?video_id=` — they've spent years getting the DASH-MPD + multi-client Innertube fallback right. Our SponsorBlock monitor runs in parallel because `xbmc.Player()` is a global accessor that works regardless of which addon initiated playback. Kodi addons are Python — the engine layer (n-param sig decoding, Innertube, SponsorBlock hashing) lives in a Rust sidecar so we get a single maintained extraction surface and clean aarch64/armv7 cross-compiles. **Three-tier resolve** because YouTube actively fights every extractor: 1. **rustypipe (Rust)** — preferred. Fast, in-process, no Python dep on the RPi. 2. **yt-dlp subprocess** — fallback when rustypipe sig-decoding falls behind YouTube's deobfuscator changes. yt-dlp updates weekly; we shell out, parse `-j` JSON. 3. **Rip-to-temp** — last resort when stream URLs 403 mid-playback (poToken expiry, cookie session mismatch). yt-dlp downloads to `/storage/.kodi/temp/torttube/.`, Kodi plays the local file. Temp dir has size cap + age cleanup. ## Status M0 scaffold. Nothing playable yet — see [MILESTONES.md](MILESTONES.md). ## Upstream — we fight with the FOSS extractor ecosystem, not next to it YouTube's anti-scraping changes hit every extractor: NewPipe, yt-dlp, Invidious, rustypipe. Every fix we make in our sidecar gets evaluated for "is this upstreamable?" — if yes, the fix lands at the upstream project, not just here. Active lanes: - **rustypipe** (Rust, codeberg.org/ThetaDev/rustypipe) — maintenance has slowed. Open PR #77 "Some fixes" is unmerged as of 2026-05-23. We will either help land it (review + ping maintainer) or fork to `Sulkta-Coop/rustypipe` if upstream stays quiet. Forking is the worst case, not the first move. - **NewPipeExtractor** (Java, github.com/TeamNewPipe/NewPipeExtractor) — actively maintained, 177 open issues. We use it as the reference implementation for Innertube behaviour. PRs to NPE land in Rust here via rustypipe, and vice versa. - **yt-dlp** (Python, github.com/yt-dlp/yt-dlp) — the gold standard. We're more consumers than contributors here, but if our rip-to-temp tier surfaces a specific extractor bug we file it. Issues we're watching: - [NPE #1339](https://github.com/TeamNewPipe/NewPipeExtractor/issues/1339) — n-parameter deobfuscation - [NPE #1444](https://github.com/TeamNewPipe/NewPipeExtractor/issues/1444) — distinguish unavailable vs unextractable - [NPE #1360](https://github.com/TeamNewPipe/NewPipeExtractor/issues/1360) — refactor link handlers (help wanted) - [NPE #1357](https://github.com/TeamNewPipe/NewPipeExtractor/issues/1357) — JDoc checks in PR pipeline (good first issue) - [rustypipe PR #77](https://codeberg.org/ThetaDev/rustypipe/pulls/77) — open as of 2026-05-23, unmerged Contribution log lives at [docs/upstream.md](docs/upstream.md) — every PR we file lands there with its outcome. ## License GPL-3.0-or-later. Matches RustyPipe and NewPipeExtractor.