Add shareable search links and watched movie indicators
Share: "Copy Link" button generates a URL with ?s={history_id} that
loads the saved search results without auth. Recipients see the same
movie picks.
Watched: When viewing history results or shared searches, cards for
movies the logged-in user has since watched are dimmed with a green
"Watched" badge. Uses a new POST /api/library/watch-check endpoint.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -33,6 +33,28 @@ async def library_stats(request: Request):
|
||||
await db.close()
|
||||
|
||||
|
||||
@router.post("/watch-check")
|
||||
async def watch_check(request: Request):
|
||||
"""Given a list of jellyfin_ids, return which ones the current user has watched."""
|
||||
user = await get_current_user(request)
|
||||
body = await request.json()
|
||||
ids = body.get("jellyfin_ids", [])
|
||||
if not ids:
|
||||
return {"watched": []}
|
||||
|
||||
db = await get_db()
|
||||
try:
|
||||
placeholders = ",".join("?" for _ in ids)
|
||||
cursor = await db.execute(
|
||||
f"SELECT jellyfin_id FROM watch_state WHERE user_id = ? AND is_played = 1 AND jellyfin_id IN ({placeholders})",
|
||||
[user["id"]] + ids,
|
||||
)
|
||||
rows = await cursor.fetchall()
|
||||
return {"watched": [row["jellyfin_id"] for row in rows]}
|
||||
finally:
|
||||
await db.close()
|
||||
|
||||
|
||||
@router.post("/sync")
|
||||
async def trigger_sync(request: Request):
|
||||
await get_current_user(request)
|
||||
|
||||
@@ -175,6 +175,29 @@ async def get_search_history(request: Request):
|
||||
await db.close()
|
||||
|
||||
|
||||
@router.get("/history/shared/{entry_id}")
|
||||
async def get_shared_history(entry_id: int):
|
||||
"""Public endpoint — returns a history entry by ID (no auth required)."""
|
||||
db = await get_db()
|
||||
try:
|
||||
cursor = await db.execute(
|
||||
"SELECT id, mood, results, meta, created_at FROM search_history WHERE id = ?",
|
||||
(entry_id,),
|
||||
)
|
||||
row = await cursor.fetchone()
|
||||
if not row:
|
||||
raise HTTPException(status_code=404, detail="Search not found")
|
||||
return {
|
||||
"id": row["id"],
|
||||
"mood": row["mood"],
|
||||
"results": json.loads(row["results"]),
|
||||
"meta": json.loads(row["meta"]) if row["meta"] else {},
|
||||
"created_at": row["created_at"],
|
||||
}
|
||||
finally:
|
||||
await db.close()
|
||||
|
||||
|
||||
@router.delete("/history/{entry_id}")
|
||||
async def delete_history_entry(entry_id: int, request: Request):
|
||||
user = await get_current_user(request)
|
||||
|
||||
Reference in New Issue
Block a user