From 9401e0727b4ce6bd11b0b0d6058b411fa633b09d Mon Sep 17 00:00:00 2001 From: "matthias@matsewe.de" Date: Tue, 21 May 2024 12:20:25 +0200 Subject: [PATCH] update --- app/main.py | 23 ++++- app/models.py | 6 +- app/routers/admin.py | 56 ++++++++--- app/routers/songs.py | 13 ++- app/routers/user.py | 18 +++- app/sql_models.py | 4 +- static/neutral.svg | 1 - static/no.svg | 1 - static/open.svg | 21 +++++ static/play.svg | 1 - static/site.css | 32 +++++-- static/stop.svg | 54 +++++++++++ static/voting_script.js | 31 +++--- templates/voting-old.html | 54 +++++++++++ templates/voting.html | 194 ++++++++++++++++++++++++++++++-------- 15 files changed, 425 insertions(+), 84 deletions(-) create mode 100644 static/open.svg create mode 100644 static/stop.svg create mode 100644 templates/voting-old.html diff --git a/app/main.py b/app/main.py index 6183e33..93a0d3e 100644 --- a/app/main.py +++ b/app/main.py @@ -5,6 +5,7 @@ from fastapi.responses import HTMLResponse from fastapi.templating import Jinja2Templates from app.dependencies import engine from app.sql_models import Base +from app.routers.songs import get_songs Base.metadata.create_all(engine) @@ -25,6 +26,24 @@ async def root(request: Request, session_id : str = ""): request=request, name="landing.html" ) else: + songs = await get_songs(session_id) + songs_by_category = {} + all_categories = set() + for song in songs: + if song.main_category not in songs_by_category: + songs_by_category[song.main_category] = [] + songs_by_category[song.main_category].append(song) + all_categories.update(song.categories.keys()) return templates.TemplateResponse( - request=request, name="voting.html" - ) \ No newline at end of file + request=request, name="voting.html", context={ + "songs_by_category": songs_by_category, + "all_categories": {c: i+1 for i, c in enumerate(all_categories)}, + "session_id": session_id + } + ) + +#@app.get("/vote", response_class=HTMLResponse) +#async def vote(request: Request, session_id : str = ""): +# return templates.TemplateResponse( +# request=request, name="voting-old.html" +# ) \ No newline at end of file diff --git a/app/models.py b/app/models.py index 195ac47..1705a26 100644 --- a/app/models.py +++ b/app/models.py @@ -13,8 +13,10 @@ class Song(BaseModel): id: int og_artist: Optional[str] aca_artist: Optional[str] - title: str - yt_url: Optional[str] + title: Optional[str] + url: Optional[str] + yt_id: Optional[str] + spfy_id: Optional[str] thumbnail: Optional[str] is_aca: bool arng_url: Optional[str] diff --git a/app/routers/admin.py b/app/routers/admin.py index 40fd220..3c3be3e 100644 --- a/app/routers/admin.py +++ b/app/routers/admin.py @@ -1,11 +1,17 @@ from fastapi import APIRouter, Security from app.sql_models import SqlSong from app.dependencies import session +from app.dependencies import engine from app.routers.user import get_current_user import pandas as pd import numpy as np import re import requests +import os +from app.sql_models import Base + + + router = APIRouter( prefix="/admin", @@ -22,7 +28,10 @@ def get_main_category(categories) -> int: else: return np.argmax(categories != None, axis=0) -def youtube_url_validation(url): +def get_youtube_id(url): + if url is None: + return None + youtube_regex = ( r'(https?://)?(www\.)?' '(youtube|youtu|youtube-nocookie)\.(com|be)/' @@ -30,23 +39,38 @@ def youtube_url_validation(url): youtube_regex_match = re.match(youtube_regex, url) if youtube_regex_match: - return youtube_regex_match + return youtube_regex_match.group(6) - return False + return None def get_thumbnail(url): - m = youtube_url_validation(url) + if url is None: + return "/static/cover.jpg" + + m = get_youtube_id(url) if m: - thumbnail_url = "https://img.youtube.com/vi/" + m.group(6) + "/mqdefault.jpg" + thumbnail_url = "https://img.youtube.com/vi/" + m + "/mqdefault.jpg" return thumbnail_url elif "spotify" in url: return re.findall(r'(https?://i.scdn.co/image[^"]+)', requests.get(url).text)[0] else: return "/static/cover.jpg" -@router.post("/process_file") -async def create_upload_file(link_share: str): - song_list = pd.read_excel(link_share) +def get_spotify_id(url): + if url is None: + return None + if "spotify" in url: + return url.split("/track/")[1] + else: + return None + +@router.post("/load_list") +async def create_upload_file(): + + Base.metadata.drop_all(engine) + Base.metadata.create_all(engine) + + song_list = pd.read_excel(os.environ['LIST_URL']) song_list = song_list.replace({np.nan: None}) song_list = song_list.replace({"n/a": None}) @@ -55,15 +79,25 @@ async def create_upload_file(link_share: str): for row in song_list[1:].iterrows(): row = np.array(row[1]) + yt_id = get_youtube_id(row[3]) + spfy_id = get_spotify_id(row[3]) + + categories = {n: v for n, v in zip( + category_names, row[6:19] != None)} + + if not np.any(list(categories.values())): + continue + s = SqlSong(og_artist=row[0], aca_artist=row[1], title=row[2], - yt_url=row[3], + url=row[3], + yt_id=yt_id, + spfy_id=spfy_id, thumbnail=get_thumbnail(row[3]), is_aca=row[4] == "ja", arng_url=row[5], - categories={n: v for n, v in zip( - category_names, row[6:19] != None)}, + categories=categories, main_category=category_names[get_main_category(row[6:19])], singable=row[19] != "nein" ) diff --git a/app/routers/songs.py b/app/routers/songs.py index 3f5fb84..e0758d4 100644 --- a/app/routers/songs.py +++ b/app/routers/songs.py @@ -9,13 +9,24 @@ router = APIRouter( responses={404: {"description": "Not found"}}, ) +async def songify(s, votes): + return Song(**s.__dict__, vote=votes.get(s.id, None)) + @router.get("/") async def get_songs(user_id : str = "") -> list[Song]: sqlsongs = session.query(SqlSong).filter(SqlSong.singable == True).all() votes = session.query(SqlVote).filter(SqlVote.user_id == user_id).all() votes = {v.song_id : v.vote for v in votes} - return [Song(**s.__dict__, vote=votes.get(s.id, None)) for s in sqlsongs] # type: ignore + songs = [] + for s in sqlsongs: + try: + songs.append(Song(**s.__dict__, vote=votes.get(s.id, None))) + except: + print(s.__dict__) + pass + return songs + #return [Song(**s.__dict__, vote=votes.get(s.id, None)) for s in sqlsongs] # type: ignore @router.post("/{song_id}/vote") async def vote(song_id : str, user_id : str, vote : int): diff --git a/app/routers/user.py b/app/routers/user.py index bd2ff26..5824a6d 100644 --- a/app/routers/user.py +++ b/app/routers/user.py @@ -6,13 +6,26 @@ from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm, Se from jose import JWTError, jwt from passlib.context import CryptContext from pydantic import BaseModel, ValidationError +import os -from app.secrets import SECRET_KEY, fake_users_db +#from app.secrets import SECRET_KEY, fake_users_db # to get a string like this run: # openssl rand -hex 32 ALGORITHM = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES = 60 * 24 * 31 +SECRET_KEY = os.environ['SECRET_KEY'] + +fake_users_db = { + "admin": { + "username": "admin", + "email": "admin@example.com", + "hashed_password": os.environ["ADMIN_PWD"], + "disabled": False, + "scopes" : ["admin", "public"] + } +} + class Token(BaseModel): @@ -28,7 +41,7 @@ class TokenData(BaseModel): class User(BaseModel): username: str email: str | None = None - full_name: str | None = None + #full_name: str | None = None disabled: bool | None = None @@ -53,6 +66,7 @@ router = APIRouter( def verify_password(plain_password, hashed_password): + print(get_password_hash(plain_password)) return pwd_context.verify(plain_password, hashed_password) diff --git a/app/sql_models.py b/app/sql_models.py index 9c46f0e..578c16c 100644 --- a/app/sql_models.py +++ b/app/sql_models.py @@ -9,7 +9,9 @@ class SqlSong(Base): og_artist = Column(String) aca_artist = Column(String) title = Column(String) - yt_url = Column(String) + url = Column(String) + yt_id = Column(String) + spfy_id = Column(String) thumbnail = Column(String) is_aca = Column(Boolean) arng_url = Column(String) diff --git a/static/neutral.svg b/static/neutral.svg index 1441229..849b9f3 100644 --- a/static/neutral.svg +++ b/static/neutral.svg @@ -1,5 +1,4 @@ - - + + + + + diff --git a/static/play.svg b/static/play.svg index c229371..7436b0b 100644 --- a/static/play.svg +++ b/static/play.svg @@ -1,5 +1,4 @@ - + + + + + + + diff --git a/static/voting_script.js b/static/voting_script.js index d472767..15dd5c1 100644 --- a/static/voting_script.js +++ b/static/voting_script.js @@ -143,6 +143,7 @@ $(document).ready(function () { "no_selected": (song.vote == -1) ? "selected" : "", "neutral_selected": (song.vote == 0) ? "selected" : "", "yes_selected": (song.vote == 1) ? "selected" : "", + "play_button": (song.yt_id || song.spfy_id) ? "play" : "open", "categories": cats })).join('') @@ -175,22 +176,30 @@ window.onSpotifyIframeApiReady = (IFrameAPI) => { IFrameAPI.createController(element, options, callback); }; +function stop() { + $("#song-" + is_playing + " .cover-container .overlay img").attr("src", "/static/play.svg"); -function play(id) { $("#yt-player").css("display", "none"); $("#spotify-player").css("display", "none"); $("#close-player").css("display", "none"); $("#yt-player").html(""); spotify_embed_controller.pause(); + is_playing = -1; +} +function play(id) { if (is_playing == id) { - is_playing = -1; + stop(); } else { + stop(); + is_playing = id; + $("#song-" + id + " .cover-container .overlay img").attr("src", "/static/stop.svg"); + song = all_songs[id]; - yt_id = song.yt_url.split('v=')[1] - spotify_id = song.yt_url.split('/track/')[1] + yt_id = song.yt_id + spotify_id = song.spfy_id if (yt_id) { $("#yt-player").css("display", "flex"); @@ -205,15 +214,9 @@ function play(id) { spotify_embed_controller.play(); } else { - $("#yt-player").css("display", "none"); - $("#spotify-player").css("display", "none"); - $("#yt-player").html(""); - spotify_embed_controller.pause(); - window.open(song.yt_url, '_blank').focus(); + stop(); + $("#song-" + id + " .cover-container .overlay img").attr("src", "/static/open.svg"); + window.open(song.url, '_blank').focus(); } } -} - -// - -// https://open.spotify.com/intl-de/track/2DS7lDZNFM7safSGNm8vd4 \ No newline at end of file +} \ No newline at end of file diff --git a/templates/voting-old.html b/templates/voting-old.html new file mode 100644 index 0000000..9f9f98b --- /dev/null +++ b/templates/voting-old.html @@ -0,0 +1,54 @@ + + + + Liederwahl + + + + + + + + + + +

Hallo :)

+
Du kannst die Liederwahl jederzeit unterbrechen und zu einem späteren Zeitpunkt weitermachen.
+
+
+
+
+ + + + + diff --git a/templates/voting.html b/templates/voting.html index 706cfb6..0cba5a2 100644 --- a/templates/voting.html +++ b/templates/voting.html @@ -1,52 +1,164 @@ - - Liederwahl - - - - - - - + + Liederwahl - -
-
-
-
- - - - + + {% endfor %} + {% endfor %} + +
+
+
+
+
+ + + \ No newline at end of file