Realized during M6 packaging that the rustypipe path returns separate
audio + video DASH streams (Opus 251 + AV1 401 on the smoke video). Kodi
can't sync those without an inputstream.adaptive DASH manifest, which
would need server-side manifest generation — M3+ territory.
Stopgap for shippable M3: new sidecar op resolve_play that asks yt-dlp
for -f best[ext=mp4]/best — one combined audio+video URL Kodi plays as
plain HTTP. ~3-5s overhead vs rustypipe but reliable sync.
main.py _play() now calls resolve_play. resolve still exists for
metadata + browse paths (M4 will use it).
Rebuilt aarch64-musl binary, repackaged plugin.video.torttube-0.0.1.zip
(38.7MB, md5 f2c08aed130b1c1bd231a9b6cbfac93c). Live at:
smb://fileserver/downloads/torttube/plugin.video.torttube-0.0.1.zip
scripts/build-addon-zip.sh runs the whole pipeline from a host with ssh build-host:
- one-shot messense/rust-musl-cross:aarch64-musl container builds the
sidecar static (6.2MB stripped). Doesn't mutate the build container.
- fetches yt-dlp_linux_aarch64 from the upstream release page so Tier 2
+ Tier 3 work on the Pi (LibreELEC ships no Python YouTube tools)
- packages everything into plugin.video.torttube.zip with the Kodi
install-from-zip layout
- drops the zip at /srv/downloads/torttube/ on the file share
Cargo.toml swaps rustypipe to default-features=false +
rustls-tls-webpki-roots so the cross-compile is openssl-free.
addon.xml drops the unused script.module.requests requirement — main.py
only uses Python stdlib + Kodi's own modules.
docs/install.md walks the Kodi UI flow + a smoke curl that fires
Player.Open via JSON-RPC. Pi-side smoke is pending install on
kodi-host.
JSON-over-stdio loop on tokio with four ops:
- ping liveness
- resolve Tier 1 rustypipe → Tier 2 yt-dlp -j fallback. Typed
errors (age/region/private/not-found) short-circuit
Tier 2 so we don't double-hit a wall. Pass-through
serialization of player.details + selected streams,
so the Python addon parses what it needs without us
coupling to rustypipe's struct shape.
- rip Tier 3 yt-dlp downloads bestvideo+bestaudio to a
caller-supplied dest_dir, returns the resulting
path + size for the addon to play as a local file.
- sponsorblock SHA-256 prefix lookup (first 4 hex), filter to the
exact video_id locally. Categories default to
[sponsor, selfpromo, interaction]; caller can override.
Smoke ran in the build container against dQw4w9WgXcQ — rustypipe 0.11.4
still resolves cleanly in 2026-05, sig decoding intact, both 4K AV1
video and Opus 128kbps audio came back with valid signed URLs.
SponsorBlock returns empty segments for music videos (as expected).
Kodi addon (plugin.video.torttube) shell with Cargo workspace for the
rustypipe-backed sidecar binary. No working extraction yet — addon.xml
parses, main.py is a notification stub, sidecar's main.rs prints scaffold
banner. See MILESTONES.md for M1..M6.
License: GPL-3.0-or-later (matches rustypipe + NewPipeExtractor).