After hitting the segment-timing wall on our hand-rolled DASH MPD
(audio drifted -25s -> -44s behind video on long content), pivoted to
delegating playback to plugin.video.youtube v7.4.3 which already has
years of sidx-parsed SegmentTimeline + multi-client fallback work.
torttube._play() now:
1. Tries _delegate_to_pv_youtube(yt_id) — sets a resolved URL of
'plugin://plugin.video.youtube/play/?video_id=<id>'. Kodi
chain-resolves to pv.youtube which builds the proper MPD and
hands inputstream.adaptive a correctly-aligned manifest. Default.
2. Falls back to our DASH builder (still in code, gated by
'dash_enabled' setting + dash.on marker) if pv.youtube is absent.
3. Falls through to yt-dlp progressive 360p as the final safety net.
When delegating, we skip our SponsorBlock monitor — pv.youtube has its
own and would double-skip otherwise.
Cobb-verified live on Livingroom Pi: LTT 'Trump Phone' (which crashed
our DASH with audio sync errors growing to -44s) now plays HD with
audio synced. 'Please sign in' message in log is from the tv_unplugged
Innertube client; pv.youtube falls back to a working client
automatically — no user account required.
Settings: prefer_pv_youtube boolean (default true). Addon v0.0.11.
Reference: https://kodi.wiki/view/Add-on:YouTube
|
||
|---|---|---|
| addon/plugin.video.torttube | ||
| docs | ||
| scripts | ||
| sidecar | ||
| .gitignore | ||
| LICENSE | ||
| MILESTONES.md | ||
| README.md | ||
torttube
Kodi addon for YouTube via RustyPipe extraction + SponsorBlock 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, settings]
└── torttube-sidecar [Rust binary — JSON-over-stdio]
├── rustypipe [Tier 1: native Rust Innertube]
├── yt-dlp subprocess [Tier 2: fallback resolve]
├── yt-dlp rip-to-temp [Tier 3: download to /storage/.kodi/temp,
│ play local file when streams die mid-play]
└── sponsorblock [REST client, SHA-256 prefix lookup]
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:
- rustypipe (Rust) — preferred. Fast, in-process, no Python dep on the RPi.
- yt-dlp subprocess — fallback when rustypipe sig-decoding falls behind YouTube's deobfuscator changes. yt-dlp updates weekly; we shell out, parse
-jJSON. - Rip-to-temp — last resort when stream URLs 403 mid-playback (poToken expiry, cookie session mismatch). yt-dlp downloads to
/storage/.kodi/temp/torttube/<id>.<ext>, Kodi plays the local file. Temp dir has size cap + age cleanup.
Status
M0 scaffold. Nothing playable yet — see 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/rustypipeif 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 — n-parameter deobfuscation
- NPE #1444 — distinguish unavailable vs unextractable
- NPE #1360 — refactor link handlers (help wanted)
- NPE #1357 — JDoc checks in PR pipeline (good first issue)
- rustypipe PR #77 — open as of 2026-05-23, unmerged
Contribution log lives at docs/upstream.md — every PR we file lands there with its outcome.
License
GPL-3.0-or-later. Matches RustyPipe and NewPipeExtractor.