Logo und andere kleinen Dinge

This commit is contained in:
mikka 2026-05-14 23:29:06 +02:00
parent 587f2546f9
commit 2623dfdf1a
9 changed files with 422 additions and 255 deletions

330
app.py
View file

@ -1,175 +1,231 @@
from flask import Flask, render_template, request, redirect
from glob import glob
import subprocess
import requests
import json import json
import os import os
import subprocess
from glob import glob
import requests
from flask import Flask, redirect, render_template, request
def wikiapi(id, field):
if os.path.isdir("data"):
pass
else:
os.mkdir("data")
name = f"data/{id}_{field}.json"
try:
with open(name, "r") as f:
data = json.load(f)
except OSError:
r = requests.get(
"https://www.wikidata.org/w/rest.php/wikibase/v1/entities/items/"
+ id
+ "?_fields="
+ field,
headers={
"user-agent": "esc/0.0(mikka@kleinrot.net)",
"Authorization": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJhNDBhYmZjYzQxZTlkOTc2YzJiN2NmODZkYzIwMmQzZiIsImp0aSI6ImQ3ODQ4YmJhNjZlMWYzYzdhZGZmODU5NTdmZWE1YjMxODBhMzE2NTc4YWYyMWMzZGZhZGJiOTZlZmM3ZTgyMmJkMTE4YTQ4YWMzMDM2ZmQyIiwiaWF0IjoxNzc1OTE4OTc1LjkzMjQsIm5iZiI6MTc3NTkxODk3NS45MzI0MDEsImV4cCI6MzMzMzI4Mjc3NzUuOTI5NDA1LCJzdWIiOiIxMzEiLCJpc3MiOiJodHRwczovL21ldGEud2lraW1lZGlhLm9yZyIsInJhdGVsaW1pdCI6eyJyZXF1ZXN0c19wZXJfdW5pdCI6NTAwMCwidW5pdCI6IkhPVVIifSwic2NvcGVzIjpbImJhc2ljIl19.WLXRXxNjsZ1kIK2RX-Wds59W8Z1CWphbiV3UBEWvm5STWZ6uvpHZpx5d9lomK5-H56G3259_DavuTymdebQTmAwkeuCGh1gb60u9_4MzmGgspQHBPq3mWX879AUVW69uqsSz2x2zIz-ZUmt5TrZM7X3OBxE01nhVBoiDWnlW4Gt19FjwBQ9WjXzrFHsH9A7BtPzgbKROMXACRQBqh9XZXkN23PvnEV08sx63AGB0cZBkteIsnIfm49-Ht2_DTZKd4_MpEw9TZjOHSjY9odyImXidZOgy7NadT-LwAKQiVlSn6UZWTvgsG6xwP6sad_ctqU1ZupcOJLzd158DhrLAEMk_Qq9-piTQDYtLzWfLx44Jatjae6-0nilOgvrB0XQJC6cTihVk3-9Lyn6Y-e6yIDnEHIIIBj0J8PUv5IJjAojo-2uZ4w8omEzCWDEzf95_GSZmRwj_nRNCVs5jQpVhG9hFpOm2OrTrhqPgYet_dsl3QVEbvtGnlVzCw7j9sj_86axAC1hklQQso6AiAAzEmOiTfC6VyrP8sFjbnDlLBCEiTkYTvOTp5nuYRC8VdwJQm6NJIafjNn5ihp4T8OvJQyzsK1HDYlthvW54-co2gPoeIX-cBItvdrCBNDofoA9bIP3zzwGXdvy1b7lofx5WekWKAGytPCfsr7i2ZJB93xU",
},
)
data = r.json()
with open(name, "x") as f:
json.dump(data, f, indent=2, ensure_ascii=False)
return data[field]
def wikiapi(id,field):
if os.path.isdir("data"):
pass
else:
os.mkdir("data")
name = f"data/{id}_{field}.json"
try:
with open(name, "r") as f:
data = json.load(f)
except OSError:
r = requests.get("https://www.wikidata.org/w/rest.php/wikibase/v1/entities/items/"+id+"?_fields="+field, headers={"user-agent":'esc/0.0(mikka@kleinrot.net)','Authorization': 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJhNDBhYmZjYzQxZTlkOTc2YzJiN2NmODZkYzIwMmQzZiIsImp0aSI6ImQ3ODQ4YmJhNjZlMWYzYzdhZGZmODU5NTdmZWE1YjMxODBhMzE2NTc4YWYyMWMzZGZhZGJiOTZlZmM3ZTgyMmJkMTE4YTQ4YWMzMDM2ZmQyIiwiaWF0IjoxNzc1OTE4OTc1LjkzMjQsIm5iZiI6MTc3NTkxODk3NS45MzI0MDEsImV4cCI6MzMzMzI4Mjc3NzUuOTI5NDA1LCJzdWIiOiIxMzEiLCJpc3MiOiJodHRwczovL21ldGEud2lraW1lZGlhLm9yZyIsInJhdGVsaW1pdCI6eyJyZXF1ZXN0c19wZXJfdW5pdCI6NTAwMCwidW5pdCI6IkhPVVIifSwic2NvcGVzIjpbImJhc2ljIl19.WLXRXxNjsZ1kIK2RX-Wds59W8Z1CWphbiV3UBEWvm5STWZ6uvpHZpx5d9lomK5-H56G3259_DavuTymdebQTmAwkeuCGh1gb60u9_4MzmGgspQHBPq3mWX879AUVW69uqsSz2x2zIz-ZUmt5TrZM7X3OBxE01nhVBoiDWnlW4Gt19FjwBQ9WjXzrFHsH9A7BtPzgbKROMXACRQBqh9XZXkN23PvnEV08sx63AGB0cZBkteIsnIfm49-Ht2_DTZKd4_MpEw9TZjOHSjY9odyImXidZOgy7NadT-LwAKQiVlSn6UZWTvgsG6xwP6sad_ctqU1ZupcOJLzd158DhrLAEMk_Qq9-piTQDYtLzWfLx44Jatjae6-0nilOgvrB0XQJC6cTihVk3-9Lyn6Y-e6yIDnEHIIIBj0J8PUv5IJjAojo-2uZ4w8omEzCWDEzf95_GSZmRwj_nRNCVs5jQpVhG9hFpOm2OrTrhqPgYet_dsl3QVEbvtGnlVzCw7j9sj_86axAC1hklQQso6AiAAzEmOiTfC6VyrP8sFjbnDlLBCEiTkYTvOTp5nuYRC8VdwJQm6NJIafjNn5ihp4T8OvJQyzsK1HDYlthvW54-co2gPoeIX-cBItvdrCBNDofoA9bIP3zzwGXdvy1b7lofx5WekWKAGytPCfsr7i2ZJB93xU'})
data = r.json()
with open(name, "x") as f:
json.dump(data, f,indent=2,ensure_ascii=False)
return data[field]
def wikisuche(text): def wikisuche(text):
mitp1344 = [] mitpartsin = []
ohnep1344 = [] ohnepartsin = []
r = requests.get("https://www.wikidata.org/w/rest.php/wikibase/v1/search/items?q="+text+"&language=en", headers={"user-agent":'esc/0.0(mikka@kleinrot.net)','Authorization': 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJhNDBhYmZjYzQxZTlkOTc2YzJiN2NmODZkYzIwMmQzZiIsImp0aSI6ImQ3ODQ4YmJhNjZlMWYzYzdhZGZmODU5NTdmZWE1YjMxODBhMzE2NTc4YWYyMWMzZGZhZGJiOTZlZmM3ZTgyMmJkMTE4YTQ4YWMzMDM2ZmQyIiwiaWF0IjoxNzc1OTE4OTc1LjkzMjQsIm5iZiI6MTc3NTkxODk3NS45MzI0MDEsImV4cCI6MzMzMzI4Mjc3NzUuOTI5NDA1LCJzdWIiOiIxMzEiLCJpc3MiOiJodHRwczovL21ldGEud2lraW1lZGlhLm9yZyIsInJhdGVsaW1pdCI6eyJyZXF1ZXN0c19wZXJfdW5pdCI6NTAwMCwidW5pdCI6IkhPVVIifSwic2NvcGVzIjpbImJhc2ljIl19.WLXRXxNjsZ1kIK2RX-Wds59W8Z1CWphbiV3UBEWvm5STWZ6uvpHZpx5d9lomK5-H56G3259_DavuTymdebQTmAwkeuCGh1gb60u9_4MzmGgspQHBPq3mWX879AUVW69uqsSz2x2zIz-ZUmt5TrZM7X3OBxE01nhVBoiDWnlW4Gt19FjwBQ9WjXzrFHsH9A7BtPzgbKROMXACRQBqh9XZXkN23PvnEV08sx63AGB0cZBkteIsnIfm49-Ht2_DTZKd4_MpEw9TZjOHSjY9odyImXidZOgy7NadT-LwAKQiVlSn6UZWTvgsG6xwP6sad_ctqU1ZupcOJLzd158DhrLAEMk_Qq9-piTQDYtLzWfLx44Jatjae6-0nilOgvrB0XQJC6cTihVk3-9Lyn6Y-e6yIDnEHIIIBj0J8PUv5IJjAojo-2uZ4w8omEzCWDEzf95_GSZmRwj_nRNCVs5jQpVhG9hFpOm2OrTrhqPgYet_dsl3QVEbvtGnlVzCw7j9sj_86axAC1hklQQso6AiAAzEmOiTfC6VyrP8sFjbnDlLBCEiTkYTvOTp5nuYRC8VdwJQm6NJIafjNn5ihp4T8OvJQyzsK1HDYlthvW54-co2gPoeIX-cBItvdrCBNDofoA9bIP3zzwGXdvy1b7lofx5WekWKAGytPCfsr7i2ZJB93xU'}) r = requests.get(
for result in r.json()["results"]: "https://www.wikidata.org/w/rest.php/wikibase/v1/search/items?q="
if getescedition(result["id"]): + text
mitp1344.append(result) + "&language=en",
else: headers={
ohnep1344.append(result) "user-agent": "esc/0.0(mikka@kleinrot.net)",
return mitp1344 + ohnep1344 "Authorization": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJhNDBhYmZjYzQxZTlkOTc2YzJiN2NmODZkYzIwMmQzZiIsImp0aSI6ImQ3ODQ4YmJhNjZlMWYzYzdhZGZmODU5NTdmZWE1YjMxODBhMzE2NTc4YWYyMWMzZGZhZGJiOTZlZmM3ZTgyMmJkMTE4YTQ4YWMzMDM2ZmQyIiwiaWF0IjoxNzc1OTE4OTc1LjkzMjQsIm5iZiI6MTc3NTkxODk3NS45MzI0MDEsImV4cCI6MzMzMzI4Mjc3NzUuOTI5NDA1LCJzdWIiOiIxMzEiLCJpc3MiOiJodHRwczovL21ldGEud2lraW1lZGlhLm9yZyIsInJhdGVsaW1pdCI6eyJyZXF1ZXN0c19wZXJfdW5pdCI6NTAwMCwidW5pdCI6IkhPVVIifSwic2NvcGVzIjpbImJhc2ljIl19.WLXRXxNjsZ1kIK2RX-Wds59W8Z1CWphbiV3UBEWvm5STWZ6uvpHZpx5d9lomK5-H56G3259_DavuTymdebQTmAwkeuCGh1gb60u9_4MzmGgspQHBPq3mWX879AUVW69uqsSz2x2zIz-ZUmt5TrZM7X3OBxE01nhVBoiDWnlW4Gt19FjwBQ9WjXzrFHsH9A7BtPzgbKROMXACRQBqh9XZXkN23PvnEV08sx63AGB0cZBkteIsnIfm49-Ht2_DTZKd4_MpEw9TZjOHSjY9odyImXidZOgy7NadT-LwAKQiVlSn6UZWTvgsG6xwP6sad_ctqU1ZupcOJLzd158DhrLAEMk_Qq9-piTQDYtLzWfLx44Jatjae6-0nilOgvrB0XQJC6cTihVk3-9Lyn6Y-e6yIDnEHIIIBj0J8PUv5IJjAojo-2uZ4w8omEzCWDEzf95_GSZmRwj_nRNCVs5jQpVhG9hFpOm2OrTrhqPgYet_dsl3QVEbvtGnlVzCw7j9sj_86axAC1hklQQso6AiAAzEmOiTfC6VyrP8sFjbnDlLBCEiTkYTvOTp5nuYRC8VdwJQm6NJIafjNn5ihp4T8OvJQyzsK1HDYlthvW54-co2gPoeIX-cBItvdrCBNDofoA9bIP3zzwGXdvy1b7lofx5WekWKAGytPCfsr7i2ZJB93xU",
},
)
for result in r.json()["results"]:
if getescedition(result["id"]):
mitpartsin.append(result)
else:
ohnepartsin.append(result)
return mitpartsin + ohnepartsin
def getescedition(songId): def getescedition(songId):
statements = wikiapi(songId,"statements") statements = wikiapi(songId, "statements")
if "P1344" in statements: if "partsin" in statements:
for statement in statements["P1344"]: for statement in statements["partsin"]:
id = statement["value"]["content"] id = statement["value"]["content"]
escdata = wikiapi(id,"statements") escdata = wikiapi(id, "statements")
if escdata["P31"][0]["value"]["content"] == "Q110288240": if escdata["P31"][0]["value"]["content"] == "Q110288240":
return id,statement return id, statement
def datei(id): def datei(id):
file = glob("static/"+id+".*") file = glob("static/" + id + ".*")
if file == []:
subprocess.run(
["yt-dlp", f"http://youtu.be/{id}", "-x", "-o", id], cwd="static"
)
file = glob("static/" + id + ".*")
if file != []:
audio = file[0].replace("static/", "")
else:
audio = None
print(audio)
return audio
if file == []:
subprocess.run(["yt-dlp",f"http://youtu.be/{id}","-x","-o",id],cwd="static")
file = glob("static/"+id+".*")
if file != []:
audio = file[0].replace("static/", "")
else:
audio = None
print(audio)
return audio
def kartenGeneriren(song): def kartenGeneriren(song):
id = song["wikiid"] id = song["wikiid"]
print(id) print(id)
statements = wikiapi(id,"statements") statements = wikiapi(id, "statements")
labels = wikiapi(id,"labels") labels = wikiapi(id, "labels")
song["titel"] = statements.get("P1476",[{"value": {"content":{"text":labels["en"]}}}])[0]["value"]["content"]["text"] song["titel"] = statements.get(
song["laenge"] = int(statements.get("P2047",[{"value": {"content":{"amount":"0"}}}])[0]["value"]["content"]["amount"]) "P1476", [{"value": {"content": {"text": labels["en"]}}}]
escedition = getescedition(id) )[0]["value"]["content"]["text"]
if escedition: song["laenge"] = int(
(escedition,statement)=escedition statements.get("P2047", [{"value": {"content": {"amount": "0"}}}])[0]["value"][
song["jahrgang"] = wikiapi(escedition,"labels")["en"] "content"
qualifiers = statement["qualifiers"] ]["amount"]
for qualifier in qualifiers: )
if qualifier["property"]["id"] == "P1352": escedition = getescedition(id)
song["plazirung"] = str(int(qualifier["value"]["content"]["amount"]))+"." if escedition:
song["interprete"] = " x ".join(set(wikiapi(statement["value"]["content"],"labels")["en"] for statement in statements.get("P175",[]))) (escedition, statement) = escedition
if "ytid" not in song and "P1651" in statements: song["jahrgang"] = wikiapi(escedition, "labels")["en"]
song["ytid"] = statements["P1651"][0]["value"]["content"] qualifiers = statement["qualifiers"]
if "ytid" in song: for qualifier in qualifiers:
song["datei"] = datei(song["ytid"]) if qualifier["property"]["id"] == "P1352":
song["img"] = f"http://img.youtube.com/vi/{ song["ytid"] }/sddefault.jpg" song["plazirung"] = (
if "P6218" in statements: str(int(qualifier["value"]["content"]["amount"])) + "."
song["text"] = f"//genius.com/{statements["P6218"][0]["value"]["content"]}" )
if "P18" in statements: song["interprete"] = " x ".join(
song["img"] = f"https://commons.wikimedia.org/w/index.php?title=Special:Redirect/file/{statements["P18"][0]["value"]["content"]}&width=300" set(
if "img" not in song: wikiapi(statement["value"]["content"], "labels")["en"]
song["img"] = "https://commons.wikimedia.org/w/index.php?title=Special:Redirect/file/Eurovision_Song_Contest_heart_(20142025).svg&width=300" for statement in statements.get("P175", [])
)
)
if "land" not in song and "P495" in statements:
song["land"] = wikiapi(statements["P495"][0]["value"]["content"], "labels")[
"de"
]
if "ytid" not in song and "P1651" in statements:
song["ytid"] = statements["P1651"][0]["value"]["content"]
if "ytid" in song:
song["datei"] = datei(song["ytid"])
song["img"] = f"http://img.youtube.com/vi/{song['ytid']}/sddefault.jpg"
if "P6218" in statements:
song["text"] = f"//genius.com/{statements['P6218'][0]['value']['content']}"
if "P18" in statements:
song["img"] = (
f"https://commons.wikimedia.org/w/index.php?title=Special:Redirect/file/{statements['P18'][0]['value']['content']}&width=300"
)
if "img" not in song:
song["img"] = (
"https://commons.wikimedia.org/w/index.php?title=Special:Redirect/file/Eurovision_Song_Contest_heart_(20142025).svg&width=300"
)
app = Flask(__name__) app = Flask(__name__)
@app.template_filter('zeit')
@app.template_filter("zeit")
def zeit(sekunden): def zeit(sekunden):
minuten = sekunden // 60 minuten = sekunden // 60
rest = sekunden - minuten * 60 rest = sekunden - minuten * 60
return f"{minuten}:{rest:02}" return f"{minuten}:{rest:02}"
@app.route("/") @app.route("/")
def hello_world(): def hello_world():
liste = request.args.get("liste") liste = request.args.get("liste")
if liste is None: if liste is None:
return redirect("/playlists") return redirect("/playlists")
with open(liste+".json","r") as f: with open(liste + ".json", "r") as f:
songs = json.load(f) songs = json.load(f)
for song in songs: for song in songs:
kartenGeneriren(song) kartenGeneriren(song)
gesamtLaenge = 0 gesamtLaenge = 0
for song in songs: for song in songs:
gesamtLaenge += song["laenge"] gesamtLaenge += song["laenge"]
return render_template('index.html', karten=songs,gesamtLaenge=gesamtLaenge,liste=liste ) return render_template(
"index.html", karten=songs, gesamtLaenge=gesamtLaenge, liste=liste
)
@app.route("/playlists") @app.route("/playlists")
def playlists(): def playlists():
listen = glob("*.json") listen = glob("*.json")
listen = (liste.replace(".json","") for liste in listen) listen = (liste.replace(".json", "") for liste in listen)
return render_template('playlists.html',lists=listen) return render_template("playlists.html", lists=listen)
@app.route("/neueliste") @app.route("/neueliste")
def neueliste(): def neueliste():
name = request.args.get("name") name = request.args.get("name")
if name is not None: if name is not None:
with open(name +".json", "x") as f: with open(name + ".json", "x") as f:
json.dump([],f) json.dump([], f)
return redirect("/?liste="+name) return redirect("/?liste=" + name)
print(liste) return render_template("neueliste.html", name=name)
return render_template('neueliste.html',name=name)
@app.route("/suche") @app.route("/suche")
def suche(): def suche():
such = request.args.get("suche") such = request.args.get("suche")
liste = request.args.get("liste") liste = request.args.get("liste")
if such is not None: if such is not None:
ergebnisse = wikisuche(such) ergebnisse = wikisuche(such)
else: else:
ergebnisse = [] ergebnisse = []
return render_template('suche.html', ergebnisse=ergebnisse,anfrage=such,liste=liste) return render_template(
"suche.html", ergebnisse=ergebnisse, anfrage=such, liste=liste
)
@app.route("/suche",methods=["POST"])
@app.route("/suche", methods=["POST"])
def suche_finden(): def suche_finden():
liste = request.args.get("liste") liste = request.args.get("liste")
with open(liste +".json","r") as f: with open(liste + ".json", "r") as f:
songs = json.load(f) songs = json.load(f)
song = {"wikiid":request.form.get("id")} song = {"wikiid": request.form.get("id")}
kartenGeneriren(song) kartenGeneriren(song)
songs.append(song) songs.append(song)
with open(liste+".json","w") as f: with open(liste + ".json", "w") as f:
json.dump(songs,f,indent=2,ensure_ascii=False) json.dump(songs, f, indent=2, ensure_ascii=False)
return redirect("/suche?liste="+liste,303) return redirect("/suche?liste=" + liste, 303)
@app.route("/remove") @app.route("/remove")
def admin(): def admin():
liste = request.args.get("liste") liste = request.args.get("liste")
if liste is None: if liste is None:
return redirect("/playlists") return redirect("/playlists")
with open(liste+".json","r") as f: with open(liste + ".json", "r") as f:
songs = json.load(f) songs = json.load(f)
for song in songs: for song in songs:
kartenGeneriren(song) kartenGeneriren(song)
gesamtLaenge = 0 gesamtLaenge = 0
for song in songs: for song in songs:
gesamtLaenge += song["laenge"] gesamtLaenge += song["laenge"]
return render_template('index.html', karten=songs,gesamtLaenge=gesamtLaenge,liste=liste,admin=True) return render_template(
"index.html", karten=songs, gesamtLaenge=gesamtLaenge, liste=liste, admin=True
)
@app.route("/remove",methods=["POST"])
@app.route("/remove", methods=["POST"])
def loeschen(): def loeschen():
liste = request.args.get("liste") liste = request.args.get("liste")
song = int(request.form.get("index")) song = int(request.form.get("index"))
with open(liste+".json","r") as f: with open(liste + ".json", "r") as f:
print(liste+".json") print(liste + ".json")
songs = json.load(f) songs = json.load(f)
print(songs) print(songs)
print(songs) print(songs)
del songs[song] del songs[song]
with open(liste+".json","w") as f: with open(liste + ".json", "w") as f:
json.dump(songs,f,indent=2,ensure_ascii=False) json.dump(songs, f, indent=2, ensure_ascii=False)
return redirect("/remove?liste="+liste,303) return redirect("/remove?liste=" + liste, 303)

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View file

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="125.33"
height="131.46"
version="1.1"
id="svg1"
sodipodi:docname="Eurovision_Song_Contest_heart_Wikidata_(20142025).svg"
xml:space="preserve"
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs1" /><sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="4.303099"
inkscape:cx="53.449851"
inkscape:cy="50.196382"
inkscape:window-width="1920"
inkscape:window-height="1011"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg1" /><g
id="g1"
transform="matrix(0.12157124,0,0,0.23068304,12.733877,4.287877)"><path
id="path1-3"
style="fill:#990000"
d="m 14.029438,47.537215 c -1.774828,0.01827 -1.013972,0.384871 -0.03213,0.626536 0.743679,-0.164572 1.490068,-0.325118 2.23313,-0.491069 -0.72782,-0.04244 -1.783992,-0.139759 -2.200998,-0.135467 z M 142.18539,59.094266 c -4.82297,3.438254 -9.69255,6.858605 -15.85683,9.685909 -9.38162,4.990549 -19.34173,9.624906 -30.380205,13.58906 -10.698213,3.846403 -21.764589,7.384325 -33.946788,9.78751 -0.669629,0.14639 -1.339128,0.292891 -2.00821,0.440268 V 399.87063 c 4.294457,2.59538 8.563573,5.20196 12.965006,7.74704 14.479715,8.05187 30.579687,15.20504 46.076377,22.69076 10.37587,4.79197 20.82658,9.52643 30.95857,14.45267 V 61.321009 c -2.64183,-0.684628 -5.26357,-1.407695 -7.80792,-2.226743 z m 37.81862,7.5523 V 459.74716 c 2.35383,1.15862 4.67161,2.33734 7.0689,3.47135 10.48296,4.92542 21.63634,9.42235 32.74186,13.94466 11.38075,4.82918 22.73005,9.68782 33.86646,14.6728 2.23876,1.1668 4.70542,2.2195 6.71546,3.49675 2.36848,1.50499 4.77459,3.02601 6.79578,4.66515 h 2.81149 V 74.402066 c -1.52365,-0.251491 -2.99632,-0.543839 -4.41806,-0.880537 -3.44536,-0.556772 -6.89455,-1.106275 -10.31417,-1.710274 -5.17069,-0.542732 -10.36811,-1.007044 -15.53551,-1.557873 -0.97125,-0.103562 -1.88782,-0.366087 -2.87576,-0.406402 -1.61527,-0.06633 -3.23252,-0.05736 -4.85184,-0.08467 -12.33914,-0.26891 -24.68661,-0.675896 -36.91894,-1.608674 -5.06761,-0.420601 -10.09953,-0.926035 -15.08567,-1.507073 z M 29.998726,98.980908 c -8.251681,1.796042 -16.220058,3.973792 -24.9660709,5.080022 -2.0724185,0.24509 -3.4743116,0.40985 -5.02855874,0.59267 V 393.09727 C 14.640724,395.66002 26.790289,396.67245 29.998726,392.34373 v -6.23996 c -0.803728,-1.96212 -2.182488,-4.26283 -4.305603,-7.01043 -0.191081,-0.24728 -0.479549,-0.48168 -0.562298,-0.74507 -0.02734,-0.087 -8.34e-4,-0.0983 0.08033,-0.0593 0.243479,0.11718 0.860945,0.67324 1.172795,0.88054 1.184122,0.78717 2.416754,1.5504 3.614778,2.32834 z" /><path
id="path2"
style="fill:#339966"
d="M 720.00374,-0.00332762 V 316.05873 c 9.4778,-7.25273 19.5086,-14.30976 29.99463,-21.17523 V 7.1933707 c -1.61483,-1.6498815 -1.49121,-3.0052856 0,-4.1232848 V -0.00332762 Z M 810.0037,7.5235722 C 799.38514,8.2567434 788.77164,8.7962855 779.993,9.4285806 V 20.232095 c 0.31997,0.13476 0.43431,0.208138 0,0.127 V 276.57002 c 3.48903,-1.88316 6.90501,-3.814 10.98893,-5.30862 6.88074,-2.51817 12.98246,-4.39552 19.02177,-5.71503 z M 299.99859,81.522564 V 499.99787 h 29.99463 V 97.160567 c -7.9882,-2.297003 -15.07698,-5.435046 -20.85325,-9.381108 -3.34736,-2.462292 -4.5133,-3.672614 -5.88004,-4.52122 -1.05183,-0.525067 -3.05402,-1.485727 -2.98822,-1.549407 0.0574,-0.05538 0.25839,0.0053 0.43377,0.06773 -0.21331,-0.09699 -0.48098,-0.163567 -0.70689,-0.254002 z m 89.99996,17.348277 c -8.20339,1.519749 -16.83464,2.407739 -25.64083,2.683949 -1.45128,-0.0369 -2.89992,-0.0475 -4.3538,-0.0677 v 398.51082 h 7.30989 c 1.48574,-6.49571 8.87825,-13.03235 22.68474,-18.01714 z" /><path
id="path3"
style="fill:#006699"
d="m 548.35799,-0.00332762 c 1.32928,3.78920772 2.24975,7.61254682 1.73509,11.48085062 -0.42645,1.741623 -0.60851,3.502756 -1.26919,5.223956 -1.60817,4.189623 -4.62212,8.251934 -8.82006,11.929586 V 418.95458 c 0.48825,-0.36573 0.93428,-0.74589 1.42985,-1.10914 2.62333,-1.9375 6.39128,-4.76412 9.10924,-6.55322 5.85514,-3.85417 12.52594,-7.29148 19.45554,-10.59185 V -0.00332762 Z m 51.6351,0 V 387.80558 c 4.47695,-1.73687 9.00958,-3.43485 13.6719,-5.04616 11.34729,-4.17629 22.86313,-8.22255 34.17171,-12.42912 7.06298,-2.78351 14.24938,-5.59077 19.96964,-9.16097 6.93356,-4.30741 12.65281,-9.01463 17.15815,-14.15633 1.65811,-1.61121 3.36978,-3.20652 5.02856,-4.81756 V -0.00332762 Z M 509.99314,42.56726 c -0.24486,0.0606 -0.47595,0.136521 -0.72296,0.194734 -8.74713,2.061395 -18.1919,2.88136 -27.56871,3.657616 -3.65751,0.48271 -1.00651,0.112622 -4.33774,0.609603 -3.88331,0.57934 -0.059,0.157044 -0.81935,-0.169334 -0.82252,-0.353035 -2.37514,1.932431 -2.6187,0.956737 -0.49781,0.226211 -1.00074,0.448451 -1.49411,0.677336 -0.3614,0.16765 -0.97876,0.756482 -1.0764,0.508003 -0.15229,-0.387359 1.54235,-1.288175 0.89968,-1.083738 -0.21675,0.06897 -0.33904,0.201743 -0.44984,0.321734 -0.44886,0.486165 -0.81218,0.98579 -1.22099,1.481674 -4.11781,5.237277 -6.68747,10.843785 -12.82042,15.604135 -5.6807,4.605146 -11.78003,9.07912 -18.65226,13.216525 -6.17704,3.674682 -12.21316,7.410557 -19.11816,10.718847 V 475.2751 c 3.0332,-0.37853 6.17199,-0.71814 9.47875,-0.99061 5.46251,-0.4501 10.93222,-0.82713 16.4352,-1.10067 0.29359,-0.0237 5.86112,-0.5336 5.88004,-0.52493 0.12774,0.0737 -0.54025,0.2544 -0.35345,0.23706 0.44544,-0.039 0.81522,-0.20879 1.22099,-0.31326 5.07815,-1.73672 9.61583,-3.74927 13.59157,-6.1807 7.3223,-4.3773 14.00387,-9.04125 21.38343,-13.39432 7.02366,-4.4061 14.2383,-8.73866 22.36343,-12.59846 z" /></g><path
d="m12.726 58.556c0.31803-28.513 15.157-37.437 23.237-37.437 11.285 0 15.946 8.6151 16.707 12.429 0.76116 3.8111 5.0324 6.8595 6.4047 0.60798 1.3734-6.2515 14.649-25.315 30.966-25.315 14.943 0 20.119 15.41 19.671 28.518-1.2228 35.683-47.19 64.158-53.239 82.143-5.3875-10.891-44.126-26.634-43.746-60.946zm82.652-58.556c-13.42 0-29.29 9.9111-38.896 26.382-2.592-5.9483-11.827-12.43-22.805-12.43-8.8462 0-33.676 11.056-33.676 46.74 0 46.052 46.593 55.508 56.011 69.825 0.64721 0.98433 2.7319 1.728 3.5276-0.62388 7.5157-22.18 65.791-47.242 65.791-92.379-5.3e-4 -25.314-16.536-37.513-29.955-37.513z"
stroke-width=".53006"
id="path1" /><g
inkscape:groupmode="layer"
id="layer1"
inkscape:label="DATA" /></svg>

After

Width:  |  Height:  |  Size: 6.6 KiB

View file

@ -1,102 +1,98 @@
const audios = document.querySelectorAll("audio") const audios = document.querySelectorAll("audio");
const articles = document.querySelectorAll("article") const articles = document.querySelectorAll("article");
const kartenContainer = document.getElementById("flex-container") const kartenContainer = document.getElementById("flex-container");
outindex = 0 outindex = 0;
playing = false playing = false;
playcolor = "#00ff3c" playcolor = "#00ff3c";
loop = true loop = true;
function onplay(id){ function onplay(id) {
//What is id id = parseInt(id);
id = parseInt(id) if (id > 0) {
if(id>0){ articles[id - 1].style.filter = "grayscale(" + (id + 1) * 20 + "%)";
articles[id-1].style.filter = "grayscale("+(id+1)*20+"%)" articles[id - 1].style.boxShadow = "0 0 0px 0px " + playcolor;
articles[id-1].style.boxShadow = "0 0 0px 0px "+playcolor
} }
if(articles[id].offsetWidth * id == window.innerWidth/2){ if (articles[id].offsetWidth * id == window.innerWidth / 2) {
console.log(articles[id].offsetWidth) console.log(articles[id].offsetWidth);
kartenContainer.scrollWidth += articles[id].offsetWidth kartenContainer.scrollWidth += articles[id].offsetWidth;
} }
articles[id].style.filter = "grayscale(0%)" articles[id].style.filter = "grayscale(0%)";
articles[id].style.margin = "8px" articles[id].style.margin = "8px";
articles[id].style.boxShadow = "0 0 6px 1px "+playcolor articles[id].style.boxShadow = "0 0 6px 1px " + playcolor;
} }
function nächste(id){ function nächste(id) {
audios[id].pause() audios[id].pause();
id = parseInt(id) + 1 id = parseInt(id) + 1;
audios[id].play() audios[id].play();
onplay(id) onplay(id);
} }
function vorherige(id){ function vorherige(id) {
audios[id].pause() audios[id].pause();
audios[id-1].play() audios[id - 1].play();
onplay(id-1) onplay(id - 1);
} }
function looptrue(){ function looptrue() {
if(loop){ if (loop) {
loop = false loop = false;
document.querySelector("#loop").innerHTML = "Kein Loop" document.querySelector("#loop").innerHTML = "Kein Loop";
document.querySelector("#loop").style.beckground document.querySelector("#loop").style.beckground;
} } else {
else{ loop = true;
loop = true document.querySelector("#loop").innerHTML = "Loop";
document.querySelector("#loop").innerHTML = "Loop"
} }
} }
function abspielendiese(id){ function abspielendiese(id) {
if(playing){ if (playing) {
//ON PAUSE //ON PAUSE
audios[id].pause() audios[id].pause();
playing = false playing = false;
articles[id].style.margin = "0px" articles[id].style.margin = "0px";
articles[id].style.boxShadow = "0 0 0px 0px "+playcolor articles[id].style.boxShadow = "0 0 0px 0px " + playcolor;
} } else {
else{
//ON PLAY //ON PLAY
audios[id].play() audios[id].play();
playing = true playing = true;
onplay(id) onplay(id);
} }
} }
function abspielen(){ function abspielen() {
if(playing){ if (playing) {
//ON PAUSE //ON PAUSE
audios[outindex].pause() audios[outindex].pause();
playing = false playing = false;
articles[outindex].style.margin = "0px" articles[outindex].style.margin = "0px";
articles[outindex].style.boxShadow = "0 0 0px 0px "+playcolor articles[outindex].style.boxShadow = "0 0 0px 0px " + playcolor;
document.querySelector("#play").innerHTML = "Abspielen" document.querySelector("#play").innerHTML = "Abspielen";
} } else {
else{
//ON PLAY //ON PLAY
audios[outindex].play() audios[outindex].play();
playing = true playing = true;
document.querySelector("#play").innerHTML = "Pausieren" document.querySelector("#play").innerHTML = "Pausieren";
onplay(outindex) onplay(outindex);
} }
} }
for (const [index,audio] of audios.entries()){ for (const [index, audio] of audios.entries()) {
audio.addEventListener("ended", (event) => { audio.addEventListener("ended", (event) => {
if (index != audios.length -1){ if (index != audios.length - 1) {
outindex = index +1 outindex = index + 1;
audios[outindex].play() audios[outindex].play();
onplay(index+1) onplay(index + 1);
} } else {
else{ //Last song ON END
//Last song ON END articles[index].style.filter = "grayscale(80%)";
articles[index].style.filter = "grayscale(80%)" articles[index].style.boxShadow = "0 0 0px 0px " + playcolor;
articles[index].style.boxShadow = "0 0 0px 0px "+playcolor articles[index].style.margin = "8px";
articles[index].style.margin = "8px" articles[index].style.boxShadow = "0 0 6px 1px " + playcolor;
articles[index].style.boxShadow = "0 0 6px 1px "+playcolor if (loop) {
if(loop){ audios[0].play();
audios[0].play() }
} }
} });
})
} }
//Audio visualising

View file

@ -1,21 +1,23 @@
<style> <style>
#flex-container{ #flex-container {
overflow: auto; overflow: auto;
scroll-snap-type: x mandatory; scroll-snap-type: x mandatory;
display: flex; display: flex;
border: none; border: none;
gap: 5px; gap: 5px;
} }
article{ article {
flex-wrap: row nowrap; flex-wrap: row nowrap;
border: none; border: none;
flex: 0 0 30rem; flex: 0 0 30rem;
} }
a,h1,h2{ a,
h1,
h2 {
display: block; display: block;
text-align: center; text-align: center;
} }
article{ article {
border: 2px solid; border: 2px solid;
border-radius: 15px; border-radius: 15px;
border-color: black; border-color: black;
@ -23,43 +25,65 @@
width: 100%; width: 100%;
padding: 20px; padding: 20px;
} }
#kursive{ #kursive {
font-style: italic; font-style: italic;
} }
img{ img {
border-radius: 2%; border-radius: 2%;
width: 100%; width: 100%;
aspect-ratio: 4/3; aspect-ratio: 4/3;
object-fit: contain; object-fit: contain;
} }
a{ a {
color: black; color: black;
} }
h2{ h2 {
text-align: center; text-align: center;
} }
article > a{ #gray {
font-size: 0.75rem; font-size: 0.75rem;
display: block; display: block;
text-align: center; text-align: center;
color: rgb(181, 181, 181); color: rgb(181, 181, 181);
} }
button{ button {
padding: 10px; padding: 10px;
margin: 5px; margin: 5px;
border: black; border: black;
border-radius: 20px; border-radius: 20px;
} }
#logo{
object-fit: scale-down;
}
#logocontaner{
margin: 0 auto;
height: 25%;
width: 25%;
}
#logo{
height: 105%;
scale: 150%;
}
#logocontaner{
margin: 0 auto;
}
</style> </style>
<a href="/" id="logocontaner"><img id="logo" src="/static/Eurovision_Song_Contest_heart_Wikidata_(20142025).svg"></img></a>
<h1>ESC Playlist</h1> <h1>ESC Playlist</h1>
<h2>2026</h2> <a href="/suche?liste={{liste}}"
<a href="/suche?liste={{liste}}">Du willst ein weiteres Lied in der Playlist?</a> >Du willst ein weiteres Lied in der Playlist?</a
<p>Die Playlist {{liste}} ist insgesamt {{ gesamtLaenge | zeit }} lang und enthält {{ karten|length }} Lieder</p> >
<p><button id="play" onclick="abspielen()">Abspielen</button><button id="loop" onclick="looptrue()">Loop</button></p> <p>
<div id = "flex-container"> Die Playlist {{liste}} ist insgesamt {{ gesamtLaenge | zeit }} lang und
{% for karte in karten %} enthält {{ karten|length }} Lieder
{% set karte_loop = loop %} </p>
{% include "karte.html" %} <p>
{% endfor %} <button id="play" onclick="abspielen()">Abspielen</button
><button id="loop" onclick="looptrue()">Loop</button>
</p>
<div id="flex-container">
{% for karte in karten %} {% set karte_loop = loop %} {% include
"karte.html" %} {% endfor %}
</div> </div>
<script src="static/script.js"></script> <script src="static/script.js"></script>

View file

@ -1,24 +1,42 @@
<article> <article>
<img src="{{ karte.img }}"/> <img src="{{ karte.img }}" />
{% if karte.ytid %} {% if karte.ytid %}
<p><button id="{{karte_loop.index0}}" onclick="vorherige(this.id)">Vorherige</button><button id="{{karte_loop.index0}}" onclick="abspielendiese(this.id)">Abspielen</button><button id="{{karte_loop.index0}}" onclick="nächste(this.id)">Nächstes</button></p> <p>
<audio controls src="/static/{{karte.datei}}"></audio> <button id="{{karte_loop.index0}}" onclick="vorherige(this.id)">
Vorherige</button
><button id="{{karte_loop.index0}}" onclick="abspielendiese(this.id)">
Abspielen</button
><button id="{{karte_loop.index0}}" onclick="nächste(this.id)">
Nächstes
</button>
</p>
<audio src="/static/{{karte.datei}}"></audio>
{% endif %} {% endif %}
<h2>{{ karte.titel}}</h2> <h2>{{ karte.titel}}</h2>
<p><b>Übersetzter Titel:</b>{{ karte.uetitel}}</p>
<p><b>Interpreten:</b>{{ karte.interprete}}</p> {% if karte.jahrgang %}
{% if karte.jahrgang %} <p><b>Jahrgang:</b> {{ karte.jahrgang }}</p>
<p><b>Jahrgang:</b> {{ karte.jahrgang }}</p> {% endif %} {% if karte.plazirung%}
{% endif %} <p><b>Plazirung:</b> {{ karte.plazirung }}</p>
{% if karte.plazirung%} {% endif %} {% if karte.land %}
<p><b>Plazirung:</b> {{ karte.plazirung }}</p> <p><b>Antretent für:</b> {{karte.land}}</p>
{% endif %}
<p><b>Länge:</b> {{karte.laenge|zeit}}</p>
<p><a href="https://www.wikidata.org/entity/{{karte.wikiid}}">Q-id:</a> {{karte.wikiid}}</p>
{% if karte.text %}
<a href="{{ karte.text }}" target="_blank">Original Text</a>
{% endif %} {% endif %}
<p><b>Interpret(en):</b> {{ karte.interprete}}</p>
<p><b>Länge:</b> {{karte.laenge|zeit}}</p>
<p id="gray">
{% if karte.text %}
<a id="gray" href="{{ karte.text }}" target="_blank">Original Text</a>
{% endif %}
<a id="gray" href="https://www.wikidata.org/entity/{{karte.wikiid}}"
>Q-id:{{karte.wikiid}}</a
>
</p>
{% if admin %} {% if admin %}
<form method="post"><button name="index" value="{{karte_loop.index0}}">&lt;X&gt;</button></form> <form method="post">
<button name="index" value="{{karte_loop.index0}}">&lt;X&gt;</button>
</form>
{% endif %} {% endif %}
</article> </article>

View file

@ -1,8 +1,19 @@
<style> <style>
body{
display: block;
text-align: center;
}
form{ form{
display: block; display: block;
text-align: center; text-align: center;
color: black; color: black;
} }
#logo{
object-fit: scale-down;
}
#logocontaner{
margin: 3px;
}
</style> </style>
<form><input name="name" value={{name}} placeholder="Name der Playlist"></form> <a href="/" id="logocontaner"><img src="/static/Eurovision_Song_Contest_heart_Wikidata_(20142025).svg"></img></a>
<form><input name="name" value={{name}} placeholder="Name der Playlist"></form>

View file

@ -11,8 +11,15 @@
text-align: center; text-align: center;
font-size: smaller; font-size: smaller;
} }
#logo{
object-fit: scale-down;
}
#logocontaner{
margin: 3px;
}
</style> </style>
<a id="logocontaner"><img src="/static/Eurovision_Song_Contest_heart_Wikidata_(20142025).svg"></img></a>
{% for list in lists %} {% for list in lists %}
<a id="playlist" href="/?liste={{list}}"> {{list}} </a> <a id="playlist" href="/?liste={{list}}"> {{list}} </a>
{% endfor %} {% endfor %}
<a href="/neueliste">Lust auf was neues?</a> <a href="/neueliste">Lust auf was neues?</a>

View file

@ -4,7 +4,14 @@
text-align: center; text-align: center;
color: black; color: black;
} }
#logo{
object-fit: scale-down;
}
#logocontaner{
margin: 3px;
}
</style> </style>
<a href="/" id="logocontaner"><img src="/static/Eurovision_Song_Contest_heart_Wikidata_(20142025).svg"></img></a>
{% if liste == empty %} {% if liste == empty %}
<p>Du musst etwas in die Playlist Screiben</p> <p>Du musst etwas in die Playlist Screiben</p>
{% endif %} {% endif %}
@ -19,4 +26,4 @@
<p>Leider gibt es den Eintrag {{anfrage}} nicht!</p> <p>Leider gibt es den Eintrag {{anfrage}} nicht!</p>
{%endif%} {%endif%}
<a href="/?liste={{liste}}">Doch nicht?</a> <a href="/?liste={{liste}}">Doch nicht?</a>