ui: loading states, player failure overlay + retry, toasts, back nav, full history page with delete
Bundle 1-4+7 from PLAN.md: skeleton loaders, player Loading/Buffering/fatal overlay with Retry, action toasts, back-to-home crumb + logo fix, ?history full-history view with per-entry delete (GET /api/history?all=1, DELETE /api/history). 14/14 tests green.
This commit is contained in:
1 parent
19e878800c
commit
2ec0f8a034
10 files changed
+414
-20
No files matched your search
+17
-4
@@ -139,10 +139,23 @@ def _save_hist(user: str, entries):
|
||||
@app.get("/api/history")
|
||||
def api_history(request: Request):
|
||||
# no-store: this JSON mutates while a tab is open (position saves);
|
||||
# a stale copy has caused "poster gone" confusion before
|
||||
return JSONResponse(
|
||||
sorted(_load_hist(request.state.user), key=lambda e: e.get("t", 0), reverse=True)[:5],
|
||||
headers={"Cache-Control": "no-store"})
|
||||
# a stale copy has caused "poster gone" confusion before.
|
||||
# ?all=1: full list for the /history page (no top-5 cap)
|
||||
entries = sorted(_load_hist(request.state.user), key=lambda e: e.get("t", 0), reverse=True)
|
||||
if request.query_params.get("all") != "1":
|
||||
entries = entries[:5]
|
||||
return JSONResponse(entries, headers={"Cache-Control": "no-store"})
|
||||
|
||||
|
||||
@app.delete("/api/history")
|
||||
def api_history_delete(request: Request, slug_id: str, ep_id: str):
|
||||
# loose str() match on purpose: legacy rows store the same ep_id as int
|
||||
# AND as string — one delete clears both ghost rows
|
||||
entries = _load_hist(request.state.user)
|
||||
keep = [e for e in entries
|
||||
if not (str(e.get("slug_id")) == slug_id and str(e.get("ep_id")) == ep_id)]
|
||||
_save_hist(request.state.user, keep)
|
||||
return {"removed": len(entries) - len(keep)}
|
||||
|
||||
|
||||
@app.post("/api/history")
|
||||
|
||||
Reference in new issue
Block a user