Reader: monotonic reading progress across devices — saved position only advances, never rewinds (explicit Mark as read/unread still resets). Plus the previously uncommitted v0.2.5–v0.2.8 work (FlareSolverr scraping, Book Info pages, deferred chapter add/delete, scanned/uploaded backup counters, Dropbox upload tuning, four inline editor formatting buttons, migration logging, "New view" needs_review fix, consecutive break-image collapsing, and the related TECHNICAL.md updates). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
71 lines
1.7 KiB
Python
71 lines
1.7 KiB
Python
import logging
|
|
from contextlib import asynccontextmanager
|
|
|
|
from fastapi import FastAPI
|
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
from fastapi.responses import JSONResponse, RedirectResponse
|
|
from fastapi.staticfiles import StaticFiles
|
|
|
|
from db import close_pool, get_db_conn, init_pool
|
|
from migrations import run_migrations
|
|
from routers.backup import start_backup_scheduler, stop_backup_scheduler
|
|
from routers import (
|
|
backup_router,
|
|
builder_router,
|
|
bulk_import_router,
|
|
changelog_router,
|
|
editor_router,
|
|
following_router,
|
|
grabber_router,
|
|
library_router,
|
|
reader_router,
|
|
search_router,
|
|
settings_router,
|
|
)
|
|
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(app: FastAPI):
|
|
init_pool()
|
|
run_migrations()
|
|
await start_backup_scheduler()
|
|
try:
|
|
yield
|
|
finally:
|
|
await stop_backup_scheduler()
|
|
close_pool()
|
|
|
|
|
|
app = FastAPI(lifespan=lifespan)
|
|
app.mount("/static", StaticFiles(directory="static"), name="static")
|
|
|
|
app.include_router(library_router)
|
|
app.include_router(reader_router)
|
|
app.include_router(editor_router)
|
|
app.include_router(grabber_router)
|
|
app.include_router(settings_router)
|
|
app.include_router(backup_router)
|
|
app.include_router(builder_router)
|
|
app.include_router(bulk_import_router)
|
|
app.include_router(following_router)
|
|
app.include_router(changelog_router)
|
|
app.include_router(search_router)
|
|
|
|
|
|
@app.get("/health")
|
|
async def health():
|
|
try:
|
|
with get_db_conn() as conn:
|
|
with conn.cursor() as cur:
|
|
cur.execute("SELECT 1")
|
|
db_ok = True
|
|
except Exception:
|
|
db_ok = False
|
|
return JSONResponse({"ok": db_ok})
|
|
|
|
|
|
@app.get("/")
|
|
async def index_redirect():
|
|
return RedirectResponse(url="/home", status_code=302)
|