Spaces:
Running
Running
| """ | |
| VNEWS Shorts Runtime Cache - External Updater Module | |
| GitHub Actions fetches YouTube shorts via yt-dlp -> POST to /api/shorts/update | |
| Space saves to RAM cache + persistent file if /data available | |
| """ | |
| import os | |
| import json | |
| import time | |
| import threading | |
| # Runtime cache (RAM) | |
| _shorts_runtime_cache = None | |
| _shorts_cache_ts = 0 | |
| _shorts_cache_lock = threading.Lock() | |
| # Secret for authenticating update requests | |
| SHORTS_UPDATE_SECRET = os.environ.get("SHORTS_UPDATE_SECRET", "vnews-shorts-2026") | |
| # Paths | |
| SHORTS_CACHE_FILE = "/data/shorts_runtime_cache.json" if os.path.isdir("/data") else "/app/shorts_runtime_cache.json" | |
| def get_runtime_cache(): | |
| """Get cached shorts (from RAM or file fallback)""" | |
| global _shorts_runtime_cache, _shorts_cache_ts | |
| with _shorts_cache_lock: | |
| if _shorts_runtime_cache is not None: | |
| age = time.time() - _shorts_cache_ts | |
| if age < 7200: # 2h fresh | |
| return _shorts_runtime_cache | |
| # Try file fallback | |
| try: | |
| if os.path.exists(SHORTS_CACHE_FILE): | |
| with open(SHORTS_CACHE_FILE, "r", encoding="utf-8") as f: | |
| data = json.load(f) | |
| age = time.time() - data.get("ts", 0) | |
| if age < 86400: # 24h stale limit | |
| items = data.get("items", []) | |
| with _shorts_cache_lock: | |
| _shorts_runtime_cache = items | |
| _shorts_cache_ts = data.get("ts", time.time()) | |
| return items | |
| except Exception as e: | |
| print(f"[cache] read error: {e}") | |
| return None | |
| def set_runtime_cache(items): | |
| """Update runtime cache from external data""" | |
| global _shorts_runtime_cache, _shorts_cache_ts | |
| ts = time.time() | |
| with _shorts_cache_lock: | |
| _shorts_runtime_cache = items | |
| _shorts_cache_ts = ts | |
| # Also write to file (persistent if /data mounted) | |
| try: | |
| os.makedirs(os.path.dirname(SHORTS_CACHE_FILE), exist_ok=True) | |
| payload = {"items": items, "ts": ts, "count": len(items)} | |
| with open(SHORTS_CACHE_FILE, "w", encoding="utf-8") as f: | |
| json.dump(payload, f, ensure_ascii=False, indent=2) | |
| print(f"[cache] saved {len(items)} shorts to {SHORTS_CACHE_FILE}") | |
| except Exception as e: | |
| print(f"[cache] write skipped: {e}") | |
| return len(items) | |
| def get_cache_status(): | |
| """Return status dict for the cache""" | |
| cache = None | |
| with _shorts_cache_lock: | |
| if _shorts_runtime_cache is not None: | |
| cache = _shorts_runtime_cache | |
| age = int(time.time() - _shorts_cache_ts) | |
| else: | |
| age = -1 | |
| return { | |
| "cached": cache is not None, | |
| "count": len(cache) if cache else 0, | |
| "age_seconds": age, | |
| "has_persistent": os.path.isdir("/data"), | |
| "cache_file_exists": os.path.exists(SHORTS_CACHE_FILE), | |
| } | |