OverviewFilesCommitsIssuesDocsReleasesPeers

kodi-jacktook commits / 9a09a22

Opt into inputstream.adaptive via a URL marker (1.15.6)
ISA stays off by default -- it stalls the audio when handed a single-variant media playlist -- but a source can now ask for it with `adaptive=1` in its own URL, alongside the existing `adaptive` data flag. The marker rides in the URL so no flag has to be plumbed through every playback path in this fork, and so a row that is not adaptive can never accidentally opt in, which is exactly how the audio broke in 1.15.4. Measured on the Pi, ISA against a MASTER ladder beats the ffmpeg demuxer on the thing that matters here: ffmpeg ignores a seek on these fMP4 segments (50% -> 1.2%, unchanged) while ISA lands it (50% -> 14:07), and pause works. Audio plays. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
9a09a22bb25f2b88dfa76f20916a95d695cce684
by plankatron <fleeky@gmail.com> · 2026-08-10T22:56:16.000Z

Changed files (3) +28 -6

plugin.video.jacktook/addon.xml +1 -1
……@@ -1,5 +1,5 @@
11<?xml version="1.0" encoding="utf-8"?>
2 <addon id="plugin.video.jacktook" name="Jacktook" version="1.15.5" provider-name="Sam-Max">
2 <addon id="plugin.video.jacktook" name="Jacktook" version="1.15.6" provider-name="Sam-Max">
33 <requires>
44 <import addon="xbmc.python" version="3.00.0"/>
55 <import addon="script.module.requests" version="2.25.1"/>
plugin.video.jacktook/lib/utils/player/utils.py +11 -5
……@@ -88,17 +88,23 @@ def set_adaptive_stream(list_item, data: Dict[str, Any]) -> Optional[str]:
8888 URL to ISA is how the previous attempt ended up fetching the variant
8989 playlist bare and taking a 403 from the CDN.
9090 """
91 # Opt-in ONLY. Engaging ISA for every .m3u8 broke audio on 2026-08-10:
91 # Opt-in ONLY, by explicit flag or an `adaptive=1` marker the source puts in
92 # its own URL. Engaging ISA for every .m3u8 broke audio on 2026-08-10:
9293 # it captured the single-variant rows as well as the adaptive one, and on
9394 # muxed HLS (audio inside the video segments, no EXT-X-MEDIA rendition) ISA
9495 # opens the aac decoder and then stalls -- "CVideoPlayerAudio::Process -
9596 # stream stalled", no sound, on content that played fine through the bare
96 # ffmpeg demuxer. Nothing sets this flag yet, so ISA stays off until a
97 # source explicitly asks for it AND the muxed-audio stall is understood.
98 if not data.get("adaptive"):
97 # ffmpeg demuxer.
98 #
99 # Handing ISA a MASTER playlist instead is fine, and measured on the Pi it
100 # is strictly better than the ffmpeg demuxer: audio plays, seek lands (50%
101 # -> 14:07, where ffmpeg ignored the same request and stayed at 1.2%) and
102 # pause works. So the opt-in exists to keep single-variant media playlists
103 # away from ISA, not to keep ISA away from ladders.
104 url = data.get("url") or ""
105 if not (data.get("adaptive") or "adaptive=1" in url):
99106 return None
100107
101 url = data.get("url") or ""
102108 kind = adaptive_manifest_type(url)
103109 if not kind:
104110 return None
plugin.video.jacktook/tests/unit/test_adaptive_stream.py +16 -0
……@@ -98,3 +98,19 @@ def test_isa_is_off_unless_a_source_opts_in():
9898 item = MagicMock()
9999 assert set_adaptive_stream(item, {"url": "http://h/a.m3u8?h=480"}) is None
100100 item.setProperty.assert_not_called()
101
102
103def test_a_url_marker_opts_in():
104 """The source marks its own adaptive URL, so no flag has to be plumbed
105 through every playback-data path in the fork."""
106 item = MagicMock()
107 url = set_adaptive_stream(item, {"url": "http://h/a.m3u8?h=auto&adaptive=1"})
108 assert url == "http://h/a.m3u8?h=auto&adaptive=1"
109 props = dict(c.args for c in item.setProperty.call_args_list)
110 assert props["inputstream"] == "inputstream.adaptive"
111
112
113def test_a_fixed_variant_url_still_does_not_opt_in():
114 item = MagicMock()
115 assert set_adaptive_stream(item, {"url": "http://h/a.m3u8?h=1080"}) is None
116 item.setProperty.assert_not_called()