Stop spamming upstream: drop video download from probe, kill re-rolls

- CDN probe no longer downloads 64KB of video (or even a variant
  playlist): one small master-playlist fetch proves reachability.
  State stays OK/DEGRADED, kbps is no longer measured, and the pill/
  panel only show a rate when one exists.
- hianime: 5x getSourcesNew re-roll -> 1 attempt. The enc payload is
  deterministic per data-id (observed identical across calls), so
  re-rolling only hammered the provider.
- anikoto: 2x re-roll -> 1 attempt per server, same reason.

Kept: idle-gated + 30-min degraded backoff from the previous commit,
the single _get retry (protects real user playback from CF blips),
and the origin page check (the 'down' signal). Net upstream traffic is
now what an actual viewer would generate, nothing more.
This commit is contained in:
jozamudi committed 2026-09-29 17:33:54 +00:00
1 parent 1154203569
commit e3ef51d141
4 files changed
+23 -33

No files matched your search

+11 -23
View File
@@ -61,23 +61,19 @@ _DEGRADED_RETRY = 1800
# origin (primary provider pages/API) health — separate host, separate failure # origin (primary provider pages/API) health — separate host, separate failure
# mode (observed 2026-09-03: CDN fine while origin 503'd "Under Maintenance") # mode (observed 2026-09-03: CDN fine while origin 503'd "Under Maintenance")
_ORIGIN = {"state": "unknown", "msg": "", "ts": 0.0, "hist": []} _ORIGIN = {"state": "unknown", "msg": "", "ts": 0.0, "hist": []}
# ponytail: fixed threshold; if the CDN's normal throughput drifts below it # kept for the /api/cdn response shape (the panel shows it only when a rate
# the pill sits on "slow" — tune via ANIWEB_CDN_KBPS, not a percentile. # was actually measured; the probe now checks reachability, not throughput)
_CDN_THRESHOLD = float(os.environ.get("ANIWEB_CDN_KBPS", "40")) _CDN_THRESHOLD = float(os.environ.get("ANIWEB_CDN_KBPS", "40"))
def _cdn_probe(): def _cdn_probe():
"""Background probe: pull 64KB from the CDN and log state flips, so """Background probe: fetch ONE small playlist and log state flips, so
server.log shows when a degraded window ends (CDN RECOVERED). Skipped server.log shows when a degraded window ends (CDN RECOVERED). No video
is downloaded just to light a status dot. Skipped
while the app is idle and backed off while DEGRADED (see _LAST_PLAY). while the app is idle and backed off while DEGRADED (see _LAST_PLAY).
Probe target: ep_id 1 = One Piece E1 on the primary provider. Probe target: ep_id 1 = One Piece E1 on the primary provider.
ponytail: single fixed episode; if it ever disappears, the probe logs ponytail: single fixed episode; if it ever disappears, the probe logs
DEGRADED forever — swap the ID, don't build a picker.""" DEGRADED forever — swap the ID, don't build a picker."""
def first(pl, base):
l = next(x.strip() for x in pl.splitlines()
if x.strip() and not x.startswith("#"))
return l if l.startswith("http") else base + l
state = None state = None
while True: while True:
if time.time() - _LAST_PLAY > _IDLE_SECS: if time.time() - _LAST_PLAY > _IDLE_SECS:
@@ -89,23 +85,15 @@ def _cdn_probe():
raise RuntimeError("no master m3u8") raise RuntimeError("no master m3u8")
# hianime's CDN 403s without the embed-origin Referer (anidb needs none) # hianime's CDN 403s without the embed-origin Referer (anidb needs none)
hdrs = upstream.stream_meta(m) or {} hdrs = upstream.stream_meta(m) or {}
base = m.rsplit("/", 1)[0] + "/" upstream._get(m, timeout=10, headers=hdrs)
v = first(upstream._get(m, timeout=10, headers=hdrs).text, base) now = "OK"
# hianime's variant playlists use URIs relative to THEIR OWN path
vbase = v.rsplit("/", 1)[0] + "/"
seg = first(upstream._get(v, timeout=10, headers=hdrs).text, vbase)
t = time.time()
r = upstream._session().get(seg, headers={**hdrs, "Range": "bytes=0-65535"},
impersonate="chrome", timeout=10)
kbps = len(r.content) / 1024 / max(time.time() - t, 0.01)
except Exception: except Exception:
kbps = 0.0 now = "DEGRADED"
now = "OK" if kbps >= _CDN_THRESHOLD else "DEGRADED"
if now != state: if now != state:
print(f"[probe] CDN {now} ({kbps:.0f} KB/s)", flush=True) print(f"[probe] CDN {now}", flush=True)
state = now state = now
_CDN.update(state=now, kbps=round(kbps), ts=time.time()) _CDN.update(state=now, kbps=0, ts=time.time())
_CDN["hist"].append({"t": time.time(), "kbps": round(kbps)}) _CDN["hist"].append({"t": time.time(), "kbps": 0})
del _CDN["hist"][:-20] del _CDN["hist"][:-20]
_origin_probe() _origin_probe()
time.sleep(_DEGRADED_RETRY if now == "DEGRADED" else 180) time.sleep(_DEGRADED_RETRY if now == "DEGRADED" else 180)
+2 -1
View File
@@ -117,7 +117,8 @@ def _master_m3u8(ep_id, lang="eng"):
url = (d.get("result") or {}).get("url") url = (d.get("result") or {}).get("url")
if not url: if not url:
continue continue
for _ in range(2): # re-roll: CDN domains rotate, most 403 our IP # ponytail: one attempt per server — the enc payload is deterministic,
# re-rolling would just spam the provider
try: try:
f = _player_file(url) f = _player_file(url)
if not f: if not f:
+3 -2
View File
@@ -105,13 +105,14 @@ def _embed_payload(embed):
if not mid: if not mid:
return None, [], None return None, [], None
host = re.match(r'https?://([^/]+)', embed).group(1) host = re.match(r'https?://([^/]+)', embed).group(1)
for _ in range(5): # ponytail: one attempt — the enc payload is deterministic per data-id,
# so re-rolling getSourcesNew would just spam the provider
d = megaplay_sources(_get(f"https://{host}/stream/getSourcesNew?id={mid.group(1)}", d = megaplay_sources(_get(f"https://{host}/stream/getSourcesNew?id={mid.group(1)}",
headers={"Referer": embed, "X-Requested-With": "XMLHttpRequest"}, headers={"Referer": embed, "X-Requested-With": "XMLHttpRequest"},
timeout=15).json()) timeout=15).json())
src = (d.get("sources") or {}).get("file") src = (d.get("sources") or {}).get("file")
if not src: if not src:
continue return None, [], None
subs = [{"label": (x or {}).get("label", ""), "src": (x or {}).get("file")} subs = [{"label": (x or {}).get("label", ""), "src": (x or {}).get("file")}
for x in d.get("tracks") or []] for x in d.get("tracks") or []]
for cand, refr in (({"Referer": embed}, embed), ({}, None)): for cand, refr in (({"Referer": embed}, embed), ({}, None)):
+7 -7
View File
@@ -957,12 +957,12 @@ function renderPill(d) {
p.querySelector(".d").className = "d" + (st ? " " + st : ""); p.querySelector(".d").className = "d" + (st ? " " + st : "");
p.querySelector("span").textContent = p.querySelector("span").textContent =
!st ? "…" : st === "down" ? "down" !st ? "…" : st === "down" ? "down"
: st === "slow" ? "slow · " + d.kbps + " KB/s" : "up"; : st === "slow" ? "slow" + (d.kbps ? " · " + d.kbps + " KB/s" : "") : "up";
p.title = "upstream site: " + d.origin.state + (d.origin.msg ? " — " + d.origin.msg : "") p.title = "upstream site: " + d.origin.state + (d.origin.msg ? " — " + d.origin.msg : "")
+ " · video CDN: " + d.state + " — " + d.kbps + " KB/s"; + " · video CDN: " + d.state + (d.kbps ? " — " + d.kbps + " KB/s" : "");
p.setAttribute("aria-label", "status: " + (!st ? "checking" p.setAttribute("aria-label", "status: " + (!st ? "checking"
: st === "down" ? "down — upstream " + d.origin.state : st === "down" ? "down — upstream " + d.origin.state
: st === "slow" ? "slow — CDN " + d.state + ", " + d.kbps + " KB/s" : st === "slow" ? "slow — CDN " + d.state + (d.kbps ? ", " + d.kbps + " KB/s" : "")
: "up")); : "up"));
} }
@@ -982,12 +982,12 @@ function renderStatusPanel(d) {
w.replaceChildren(); w.replaceChildren();
w.append(el("div", "sp-row", "upstream: " + d.origin.state w.append(el("div", "sp-row", "upstream: " + d.origin.state
+ (d.origin.msg ? " (" + d.origin.msg + ")" : ""))); + (d.origin.msg ? " (" + d.origin.msg + ")" : "")));
w.append(el("div", "sp-row", "CDN: " + d.state + " — " + d.kbps + " KB/s")); w.append(el("div", "sp-row", "CDN: " + d.state + (d.kbps ? " — " + d.kbps + " KB/s" : "")));
const ch = d.hist || []; const ch = d.hist || [];
if (ch.length > 1) { if (ch.length > 1) {
w.append(sparkline(ch.map(s => s.kbps), d.threshold)); w.append(sparkline(ch.map(s => s.kbps), d.kbps ? d.threshold : null));
w.append(el("div", "sp-cap", "CDN, last " + _mins(ch) w.append(el("div", "sp-cap", "CDN, last " + _mins(ch) + " min"
+ " min (dashed = slow threshold " + Math.round(d.threshold) + " KB/s)")); + (d.kbps ? " (dashed = slow threshold " + Math.round(d.threshold) + " KB/s)" : "")));
} }
const oh = d.origin.hist || []; const oh = d.origin.hist || [];
if (oh.length > 1) { if (oh.length > 1) {