Add runtime filter, kid-friendly toggle, surprise me, and re-roll
- Runtime quick-select buttons (Any/90m/2h/2.5h) filter movies by length - Kid-friendly toggle forces PG-13 max and boosts Family/Animation genres - Surprise Me picks a random mood prompt from 20 curated options - Show Me More re-rolls same mood excluding already-shown movies - Re-roll appends new results to the existing search history entry Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+42
-11
@@ -32,6 +32,16 @@ async def get_mood_recommendations(request: Request, body: MoodRequest):
|
||||
|
||||
# Get unwatched movies from cache
|
||||
unwatched_raw = await get_unwatched_movies(user_ids)
|
||||
|
||||
# Exclude previously shown movies (re-roll)
|
||||
if body.exclude_ids:
|
||||
exclude_set = set(body.exclude_ids)
|
||||
unwatched_raw = [m for m in unwatched_raw if m["jellyfin_id"] not in exclude_set]
|
||||
|
||||
# Filter by max runtime
|
||||
if body.max_runtime:
|
||||
unwatched_raw = [m for m in unwatched_raw if not m.get("runtime_minutes") or m["runtime_minutes"] <= body.max_runtime]
|
||||
|
||||
total_unwatched = len(unwatched_raw)
|
||||
|
||||
if total_unwatched == 0:
|
||||
@@ -47,7 +57,8 @@ async def get_mood_recommendations(request: Request, body: MoodRequest):
|
||||
|
||||
# Pre-filter to narrow candidates
|
||||
candidates = prefilter_candidates(
|
||||
unwatched_raw, body.mood, max_candidates=settings.max_candidates
|
||||
unwatched_raw, body.mood, max_candidates=settings.max_candidates,
|
||||
kid_friendly=body.kid_friendly,
|
||||
)
|
||||
logger.info(f"Pre-filtered {total_unwatched} movies to {len(candidates)} candidates for mood: '{body.mood}'")
|
||||
|
||||
@@ -98,25 +109,45 @@ async def get_mood_recommendations(request: Request, body: MoodRequest):
|
||||
}
|
||||
|
||||
# Save to search history
|
||||
history_id = None
|
||||
try:
|
||||
db = await get_db()
|
||||
try:
|
||||
await db.execute(
|
||||
"INSERT INTO search_history (user_id, mood, results, meta, created_at) VALUES (?, ?, ?, ?, ?)",
|
||||
(
|
||||
user["id"],
|
||||
body.mood,
|
||||
json.dumps([r.model_dump() for r in recommendations]),
|
||||
json.dumps(meta),
|
||||
datetime.now(timezone.utc).isoformat(),
|
||||
),
|
||||
)
|
||||
if body.history_id:
|
||||
# Re-roll: append new results to existing history entry
|
||||
cursor = await db.execute(
|
||||
"SELECT results FROM search_history WHERE id = ? AND user_id = ?",
|
||||
(body.history_id, user["id"]),
|
||||
)
|
||||
row = await cursor.fetchone()
|
||||
if row:
|
||||
existing = json.loads(row["results"])
|
||||
combined = existing + [r.model_dump() for r in recommendations]
|
||||
await db.execute(
|
||||
"UPDATE search_history SET results = ?, meta = ? WHERE id = ? AND user_id = ?",
|
||||
(json.dumps(combined), json.dumps(meta), body.history_id, user["id"]),
|
||||
)
|
||||
history_id = body.history_id
|
||||
else:
|
||||
# Fallback: create new entry if original not found
|
||||
cursor = await db.execute(
|
||||
"INSERT INTO search_history (user_id, mood, results, meta, created_at) VALUES (?, ?, ?, ?, ?)",
|
||||
(user["id"], body.mood, json.dumps([r.model_dump() for r in recommendations]), json.dumps(meta), datetime.now(timezone.utc).isoformat()),
|
||||
)
|
||||
history_id = cursor.lastrowid
|
||||
else:
|
||||
cursor = await db.execute(
|
||||
"INSERT INTO search_history (user_id, mood, results, meta, created_at) VALUES (?, ?, ?, ?, ?)",
|
||||
(user["id"], body.mood, json.dumps([r.model_dump() for r in recommendations]), json.dumps(meta), datetime.now(timezone.utc).isoformat()),
|
||||
)
|
||||
history_id = cursor.lastrowid
|
||||
await db.commit()
|
||||
finally:
|
||||
await db.close()
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to save search history: {e}")
|
||||
|
||||
meta["history_id"] = history_id
|
||||
return MoodResponse(recommendations=recommendations, meta=meta)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user