| … | … | @@ -533,7 +533,7 @@ TV_GENRES = [ |
| 533 | 533 | |
| 534 | 534 | MANIFEST = { |
| 535 | 535 | "id": "org.tabertron.vsembed", |
| 536 | | "version": "0.12.1", |
| 536 | "version": "0.12.2", |
| 537 | 537 | "name": "Tabertron VsEmbed", |
| 538 | 538 | "description": "Self-hosted HLS extractor with TMDB browse + search, played via vidcore", |
| 539 | 539 | "types": ["movie", "series"], |
| … | … | @@ -1007,6 +1007,26 @@ def _serve_vidcore(url: str): |
| 1007 | 1007 | return redirect(_cap_variant(url, _requested_height()), code=302) |
| 1008 | 1008 | |
| 1009 | 1009 | |
| 1010 | def _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 | |
| 1010 | 1030 | def _log_client_headers(route: str) -> None: |
| 1011 | 1031 | """Record which request headers the client actually forwarded. |
| 1012 | 1032 | |
| … | … | @@ -1023,12 +1043,16 @@ def vidcore_movie(ident: str): |
| 1023 | 1043 | _log_client_headers("vidcore/movie") |
| 1024 | 1044 | if not re.fullmatch(VIDCORE_IDENT, ident): |
| 1025 | 1045 | abort(404) |
| 1046 | height = _requested_height() |
| 1047 | local = _local_redirect("movie", ident, 0, 0, height) |
| 1048 | if local: |
| 1049 | return local |
| 1026 | 1050 | url = _resolve_vidcore("movie", ident) |
| 1027 | 1051 | if not url: |
| 1028 | 1052 | abort(404) |
| 1029 | 1053 | # Playing is the honest "I chose this" signal, so keep a copy of what is |
| 1030 | 1054 | # 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) |
| 1032 | 1056 | return _serve_vidcore(url) |
| 1033 | 1057 | |
| 1034 | 1058 | |
| … | … | @@ -1038,11 +1062,14 @@ def vidcore_series(ident: str): |
| 1038 | 1062 | m = re.fullmatch(rf"({VIDCORE_IDENT}):(\d+):(\d+)", ident) |
| 1039 | 1063 | if not m: |
| 1040 | 1064 | 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) |
| 1044 | 1065 | season, episode = int(m.group(2)), int(m.group(3)) |
| 1045 | 1066 | 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) |
| 1046 | 1073 | _ensure_ingest("series", m.group(1), season, episode, height=height) |
| 1047 | 1074 | _queue_next_episode(m.group(1), season, episode, height) |
| 1048 | 1075 | return _serve_vidcore(url) |