Merge remote-tracking branch 'Quizifiy/main'
This commit is contained in:
97
app.py
97
app.py
@@ -10,6 +10,9 @@ 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")
|
||||
@@ -34,15 +37,13 @@ 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=".cache"
|
||||
cache_path=None # <--- wichtig!
|
||||
)
|
||||
if sp_oauth.is_token_expired(token_info):
|
||||
token_info = sp_oauth.refresh_access_token(token_info['refresh_token'])
|
||||
@@ -53,13 +54,20 @@ 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("'", "") # Optional: alle Apostrophen entfernen
|
||||
return title.strip()
|
||||
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()
|
||||
|
||||
def get_all_playlist_tracks(sp, playlist_id):
|
||||
tracks = []
|
||||
@@ -109,17 +117,28 @@ def callback():
|
||||
user = sp.current_user()
|
||||
session["user"] = user
|
||||
|
||||
return redirect("/playlists")
|
||||
# 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
|
||||
|
||||
@app.route("/playlists")
|
||||
def playlists():
|
||||
sp = get_spotify_client()
|
||||
playlists = sp.current_user_playlists()["items"]
|
||||
return render_template("playlists.html", playlists=playlists, translations=get_translations())
|
||||
user = get_user_from_cookie()
|
||||
return render_template("playlists.html", playlists=playlists, translations=get_translations(), user=user)
|
||||
|
||||
@app.route("/quiz/<playlist_id>")
|
||||
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)
|
||||
@@ -161,8 +180,10 @@ 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(
|
||||
"quiz.html",
|
||||
template,
|
||||
track=track,
|
||||
access_token=access_token,
|
||||
playlist_id=playlist_id,
|
||||
@@ -172,7 +193,8 @@ def quiz(playlist_id):
|
||||
total_questions=len(tracks),
|
||||
score=score,
|
||||
answered=answered,
|
||||
translations=get_translations()
|
||||
translations=get_translations(),
|
||||
user=user
|
||||
)
|
||||
|
||||
@app.route("/search_track", methods=["POST"])
|
||||
@@ -215,7 +237,8 @@ def check_answer():
|
||||
game_mode = data.get('game_mode', 'artist')
|
||||
playlist_id = data.get('playlist_id')
|
||||
|
||||
if game_mode == 'title':
|
||||
# Immer clean_title für title und artist
|
||||
if game_mode in ['title', 'artist']:
|
||||
guess = clean_title(guess)
|
||||
correct_answer = clean_title(correct_answer)
|
||||
|
||||
@@ -279,12 +302,9 @@ def toggle_playback():
|
||||
@app.route('/logout')
|
||||
def logout():
|
||||
session.clear()
|
||||
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())
|
||||
resp = redirect(url_for('home'))
|
||||
resp.set_cookie("quizify_user", "", expires=0)
|
||||
return resp
|
||||
|
||||
@app.route("/reset_quiz/<playlist_id>")
|
||||
def reset_quiz(playlist_id):
|
||||
@@ -295,5 +315,50 @@ 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/<playlist_id>")
|
||||
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/<token>")
|
||||
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/<playlist_id>")
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user