Spaces:
Running
Running
Upload _run.py with huggingface_hub
Browse files
_run.py
CHANGED
|
@@ -6,9 +6,11 @@ from app_v2_entry import app # v5-stable inline bongda proxy
|
|
| 6 |
|
| 7 |
# Import and initialize the resilient shorts updater
|
| 8 |
try:
|
| 9 |
-
from shorts_updater import get_shorts, get_shorts_with_status, init_updater, FALLBACK_SHORTS, _load_cache
|
|
|
|
| 10 |
import threading
|
| 11 |
import time
|
|
|
|
| 12 |
|
| 13 |
# Initialize on startup
|
| 14 |
init_updater()
|
|
@@ -16,17 +18,17 @@ try:
|
|
| 16 |
# Memory cache for fast access
|
| 17 |
_shorts_mem_cache = {"t": 0, "d": [], "updating": False}
|
| 18 |
|
| 19 |
-
# Load existing cache on module load
|
| 20 |
try:
|
| 21 |
_existing_cache = _load_cache()
|
|
|
|
| 22 |
if _existing_cache.get("d"):
|
| 23 |
_shorts_mem_cache["d"] = _existing_cache["d"][:40]
|
| 24 |
_shorts_mem_cache["t"] = _existing_cache.get("t", time.time())
|
| 25 |
-
print(f"[Shorts] Loaded {len(_shorts_mem_cache['d'])} shorts from cache")
|
| 26 |
except Exception as e:
|
| 27 |
print(f"[Shorts] Initial cache load error: {e}")
|
| 28 |
|
| 29 |
-
# Override the /api/shorts endpoint with timeout-safe version
|
| 30 |
from fastapi import Query
|
| 31 |
from fastapi.responses import JSONResponse
|
| 32 |
|
|
@@ -38,12 +40,13 @@ try:
|
|
| 38 |
"""
|
| 39 |
Resilient shorts endpoint - returns immediately from cache,
|
| 40 |
triggers background update if stale, never hangs.
|
|
|
|
| 41 |
"""
|
| 42 |
now = time.time()
|
| 43 |
|
| 44 |
-
# If refresh requested
|
| 45 |
cache_age = now - _shorts_mem_cache.get("t", 0)
|
| 46 |
-
if refresh or cache_age >
|
| 47 |
if not _shorts_mem_cache.get("updating"):
|
| 48 |
_shorts_mem_cache["updating"] = True
|
| 49 |
threading.Thread(target=update_shorts_if_stale, daemon=True).start()
|
|
@@ -57,28 +60,60 @@ try:
|
|
| 57 |
|
| 58 |
return JSONResponse(result)
|
| 59 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
def update_shorts_if_stale():
|
| 61 |
"""Background task to update shorts cache"""
|
| 62 |
try:
|
| 63 |
-
|
| 64 |
-
shorts =
|
| 65 |
-
|
| 66 |
-
# If empty (first load or all sources failed), use fallback
|
| 67 |
-
if not shorts:
|
| 68 |
-
shorts = FALLBACK_SHORTS
|
| 69 |
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
except Exception as e:
|
| 75 |
print(f"[Shorts] Update error: {e}")
|
|
|
|
|
|
|
|
|
|
| 76 |
finally:
|
| 77 |
_shorts_mem_cache["updating"] = False
|
|
|
|
|
|
|
|
|
|
| 78 |
|
| 79 |
except Exception as e:
|
| 80 |
print(f"[Shorts] Failed to load updater module: {e}")
|
| 81 |
-
# Fallback: define
|
| 82 |
from fastapi import Query
|
| 83 |
from fastapi.responses import JSONResponse
|
| 84 |
|
|
|
|
| 6 |
|
| 7 |
# Import and initialize the resilient shorts updater
|
| 8 |
try:
|
| 9 |
+
from shorts_updater import get_shorts, get_shorts_with_status, init_updater, FALLBACK_SHORTS, _load_cache, clear_cache, update_shorts_background, YOUTUBE_HANDLES
|
| 10 |
+
import subprocess
|
| 11 |
import threading
|
| 12 |
import time
|
| 13 |
+
import json
|
| 14 |
|
| 15 |
# Initialize on startup
|
| 16 |
init_updater()
|
|
|
|
| 18 |
# Memory cache for fast access
|
| 19 |
_shorts_mem_cache = {"t": 0, "d": [], "updating": False}
|
| 20 |
|
| 21 |
+
# Load existing cache on module load (but mark as stale if old)
|
| 22 |
try:
|
| 23 |
_existing_cache = _load_cache()
|
| 24 |
+
cache_age = time.time() - _existing_cache.get("t", 0)
|
| 25 |
if _existing_cache.get("d"):
|
| 26 |
_shorts_mem_cache["d"] = _existing_cache["d"][:40]
|
| 27 |
_shorts_mem_cache["t"] = _existing_cache.get("t", time.time())
|
| 28 |
+
print(f"[Shorts] Loaded {len(_shorts_mem_cache['d'])} shorts from cache (age: {int(cache_age/60)}min)")
|
| 29 |
except Exception as e:
|
| 30 |
print(f"[Shorts] Initial cache load error: {e}")
|
| 31 |
|
|
|
|
| 32 |
from fastapi import Query
|
| 33 |
from fastapi.responses import JSONResponse
|
| 34 |
|
|
|
|
| 40 |
"""
|
| 41 |
Resilient shorts endpoint - returns immediately from cache,
|
| 42 |
triggers background update if stale, never hangs.
|
| 43 |
+
Query refresh=1 to force immediate update.
|
| 44 |
"""
|
| 45 |
now = time.time()
|
| 46 |
|
| 47 |
+
# If refresh requested, trigger immediate background update
|
| 48 |
cache_age = now - _shorts_mem_cache.get("t", 0)
|
| 49 |
+
if refresh or cache_age > 300 or not _shorts_mem_cache.get("d"): # Reduced TTL: 5 min
|
| 50 |
if not _shorts_mem_cache.get("updating"):
|
| 51 |
_shorts_mem_cache["updating"] = True
|
| 52 |
threading.Thread(target=update_shorts_if_stale, daemon=True).start()
|
|
|
|
| 60 |
|
| 61 |
return JSONResponse(result)
|
| 62 |
|
| 63 |
+
@app.post('/api/shorts/refresh')
|
| 64 |
+
def force_refresh_shorts():
|
| 65 |
+
"""Force immediate refresh of shorts cache - admin endpoint"""
|
| 66 |
+
if _shorts_mem_cache.get("updating"):
|
| 67 |
+
return JSONResponse({"status": "already_updating", "message": "Refresh in progress"})
|
| 68 |
+
|
| 69 |
+
# Clear cache first to force fresh fetch
|
| 70 |
+
clear_cache()
|
| 71 |
+
_shorts_mem_cache["d"] = []
|
| 72 |
+
_shorts_mem_cache["t"] = 0
|
| 73 |
+
|
| 74 |
+
threading.Thread(target=update_shorts_if_stale, daemon=True).start()
|
| 75 |
+
return JSONResponse({"status": "refresh_started", "message": "Fetching fresh shorts..."})
|
| 76 |
+
|
| 77 |
+
@app.get('/api/shorts/debug')
|
| 78 |
+
def debug_shorts():
|
| 79 |
+
"""Debug endpoint to check cache status"""
|
| 80 |
+
return JSONResponse({
|
| 81 |
+
"cache_exists": bool(_shorts_mem_cache.get("d")),
|
| 82 |
+
"cache_count": len(_shorts_mem_cache.get("d", [])),
|
| 83 |
+
"cache_age_seconds": int(time.time() - _shorts_mem_cache.get("t", 0)),
|
| 84 |
+
"updating": _shorts_mem_cache.get("updating", False),
|
| 85 |
+
"channels_monitored": YOUTUBE_HANDLES
|
| 86 |
+
})
|
| 87 |
+
|
| 88 |
def update_shorts_if_stale():
|
| 89 |
"""Background task to update shorts cache"""
|
| 90 |
try:
|
| 91 |
+
# Force fresh fetch (not from cache)
|
| 92 |
+
shorts, errors = _fetch_all_shorts()
|
|
|
|
|
|
|
|
|
|
|
|
|
| 93 |
|
| 94 |
+
if shorts:
|
| 95 |
+
_shorts_mem_cache["d"] = shorts[:40]
|
| 96 |
+
_shorts_mem_cache["t"] = time.time()
|
| 97 |
+
print(f"[Shorts] Cache updated: {len(shorts)} items from channels")
|
| 98 |
+
else:
|
| 99 |
+
# Use fallback if all sources failed
|
| 100 |
+
_shorts_mem_cache["d"] = FALLBACK_SHORTS
|
| 101 |
+
_shorts_mem_cache["t"] = time.time()
|
| 102 |
+
print(f"[Shorts] Using fallback shorts, errors: {errors}")
|
| 103 |
except Exception as e:
|
| 104 |
print(f"[Shorts] Update error: {e}")
|
| 105 |
+
# Ensure we always have fallback
|
| 106 |
+
_shorts_mem_cache["d"] = FALLBACK_SHORTS
|
| 107 |
+
_shorts_mem_cache["t"] = time.time()
|
| 108 |
finally:
|
| 109 |
_shorts_mem_cache["updating"] = False
|
| 110 |
+
|
| 111 |
+
# Need to import the _fetch_all_shorts function
|
| 112 |
+
from shorts_updater import _fetch_all_shorts
|
| 113 |
|
| 114 |
except Exception as e:
|
| 115 |
print(f"[Shorts] Failed to load updater module: {e}")
|
| 116 |
+
# Fallback: define minimal endpoints
|
| 117 |
from fastapi import Query
|
| 118 |
from fastapi.responses import JSONResponse
|
| 119 |
|