Commit graph

10 commits

Author SHA1 Message Date
ffc7332910 Declare plugin.video.youtube as a Kodi addon dep
addon.xml now requires plugin.video.youtube >=7.0.0 in addition to
xbmc.python and (optional) inputstream.adaptive. When a user installs
torttube, Kodi resolves the dep and auto-fetches plugin.video.youtube
from the official Kodi addon repository — user only manages torttube,
the dep is transparent.

This is Cobb's preferred 'one-addon experience' without the
maintenance liability of vendoring + maintaining 5.6MB / 15k LOC of
their player code in our tree.

README architecture diagram updated to show pv.youtube as a dependency
rather than a sibling. docs/install.md notes that Kodi auto-installs
the dep — no manual pv.youtube step needed.

Addon version 0.0.12.
2026-05-23 12:15:06 -07:00
9ed0aae2d0 M7 DONE via delegation — pv.youtube plays HD with audio
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
2026-05-23 11:58:12 -07:00
0a289fea3a M7 — DASH partial: MPD serves OK, segment alignment still WIP
Big strides today:
- Sidecar resolve_dash op works (verified live on Pi)
- MPD builder generates valid MPEG-DASH on-demand manifest with
  H.264 720p/1080p video reps + best AAC audio rep
- ThreadingHTTPServer serves the MPD over the LAN IP (not 127.0.0.1
  — curl in Kodi 20's inputstream.adaptive can't open that)
- inputstream.adaptive PARSES our manifest cleanly: 'Successfully
  parsed manifest file (Periods: 1, Streams in first period: 2)'
- Segment GETs work once we set stream_headers with User-Agent
  + Origin + Referer (otherwise googlevideo 403s the audio segments)

Remaining issue:
- Audio drifts -25s → -44s behind video within seconds of playback
  start. inputstream.adaptive needs explicit SegmentTimeline timing
  derived from each rep's sidx box to stay aligned. Plugin.video.youtube
  does this; we'd need to fetch+parse sidx ourselves or fork their
  MPD-builder. Documented as M7-blocking + upstream PR candidate.

Default remains the stable yt-dlp progressive 360p path. DASH is
behind dash_enabled setting OR a dash.on marker file in addon_data.
Toggle on via:
  ssh <kodi> 'touch /storage/.kodi/userdata/addon_data/plugin.video.torttube/dash.on'
Toggle off:
  ssh <kodi> 'rm /storage/.kodi/userdata/addon_data/plugin.video.torttube/dash.on'

Addon v0.0.10. docs/upstream.md has the full segment-timing analysis.
2026-05-23 11:46:56 -07:00
a784321759 M4 wrap — playlist browse + addon settings + upstream PR-77 notes
Sidecar Playlist op via rustypipe playlist(). Returns playlist metadata
block (id, name, channel, video_count) + items array. Verified live
against LTT's 'Consumer Advocacy' (PL8mG-RkN2uTzwoF72GqeqAJMI-N7scqtI):
returns the single video with full metadata.

Addon ?action=playlist&id=PL... lists items via _add_video_items reuse.
Verified via Files.GetDirectory JSON-RPC.

resources/settings.xml gains a 'dash_enabled' toggle (boolean, default
off). main.py checks ADDON.getSettingBool('dash_enabled') OR the
TORTTUBE_DASH env fallback before attempting the DASH path. Toggle via
Kodi Settings → Add-on settings → torttube, OR via
Addons.SetSettings JSON-RPC.

docs/upstream.md: filed a 'watching' entry for rustypipe PR #77
(Schmiddiii's late-May YouTube parsing fixes) with our independent
test data — player(), search(), and channel_videos() all still work
against current YouTube on 0.11.4, suggesting the PR fixes code paths
torttube doesn't yet exercise. Endorsement comment pending: gated on
creating a Sulkta-Coop codeberg account.

Observation from kodi.log: plugin.video.youtube successfully parsed a
DASH MPD with 26 streams via inputstream.adaptive on this same Pi —
proves DASH is solvable on our setup, just need to match the URL
pattern they use. M7 stabilization carrying forward.

Addon version 0.0.9.
2026-05-23 11:33:20 -07:00
d463781aae M4 — channel browse + context-menu drill-down
Sidecar ChannelVideos op via rustypipe channel_videos(). Returns the
channel metadata block (id, name, subscribers, banner) alongside the
items array — same VideoItem shape as search.

Addon refactor: _add_video_items is now the shared listing builder.
Both _search_directory and _channel_directory call it. Each video
result gets a 'Go to <channel>' context-menu entry that
Container.Update's to ?action=channel&id=<channel_id> — so from any
search result, the user can drill into that channel's recent uploads
without going back through search.

Smoke verified on the Pi via Files.GetDirectory: LTT channel
(UCXuqSBlHAE6Xw-yeJA0Tunw) returned 30 recent videos.

Addon version 0.0.7.
2026-05-23 11:24:59 -07:00
1b18c67fff M4 partial — Search shipped, browse UI live on the Pi
Sidecar gains the 'search' op via rustypipe's
query().search::<VideoItem,_>() — returns id, title, channel, duration,
thumbnails, view_count. Default limit 25.

Addon root directory is no longer a placeholder notification:
- 'Search' entry → ?action=search → keyboard input → result list →
  tap a result to play (each result is a play-action plugin URL).
- 'Play by URL' entry → ?action=play_by_url → keyboard input → PlayMedia.
- ?action=search also accepts inline 'q=…' so JSON-RPC clients can
  drive search without going through the on-TV keyboard (useful for
  share-to-TV from phone + tests).
- Result labels formatted as 'Title  ·  Channel  ·  Duration  ·  Views',
  with thumbnail + Kodi InfoLabels for richer skin views.

Verified via Files.GetDirectory JSON-RPC: 19 well-formatted LTT results
returned for query 'linus tech tips'.

Pending M4: channel browse, playlist browse, pagination, search history.
Addon version 0.0.6.
2026-05-23 11:20:41 -07:00
45e1306bf3 DASH HD playback — WIP behind TORTTUBE_DASH=1 + upstream notes
Sidecar resolve_dash op shipped — returns rustypipe's full video_only_streams
+ audio_streams (16+ representations for NGGYU, from 360p H.264 through 4K
AV1). Addon _build_dash_mpd assembles a valid on-demand MPEG-DASH manifest
filtered to H.264 ≤1080p + best AAC audio.

Two unblocked-by-WIP issues surfaced during integration:
- inputstream.adaptive's libcurl can't open file:// URLs (logged in
  docs/upstream.md as an enhancement-target).
- Rapid Player.Open retries can trigger Kodi's 'two concurrent
  busydialogs' fatal exit; need lifecycle hardening before re-enabling.

Pivoted to localhost HTTP-server serving (ThreadingHTTPServer on a
port-0 socket, MPD bytes captured in a per-instance handler subclass).
Lifecycle: server.shutdown() runs in a finally block after the
SponsorBlockMonitor watcher exits. Works in isolation but Kodi crashed
under rapid retry conditions — needs more testing.

For v0.0.5: DASH path is gated behind TORTTUBE_DASH=1 env var; default
falls through to the stable yt-dlp progressive 360p path that's been
verified live. M7 milestone added to track the remaining work; PRs
to inputstream.adaptive + Kodi candidates logged in docs/upstream.md.
2026-05-23 11:14:56 -07:00
f610965fcf M5 DONE — SponsorBlock auto-skip wired + verified on the TV
SponsorBlockMonitor (xbmc.Monitor subclass) attaches after setResolvedUrl:
- fetches segments from sidecar via the existing sponsorblock op
  (SHA-256 prefix lookup, defaults to sponsor + selfpromo + interaction
  categories)
- waits up to 30s for playback to actually start, then polls
  Player.getTime() every 0.5s
- when position enters a skip segment, calls seekTime(end) and shows
  a 'SponsorBlock — Skipped <category> (<duration>s)' toast
- UUIDs are remembered so a manual rewind into a previously-skipped
  segment doesn't trigger again
- exits cleanly on playback stop or Kodi shutdown

Live-verified on the Livingroom Pi with LTT 2T8x5antlnc ('Trump Phone'),
which has two locked sponsor segments. Sought to 1:45, the monitor
fired at 108.3s and seeked to 128.4s — log line:

  [torttube] sponsorblock skip: sponsor 108.3-128.4 (20s)

addon.xml v0.0.1 → v0.0.2.

Deferred for v0.0.3+: settings.xml category toggles + a skip-counter,
support for non-skip action types (mute, full, poi).
2026-05-23 10:23:07 -07:00
f4ceae3b70 M6 — cross-compile aarch64-musl + addon.zip + install docs
scripts/build-addon-zip.sh runs the whole pipeline from a host with ssh
lucy:
- one-shot messense/rust-musl-cross:aarch64-musl container builds the
  sidecar static (6.2MB stripped). Doesn't mutate crafting-table.
- 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 /mnt/user/downloads/torttube/ on Lucy SMB

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 Cobb's install on
192.168.0.158.
2026-05-23 08:54:46 -07:00
238dfb8391 M0 scaffold — Python addon + Rust sidecar
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).
2026-05-23 08:14:09 -07:00