Able to be edited, other cleanup

This commit is contained in:
2026-05-09 15:12:15 -05:00
parent e8b385c923
commit 486cb348bb
11 changed files with 1061 additions and 669 deletions
+92
View File
@@ -0,0 +1,92 @@
import asyncio
import json
import secrets
from collections import Counter
from contextlib import asynccontextmanager
from fastapi import Depends, FastAPI, HTTPException
from fastapi.responses import FileResponse
from fastapi.security import HTTPBasic, HTTPBasicCredentials
import db
import worker
from config import OUTPUTS, USERNAME, PASSWORD, PORT
from routes.decks import router as decks_router
from routes.cards import router as cards_router, public_router
from worker import safe_filename
security = HTTPBasic()
def auth(creds: HTTPBasicCredentials = Depends(security)):
ok = (
secrets.compare_digest(creds.username.encode(), USERNAME.encode())
and secrets.compare_digest(creds.password.encode(), PASSWORD.encode())
)
if not ok:
raise HTTPException(401, headers={"WWW-Authenticate": "Basic"})
@asynccontextmanager
async def lifespan(app: FastAPI):
db.init()
OUTPUTS.mkdir(exist_ok=True)
for d in OUTPUTS.iterdir():
if not d.is_dir() or not (d / "cards.txt").exists():
continue
slug = d.name
if db.get_deck(slug):
continue
card_names = [l for l in (d / "cards.txt").read_text().splitlines() if l]
status = "failed"
deck_name = slug.replace("_", " ").title()
if (d / "deck.tts.json").exists():
status = "complete"
try:
deck_name = json.loads((d / "deck.tts.json").read_text()).get("SaveName", deck_name)
except Exception:
pass
counts = Counter(card_names)
seen: Counter = Counter()
with db.conn() as c:
c.execute(
"INSERT OR IGNORE INTO decks (slug, deck_name, status, commander, price_usd, done, total) VALUES (?,?,?,?,0,?,?)",
(slug, deck_name, status, card_names[0] if card_names else None, len(card_names), len(card_names))
)
for i, name in enumerate(card_names):
seen[name] += 1
occ = seen[name]
total = counts[name]
base = safe_filename(name)
suffix = f"_{occ}" if total > 1 else ""
filename = f"{base}{suffix}.png"
exists = (d / filename).exists()
c.execute(
"INSERT INTO cards (deck_slug, name, position, filename, fetch_status) VALUES (?,?,?,?,?)",
(slug, name, i + 1, filename if exists else None, "done" if exists else "failed")
)
c.execute("INSERT INTO logs (deck_slug, line) VALUES (?,?)", (slug, "Loaded from disk."))
asyncio.create_task(worker.run())
yield
app = FastAPI(lifespan=lifespan)
app.include_router(decks_router, dependencies=[Depends(auth)])
app.include_router(cards_router, dependencies=[Depends(auth)])
app.include_router(public_router) # no auth — TTS app fetches card images directly
@app.get("/")
async def index(_=Depends(auth)):
return FileResponse("static/index.html")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=PORT)