diff --git a/app.py b/app.py index cb75c93..e0d0daa 100644 --- a/app.py +++ b/app.py @@ -10,9 +10,6 @@ import random from difflib import SequenceMatcher import re import json -import unicodedata -import secrets -from datetime import datetime, timedelta app = Flask(__name__) app.secret_key = os.getenv("SECRET_KEY") @@ -37,13 +34,15 @@ def get_translations(): def get_spotify_client(): token_info = session.get("token_info", None) if not token_info: + # Kein Token, redirect handled elsewhere return None + # Prüfen, ob Token abgelaufen ist sp_oauth = SpotifyOAuth( client_id=os.getenv("SPOTIPY_CLIENT_ID"), client_secret=os.getenv("SPOTIPY_CLIENT_SECRET"), redirect_uri=os.getenv("SPOTIPY_REDIRECT_URI"), scope=SCOPE, - cache_path=None # <--- wichtig! + cache_path=".cache" ) if sp_oauth.is_token_expired(token_info): token_info = sp_oauth.refresh_access_token(token_info['refresh_token']) @@ -54,20 +53,13 @@ def similarity(a, b): return SequenceMatcher(None, a.lower(), b.lower()).ratio() def clean_title(title): - # Unicode-Normalisierung (z.B. é -> e) - title = unicodedata.normalize('NFKD', title) - title = "".join([c for c in title if not unicodedata.combining(c)]) # Entfernt alles in () oder [] title = re.sub(r"(\s*[\(\[][^)\]]*[\)\]])", "", title) # Vereinheitliche Apostrophen und Anführungszeichen title = title.replace("’", "'").replace("‘", "'").replace("`", "'") title = title.replace('"', '').replace("„", '').replace("“", '').replace("”", '') - title = title.replace("'", "") - # Entferne alle nicht-alphanumerischen Zeichen (außer Leerzeichen) - title = re.sub(r"[^a-zA-Z0-9äöüÄÖÜß ]", "", title) - # Mehrfache Leerzeichen zu einem - title = re.sub(r"\s+", " ", title) - return title.strip().lower() + title = title.replace("'", "") # Optional: alle Apostrophen entfernen + return title.strip() def get_all_playlist_tracks(sp, playlist_id): tracks = [] @@ -117,28 +109,17 @@ def callback(): user = sp.current_user() session["user"] = user - # Setze ein 30-Tage-Cookie mit Userdaten (ohne Token!) - resp = redirect("/playlists") - user_cookie = json.dumps({ - "id": user.get("id"), - "display_name": user.get("display_name"), - "email": user.get("email"), - "images": user.get("images"), - }) - resp.set_cookie("quizify_user", user_cookie, max_age=60*60*24*30, httponly=True, samesite="Lax") - return resp + return redirect("/playlists") @app.route("/playlists") def playlists(): sp = get_spotify_client() playlists = sp.current_user_playlists()["items"] - user = get_user_from_cookie() - return render_template("playlists.html", playlists=playlists, translations=get_translations(), user=user) + return render_template("playlists.html", playlists=playlists, translations=get_translations()) @app.route("/quiz/") def quiz(playlist_id): game_mode = request.args.get('mode', 'artist') - is_multiplayer = request.args.get('local_multiplayer') == '1' sp = get_spotify_client() tracks = get_all_playlist_tracks(sp, playlist_id) @@ -180,10 +161,8 @@ def quiz(playlist_id): } all_tracks.append(track_info) - user = get_user_from_cookie() - template = "quiz_multiplayer.html" if is_multiplayer else "quiz_single.html" return render_template( - template, + "quiz.html", track=track, access_token=access_token, playlist_id=playlist_id, @@ -193,8 +172,7 @@ def quiz(playlist_id): total_questions=len(tracks), score=score, answered=answered, - translations=get_translations(), - user=user + translations=get_translations() ) @app.route("/search_track", methods=["POST"]) @@ -237,8 +215,7 @@ def check_answer(): game_mode = data.get('game_mode', 'artist') playlist_id = data.get('playlist_id') - # Immer clean_title für title und artist - if game_mode in ['title', 'artist']: + if game_mode == 'title': guess = clean_title(guess) correct_answer = clean_title(correct_answer) @@ -267,13 +244,7 @@ def play_track(): return {"error": "Missing device_id or track_uri"}, 400 sp = get_spotify_client() - try: - sp.start_playback(device_id=device_id, uris=[track_uri], position_ms=position_ms) - except spotipy.exceptions.SpotifyException as e: - if "Device not found" in str(e): - # Spezieller Fehlercode, damit das Frontend weiß, dass es neu laden soll - return {"error": "device_not_found", "message": "Spotify-Player nicht gefunden. Die Seite wird neu geladen..."}, 409 - return {"error": str(e)}, 500 + sp.start_playback(device_id=device_id, uris=[track_uri], position_ms=position_ms) return {"success": True} @@ -302,9 +273,12 @@ def toggle_playback(): @app.route('/logout') def logout(): session.clear() - resp = redirect(url_for('home')) - resp.set_cookie("quizify_user", "", expires=0) - return resp + return redirect(url_for('home')) + +@app.route('/') +def index(): + user = session.get('user') # Benutzerinfos aus der Session holen, falls vorhanden + return render_template('index.html', user=user, translations=get_translations()) @app.route("/reset_quiz/") def reset_quiz(playlist_id): @@ -315,50 +289,5 @@ def reset_quiz(playlist_id): return redirect(url_for('quiz', playlist_id=playlist_id, mode=next_mode)) return redirect(url_for('playlists')) -@app.route("/gamemodes/") -def gamemodes(playlist_id): - return render_template("gamemodes.html", playlist_id=playlist_id, translations=get_translations()) - -invites = {} # {token: expiry_datetime} - -@app.route("/invite") -def invite(): - duration = int(request.args.get("duration", 60)) # Minuten - token = secrets.token_urlsafe(16) - expires = datetime.utcnow() + timedelta(minutes=duration) - invites[token] = expires - invite_link = url_for('guest_join', token=token, _external=True) - # Gib nur den Link als Klartext zurück! - return invite_link - -@app.route("/invite/") -def guest_join(token): - expires = invites.get(token) - if not expires or expires < datetime.utcnow(): - return "Invite link expired or invalid.", 403 - # Setze ein Cookie, damit der Gast als eingeladener User erkannt wird (optional) - resp = redirect(url_for('login')) - resp.set_cookie("guest_token", token, max_age=60*60) # 1 Stunde gültig - return resp - -def get_user_from_cookie(): - user_cookie = request.cookies.get("quizify_user") - if user_cookie: - try: - return json.loads(user_cookie) - except Exception: - return None - return None - -@app.route("/playerselect/") -def playerselect(playlist_id): - game_mode = request.args.get('mode', 'artist') - return render_template( - "playerselect.html", - playlist_id=playlist_id, - game_mode=game_mode, - translations=get_translations() - ) - if __name__ == "__main__": app.run(host="0.0.0.0", port=5000, debug=True) diff --git a/templates/quiz.html b/templates/quiz.html index fbb5d91..6ee08d9 100644 --- a/templates/quiz.html +++ b/templates/quiz.html @@ -6,15 +6,10 @@