99 lines
2.7 KiB
Python
99 lines
2.7 KiB
Python
import hashlib
|
|
import sqlite3
|
|
import time
|
|
|
|
from flask import g
|
|
|
|
DB_PATH = "/data/translations.db"
|
|
|
|
|
|
def _make_key(*parts: str) -> str:
|
|
return hashlib.sha256(":".join(parts).encode()).hexdigest()
|
|
|
|
|
|
def init_db():
|
|
db = sqlite3.connect(DB_PATH)
|
|
db.execute("PRAGMA journal_mode=WAL")
|
|
db.executescript("""
|
|
CREATE TABLE IF NOT EXISTS cache (
|
|
key TEXT PRIMARY KEY,
|
|
value TEXT NOT NULL,
|
|
created_at REAL NOT NULL
|
|
);
|
|
CREATE TABLE IF NOT EXISTS feeds (
|
|
key TEXT PRIMARY KEY,
|
|
content BLOB NOT NULL,
|
|
fetched_at REAL NOT NULL
|
|
);
|
|
""")
|
|
db.close()
|
|
|
|
|
|
def get_db():
|
|
if "db" not in g:
|
|
conn = sqlite3.connect(DB_PATH)
|
|
conn.row_factory = sqlite3.Row
|
|
g.db = conn
|
|
return g.db
|
|
|
|
|
|
def close_db(exc):
|
|
db = g.pop("db", None)
|
|
if db is not None:
|
|
db.close()
|
|
|
|
|
|
# ── Translation cache ─────────────────────────────────────────────────────────
|
|
|
|
def cache_key(text: str, lang: str) -> str:
|
|
return _make_key(lang, text)
|
|
|
|
|
|
def get_translation(db, key: str, ttl: float):
|
|
"""Return cached translation value if present and fresh, else None."""
|
|
row = db.execute(
|
|
"SELECT value, created_at FROM cache WHERE key=?", (key,)
|
|
).fetchone()
|
|
if row and (time.time() - row["created_at"]) < ttl:
|
|
return row["value"]
|
|
return None
|
|
|
|
|
|
def set_translation(db, key: str, value: str):
|
|
db.execute(
|
|
"INSERT OR REPLACE INTO cache (key, value, created_at) VALUES (?,?,?)",
|
|
(key, value, time.time()),
|
|
)
|
|
db.commit()
|
|
|
|
|
|
def prune_translations(db, max_age: float):
|
|
db.execute(
|
|
"DELETE FROM cache WHERE (? - created_at) > ?",
|
|
(time.time(), max_age),
|
|
)
|
|
db.commit()
|
|
|
|
|
|
# ── Feed cache ────────────────────────────────────────────────────────────────
|
|
|
|
def feed_cache_key(lang: str, path: str) -> str:
|
|
return _make_key(lang, path)
|
|
|
|
|
|
def get_feed_cache(db, key: str, ttl: float):
|
|
"""Return (content: bytes, fetched_at: float) if fresh, else None."""
|
|
row = db.execute(
|
|
"SELECT content, fetched_at FROM feeds WHERE key=?", (key,)
|
|
).fetchone()
|
|
if row and (time.time() - row["fetched_at"]) < ttl:
|
|
return bytes(row["content"]), row["fetched_at"]
|
|
return None
|
|
|
|
|
|
def set_feed_cache(db, key: str, content: bytes, fetched_at: float):
|
|
db.execute(
|
|
"INSERT OR REPLACE INTO feeds (key, content, fetched_at) VALUES (?,?,?)",
|
|
(key, content, fetched_at),
|
|
)
|
|
db.commit()
|