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.
This commit is contained in:
parent
d463781aae
commit
a784321759
7 changed files with 94 additions and 7 deletions
|
|
@ -314,7 +314,13 @@ def _play(yt_id: str) -> None:
|
|||
|
||||
mpd_bytes: bytes | None = None
|
||||
dash_resp: dict[str, Any] = {}
|
||||
if os.environ.get("TORTTUBE_DASH") == "1":
|
||||
dash_enabled = False
|
||||
try:
|
||||
dash_enabled = ADDON.getSettingBool("dash_enabled")
|
||||
except Exception:
|
||||
# Setting might not exist on older configs; treat as off.
|
||||
pass
|
||||
if dash_enabled or os.environ.get("TORTTUBE_DASH") == "1":
|
||||
mpd_bytes, dash_resp = _try_dash(yt_id)
|
||||
if mpd_bytes:
|
||||
details = dash_resp.get("details") or {}
|
||||
|
|
@ -638,6 +644,36 @@ def _search_directory(query: str | None = None) -> None:
|
|||
xbmcplugin.endOfDirectory(_HANDLE)
|
||||
|
||||
|
||||
def _playlist_directory(playlist_id: str) -> None:
|
||||
"""List a playlist's videos."""
|
||||
try:
|
||||
resp = _call_sidecar(
|
||||
{"op": "playlist", "id": playlist_id, "limit": 100}, timeout_s=15
|
||||
)
|
||||
except Exception as e:
|
||||
_log(f"playlist failed: {e}", xbmc.LOGERROR)
|
||||
xbmcgui.Dialog().notification(
|
||||
"torttube", f"playlist failed: {e}", xbmcgui.NOTIFICATION_ERROR, 4000
|
||||
)
|
||||
xbmcplugin.endOfDirectory(_HANDLE, succeeded=False)
|
||||
return
|
||||
if not resp.get("ok"):
|
||||
xbmcgui.Dialog().notification(
|
||||
"torttube",
|
||||
f"playlist: {resp.get('error', 'unknown')}",
|
||||
xbmcgui.NOTIFICATION_WARNING,
|
||||
4000,
|
||||
)
|
||||
xbmcplugin.endOfDirectory(_HANDLE, succeeded=False)
|
||||
return
|
||||
|
||||
items = resp.get("items") or []
|
||||
pl = resp.get("playlist") or {}
|
||||
_log(f"playlist {pl.get('name') or playlist_id}: {len(items)} items")
|
||||
_add_video_items(items)
|
||||
xbmcplugin.endOfDirectory(_HANDLE)
|
||||
|
||||
|
||||
def _channel_directory(channel_id: str) -> None:
|
||||
"""List a channel's recent videos."""
|
||||
try:
|
||||
|
|
@ -707,6 +743,8 @@ def main() -> None:
|
|||
_search_directory(query=params.get("q"))
|
||||
elif action == "channel":
|
||||
_channel_directory(params.get("id") or "")
|
||||
elif action == "playlist":
|
||||
_playlist_directory(params.get("id") or "")
|
||||
elif action == "play_by_url":
|
||||
_play_by_url_prompt()
|
||||
else:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue