Subtitles: wire hianime's external .vtt into the player

- hianime.py: capture the first .vtt from the deobfuscated embed JSON
  (SUBS), expose subtitles(ep_id)
- upstream.py: subtitles() dispatcher (None for anidb, which bakes subs in)
- app.py: /api/episode/{id}/stream also returns a 'sub' stream token
- app.js: add a native <track> after hls.attachMedia (hls.js _cleanTracks
  disables tracks present at attach time — that silently killed earlier
  attempts) and set mode=showing so Chrome fetches the cues
This commit is contained in:
jozamudi committed 2026-09-07 02:46:28 +00:00
1 parent 834ca80a8c
commit 5b8170ece0
4 files changed
+37 -1

No files matched your search

+5 -1
View File
@@ -533,7 +533,11 @@ def api_stream(ep_id: int, lang: str = "jpn", request: Request = None):
master = _upstream(upstream.master_m3u8, ep_id, lang)
if not master:
raise HTTPException(404, f"no {lang} stream for episode {ep_id}")
return {"token": _b64(master)}
out = {"token": _b64(master)}
sub = upstream.subtitles(ep_id) # external .vtt (hianime); anidb bakes subs in
if sub:
out["sub"] = _b64(sub)
return out
try:
out = go()
+9
View File
@@ -20,6 +20,7 @@ KEY = b"otaku-embed-v1"
REFERER = None # embed origin, set when a master playlist is resolved
STREAM_HOSTS = set() # playlist/segment hosts the /stream proxy may fetch
SUBS = {} # ep_id -> external .vtt url (the player bakes no subs)
def _search(q):
@@ -107,6 +108,9 @@ def _master_m3u8(ep_id, lang="eng"):
if line and not line.startswith("#"):
hosts.add(urlparse(urljoin(master, line)).netloc)
STREAM_HOSTS |= hosts
subs = j.get("subtitles") or []
if subs and (subs[0] or {}).get("src"):
SUBS[ep_id] = subs[0]["src"] # first track is the english one
return master
return None
@@ -124,3 +128,8 @@ def stream_meta(url):
if REFERER and urlparse(url).netloc in STREAM_HOSTS:
return {"Referer": REFERER}
return None
def subtitles(ep_id):
"""External .vtt for this episode, or None (anidb bakes subs in)."""
return SUBS.get(ep_id)
+11
View File
@@ -205,6 +205,17 @@ def stream_meta(url):
return None
def subtitles(ep_id):
"""External .vtt url for an episode, or None (anidb bakes subs in)."""
for p in _providers():
fn = getattr(_prov(p), "subtitles", None)
if fn:
v = fn(ep_id)
if v:
return v
return None
if __name__ == "__main__":
# ponytail: assert self-check instead of a test framework.
# Needs a live source: ANI_SOURCE=<provider> python -m server.upstream