"""VNEWS boot entry — self-heal + HLS live fixes before import. 1) If main.py is the PLACEHOLDER stub (or otherwise damaged), restore the known-good version from commit 5b6000c via huggingface_hub. 2) Apply the m3u_hls live fix to main.py if it still has the old 3-segment manifest: bump to 8 repeating #EXTINF:8.0 segments, add #EXT-X-DISCONTINUITY-SEQUENCE:0, keep the playlist open (no ENDLIST, no trailing #EXT-X-DISCONTINUITY). 3) Apply Hls.js live tuning to static/vtv_init.js if not present: liveDurationInfinity / liveSyncDurationCount / maxBufferLength. 4) Persist any local changes back to the repo 'main' branch (best-effort, requires a write token in the Space env, e.g. HF_TOKEN secret). """ import os _APP_DIR = os.path.dirname(os.path.abspath(__file__)) _MAIN = os.path.join(_APP_DIR, "main.py") _VTV = os.path.join(_APP_DIR, "static", "vtv_init.js") _GOOD_REV = "5b6000c58f89723b3d228afb06c891ce909ac488" _REPO = "bep40/VNEWS" def _read(p): try: with open(p, encoding="utf-8", errors="replace") as f: return f.read() except Exception: return "" def _write(p, s): with open(p, "w", encoding="utf-8") as f: f.write(s) def _main_is_broken(path): try: if os.path.getsize(path) < 50000: return True head = _read(path)[:2048] return "PLACEHOLDER" in head or "app = FastAPI()" not in head except Exception: return True # --- old 3-segment manifest block in main.py (verified against 5b6000c) --- _OLD_MANIFEST = ( ' _seg = seg_proxy_base\n' ' manifest = (\n' ' "#EXTM3U\\n"\n' ' "#EXT-X-VERSION:6\\n"\n' ' "#EXT-X-TARGETDURATION:8\\n"\n' ' "#EXT-X-MEDIA-SEQUENCE:0\\n"\n' ' "#EXT-X-START:TIME-OFFSET=0,PRECISE=YES\\n"\n' ' "#EXTINF:8.0,\\n"\n' ' + _seg + "\\n"\n' ' "#EXTINF:8.0,\\n"\n' ' + _seg + "\\n"\n' ' "#EXTINF:8.0,\\n"\n' ' + _seg + "\\n"\n' ' )\n' ) _NEW_MANIFEST = ( ' _seg = seg_proxy_base\n' ' manifest = (\n' ' "#EXTM3U\\n"\n' ' "#EXT-X-VERSION:6\\n"\n' ' "#EXT-X-TARGETDURATION:8\\n"\n' ' "#EXT-X-MEDIA-SEQUENCE:0\\n"\n' ' "#EXT-X-DISCONTINUITY-SEQUENCE:0\\n"\n' ' "#EXT-X-START:TIME-OFFSET=0,PRECISE=YES\\n"\n' + ''.join(' "#EXTINF:8.0,\\n"\n + _seg + "\\n"\n' for _ in range(8)) + ' )\n' ) def _fix_main_hls(content): if "#EXT-X-DISCONTINUITY-SEQUENCE" in content: return content, False if content.count("#EXTINF:8.0") >= 8: return content, False if _OLD_MANIFEST not in content: return content, False new = content.replace(_OLD_MANIFEST, _NEW_MANIFEST, 1) if new != content: return new, True return content, False _OLD_HLS_CONFIG = "new Hls({ enableWorker: false })" _NEW_HLS_CONFIG = ( "new Hls({ enableWorker: false, liveDurationInfinity: true, " "liveSyncDurationCount: 5, maxBufferLength: 60, maxMaxBufferLength: 240 })" ) def _fix_vtv(content): if "liveDurationInfinity" in content: return content, False if _OLD_HLS_CONFIG not in content: return content, False new = content.replace(_OLD_HLS_CONFIG, _NEW_HLS_CONFIG, 1) return new, new != content def _persist(fn, data): """Best-effort: push patched file back to the repo 'main' branch so the fix is permanent, not just container-local. Never raises.""" try: token = os.environ.get("HF_TOKEN") if not token: print(f"[self-heal] no HF_TOKEN — skip persist {fn}", flush=True) return False from huggingface_hub import upload_file upload_file( path_or_fileobj=data.encode("utf-8"), path_in_repo=fn, repo_id=_REPO, repo_type="space", token=token, commit_message=f"[hls-fix] {fn}: 8 segments + live config", ) print(f"[self-heal] persisted {fn}", flush=True) return True except Exception as e: print(f"[self-heal] persist {fn} failed: {e}", flush=True) return False def _restore_main(): print(f"[self-heal] main.py damaged -> restoring from {_GOOD_REV}", flush=True) try: from huggingface_hub import hf_hub_download good = hf_hub_download( repo_id=_REPO, filename="main.py", revision=_GOOD_REV, repo_type="space", ) with open(good, encoding="utf-8") as f: data = f.read() assert "app = FastAPI()" in data and "proxy_m3u_hls" in data _write(_MAIN, data) print(f"[self-heal] main.py restored ({len(data)} bytes)", flush=True) return True except Exception as e: print(f"[self-heal] FAILED to restore main.py: {e}", flush=True) return False def _apply_fixes(): changed = [] try: if _main_is_broken(_MAIN): _restore_main() mc = _read(_MAIN) if mc: nm, changed_m = _fix_main_hls(mc) if changed_m: _write(_MAIN, nm) print("[hls] main.py patched: 8 segments + DISCONTINUITY-SEQUENCE:0", flush=True) changed.append("main.py") vc = _read(_VTV) if vc: nv, changed_v = _fix_vtv(vc) if changed_v: _write(_VTV, nv) print("[hls] vtv_init.js patched: liveDurationInfinity config", flush=True) changed.append("static/vtv_init.js") except Exception as e: print(f"[hls] review fixes failed (non-fatal): {e}", flush=True) for fn in changed: try: _persist(fn, _read(os.path.join(_APP_DIR, fn))) except Exception as e: print(f"[hls] persist {fn} error: {e}", flush=True) _apply_fixes() from app_v2_entry import app # v5-stable inline bongda proxy