OverviewFilesCommitsIssuesDocsReleasesPeers

stremio-vsembed commits / 555f6ca

Vidcore rows prefer the local copy too (0.12.2)
Closes design item C on labs#5. Playing "720p vidcore" on a title already in the library streamed from the CDN, ignoring the seekable file on disk -- only the /mp4/ route and the row had been wired to prefer local. The substance is the ORDERING, not the redirect: the check happens before _resolve_vidcore, so a title we already hold no longer costs an ~11s browser resolve to play. It redirects rather than serving inline, which hands the player a URL that actually ends in .mp4 and routes through /mp4/ -- the single place local files are served, so Range support and rolling forward are not duplicated. 4 new tests, 138 pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
555f6ca426ebb8199a1a3339cf28dfdb1ca81fef
by plankatron <fleeky@gmail.com> · 2026-08-11T15:28:27.000Z

Changed files (2) +76 -5

addon.py +32 -5
……@@ -533,7 +533,7 @@ TV_GENRES = [
533533
534534MANIFEST = {
535535 "id": "org.tabertron.vsembed",
536 "version": "0.12.1",
536 "version": "0.12.2",
537537 "name": "Tabertron VsEmbed",
538538 "description": "Self-hosted HLS extractor with TMDB browse + search, played via vidcore",
539539 "types": ["movie", "series"],
……@@ -1007,6 +1007,26 @@ def _serve_vidcore(url: str):
10071007 return redirect(_cap_variant(url, _requested_height()), code=302)
10081008
10091009
1010def _local_redirect(kind: str, ident: str, season: int, episode: int,
1011 height: int):
1012 """302 to the local copy when we hold one, else None.
1013
1014 Checked BEFORE resolving, which is the substance of this rather than the
1015 redirect itself: a resolve costs ~11s and launches a browser, and paying
1016 that for a title already sitting on disk is pure waste.
1017
1018 Redirecting rather than serving inline hands the player a URL that actually
1019 ends in .mp4, and routes it through /mp4/ — the single place local files are
1020 served, so Range support and rolling forward are not duplicated here.
1021 """
1022 if not _playable_path(kind, ident, season, episode, height):
1023 return None
1024 path = (f"/mp4/series/{ident}:{season}:{episode}.mp4" if kind == "series"
1025 else f"/mp4/movie/{ident}.mp4")
1026 log.info("vidcore: serving %s from the local copy", ident)
1027 return redirect(f"{path}?h={height}", code=302)
1028
1029
10101030def _log_client_headers(route: str) -> None:
10111031 """Record which request headers the client actually forwarded.
10121032
……@@ -1023,12 +1043,16 @@ def vidcore_movie(ident: str):
10231043 _log_client_headers("vidcore/movie")
10241044 if not re.fullmatch(VIDCORE_IDENT, ident):
10251045 abort(404)
1046 height = _requested_height()
1047 local = _local_redirect("movie", ident, 0, 0, height)
1048 if local:
1049 return local
10261050 url = _resolve_vidcore("movie", ident)
10271051 if not url:
10281052 abort(404)
10291053 # Playing is the honest "I chose this" signal, so keep a copy of what is
10301054 # being watched. Idempotent, and skipped when the library already has it.
1031 _ensure_ingest("movie", ident, height=_requested_height())
1055 _ensure_ingest("movie", ident, height=height)
10321056 return _serve_vidcore(url)
10331057
10341058
……@@ -1038,11 +1062,14 @@ def vidcore_series(ident: str):
10381062 m = re.fullmatch(rf"({VIDCORE_IDENT}):(\d+):(\d+)", ident)
10391063 if not m:
10401064 abort(404)
1041 url = _resolve_vidcore("series", m.group(1), int(m.group(2)), int(m.group(3)))
1042 if not url:
1043 abort(404)
10441065 season, episode = int(m.group(2)), int(m.group(3))
10451066 height = _requested_height()
1067 local = _local_redirect("series", m.group(1), season, episode, height)
1068 if local:
1069 return local
1070 url = _resolve_vidcore("series", m.group(1), season, episode)
1071 if not url:
1072 abort(404)
10461073 _ensure_ingest("series", m.group(1), season, episode, height=height)
10471074 _queue_next_episode(m.group(1), season, episode, height)
10481075 return _serve_vidcore(url)
test_library_ingest.py +44 -0
……@@ -612,6 +612,50 @@ def test_a_tmdb_failure_stops_rolling_rather_than_guessing(rolling, monkeypatch)
612612 assert addon._next_episode("1", 1, 1) is None
613613
614614
615# --- the vidcore rows also prefer a local copy ------------------------------
616
617def test_a_vidcore_row_redirects_to_the_local_copy(rolling):
618 """Playing "720p vidcore" on a title already in the library streamed from
619 the CDN, ignoring the seekable file sitting on disk."""
620 dest = addon._library_path("series", "Show", "2020", "1",
621 season=1, episode=1, episode_title="E1")
622 os.makedirs(os.path.dirname(dest), exist_ok=True)
623 open(dest, "wb").write(b"x" * 10)
624 r = addon.app.test_client().get("/vidcore/series/tmdb:1:1:1.m3u8?h=720")
625 assert r.status_code == 302
626 assert "/mp4/series/tmdb:1:1:1.mp4" in r.headers["Location"]
627
628
629def test_the_local_check_happens_before_the_browser_resolve(rolling, monkeypatch):
630 """A resolve costs ~11s and launches a browser. Paying that for a title we
631 already hold on disk is the whole point of checking first."""
632 resolved = []
633 monkeypatch.setattr(addon, "_resolve_vidcore",
634 lambda *a, **k: resolved.append(a) or "http://cdn/m.m3u8")
635 dest = addon._library_path("series", "Show", "2020", "1",
636 season=1, episode=1, episode_title="E1")
637 os.makedirs(os.path.dirname(dest), exist_ok=True)
638 open(dest, "wb").write(b"x" * 10)
639 addon.app.test_client().get("/vidcore/series/tmdb:1:1:1.m3u8?h=720")
640 assert resolved == [], "no browser should be launched for a local title"
641
642
643def test_without_a_local_copy_the_vidcore_row_still_streams(rolling):
644 r = addon.app.test_client().get("/vidcore/series/tmdb:1:1:1.m3u8?h=720")
645 assert r.status_code == 302
646 assert "/mp4/" not in r.headers["Location"]
647
648
649def test_a_movie_vidcore_row_also_prefers_the_local_copy(rolling, tmdb):
650 tmdb.responses["movie/5"] = {"title": "Film", "release_date": "2020-01-01"}
651 dest = addon._library_path("movie", "Film", "2020", "5")
652 os.makedirs(os.path.dirname(dest), exist_ok=True)
653 open(dest, "wb").write(b"x" * 10)
654 r = addon.app.test_client().get("/vidcore/movie/tmdb:5.m3u8?h=720")
655 assert r.status_code == 302
656 assert "/mp4/movie/tmdb:5.mp4" in r.headers["Location"]
657
658
615659def test_ingest_resolves_at_run_time_not_at_queue_time(ingest, monkeypatch):
616660 """Variant URLs are signed and expire in ~4h. A job that resolved when it
617661 was queued would fetch a dead link once the queue backs up."""