Background CDN probe: log throughput + state flips every 3 min

64KB Range fetch from a fixed episode (JJK S2 E25) on a daemon thread;
logs '[probe] CDN OK/DEGRADED (N KB/s)' on state change so server.log
shows exactly when a degraded window ends. 18/18 tests, verified live.
This commit is contained in:
jozamudi committed 2026-08-31 15:17:20 +00:00
1 parent 4c5dbab4b0
commit eea538ab17
1 file changed
+37
+37
View File
@@ -7,6 +7,7 @@ Cloudflare workaround) and rewrites playlist URIs to go through itself.
import base64
import json
import os
import threading
import time
from collections import Counter, OrderedDict
from datetime import datetime
@@ -24,6 +25,42 @@ from . import db, upstream, users
ROOT = Path(__file__).parent.parent
app = FastAPI(title="ani-web")
def _cdn_probe():
"""Background probe: pull 64KB from the CDN every 3 min and log state
flips, so server.log shows when a degraded window ends (CDN RECOVERED).
Probe target: any valid episode (36019 = JJK S2 E25).
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:
try:
m = upstream.master_m3u8(36019, "jpn")
if not m:
raise RuntimeError("no master m3u8")
base = m.rsplit("/", 1)[0] + "/"
v = first(upstream._get(m, timeout=10).text, base)
seg = first(upstream._get(v, timeout=10).text, base)
t = time.time()
r = upstream._session().get(seg, headers={"Range": "bytes=0-65535"},
impersonate="chrome", timeout=10)
kbps = len(r.content) / 1024 / max(time.time() - t, 0.01)
except Exception:
kbps = 0.0
now = "OK" if kbps >= 40 else "DEGRADED"
if now != state:
print(f"[probe] CDN {now} ({kbps:.0f} KB/s)", flush=True)
state = now
time.sleep(180)
threading.Thread(target=_cdn_probe, daemon=True).start()
# ---------- auth: multi-user, signed cookies ----------
users.migrate_legacy() # file-based legacy import; db.init() absorbs its output
db.init()