OverviewFilesCommitsIssuesDocsReleasesPeers

kodi-jacktook commits / 84706a8

Make inputstream.adaptive opt-in — it broke audio (1.15.5)
Engaging ISA for every .m3u8 was wrong twice over. It captured the single-variant rows as well as the adaptive one, so the fallback that was supposed to keep playing if ISA misbehaved was itself routed through ISA; and on this muxed HLS content -- audio inside the video segments, no EXT-X-MEDIA rendition -- ISA opens the aac decoder and then stalls: inputstream.adaptive: Manifest successfully parsed (Streams: 2, Type: live) CDVDAudioCodecFFmpeg::Open() Successful opened audio decoder aac CVideoPlayerAudio::Process - stream stalled No sound, on an episode that played fine through the bare ffmpeg demuxer. Measured on a ?h=480 row, i.e. a plain single variant that had nothing to do with adaptive playback. set_adaptive_stream() now returns early unless the source sets `adaptive`. Nothing sets it, so ISA is off and playback is back to what it was. The mechanism and its tests stay, because the reason to want ISA has not changed -- but it needs the muxed-audio stall understood before anything opts in. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
84706a873c613e5a72ad6b604405daf75cdd0177
by plankatron <fleeky@gmail.com> · 2026-08-10T22:12:22.000Z

Changed files (3) +27 -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.4" provider-name="Sam-Max">
2 <addon id="plugin.video.jacktook" name="Jacktook" version="1.15.5" 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 +10 -0
……@@ -88,6 +88,16 @@ 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:
92 # it captured the single-variant rows as well as the adaptive one, and on
93 # muxed HLS (audio inside the video segments, no EXT-X-MEDIA rendition) ISA
94 # opens the aac decoder and then stalls -- "CVideoPlayerAudio::Process -
95 # 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"):
99 return None
100
91101 url = data.get("url") or ""
92102 kind = adaptive_manifest_type(url)
93103 if not kind:
plugin.video.jacktook/tests/unit/test_adaptive_stream.py +16 -5
……@@ -31,7 +31,7 @@ def test_non_manifests_are_left_alone():
3131
3232def test_engages_isa_for_a_manifest():
3333 item = MagicMock()
34 url = set_adaptive_stream(item, {"url": "http://h:7220/a.m3u8?h=auto"})
34 url = set_adaptive_stream(item, {"adaptive": True, "url": "http://h:7220/a.m3u8?h=auto"})
3535 assert url == "http://h:7220/a.m3u8?h=auto"
3636 props = dict(c.args for c in item.setProperty.call_args_list)
3737 assert props["inputstream"] == "inputstream.adaptive"
……@@ -41,7 +41,7 @@ def test_engages_isa_for_a_manifest():
4141def test_leaves_other_sources_untouched():
4242 """A torrent/debrid/plugin URL must not be handed to ISA."""
4343 item = MagicMock()
44 assert set_adaptive_stream(item, {"url": "https://h/movie.mkv"}) is None
44 assert set_adaptive_stream(item, {"adaptive": True, "url": "https://h/movie.mkv"}) is None
4545 item.setProperty.assert_not_called()
4646
4747
……@@ -51,7 +51,7 @@ def test_strips_the_header_suffix_from_the_played_url():
5151 previous attempt fetched the variant playlist bare and took a 403."""
5252 item = MagicMock()
5353 url = set_adaptive_stream(
54 item, {"url": "http://h/a.m3u8|Referer=https%3A%2F%2Fvidcore.net%2F"}
54 item, {"adaptive": True, "url": "http://h/a.m3u8|Referer=https%3A%2F%2Fvidcore.net%2F"}
5555 )
5656 assert url == "http://h/a.m3u8"
5757 assert "|" not in url
……@@ -62,6 +62,7 @@ def test_headers_move_to_isa_properties():
6262 set_adaptive_stream(
6363 item,
6464 {
65 "adaptive": True,
6566 "url": "http://h/a.m3u8",
6667 "proxyHeaders": {"Referer": "https://vidcore.net/", "User-Agent": "UA/1.0"},
6768 },
……@@ -74,7 +75,7 @@ def test_headers_move_to_isa_properties():
7475
7576def test_no_header_properties_when_there_are_none():
7677 item = MagicMock()
77 set_adaptive_stream(item, {"url": "http://h/a.m3u8"})
78 set_adaptive_stream(item, {"adaptive": True, "url": "http://h/a.m3u8"})
7879 props = dict(c.args for c in item.setProperty.call_args_list)
7980 assert "inputstream.adaptive.manifest_headers" not in props
8081
……@@ -85,5 +86,15 @@ def test_mimetype_is_set_per_manifest_kind():
8586 ("http://h/a.mpd", "application/dash+xml"),
8687 ):
8788 item = MagicMock()
88 set_adaptive_stream(item, {"url": url})
89 set_adaptive_stream(item, {"adaptive": True, "url": url})
8990 item.setMimeType.assert_called_once_with(mime)
91
92
93def test_isa_is_off_unless_a_source_opts_in():
94 """Regression, 2026-08-10: engaging ISA for every .m3u8 captured the
95 single-variant rows too, and ISA stalls the audio on muxed HLS -- the aac
96 decoder opens and then no sound. Content that plays fine on the bare ffmpeg
97 demuxer must keep doing so."""
98 item = MagicMock()
99 assert set_adaptive_stream(item, {"url": "http://h/a.m3u8?h=480"}) is None
100 item.setProperty.assert_not_called()