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], }