OverviewFilesCommitsIssuesDocsReleasesPeers

stremio-vsembed commits / 5f982e5

vidcore: drop the adaptive row — ISA cannot play this CDN's audio (0.8.2)
Root cause, found by probing the media instead of the logs. Pulled an init segment and a media segment and ran ffprobe: init-s1080p-v1-a1.mp4 -> index=0 h264 video index=1 aac audio 48000Hz 2ch (real audio: mean_volume -32.0dB, max_volume -14.7dB, 577536 samples) Video and audio are MUXED into a single fMP4 track set. inputstream.adaptive builds its stream list from the manifest CODECS ("avc1...,mp4a..."), so it reports "Streams in first period: 2" and opens the aac decoder from that metadata -- but its HLS fMP4 reader only ever feeds the first track. The audio stream receives no samples, which is what "CVideoPlayerAudio::Process - stream stalled" reports, and the result is perfect video with no sound. ffmpeg demuxes the container itself, gets both tracks, and plays audio fine. This is an incompatibility in the media, not in how the stream is requested, which is why none of the property-level attempts worked: the mimetype and header properties were never the cause, and neither was the double open (both of those fixes were real, but they were fixing things that were not this). Consequence: on this source audio and seek are mutually exclusive. ffmpeg has audio and ignores seeks (request 50%, stay at 1.2%); ISA seeks correctly and is silent. Audio wins, so only the fixed-variant rows are offered. The ?h=auto ladder endpoint and the fork's opt-in marker are kept and still tested -- they are correct for a source whose audio is a separate rendition. Getting seek on THIS content needs different media: a progressive MP4, such as the one vidlink serves, seeks natively under ffmpeg. Lesson for the next person: "stream stalled" is not evidence of silence -- it appears in audible playback too. Probe the segment. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
5f982e50a6f332f7848afd48462299a4df7ec4ef
by plankatron <fleeky@gmail.com> · 2026-08-11T00:48:18.000Z

Changed files (3) +31 -19

addon.py +22 -10
……@@ -533,7 +533,7 @@ TV_GENRES = [
533533
534534MANIFEST = {
535535 "id": "org.tabertron.vsembed",
536 "version": "0.8.1",
536 "version": "0.8.2",
537537 "name": "Tabertron VsEmbed",
538538 "description": "Self-hosted HLS extractor with TMDB browse + search, played via vidcore",
539539 "types": ["movie", "series"],
……@@ -1072,15 +1072,27 @@ def _append_vidcore_row(out: list, kind: str, ident: Optional[str],
10721072 _prefetch_vidcore(kind, ident, season, episode)
10731073 except Exception as exc: # never let a warm-up break /stream
10741074 log.warning("vidcore prefetch could not start: %s", exc)
1075 # Auto first, fixed heights under it -- the two paths trade off against each
1076 # other and neither is strictly better yet:
1077 # Auto -> inputstream.adaptive. Seek and resume work (ffmpeg ignores a
1078 # seek on these fMP4 segments: 50% -> 1.2%, vs ISA 50% -> 14:07)
1079 # but audio is currently silent through Jacktook.
1080 # fixed -> bare ffmpeg. Audio works, seek does not.
1081 # Until the ISA audio problem is solved, offering only Auto would mean
1082 # offering only a silent stream, so the working path stays one click away.
1083 for height in (VIDCORE_AUTO, *VIDCORE_HEIGHTS):
1075 # Fixed variants only. The adaptive row is NOT offered: inputstream.adaptive
1076 # cannot play this CDN's audio, and the cause is in the media, not in how we
1077 # ask for it. Measured 2026-08-10 by pulling a segment and probing it:
1078 #
1079 # init-s1080p-v1-a1.mp4 -> index=0 h264 video
1080 # index=1 aac audio 48000Hz 2ch (real audio,
1081 # mean_volume -32.0dB, max -14.7dB)
1082 #
1083 # Video and audio are MUXED into one fMP4 track set. ISA builds its stream
1084 # list from the manifest CODECS ("avc1...,mp4a..."), so it reports two
1085 # streams and opens the aac decoder from that metadata, but its HLS fMP4
1086 # reader only feeds the first track -- the audio stream gets no samples,
1087 # which is the "CVideoPlayerAudio::Process - stream stalled" line, and the
1088 # result is perfect video with no sound. ffmpeg demuxes the container itself
1089 # and gets both tracks, which is why the fixed rows have audio.
1090 #
1091 # The cost is seek: ffmpeg accepts a seek on these segments and ignores it
1092 # (request 50%, stay at 1.2%), while ISA seeks correctly. On this source the
1093 # two are mutually exclusive, and audio wins. Seek needs a source that is not
1094 # muxed fMP4 HLS -- a progressive MP4 (vidlink) seeks natively under ffmpeg.
1095 for height in VIDCORE_HEIGHTS:
10841096 out.append(_stream_dict(
10851097 _vidcore_row(request.host, kind, ident, season, episode, height=height)))
10861098
test_vidcore_adaptive.py +7 -7
……@@ -171,15 +171,15 @@ def test_unresolvable_title_still_404s(client, monkeypatch):
171171
172172# --- the rows offered ------------------------------------------------------
173173
174def test_auto_first_then_fixed_heights(monkeypatch):
175 """Auto seeks but is currently silent through Jacktook; the fixed rows have
176 working audio. Both are offered until that is resolved."""
174def test_no_adaptive_row_is_offered(monkeypatch):
175 """ISA cannot play this CDN's audio: video and audio are muxed into one
176 fMP4 track set and ISA's HLS reader feeds only the first track, so the aac
177 decoder opens and never receives a sample. Offering the row would offer a
178 silent stream. The ?h=auto endpoint stays for a future non-muxed source."""
177179 monkeypatch.setattr(addon, '_prefetch_vidcore', lambda *a, **k: None)
178180 with addon.app.test_request_context('/stream/series/fxl:1:2:7.json'):
179181 out = []
180182 addon._append_vidcore_row(out, 'series', 'tmdb:1', 2, 7)
181 assert len(out) == 1 + len(addon.VIDCORE_HEIGHTS)
182 assert 'h=auto' in out[0]['url'] and 'adaptive=1' in out[0]['url']
183 assert [r['url'].split('h=')[1].split('&')[0] for r in out[1:]] == [str(h) for h in addon.VIDCORE_HEIGHTS]
184 assert not any('adaptive=1' in r['url'] for r in out[1:])
183 assert len(out) == len(addon.VIDCORE_HEIGHTS)
184 assert not any('adaptive=1' in r['url'] or 'h=auto' in r['url'] for r in out)
185185 assert all('S02E07' in r['title'] for r in out)
test_vidcore_prefetch.py +2 -2
……@@ -121,7 +121,7 @@ def test_stream_request_triggers_a_prefetch(monkeypatch):
121121 out = []
122122 addon._append_vidcore_row(out, KIND, IDENT, S, E)
123123 assert seen == [(KIND, IDENT, S, E)]
124 assert len(out) == 1 + len(addon.VIDCORE_HEIGHTS)
124 assert len(out) == len(addon.VIDCORE_HEIGHTS)
125125
126126
127127def test_a_known_miss_prefetches_nothing(monkeypatch):
……@@ -143,4 +143,4 @@ def test_prefetch_failure_never_breaks_the_stream_response(monkeypatch):
143143 with addon.app.test_request_context("/stream/series/fxl:138502:2:7.json"):
144144 out = []
145145 addon._append_vidcore_row(out, KIND, IDENT, S, E)
146 assert len(out) == 1 + len(addon.VIDCORE_HEIGHTS)
146 assert len(out) == len(addon.VIDCORE_HEIGHTS)