| … | … | @@ -533,7 +533,7 @@ TV_GENRES = [ |
| 533 | 533 | |
| 534 | 534 | MANIFEST = { |
| 535 | 535 | "id": "org.tabertron.vsembed", |
| 536 | "version": "0.8.0", | |
| 536 | "version": "0.8.1", | |
| 537 | 537 | "name": "Tabertron VsEmbed", |
| 538 | 538 | "description": "Self-hosted HLS extractor with TMDB browse + search, played via vidcore", |
| 539 | 539 | "types": ["movie", "series"], |
| … | … | @@ -1072,14 +1072,17 @@ def _append_vidcore_row(out: list, kind: str, ident: Optional[str], |
| 1072 | 1072 | _prefetch_vidcore(kind, ident, season, episode) |
| 1073 | 1073 | except Exception as exc: # never let a warm-up break /stream |
| 1074 | 1074 | log.warning("vidcore prefetch could not start: %s", exc) |
| 1075 | # ONE row. The client picks nothing: inputstream.adaptive chooses the rung | |
| 1076 | # and adapts, which is the only form of "choose a quality" that is reachable | |
| 1077 | # from a remote app like Kore -- it cannot drive Kodi's player OSD. The | |
| 1078 | # ladder is also what makes seek work: measured on the Pi, the bare ffmpeg | |
| 1079 | # demuxer ignores a seek on these fMP4 segments (50% -> 1.2%) while ISA | |
| 1080 | # lands it (50% -> 14:07). | |
| 1081 | out.append(_stream_dict( | |
| 1082 | _vidcore_row(request.host, kind, ident, season, episode, height=VIDCORE_AUTO))) | |
| 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): | |
| 1084 | out.append(_stream_dict( | |
| 1085 | _vidcore_row(request.host, kind, ident, season, episode, height=height))) | |
| 1083 | 1086 | |
| 1084 | 1087 | |
| 1085 | 1088 | @app.route("/stream/movie/<path:ident>.json") |
| … | … | @@ -171,21 +171,15 @@ def test_unresolvable_title_still_404s(client, monkeypatch): |
| 171 | 171 | |
| 172 | 172 | # --- the rows offered ------------------------------------------------------ |
| 173 | 173 | |
| 174 | def test_a_single_adaptive_row_is_offered(monkeypatch): | |
| 175 | """One row, no choosing: Kore cannot drive Kodi's OSD, so quality has to be | |
| 176 | handled by ISA rather than by picking a row up front.""" | |
| 174 | def 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.""" | |
| 177 | 177 | monkeypatch.setattr(addon, '_prefetch_vidcore', lambda *a, **k: None) |
| 178 | 178 | with addon.app.test_request_context('/stream/series/fxl:1:2:7.json'): |
| 179 | 179 | out = [] |
| 180 | 180 | addon._append_vidcore_row(out, 'series', 'tmdb:1', 2, 7) |
| 181 | assert len(out) == 1 | |
| 182 | assert 'h=auto' in out[0]['url'] | |
| 183 | assert 'adaptive=1' in out[0]['url'] | |
| 184 | assert 'S02E07' in out[0]['title'] | |
| 185 | ||
| 186 | ||
| 187 | def test_only_the_adaptive_row_asks_for_isa(): | |
| 188 | """A fixed-height URL must never carry the opt-in marker: ISA stalls the | |
| 189 | audio on a single-variant media playlist.""" | |
| 190 | row = addon._vidcore_row('h:1', 'series', 'tmdb:1', 2, 7, height=1080) | |
| 191 | assert 'adaptive=1' not in row.url | |
| 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:]) | |
| 185 | assert all('S02E07' in r['title'] for r in out) |
| … | … | @@ -121,7 +121,7 @@ def test_stream_request_triggers_a_prefetch(monkeypatch): |
| 121 | 121 | out = [] |
| 122 | 122 | addon._append_vidcore_row(out, KIND, IDENT, S, E) |
| 123 | 123 | assert seen == [(KIND, IDENT, S, E)] |
| 124 | assert len(out) == 1 # single adaptive row | |
| 124 | assert len(out) == 1 + len(addon.VIDCORE_HEIGHTS) | |
| 125 | 125 | |
| 126 | 126 | |
| 127 | 127 | def test_a_known_miss_prefetches_nothing(monkeypatch): |
| … | … | @@ -143,4 +143,4 @@ def test_prefetch_failure_never_breaks_the_stream_response(monkeypatch): |
| 143 | 143 | with addon.app.test_request_context("/stream/series/fxl:138502:2:7.json"): |
| 144 | 144 | out = [] |
| 145 | 145 | addon._append_vidcore_row(out, KIND, IDENT, S, E) |
| 146 | assert len(out) == 1 | |
| 146 | assert len(out) == 1 + len(addon.VIDCORE_HEIGHTS) |