novela/containers/novela/routers/following.py
2026-04-15 21:39:20 +02:00

68 lines
2.3 KiB
Python

from urllib.parse import unquote
from fastapi import APIRouter, Request
from fastapi.responses import HTMLResponse
from shared_templates import templates
from db import get_db_conn
router = APIRouter()
@router.get("/following", response_class=HTMLResponse)
async def following_page(request: Request):
return templates.TemplateResponse(request, "following.html", {"active": "following"})
@router.get("/api/following")
async def get_following():
"""Return all distinct library authors with their URL (if any) and book stats."""
with get_db_conn() as conn:
with conn.cursor() as cur:
cur.execute(
"""
SELECT
l.author,
COUNT(l.filename)::int AS book_count,
MAX(l.created_at) AS last_added,
a.url
FROM library l
LEFT JOIN authors a ON a.name = l.author
WHERE l.author IS NOT NULL AND l.author <> '' AND NOT l.archived
GROUP BY l.author, a.url
ORDER BY l.author
"""
)
return [
{
"name": r[0],
"book_count": r[1],
"last_added": r[2].isoformat() if r[2] else None,
"url": r[3],
}
for r in cur.fetchall()
]
@router.post("/api/following/{author_name:path}")
async def set_author_url(author_name: str, request: Request):
"""Set or clear the URL for an author (empty url removes the entry)."""
author_name = unquote(author_name)
body = await request.json()
url = (body.get("url") or "").strip()
with get_db_conn() as conn:
with conn:
with conn.cursor() as cur:
if url:
cur.execute(
"""
INSERT INTO authors (name, url)
VALUES (%s, %s)
ON CONFLICT (name) DO UPDATE SET url = EXCLUDED.url, updated_at = NOW()
""",
(author_name, url),
)
else:
cur.execute("DELETE FROM authors WHERE name = %s", (author_name,))
return {"ok": True}