Files
filmdle/app/routes.py
2026-08-07 22:43:30 +02:00

239 lines
7.4 KiB
Python

from flask import Blueprint, jsonify, render_template, request
from . import db
from .game import (
_game_date, compare, daily_target, existing_daily_session, finish_session,
get_max_attempts, get_or_create_player, get_streaks, is_correct, random_target,
)
from .models import Movie, Player, Session
bp = Blueprint("main", __name__)
# ---------- Seiten ----------
@bp.route("/")
def index():
return render_template("index.html", mode="daily")
@bp.route("/unlimited")
def unlimited():
return render_template("index.html", mode="unlimited")
# ---------- API ----------
@bp.route("/api/player", methods=["POST"])
def api_player():
data = request.get_json(silent=True) or {}
nickname = (data.get("nickname") or "").strip()
if not nickname:
return jsonify({"error": "nickname required"}), 400
player = get_or_create_player(nickname)
return jsonify({
"player": {"id": player.id, "nickname": player.nickname},
"streaks": get_streaks(player.id),
})
@bp.route("/api/search")
def api_search():
from difflib import SequenceMatcher
q = (request.args.get("q") or "").strip().lower()
if not q:
return jsonify([])
movies = Movie.query.filter(Movie.title.ilike(f"%{q}%")).limit(50).all()
results = []
for m in movies:
score = SequenceMatcher(None, q, m.title.lower()).ratio()
# Substring-Treffer gelten bereits als starke Uebereinstimmung
if q in m.title.lower():
score = max(score, 0.6)
if score >= 0.6:
results.append((score, m))
results.sort(key=lambda x: x[1].year, reverse=True)
results.sort(key=lambda x: x[0], reverse=True)
return jsonify([
{"id": m.id, "title": m.title, "year": m.year}
for _, m in results[:10]
])
@bp.route("/api/start", methods=["POST"])
def api_start():
data = request.get_json(silent=True) or {}
player_id = data.get("player_id")
mode = data.get("mode", "daily")
if not player_id:
return jsonify({"error": "player_id required"}), 400
if Player.query.get(player_id) is None:
return jsonify({"error": "player not found"}), 404
if mode not in ("daily", "unlimited"):
return jsonify({"error": "invalid mode"}), 400
max_attempts = get_max_attempts()
if mode == "daily":
game_date = _game_date()
target = daily_target(game_date)
# Bereits heute gespielt?
existing = existing_daily_session(player_id, game_date)
if existing and existing.status != "in_progress":
return jsonify({
"session_id": existing.id,
"mode": mode,
"max_attempts": max_attempts,
"status": existing.status,
"already_played": True,
"target": _movie_public(target),
"attempts_used": existing.attempts_used,
})
# In-progress Rueckgabe, sonst neue Runde
if existing:
return jsonify({
"session_id": existing.id,
"mode": mode,
"max_attempts": max_attempts,
"status": existing.status,
"already_played": False,
"attempts_used": existing.attempts_used,
})
session = Session(
player_id=player_id, mode=mode, target_movie_id=target.id,
status="in_progress", attempts_used=0, date=game_date,
)
db.session.add(session)
db.session.commit()
return jsonify({
"session_id": session.id,
"mode": mode,
"max_attempts": max_attempts,
"status": "in_progress",
"already_played": False,
"attempts_used": 0,
})
# Unbegrenzt: neue Zufallsrunde
target = random_target()
if target is None:
return jsonify({"error": "no movies"}), 500
session = Session(
player_id=player_id, mode="unlimited", target_movie_id=target.id,
status="in_progress", attempts_used=0,
)
db.session.add(session)
db.session.commit()
return jsonify({
"session_id": session.id,
"mode": mode,
"max_attempts": max_attempts,
"status": "in_progress",
"already_played": False,
"attempts_used": 0,
})
@bp.route("/api/guess", methods=["POST"])
def api_guess():
data = request.get_json(silent=True) or {}
session_id = data.get("session_id")
movie_id = data.get("movie_id")
if not session_id or not movie_id:
return jsonify({"error": "session_id and movie_id required"}), 400
session = Session.query.get(session_id)
if session is None:
return jsonify({"error": "session not found"}), 404
if session.status != "in_progress":
return jsonify({"error": "session already finished", "status": session.status}), 409
guess = Movie.query.get(movie_id)
if guess is None:
return jsonify({"error": "movie not found"}), 404
target = Movie.query.get(session.target_movie_id)
max_attempts = get_max_attempts()
compared = compare(guess, target)
session.attempts_used += 1
used = session.attempts_used
finished = False
status = "in_progress"
won = False
if is_correct(compared):
finish_session(session, True)
finished = True
won = True
status = "won"
elif used >= max_attempts:
finish_session(session, False)
finished = True
won = False
status = "lost"
response = {
"session_id": session.id,
"attempts_used": used,
"max_attempts": max_attempts,
"status": status,
"finished": finished,
"won": won,
"row": compared,
}
if finished:
response["target"] = _movie_public(target)
response["streaks"] = get_streaks(session.player_id)
return jsonify(response)
@bp.route("/api/streaks", methods=["POST"])
def api_streaks():
data = request.get_json(silent=True) or {}
player_id = data.get("player_id")
if not player_id:
return jsonify({"error": "player_id required"}), 400
return jsonify(get_streaks(player_id) or {"error": "player not found"})
@bp.route("/api/new-game", methods=["POST"])
def api_new_game():
"""Startet (fuer den Unbegrenzt-Modus) eine neue Zufallsrunde."""
data = request.get_json(silent=True) or {}
player_id = data.get("player_id")
if not player_id or Player.query.get(player_id) is None:
return jsonify({"error": "player not found"}), 404
target = random_target()
if target is None:
return jsonify({"error": "no movies"}), 500
session = Session(
player_id=player_id, mode="unlimited", target_movie_id=target.id,
status="in_progress", attempts_used=0,
)
db.session.add(session)
db.session.commit()
return jsonify({
"session_id": session.id,
"mode": "unlimited",
"max_attempts": get_max_attempts(),
"status": "in_progress",
"attempts_used": 0,
})
def _movie_public(movie):
return {
"id": movie.id,
"title": movie.title,
"year": movie.year,
"fsk": movie.fsk,
"studio": movie.studio.name if movie.studio else None,
"director": movie.director,
"budget": movie.budget,
"universe": movie.universe.name if movie.universe else None,
"genres": [g.name for g in movie.genres],
"platforms": [p.name for p in movie.platforms],
}