226 lines
6.9 KiB
Python
226 lines
6.9 KiB
Python
__version__ = "pre-dev"
|
|
__all__ = ["quizify"]
|
|
__author__ = "SimolZimol"
|
|
|
|
from flask import Flask, redirect, request, session, url_for, render_template
|
|
import os
|
|
import spotipy
|
|
from spotipy.oauth2 import SpotifyOAuth
|
|
import random
|
|
from difflib import SequenceMatcher
|
|
import re
|
|
|
|
app = Flask(__name__)
|
|
app.secret_key = os.getenv("SECRET_KEY")
|
|
|
|
# Erweiterte Berechtigungen für Web Playback SDK
|
|
SCOPE = "user-library-read playlist-read-private streaming user-read-email user-read-private"
|
|
|
|
def get_spotify_client():
|
|
return spotipy.Spotify(auth_manager=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"
|
|
))
|
|
|
|
def similarity(a, b):
|
|
return SequenceMatcher(None, a.lower(), b.lower()).ratio()
|
|
|
|
def clean_title(title):
|
|
# Entfernt (feat. ...), [Remix ...], (Remix), [xyz], usw.
|
|
return re.sub(r"(\s*[\(\[][^)\]]*[\)\]])", "", title).strip()
|
|
|
|
@app.route("/")
|
|
def home():
|
|
return render_template("login.html")
|
|
|
|
@app.route("/login")
|
|
def login():
|
|
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
|
|
)
|
|
auth_url = sp_oauth.get_authorize_url()
|
|
return redirect(auth_url)
|
|
|
|
@app.route("/callback")
|
|
def callback():
|
|
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
|
|
)
|
|
session.clear()
|
|
code = request.args.get('code')
|
|
token_info = sp_oauth.get_access_token(code)
|
|
session["token_info"] = token_info
|
|
return redirect("/playlists")
|
|
|
|
@app.route("/playlists")
|
|
def playlists():
|
|
sp = get_spotify_client()
|
|
playlists = sp.current_user_playlists()["items"]
|
|
return render_template("playlists.html", playlists=playlists)
|
|
|
|
@app.route("/quiz/<playlist_id>")
|
|
def quiz(playlist_id):
|
|
game_mode = request.args.get('mode', 'artist')
|
|
|
|
sp = get_spotify_client()
|
|
items = sp.playlist_items(playlist_id, additional_types=["track"])["items"]
|
|
tracks = [item["track"] for item in items if item.get("track")]
|
|
|
|
if not tracks:
|
|
return "Keine Tracks verfügbar!"
|
|
|
|
# Gespielte Tracks aus der Session holen
|
|
played_tracks = session.get(f'played_tracks_{playlist_id}', [])
|
|
|
|
# Filtere bereits gespielte Tracks heraus
|
|
available_tracks = [t for t in tracks if t["id"] not in played_tracks]
|
|
|
|
# Wenn alle gespielt wurden, zurücksetzen
|
|
if not available_tracks:
|
|
played_tracks = []
|
|
available_tracks = tracks
|
|
|
|
track = random.choice(available_tracks)
|
|
played_tracks.append(track["id"])
|
|
session[f'played_tracks_{playlist_id}'] = played_tracks
|
|
|
|
# Token aus der Sitzung holen für das Web Playback SDK
|
|
token_info = session.get('token_info', None)
|
|
if not token_info:
|
|
return redirect('/login')
|
|
|
|
# Zugriff auf access_token
|
|
access_token = token_info['access_token']
|
|
|
|
# Alle Tracks für die Suchfunktion (für title und artist mode)
|
|
all_tracks = []
|
|
for item in tracks:
|
|
track_info = {
|
|
"id": item["id"],
|
|
"name": item["name"],
|
|
"artist": item["artists"][0]["name"],
|
|
"uri": item["uri"],
|
|
"release_date": item.get("album", {}).get("release_date", "Unbekannt")[:4] # Nur das Jahr
|
|
}
|
|
all_tracks.append(track_info)
|
|
|
|
return render_template(
|
|
"quiz.html",
|
|
track=track,
|
|
access_token=access_token,
|
|
playlist_id=playlist_id,
|
|
game_mode=game_mode,
|
|
all_tracks=all_tracks
|
|
)
|
|
|
|
@app.route("/search_track", methods=["POST"])
|
|
def search_track():
|
|
data = request.json
|
|
query = data.get('query', '').lower()
|
|
all_tracks = data.get('all_tracks', [])
|
|
|
|
if not query or not all_tracks:
|
|
return {"results": []}
|
|
|
|
# Tracks nach Ähnlichkeit filtern (80% Übereinstimmung)
|
|
results = []
|
|
for track in all_tracks:
|
|
name_similarity = similarity(query, track["name"])
|
|
artist_similarity = similarity(query, track["artist"])
|
|
|
|
# Wenn Name oder Künstler zu 80% übereinstimmt
|
|
if name_similarity >= 0.8 or artist_similarity >= 0.8:
|
|
results.append({
|
|
"id": track["id"],
|
|
"name": track["name"],
|
|
"artist": track["artist"],
|
|
"uri": track["uri"],
|
|
"similarity": max(name_similarity, artist_similarity)
|
|
})
|
|
|
|
# Nach Ähnlichkeit sortieren
|
|
results.sort(key=lambda x: x["similarity"], reverse=True)
|
|
|
|
return {"results": results}
|
|
|
|
@app.route("/check_answer", methods=["POST"])
|
|
def check_answer():
|
|
data = request.json
|
|
guess = data.get('guess', '').lower()
|
|
correct_answer = data.get('correct_answer', '').lower()
|
|
game_mode = data.get('game_mode', 'artist')
|
|
|
|
# Titel ggf. bereinigen
|
|
if game_mode == 'title':
|
|
guess = clean_title(guess)
|
|
correct_answer = clean_title(correct_answer)
|
|
|
|
# Bei Jahr-Modus: Exakte Übereinstimmung prüfen
|
|
if game_mode == 'year':
|
|
is_correct = guess == correct_answer
|
|
else:
|
|
# Bei anderen Modi: Ähnlichkeitsprüfung (90% Übereinstimmung gilt als korrekt)
|
|
is_correct = similarity(guess, correct_answer) >= 0.9
|
|
|
|
return {
|
|
"correct": is_correct,
|
|
"correct_answer": correct_answer
|
|
}
|
|
|
|
@app.route("/play_track", methods=["POST"])
|
|
def play_track():
|
|
device_id = request.args.get('device_id')
|
|
track_uri = request.args.get('track_uri')
|
|
|
|
if not device_id or not track_uri:
|
|
return {"error": "Missing device_id or track_uri"}, 400
|
|
|
|
sp = get_spotify_client()
|
|
sp.start_playback(device_id=device_id, uris=[track_uri])
|
|
|
|
return {"success": True}
|
|
|
|
@app.route("/toggle_playback", methods=["POST"])
|
|
def toggle_playback():
|
|
data = request.json
|
|
device_id = data.get('device_id')
|
|
|
|
if not device_id:
|
|
return {"error": "Missing device_id"}, 400
|
|
|
|
sp = get_spotify_client()
|
|
# Playback-Status für das richtige Gerät prüfen
|
|
current_playback = sp.current_playback()
|
|
is_playing = False
|
|
if current_playback and current_playback.get('device', {}).get('id') == device_id:
|
|
is_playing = current_playback.get('is_playing', False)
|
|
|
|
if is_playing:
|
|
sp.pause_playback(device_id=device_id)
|
|
else:
|
|
sp.start_playback(device_id=device_id)
|
|
|
|
return {"success": True}
|
|
|
|
@app.route('/logout')
|
|
def logout():
|
|
session.pop('user', None)
|
|
return redirect(url_for('index'))
|
|
|
|
@app.route('/')
|
|
def index():
|
|
user = session.get('user') # Benutzerinfos aus der Session holen, falls vorhanden
|
|
return render_template('index.html', user=user)
|
|
|
|
if __name__ == "__main__":
|
|
app.run(host="0.0.0.0", port=5000, debug=True)
|