Able to be edited, other cleanup
This commit is contained in:
@@ -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)
|
||||
Reference in New Issue
Block a user