M6 DONE — torttube ships, Rick Astley plays fullscreen on the Livingroom Pi

Live install verified end-to-end:
- SSH'd into 192.168.0.158 (LibreELEC, Kodi 20.3 Nexus, kernel aarch64
  / userspace armhf — that's why the static Rust sidecar runs but the
  PyInstaller yt-dlp binary couldn't)
- Dropped addon dir into /storage/.kodi/addons/
- systemctl restart kodi → Kodi rescans /storage/.kodi/addons/
- JSON-RPC Addons.SetAddonEnabled flipped enabled:false → true
- Player.Open with plugin URL → 7s yt-dlp resolve → VideoFullScreen.xml,
  fullscreen:true, currentwindow 12005, audio+video synced

Fixes that surfaced during the install:
- yt-dlp swap: PyInstaller aarch64 binary needs ld-linux-aarch64.so.1
  which LibreELEC doesn't ship. Switched to the universal Python zipapp
  (~3MB) which runs on /usr/bin/python3.11. build-addon-zip.sh updated.
- main.py now puts the addon's bin/ dir on PATH so the sidecar's
  Command::new('yt-dlp') call resolves to the bundled zipapp.
- Cosmetic fix: resolve.rs's classify_yt_dlp_error preserves the
  original error message (was downcasing it for keyword matching and
  then using the lowercased copy as the user-facing error).

Caveats logged for later:
- 360p ceiling (yt-dlp '-f best[ext=mp4]' picks itag 18; 720p
  progressive itag 22 is deprecated by YouTube; higher quality wants
  DASH manifest generation).
- ALSA sink: device 'sysdefault:CARD=vc4hdmi1' fails to open on this
  Pi but Kodi auto-falls-back to 'sysdefault' so audio works. Worth
  cleaning up in Kodi audio settings later.

MILESTONES + docs/install.md updated with the SSH + JSON-RPC alternate
install path.
This commit is contained in:
Kayos 2026-05-23 10:18:26 -07:00
parent 283693525c
commit 284fe5fde7
5 changed files with 72 additions and 40 deletions

View file

@ -65,17 +65,26 @@ def _extract_id(url_or_id: str) -> str:
def _call_sidecar(request: dict, timeout_s: int = 30) -> dict:
"""Invoke the sidecar with one JSON request, parse one JSON response."""
"""Invoke the sidecar with one JSON request, parse one JSON response.
Puts the addon's bin/ on PATH so the sidecar's `yt-dlp` shell-outs find
the bundled zipapp (LibreELEC has no system yt-dlp).
"""
if not os.path.isfile(SIDECAR_BIN):
raise RuntimeError(f"sidecar binary missing at {SIDECAR_BIN}")
if not os.access(SIDECAR_BIN, os.X_OK):
raise RuntimeError(f"sidecar binary not executable at {SIDECAR_BIN}")
env = os.environ.copy()
addon_bin = os.path.join(ADDON_PATH, "bin")
env["PATH"] = addon_bin + os.pathsep + env.get("PATH", "")
proc = subprocess.run(
[SIDECAR_BIN],
input=(json.dumps(request) + "\n").encode("utf-8"),
capture_output=True,
timeout=timeout_s,
env=env,
)
if proc.returncode != 0:
raise RuntimeError(