Add animekai source with 1anime direct-MP4 backend (independent CDN)
animekai.be fronted two server backends per episode: megaplay.buzz (same player/CDN family as hianime — 403s our egress IP) and my.1anime.site (direct progressive MP4, independent CDN — verified serving our IP at ~2.4MB/s). This is the rescue path around the MegaPlay Cloudflare block, per the ani-cli #1945/#1918 work. - providers/animekai.py: standard interface, per-episode backend dispatch (1anime first, then megaplay), same listed-but-dead -> raise semantics as hianime. All endpoints ride the shared TTL cache (no re-fetching on repeat UI hits). - upstream.py: megaplay_master() moved out of hianime — the MegaPlay chain (embed -> data-id -> getSourcesNew -> enc decrypt -> CDN proof) is now shared by every provider fronting that player. - app.py: /stream forwards Range for progressive files (206 + Content-Range passthrough, partial bodies never LRU-cached, 8MB cap on the parallel path so a 250MB MP4 can't pin RAM). api_stream reports hls=true/false from the URL — the player kind is a property of the URL, so future stream types slot in without app changes. - app.js: hls===false -> native <video> (existing Range-seeking), hls.js path untouched. - run.sh: ANI_SOURCE=animekai,hianime,anidb,anikoto (revert to the old chain when the MegaPlay block lifts). - tests: test_animekai.py (offline: interface, enc decrypt, /stream Range via monkeypatched network) + test_animekai_live.py (opt-in ANI_LIVE=1 end-to-end, skipped by default so the suite never touches animekai.be).
This commit is contained in:
1 parent
e3ef51d141
commit
d12ff79d29
8 files changed
+504
-35
No files matched your search
@@ -79,6 +79,39 @@ def megaplay_sources(d):
|
||||
return d
|
||||
|
||||
|
||||
def megaplay_master(embed, referer):
|
||||
"""MegaPlay embed url -> (master_url, [{label, src} subs], referer_or_None).
|
||||
|
||||
Shared by every provider fronting the MegaPlay player (hianime,
|
||||
animekai): embed page (referer-gated) -> data-id -> getSourcesNew
|
||||
(megaplay_sources) -> prove the CDN serves us, remembering which
|
||||
Referer variant worked. referer = the front site's home (the embed
|
||||
page 403s a stub without it). One attempt: the enc payload is
|
||||
deterministic per data-id, re-rolling would just spam the provider.
|
||||
The caller registers the returned master's hosts in its own
|
||||
/stream allowlist."""
|
||||
page = _get(embed, headers={"Referer": referer}, timeout=15).text
|
||||
mid = re.search(r'data-id="(\d+)"', page)
|
||||
if not mid:
|
||||
return None, [], None
|
||||
host = re.match(r'https?://([^/]+)', embed).group(1)
|
||||
d = megaplay_sources(_get(f"https://{host}/stream/getSourcesNew?id={mid.group(1)}",
|
||||
headers={"Referer": embed, "X-Requested-With": "XMLHttpRequest"},
|
||||
timeout=15).json())
|
||||
src = (d.get("sources") or {}).get("file")
|
||||
if not src:
|
||||
return None, [], None
|
||||
subs = [{"label": (x or {}).get("label", ""), "src": (x or {}).get("file")}
|
||||
for x in d.get("tracks") or []]
|
||||
for cand, refr in (({"Referer": embed}, embed), ({}, None)):
|
||||
try:
|
||||
_get(src, headers=cand, timeout=10)
|
||||
return src, subs, refr
|
||||
except Exception:
|
||||
continue
|
||||
return None, [], None
|
||||
|
||||
|
||||
def _get(url, **kw):
|
||||
# ponytail: one retry (300ms) on transient upstream errors (Cloudflare
|
||||
# 403/503, 429, 5xx); 404 and other 4xx are final. Failing fast matters:
|
||||
|
||||
Reference in new issue
Block a user