modified: .env.example

modified:   Dockerfile
	modified:   app.py
	new file:   locales/de-DE.json
	modified:   templates/login.html
	modified:   templates/playlists.html
	modified:   templates/quiz.html
This commit is contained in:
SimolZimol
2025-05-19 17:39:11 +02:00
parent 53e669b5c1
commit d38254bc3c
7 changed files with 69 additions and 23 deletions

View File

@@ -7,4 +7,6 @@ SPOTIPY_REDIRECT_URI=http://localhost:5000/callback
SECRET_KEY=dein_geheimer_flask_key SECRET_KEY=dein_geheimer_flask_key
# Flask Umgebung (optional) # Flask Umgebung (optional)
FLASK_ENV=development FLASK_ENV=development
LANG=de-DE

View File

@@ -17,6 +17,7 @@ ENV SPOTIPY_CLIENT_ID=$SPOTIPY_CLIENT_ID
ENV SPOTIPY_CLIENT_SECRET=$SPOTIPY_CLIENT_SECRET ENV SPOTIPY_CLIENT_SECRET=$SPOTIPY_CLIENT_SECRET
ENV SPOTIPY_REDIRECT_URI=$SPOTIPY_REDIRECT_URI ENV SPOTIPY_REDIRECT_URI=$SPOTIPY_REDIRECT_URI
ENV FLASK_ENV=development ENV FLASK_ENV=development
ENV LANG=$LANG
# Starten mit Gunicorn für Production # Starten mit Gunicorn für Production
CMD ["python", "app.py"] CMD ["python", "app.py"]

18
app.py
View File

@@ -9,6 +9,7 @@ from spotipy.oauth2 import SpotifyOAuth
import random import random
from difflib import SequenceMatcher from difflib import SequenceMatcher
import re import re
import json
app = Flask(__name__) app = Flask(__name__)
app.secret_key = os.getenv("SECRET_KEY") app.secret_key = os.getenv("SECRET_KEY")
@@ -16,6 +17,20 @@ app.secret_key = os.getenv("SECRET_KEY")
# Erweiterte Berechtigungen für Web Playback SDK # Erweiterte Berechtigungen für Web Playback SDK
SCOPE = "user-library-read playlist-read-private streaming user-read-email user-read-private" SCOPE = "user-library-read playlist-read-private streaming user-read-email user-read-private"
def get_locale():
return os.getenv("LANG", "de-DE")
def get_translations():
lang = get_locale()
path = os.path.join(os.path.dirname(__file__), "locales", f"{lang}.json")
try:
with open(path, encoding="utf-8") as f:
return json.load(f)
except Exception:
# Fallback auf Deutsch
with open(os.path.join(os.path.dirname(__file__), "locales", "de-DE.json"), encoding="utf-8") as f:
return json.load(f)
def get_spotify_client(): def get_spotify_client():
token_info = session.get("token_info", None) token_info = session.get("token_info", None)
if not token_info: if not token_info:
@@ -150,7 +165,8 @@ def quiz(playlist_id):
question_number=len(played_tracks), question_number=len(played_tracks),
total_questions=len(tracks), total_questions=len(tracks),
score=score, score=score,
answered=answered answered=answered,
translations=get_translations()
) )
@app.route("/search_track", methods=["POST"]) @app.route("/search_track", methods=["POST"])

24
locales/de-DE.json Normal file
View File

@@ -0,0 +1,24 @@
{
"login_title": "Login mit Spotify",
"login_button": "Mit Spotify einloggen",
"quiz_title": "Musik Quiz",
"choose_playlist": "Wähle eine Playlist:",
"guess_artist": "Künstler erraten",
"guess_title": "Titel erraten",
"guess_year": "Jahr erraten",
"question_artist": "Wer ist der Künstler dieses Songs?",
"question_title": "Wie heißt dieser Song?",
"question_year": "In welchem Jahr wurde dieser Song veröffentlicht?",
"input_artist": "Künstlername eingeben...",
"input_title": "Songtitel eingeben...",
"input_year": "Jahr eingeben...",
"answer_button": "Antworten",
"next_question": "Nächste Frage",
"quiz_end": "Quiz beenden",
"tip_artist": "Tipp: Gib den Namen des Künstlers ein, der diesen Song performt.",
"tip_title": "Tipp: Gib den Titel des Songs ein, den du gerade hörst.",
"tip_year": "Tipp: Gib das Erscheinungsjahr des Songs ein.",
"correct": "Richtig! 🎉",
"wrong": "Falsch 😢",
"right_answer": "Die richtige Antwort ist:"
}

View File

@@ -1,7 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>Login mit Spotify</title> <title>{{ translations['login_title'] }}</title>
<style> <style>
body { body {
background: linear-gradient(135deg, #1DB954 0%, #191414 100%); background: linear-gradient(135deg, #1DB954 0%, #191414 100%);
@@ -46,7 +46,7 @@
<body> <body>
<div class="login-container"> <div class="login-container">
<h1>Quizify Musik Quiz</h1> <h1>Quizify Musik Quiz</h1>
<a href="/login" class="button">Mit Spotify einloggen</a> <a href="/login" class="button">{{ translations['login_button'] }}</a>
</div> </div>
</body> </body>
</html> </html>

View File

@@ -1,7 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>Deine Playlists</title> <title>{{ translations['quiz_title'] }}</title>
<style> <style>
body { body {
background: linear-gradient(135deg, #191414 0%, #1DB954 100%); background: linear-gradient(135deg, #191414 0%, #1DB954 100%);
@@ -55,7 +55,7 @@
</head> </head>
<body> <body>
<div class="playlist-container"> <div class="playlist-container">
<h2>Wähle eine Playlist:</h2> <h2>{{ translations['choose_playlist'] }}</h2>
<ul> <ul>
{% for pl in playlists %} {% for pl in playlists %}
<li><a class="playlist-link" href="/quiz/{{ pl.id }}">{{ pl.name }}</a></li> <li><a class="playlist-link" href="/quiz/{{ pl.id }}">{{ pl.name }}</a></li>

View File

@@ -1,7 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>Musik Quiz</title> <title>{{ translations['quiz_title'] }}</title>
<!-- Spotify Web Playback SDK --> <!-- Spotify Web Playback SDK -->
<script src="https://sdk.scdn.co/spotify-player.js"></script> <script src="https://sdk.scdn.co/spotify-player.js"></script>
<style> <style>
@@ -104,6 +104,9 @@
let currentGameMode = "{{ game_mode }}"; let currentGameMode = "{{ game_mode }}";
let correctAnswer = ""; let correctAnswer = "";
// translations für JS verfügbar machen
const i18n = {{ translations|tojson }};
// Wird aufgerufen, wenn Spotify Web Playback SDK geladen ist // Wird aufgerufen, wenn Spotify Web Playback SDK geladen ist
window.onSpotifyWebPlaybackSDKReady = () => { window.onSpotifyWebPlaybackSDKReady = () => {
const token = '{{ access_token }}'; const token = '{{ access_token }}';
@@ -184,16 +187,16 @@
function setCorrectAnswer() { function setCorrectAnswer() {
if (currentGameMode === 'artist') { if (currentGameMode === 'artist') {
correctAnswer = "{{ track.artists[0].name }}"; correctAnswer = "{{ track.artists[0].name }}";
document.getElementById('question-text').innerText = "Wer ist der Künstler dieses Songs?"; document.getElementById('question-text').innerText = i18n.question_artist;
document.getElementById('answerInput').placeholder = "Künstlername eingeben..."; document.getElementById('answerInput').placeholder = i18n.input_artist;
} else if (currentGameMode === 'title') { } else if (currentGameMode === 'title') {
correctAnswer = "{{ track.name }}"; correctAnswer = "{{ track.name }}";
document.getElementById('question-text').innerText = "Wie heißt dieser Song?"; document.getElementById('question-text').innerText = i18n.question_title;
document.getElementById('answerInput').placeholder = "Songtitel eingeben..."; document.getElementById('answerInput').placeholder = i18n.input_title;
} else if (currentGameMode === 'year') { } else if (currentGameMode === 'year') {
correctAnswer = "{{ track.album.release_date[:4] }}"; correctAnswer = "{{ track.album.release_date[:4] }}";
document.getElementById('question-text').innerText = "In welchem Jahr wurde dieser Song veröffentlicht?"; document.getElementById('question-text').innerText = i18n.question_year;
document.getElementById('answerInput').placeholder = "Jahr eingeben..."; document.getElementById('answerInput').placeholder = i18n.input_year;
document.getElementById('answerInput').type = "number"; document.getElementById('answerInput').type = "number";
} }
} }
@@ -332,16 +335,16 @@ window.onload = function() {
<div style="text-align:center; margin-bottom: 20px;"> <div style="text-align:center; margin-bottom: 20px;">
<a href="/reset_quiz/{{ playlist_id }}" class="btn btn-danger" style="margin-top:10px;">Quiz beenden</a> <a href="/reset_quiz/{{ playlist_id }}" class="btn btn-danger" style="margin-top:10px;">Quiz beenden</a>
</div> </div>
<h2 id="question-text">Wer ist der Künstler dieses Songs?</h2> <h2 id="question-text">{{ translations['question_artist'] }}</h2>
<!-- Verstecktes Feld für device_id --> <!-- Verstecktes Feld für device_id -->
<input type="hidden" id="device_id" value=""> <input type="hidden" id="device_id" value="">
<!-- Spielmodi --> <!-- Spielmodi -->
<div class="game-modes"> <div class="game-modes">
<button class="btn {{ 'btn-success' if game_mode == 'artist' else 'btn-secondary' }}" onclick="switchGameMode('artist')">Künstler erraten</button> <button class="btn {{ 'btn-success' if game_mode == 'artist' else 'btn-secondary' }}" onclick="switchGameMode('artist')">{{ translations['guess_artist'] }}</button>
<button class="btn {{ 'btn-success' if game_mode == 'title' else 'btn-secondary' }}" onclick="switchGameMode('title')">Titel erraten</button> <button class="btn {{ 'btn-success' if game_mode == 'title' else 'btn-secondary' }}" onclick="switchGameMode('title')">{{ translations['guess_title'] }}</button>
<button class="btn {{ 'btn-success' if game_mode == 'year' else 'btn-secondary' }}" onclick="switchGameMode('year')">Jahr erraten</button> <button class="btn {{ 'btn-success' if game_mode == 'year' else 'btn-secondary' }}" onclick="switchGameMode('year')">{{ translations['guess_year'] }}</button>
</div> </div>
<!-- Optionen für das Spiel --> <!-- Optionen für das Spiel -->
@@ -369,8 +372,8 @@ window.onload = function() {
<!-- Antwort-Eingabe --> <!-- Antwort-Eingabe -->
<div style="text-align: center; margin-top: 30px;"> <div style="text-align: center; margin-top: 30px;">
<input type="text" id="answerInput" placeholder="Gib deine Antwort ein..." oninput="searchTracks()"> <input type="text" id="answerInput" placeholder="{{ translations['input_artist'] }}" oninput="searchTracks()">
<button class="btn" onclick="checkAnswer()">Antworten</button> <button class="btn" onclick="checkAnswer()">{{ translations['answer_button'] }}</button>
<!-- Suchergebnisse --> <!-- Suchergebnisse -->
<div id="searchResults" class="search-results"></div> <div id="searchResults" class="search-results"></div>
@@ -379,17 +382,17 @@ window.onload = function() {
<div id="resultContainer" class="result-container"></div> <div id="resultContainer" class="result-container"></div>
<!-- Nächste Frage Button, wird nach Antwort angezeigt --> <!-- Nächste Frage Button, wird nach Antwort angezeigt -->
<a id="nextQuestionBtn" href="/quiz/{{ playlist_id }}?mode={{ game_mode }}" class="btn" style="display: none;">Nächste Frage</a> <a id="nextQuestionBtn" href="/quiz/{{ playlist_id }}?mode={{ game_mode }}" class="btn" style="display: none;">{{ translations['next_question'] }}</a>
</div> </div>
<!-- Hilfe-Text je nach Modus --> <!-- Hilfe-Text je nach Modus -->
<div class="hint-container"> <div class="hint-container">
{% if game_mode == 'artist' %} {% if game_mode == 'artist' %}
<p>Tipp: Gib den Namen des Künstlers ein, der diesen Song performt.</p> <p>{{ translations['tip_artist'] }}</p>
{% elif game_mode == 'title' %} {% elif game_mode == 'title' %}
<p>Tipp: Gib den Titel des Songs ein, den du gerade hörst.</p> <p>{{ translations['tip_title'] }}</p>
{% elif game_mode == 'year' %} {% elif game_mode == 'year' %}
<p>Tipp: Gib das Erscheinungsjahr des Songs ein.</p> <p>{{ translations['tip_year'] }}</p>
{% endif %} {% endif %}
</div> </div>
</body> </body>