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:
1 parent
1154203569
commit
e3ef51d141
4 files changed
+23
-33
No files matched your search
+11
-23
@@ -61,23 +61,19 @@ _DEGRADED_RETRY = 1800
|
||||
# origin (primary provider pages/API) health — separate host, separate failure
|
||||
# mode (observed 2026-09-03: CDN fine while origin 503'd "Under Maintenance")
|
||||
_ORIGIN = {"state": "unknown", "msg": "", "ts": 0.0, "hist": []}
|
||||
# ponytail: fixed threshold; if the CDN's normal throughput drifts below it
|
||||
# the pill sits on "slow" — tune via ANIWEB_CDN_KBPS, not a percentile.
|
||||
# kept for the /api/cdn response shape (the panel shows it only when a rate
|
||||
# was actually measured; the probe now checks reachability, not throughput)
|
||||
_CDN_THRESHOLD = float(os.environ.get("ANIWEB_CDN_KBPS", "40"))
|
||||
|
||||
|
||||
def _cdn_probe():
|
||||
"""Background probe: pull 64KB from the CDN and log state flips, so
|
||||
server.log shows when a degraded window ends (CDN RECOVERED). Skipped
|
||||
"""Background probe: fetch ONE small playlist and log state flips, so
|
||||
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).
|
||||
Probe target: ep_id 1 = One Piece E1 on the primary provider.
|
||||
ponytail: single fixed episode; if it ever disappears, the probe logs
|
||||
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
|
||||
while True:
|
||||
if time.time() - _LAST_PLAY > _IDLE_SECS:
|
||||
@@ -89,23 +85,15 @@ def _cdn_probe():
|
||||
raise RuntimeError("no master m3u8")
|
||||
# hianime's CDN 403s without the embed-origin Referer (anidb needs none)
|
||||
hdrs = upstream.stream_meta(m) or {}
|
||||
base = m.rsplit("/", 1)[0] + "/"
|
||||
v = first(upstream._get(m, timeout=10, headers=hdrs).text, base)
|
||||
# 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)
|
||||
upstream._get(m, timeout=10, headers=hdrs)
|
||||
now = "OK"
|
||||
except Exception:
|
||||
kbps = 0.0
|
||||
now = "OK" if kbps >= _CDN_THRESHOLD else "DEGRADED"
|
||||
now = "DEGRADED"
|
||||
if now != state:
|
||||
print(f"[probe] CDN {now} ({kbps:.0f} KB/s)", flush=True)
|
||||
print(f"[probe] CDN {now}", flush=True)
|
||||
state = now
|
||||
_CDN.update(state=now, kbps=round(kbps), ts=time.time())
|
||||
_CDN["hist"].append({"t": time.time(), "kbps": round(kbps)})
|
||||
_CDN.update(state=now, kbps=0, ts=time.time())
|
||||
_CDN["hist"].append({"t": time.time(), "kbps": 0})
|
||||
del _CDN["hist"][:-20]
|
||||
_origin_probe()
|
||||
time.sleep(_DEGRADED_RETRY if now == "DEGRADED" else 180)
|
||||
|
||||
@@ -117,7 +117,8 @@ def _master_m3u8(ep_id, lang="eng"):
|
||||
url = (d.get("result") or {}).get("url")
|
||||
if not url:
|
||||
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:
|
||||
f = _player_file(url)
|
||||
if not f:
|
||||
|
||||
@@ -105,13 +105,14 @@ def _embed_payload(embed):
|
||||
if not mid:
|
||||
return None, [], None
|
||||
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)}",
|
||||
headers={"Referer": embed, "X-Requested-With": "XMLHttpRequest"},
|
||||
timeout=15).json())
|
||||
src = (d.get("sources") or {}).get("file")
|
||||
if not src:
|
||||
continue
|
||||
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)):
|
||||
|
||||
+7
-7
@@ -957,12 +957,12 @@ function renderPill(d) {
|
||||
p.querySelector(".d").className = "d" + (st ? " " + st : "");
|
||||
p.querySelector("span").textContent =
|
||||
!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 : "")
|
||||
+ " · 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"
|
||||
: 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"));
|
||||
}
|
||||
|
||||
@@ -982,12 +982,12 @@ function renderStatusPanel(d) {
|
||||
w.replaceChildren();
|
||||
w.append(el("div", "sp-row", "upstream: " + d.origin.state
|
||||
+ (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 || [];
|
||||
if (ch.length > 1) {
|
||||
w.append(sparkline(ch.map(s => s.kbps), d.threshold));
|
||||
w.append(el("div", "sp-cap", "CDN, last " + _mins(ch)
|
||||
+ " min (dashed = slow threshold " + Math.round(d.threshold) + " KB/s)"));
|
||||
w.append(sparkline(ch.map(s => s.kbps), d.kbps ? d.threshold : null));
|
||||
w.append(el("div", "sp-cap", "CDN, last " + _mins(ch) + " min"
|
||||
+ (d.kbps ? " (dashed = slow threshold " + Math.round(d.threshold) + " KB/s)" : "")));
|
||||
}
|
||||
const oh = d.origin.hist || [];
|
||||
if (oh.length > 1) {
|
||||
|
||||
Reference in new issue
Block a user