perf: persistance du cache concerts en SQLite (survit aux redémarrages)
Docker / docker (push) Successful in 3m31s

Le cache en mémoire (6h TTL) est désormais sauvegardé dans concerts_cache.
Au redémarrage, si le cache SQLite est récent, aucune requête réseau n'est faite.
Le bouton Rafraîchir vide aussi le cache SQLite pour forcer un re-scrape.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
dev
2026-05-02 20:29:17 +02:00
parent 4fe24af251
commit d729334c9b
+59
View File
@@ -1,4 +1,5 @@
import re import re
import sqlite3
import time import time
import logging import logging
import asyncio import asyncio
@@ -11,8 +12,51 @@ import tmdb as _tmdb
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
CACHE_TTL = 6 * 3600 CACHE_TTL = 6 * 3600
DB_PATH = "arte_dl.db"
_cache: dict = {"data": [], "ts": 0} _cache: dict = {"data": [], "ts": 0}
def _db():
conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row
return conn
def _init_concerts_cache_table():
with _db() as conn:
conn.execute("""
CREATE TABLE IF NOT EXISTS concerts_cache (
id INTEGER PRIMARY KEY CHECK (id = 1),
data TEXT NOT NULL,
ts REAL NOT NULL
)
""")
_init_concerts_cache_table()
def _load_db_cache() -> tuple[list, float]:
try:
with _db() as conn:
row = conn.execute("SELECT data, ts FROM concerts_cache WHERE id=1").fetchone()
if row:
return json.loads(row["data"]), row["ts"]
except Exception:
pass
return [], 0.0
def _save_db_cache(data: list, ts: float):
try:
with _db() as conn:
conn.execute(
"INSERT OR REPLACE INTO concerts_cache (id, data, ts) VALUES (1, ?, ?)",
(json.dumps(data), ts),
)
except Exception as e:
logger.warning("Failed to save concerts cache: %s", e)
PLAYER_API = "https://api.arte.tv/api/player/v2/config/fr/{pid}" PLAYER_API = "https://api.arte.tv/api/player/v2/config/fr/{pid}"
SEARCH_URL = "https://www.arte.tv/fr/search/?q={q}" SEARCH_URL = "https://www.arte.tv/fr/search/?q={q}"
@@ -157,11 +201,21 @@ async def get_all_concerts() -> list[dict]:
now = time.time() now = time.time()
if _cache["data"] and now - _cache["ts"] < CACHE_TTL: if _cache["data"] and now - _cache["ts"] < CACHE_TTL:
return _cache["data"] return _cache["data"]
# Try SQLite cache before hitting the network
db_data, db_ts = _load_db_cache()
if db_data and now - db_ts < CACHE_TTL:
logger.info("Concerts cache loaded from DB (%d concerts)", len(db_data))
_cache["data"] = db_data
_cache["ts"] = db_ts
return _cache["data"]
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
data = await loop.run_in_executor(None, _fetch_all_sync) data = await loop.run_in_executor(None, _fetch_all_sync)
if data: if data:
_cache["data"] = data _cache["data"] = data
_cache["ts"] = now _cache["ts"] = now
_save_db_cache(data, now)
return _cache["data"] return _cache["data"]
@@ -208,5 +262,10 @@ async def fetch_concerts(page: int = 1, search: str = "", page_size: int = 24, c
async def invalidate_cache() -> int: async def invalidate_cache() -> int:
_cache["ts"] = 0 _cache["ts"] = 0
try:
with _db() as conn:
conn.execute("DELETE FROM concerts_cache")
except Exception:
pass
data = await get_all_concerts() data = await get_all_concerts()
return len(data) return len(data)