update
21
app/main.py
@@ -5,6 +5,7 @@ from fastapi.responses import HTMLResponse
|
|||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
from app.dependencies import engine
|
from app.dependencies import engine
|
||||||
from app.sql_models import Base
|
from app.sql_models import Base
|
||||||
|
from app.routers.songs import get_songs
|
||||||
|
|
||||||
Base.metadata.create_all(engine)
|
Base.metadata.create_all(engine)
|
||||||
|
|
||||||
@@ -25,6 +26,24 @@ async def root(request: Request, session_id : str = ""):
|
|||||||
request=request, name="landing.html"
|
request=request, name="landing.html"
|
||||||
)
|
)
|
||||||
else:
|
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(
|
return templates.TemplateResponse(
|
||||||
request=request, name="voting.html"
|
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"
|
||||||
|
# )
|
||||||
@@ -13,8 +13,10 @@ class Song(BaseModel):
|
|||||||
id: int
|
id: int
|
||||||
og_artist: Optional[str]
|
og_artist: Optional[str]
|
||||||
aca_artist: Optional[str]
|
aca_artist: Optional[str]
|
||||||
title: str
|
title: Optional[str]
|
||||||
yt_url: Optional[str]
|
url: Optional[str]
|
||||||
|
yt_id: Optional[str]
|
||||||
|
spfy_id: Optional[str]
|
||||||
thumbnail: Optional[str]
|
thumbnail: Optional[str]
|
||||||
is_aca: bool
|
is_aca: bool
|
||||||
arng_url: Optional[str]
|
arng_url: Optional[str]
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
from fastapi import APIRouter, Security
|
from fastapi import APIRouter, Security
|
||||||
from app.sql_models import SqlSong
|
from app.sql_models import SqlSong
|
||||||
from app.dependencies import session
|
from app.dependencies import session
|
||||||
|
from app.dependencies import engine
|
||||||
from app.routers.user import get_current_user
|
from app.routers.user import get_current_user
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import re
|
import re
|
||||||
import requests
|
import requests
|
||||||
|
import os
|
||||||
|
from app.sql_models import Base
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
router = APIRouter(
|
router = APIRouter(
|
||||||
prefix="/admin",
|
prefix="/admin",
|
||||||
@@ -22,7 +28,10 @@ def get_main_category(categories) -> int:
|
|||||||
else:
|
else:
|
||||||
return np.argmax(categories != None, axis=0)
|
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 = (
|
youtube_regex = (
|
||||||
r'(https?://)?(www\.)?'
|
r'(https?://)?(www\.)?'
|
||||||
'(youtube|youtu|youtube-nocookie)\.(com|be)/'
|
'(youtube|youtu|youtube-nocookie)\.(com|be)/'
|
||||||
@@ -30,23 +39,38 @@ def youtube_url_validation(url):
|
|||||||
|
|
||||||
youtube_regex_match = re.match(youtube_regex, url)
|
youtube_regex_match = re.match(youtube_regex, url)
|
||||||
if youtube_regex_match:
|
if youtube_regex_match:
|
||||||
return youtube_regex_match
|
return youtube_regex_match.group(6)
|
||||||
|
|
||||||
return False
|
return None
|
||||||
|
|
||||||
def get_thumbnail(url):
|
def get_thumbnail(url):
|
||||||
m = youtube_url_validation(url)
|
if url is None:
|
||||||
|
return "/static/cover.jpg"
|
||||||
|
|
||||||
|
m = get_youtube_id(url)
|
||||||
if m:
|
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
|
return thumbnail_url
|
||||||
elif "spotify" in url:
|
elif "spotify" in url:
|
||||||
return re.findall(r'(https?://i.scdn.co/image[^"]+)', requests.get(url).text)[0]
|
return re.findall(r'(https?://i.scdn.co/image[^"]+)', requests.get(url).text)[0]
|
||||||
else:
|
else:
|
||||||
return "/static/cover.jpg"
|
return "/static/cover.jpg"
|
||||||
|
|
||||||
@router.post("/process_file")
|
def get_spotify_id(url):
|
||||||
async def create_upload_file(link_share: str):
|
if url is None:
|
||||||
song_list = pd.read_excel(link_share)
|
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({np.nan: None})
|
||||||
song_list = song_list.replace({"n/a": 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():
|
for row in song_list[1:].iterrows():
|
||||||
row = np.array(row[1])
|
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],
|
s = SqlSong(og_artist=row[0],
|
||||||
aca_artist=row[1],
|
aca_artist=row[1],
|
||||||
title=row[2],
|
title=row[2],
|
||||||
yt_url=row[3],
|
url=row[3],
|
||||||
|
yt_id=yt_id,
|
||||||
|
spfy_id=spfy_id,
|
||||||
thumbnail=get_thumbnail(row[3]),
|
thumbnail=get_thumbnail(row[3]),
|
||||||
is_aca=row[4] == "ja",
|
is_aca=row[4] == "ja",
|
||||||
arng_url=row[5],
|
arng_url=row[5],
|
||||||
categories={n: v for n, v in zip(
|
categories=categories,
|
||||||
category_names, row[6:19] != None)},
|
|
||||||
main_category=category_names[get_main_category(row[6:19])],
|
main_category=category_names[get_main_category(row[6:19])],
|
||||||
singable=row[19] != "nein"
|
singable=row[19] != "nein"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,13 +9,24 @@ router = APIRouter(
|
|||||||
responses={404: {"description": "Not found"}},
|
responses={404: {"description": "Not found"}},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def songify(s, votes):
|
||||||
|
return Song(**s.__dict__, vote=votes.get(s.id, None))
|
||||||
|
|
||||||
@router.get("/")
|
@router.get("/")
|
||||||
async def get_songs(user_id : str = "") -> list[Song]:
|
async def get_songs(user_id : str = "") -> list[Song]:
|
||||||
sqlsongs = session.query(SqlSong).filter(SqlSong.singable == True).all()
|
sqlsongs = session.query(SqlSong).filter(SqlSong.singable == True).all()
|
||||||
votes = session.query(SqlVote).filter(SqlVote.user_id == user_id).all()
|
votes = session.query(SqlVote).filter(SqlVote.user_id == user_id).all()
|
||||||
votes = {v.song_id : v.vote for v in votes}
|
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")
|
@router.post("/{song_id}/vote")
|
||||||
async def vote(song_id : str, user_id : str, vote : int):
|
async def vote(song_id : str, user_id : str, vote : int):
|
||||||
|
|||||||
@@ -6,13 +6,26 @@ from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm, Se
|
|||||||
from jose import JWTError, jwt
|
from jose import JWTError, jwt
|
||||||
from passlib.context import CryptContext
|
from passlib.context import CryptContext
|
||||||
from pydantic import BaseModel, ValidationError
|
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:
|
# to get a string like this run:
|
||||||
# openssl rand -hex 32
|
# openssl rand -hex 32
|
||||||
|
|
||||||
ALGORITHM = "HS256"
|
ALGORITHM = "HS256"
|
||||||
ACCESS_TOKEN_EXPIRE_MINUTES = 60 * 24 * 31
|
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):
|
class Token(BaseModel):
|
||||||
@@ -28,7 +41,7 @@ class TokenData(BaseModel):
|
|||||||
class User(BaseModel):
|
class User(BaseModel):
|
||||||
username: str
|
username: str
|
||||||
email: str | None = None
|
email: str | None = None
|
||||||
full_name: str | None = None
|
#full_name: str | None = None
|
||||||
disabled: bool | None = None
|
disabled: bool | None = None
|
||||||
|
|
||||||
|
|
||||||
@@ -53,6 +66,7 @@ router = APIRouter(
|
|||||||
|
|
||||||
|
|
||||||
def verify_password(plain_password, hashed_password):
|
def verify_password(plain_password, hashed_password):
|
||||||
|
print(get_password_hash(plain_password))
|
||||||
return pwd_context.verify(plain_password, hashed_password)
|
return pwd_context.verify(plain_password, hashed_password)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ class SqlSong(Base):
|
|||||||
og_artist = Column(String)
|
og_artist = Column(String)
|
||||||
aca_artist = Column(String)
|
aca_artist = Column(String)
|
||||||
title = Column(String)
|
title = Column(String)
|
||||||
yt_url = Column(String)
|
url = Column(String)
|
||||||
|
yt_id = Column(String)
|
||||||
|
spfy_id = Column(String)
|
||||||
thumbnail = Column(String)
|
thumbnail = Column(String)
|
||||||
is_aca = Column(Boolean)
|
is_aca = Column(Boolean)
|
||||||
arng_url = Column(String)
|
arng_url = Column(String)
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
|
||||||
|
|
||||||
<svg
|
<svg
|
||||||
width="326.09866"
|
width="326.09866"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 789 B After Width: | Height: | Size: 708 B |
@@ -1,5 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
|
||||||
|
|
||||||
<svg
|
<svg
|
||||||
width="466.66666"
|
width="466.66666"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 529 B After Width: | Height: | Size: 448 B |
21
static/open.svg
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="600.07782"
|
||||||
|
height="600.07782"
|
||||||
|
viewBox="0 0 18.002335 18.002335"
|
||||||
|
fill="none"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs1" />
|
||||||
|
<path
|
||||||
|
d="m 17.002335,1 -8,8 m 8,-8 v 4.5 m 0,-4.5 h -4.5 m 3.5,8.5 v 4.3 c 0,1.1201 0,1.6802 -0.218,2.108 -0.1917,0.3763 -0.4977,0.6823 -0.874,0.874 -0.4278,0.218 -0.9879,0.218 -2.108,0.218 h -8.6 c -1.1201,0 -1.68016,0 -2.10798,-0.218 C 1.718025,16.5903 1.412065,16.2843 1.220325,15.908 1.002335,15.4802 1.002335,14.9201 1.002335,13.8 V 5.2 c 0,-1.1201 0,-1.68016 0.21799,-2.10798 0.19174,-0.37633 0.4977,-0.68229 0.87403,-0.87403 C 2.522175,2 3.082225,2 4.202335,2 h 4.3"
|
||||||
|
stroke="#000000"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
id="path1" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 902 B |
@@ -1,5 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
|
||||||
|
|
||||||
<svg
|
<svg
|
||||||
width="259.76822"
|
width="259.76822"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 971 B |
@@ -2,17 +2,31 @@
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vote-buttons,
|
||||||
|
.cover-container,
|
||||||
|
.categories {
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
-ms-user-select: none;
|
-ms-user-select: none;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@media only screen and (min-resolution: 200dpi) {
|
@media only screen and (min-resolution: 200dpi) {
|
||||||
body {
|
body {
|
||||||
font-size: 3.2vmin;
|
font-size: 3.2vmin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.text {
|
||||||
|
padding: 0.3em;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
.clear {
|
.clear {
|
||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
@@ -101,11 +115,12 @@
|
|||||||
.button {
|
.button {
|
||||||
height: 1.5em;
|
height: 1.5em;
|
||||||
width: 3em;
|
width: 3em;
|
||||||
display: inline-block;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
font-size: 1.5em;
|
font-size: 1.5em;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
float: left;
|
||||||
|
clear: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button img {
|
.button img {
|
||||||
@@ -202,6 +217,8 @@
|
|||||||
font-size: 0.7em;
|
font-size: 0.7em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
padding: 0.1em;
|
padding: 0.1em;
|
||||||
@@ -224,20 +241,21 @@ h1 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#spotify-player {
|
#spotify-player {
|
||||||
bottom: 0.2em;
|
bottom: 0.4em;
|
||||||
background-color: blue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#close-player {
|
#close-player {
|
||||||
position: absolute;
|
position: fixed;
|
||||||
bottom: 320px;
|
bottom: calc(360px + 0.2em - 3em);
|
||||||
right: 0.5em;
|
right: 0.7em;
|
||||||
background-color: rgba(255,255,255,0.9);
|
background-color: rgba(255, 255, 255, 1);
|
||||||
width: 3em;
|
width: 3em;
|
||||||
height: 3em;
|
height: 3em;
|
||||||
border-radius: 1.5em;
|
border-radius: 1.5em;
|
||||||
display: none;
|
display: none;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
#close-player img {
|
#close-player img {
|
||||||
position: relative;
|
position: relative;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
|
|||||||
54
static/stop.svg
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="176.76801"
|
||||||
|
height="419.52487"
|
||||||
|
viewBox="0 0 5.3030402 12.585746"
|
||||||
|
fill="none"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
sodipodi:docname="stop.svg"
|
||||||
|
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
||||||
|
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">
|
||||||
|
<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="1.916407"
|
||||||
|
inkscape:cx="104.36196"
|
||||||
|
inkscape:cy="177.15443"
|
||||||
|
inkscape:window-width="2560"
|
||||||
|
inkscape:window-height="1351"
|
||||||
|
inkscape:window-x="-9"
|
||||||
|
inkscape:window-y="-9"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg1" />
|
||||||
|
<defs
|
||||||
|
id="defs1" />
|
||||||
|
<path
|
||||||
|
d="M 1.0001448,2.2242414 V 10.361541"
|
||||||
|
stroke="#000000"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
id="path1"
|
||||||
|
style="stroke:#000000;stroke-opacity:1"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
<path
|
||||||
|
d="m 4.2993174,2.22424 v 8.1373"
|
||||||
|
stroke="#000000"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
id="path1-3"
|
||||||
|
style="stroke:#000000;stroke-opacity:1"
|
||||||
|
sodipodi:nodetypes="cc" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -143,6 +143,7 @@ $(document).ready(function () {
|
|||||||
"no_selected": (song.vote == -1) ? "selected" : "",
|
"no_selected": (song.vote == -1) ? "selected" : "",
|
||||||
"neutral_selected": (song.vote == 0) ? "selected" : "",
|
"neutral_selected": (song.vote == 0) ? "selected" : "",
|
||||||
"yes_selected": (song.vote == 1) ? "selected" : "",
|
"yes_selected": (song.vote == 1) ? "selected" : "",
|
||||||
|
"play_button": (song.yt_id || song.spfy_id) ? "play" : "open",
|
||||||
"categories": cats
|
"categories": cats
|
||||||
})).join('')
|
})).join('')
|
||||||
|
|
||||||
@@ -175,22 +176,30 @@ window.onSpotifyIframeApiReady = (IFrameAPI) => {
|
|||||||
IFrameAPI.createController(element, options, callback);
|
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");
|
$("#yt-player").css("display", "none");
|
||||||
$("#spotify-player").css("display", "none");
|
$("#spotify-player").css("display", "none");
|
||||||
$("#close-player").css("display", "none");
|
$("#close-player").css("display", "none");
|
||||||
$("#yt-player").html("");
|
$("#yt-player").html("");
|
||||||
spotify_embed_controller.pause();
|
spotify_embed_controller.pause();
|
||||||
|
|
||||||
if (is_playing == id) {
|
|
||||||
is_playing = -1;
|
is_playing = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function play(id) {
|
||||||
|
if (is_playing == id) {
|
||||||
|
stop();
|
||||||
} else {
|
} else {
|
||||||
|
stop();
|
||||||
|
|
||||||
is_playing = id;
|
is_playing = id;
|
||||||
|
|
||||||
|
$("#song-" + id + " .cover-container .overlay img").attr("src", "/static/stop.svg");
|
||||||
|
|
||||||
song = all_songs[id];
|
song = all_songs[id];
|
||||||
yt_id = song.yt_url.split('v=')[1]
|
yt_id = song.yt_id
|
||||||
spotify_id = song.yt_url.split('/track/')[1]
|
spotify_id = song.spfy_id
|
||||||
|
|
||||||
if (yt_id) {
|
if (yt_id) {
|
||||||
$("#yt-player").css("display", "flex");
|
$("#yt-player").css("display", "flex");
|
||||||
@@ -205,15 +214,9 @@ function play(id) {
|
|||||||
spotify_embed_controller.play();
|
spotify_embed_controller.play();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$("#yt-player").css("display", "none");
|
stop();
|
||||||
$("#spotify-player").css("display", "none");
|
$("#song-" + id + " .cover-container .overlay img").attr("src", "/static/open.svg");
|
||||||
$("#yt-player").html("");
|
window.open(song.url, '_blank').focus();
|
||||||
spotify_embed_controller.pause();
|
|
||||||
window.open(song.yt_url, '_blank').focus();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//<iframe style="border-radius:12px" src="https://open.spotify.com/embed/track/2DS7lDZNFM7safSGNm8vd4?utm_source=generator" width="100%" height="352" frameBorder="0" allowfullscreen="" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy"></iframe>
|
|
||||||
|
|
||||||
// https://open.spotify.com/intl-de/track/2DS7lDZNFM7safSGNm8vd4
|
|
||||||
54
templates/voting-old.html
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Liederwahl</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/static/colors.css">
|
||||||
|
<link rel="stylesheet" type="text/css" href="/static/site.css">
|
||||||
|
<script src="https://open.spotify.com/embed/iframe-api/v1" async></script>
|
||||||
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
|
||||||
|
<script src="/static/voting_script.js"></script>
|
||||||
|
<script type="text/template" data-template="song">
|
||||||
|
<div class="song" id="song-${id}">
|
||||||
|
<div class="cover-container">
|
||||||
|
<img src="${cover_image}" class="cover">
|
||||||
|
<div class="overlay" onclick="play(${id})"><img src="/static/${play_button}.svg"></div>
|
||||||
|
</div>
|
||||||
|
<div class="song-title">${title}</div>
|
||||||
|
<div class="song-artist">${artist}</div>
|
||||||
|
<div class="categories" id="container">
|
||||||
|
${categories}<span style="--main-color: transparent;"> </span>
|
||||||
|
</div>
|
||||||
|
<div class="vote-buttons">
|
||||||
|
<div class="button button-no ${no_selected}" onmousedown="vote(${id}, -1); return false;" onclick="return false;"><img src="/static/no.svg"></div><div class="button button-neutral ${neutral_selected}" onmousedown="vote(${id}, 0)"><img src="/static/neutral.svg"></div><div class="button button-yes ${yes_selected}" onmousedown="vote(${id}, 1)"><img src="/static/yes.svg"></div>
|
||||||
|
</div>
|
||||||
|
<div class="clear"></div>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1 style="--main-color: #888888; ">Hallo :)</h1>
|
||||||
|
<div class="text">Du kannst die Liederwahl jederzeit unterbrechen und zu einem späteren Zeitpunkt weitermachen.</div>
|
||||||
|
<div id="songs"></div>
|
||||||
|
<div id="spotify-player"><div id="spotify-embed"></div></div>
|
||||||
|
<div id="yt-player"></div>
|
||||||
|
<div id="close-player" onclick="stop(); return false;"><img src="/static/no.svg"></div>
|
||||||
|
|
||||||
|
<!--<div class="song">
|
||||||
|
<div class="cover-container">
|
||||||
|
<img src="{{ url_for('static', path='/cover.jpg') }}" class="cover">
|
||||||
|
<div class="overlay"><img src="{{ url_for('static', path='/play.svg') }}"></div>
|
||||||
|
</div>
|
||||||
|
<div class="song-data">VoicePlay: In The Air Tonight</div>
|
||||||
|
<div class="categories" id="container">
|
||||||
|
<span class="cat-1">Ballade</span><span class="cat-2">< 90er Remake</span><span class="cat-3">Something else </span><span class="cat-4">Something else </span>
|
||||||
|
</div>
|
||||||
|
<div class="vote-buttons">
|
||||||
|
<div class="button button-no"><img src="{{ url_for('static', path='/no.svg') }}"></div><div class="button button-neutral"><img src="{{ url_for('static', path='/neutral.svg') }}"></div><div class="button button-yes selected"><img src="{{ url_for('static', path='/yes.svg') }}"></div>
|
||||||
|
</div>
|
||||||
|
<div class="clear"></div>
|
||||||
|
</div>-->
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
@@ -1,52 +1,164 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<title>Liederwahl</title>
|
<title>Liederwahl</title>
|
||||||
|
|
||||||
|
<link rel="apple-touch-icon" href="https://choriosity.de/assets/images/apple-touch-icon.png" type="image/png">
|
||||||
|
<link rel="alternate icon" href="https://choriosity.de/assets/images/favicon.png" type="image/png">
|
||||||
|
<link rel="shortcut icon" href="https://choriosity.de/assets/images/favicon.svg" type="image/svg+xml">
|
||||||
|
|
||||||
<link rel="stylesheet" type="text/css" href="/static/colors.css">
|
<link rel="stylesheet" type="text/css" href="/static/colors.css">
|
||||||
<link rel="stylesheet" type="text/css" href="/static/site.css">
|
<link rel="stylesheet" type="text/css" href="/static/site.css">
|
||||||
<script src="https://open.spotify.com/embed/iframe-api/v1" async></script>
|
<script src="https://open.spotify.com/embed/iframe-api/v1" async></script>
|
||||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
|
||||||
<script src="/static/voting_script.js"></script>
|
<script type="text/javascript">
|
||||||
<script type="text/template" data-template="song">
|
var spotify_embed_controller;
|
||||||
<div class="song" id="song-${id}">
|
|
||||||
<div class="cover-container">
|
|
||||||
<img src="${cover_image}" class="cover">
|
|
||||||
<div class="overlay" onclick="play(${id})"><img src="/static/play.svg"></div>
|
|
||||||
</div>
|
|
||||||
<div class="song-title">${title}</div>
|
|
||||||
<div class="song-artist">${artist}</div>
|
|
||||||
<div class="categories" id="container">
|
|
||||||
${categories}<span style="--main-color: transparent;"> </span>
|
|
||||||
</div>
|
|
||||||
<div class="vote-buttons">
|
|
||||||
<div class="button button-no ${no_selected}" onmousedown="vote(${id}, -1); return false;" onclick="return false;"><img src="/static/no.svg"></div><div class="button button-neutral ${neutral_selected}" onmousedown="vote(${id}, 0)"><img src="/static/neutral.svg"></div><div class="button button-yes ${yes_selected}" onmousedown="vote(${id}, 1)"><img src="/static/yes.svg"></div>
|
|
||||||
</div>
|
|
||||||
<div class="clear"></div>
|
|
||||||
</div>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
window.onSpotifyIframeApiReady = (IFrameAPI) => {
|
||||||
|
const element = document.getElementById('spotify-embed');
|
||||||
|
const options = {
|
||||||
|
width: '640',
|
||||||
|
height: '360'
|
||||||
|
};
|
||||||
|
const callback = (EmbedController) => {
|
||||||
|
spotify_embed_controller = EmbedController;
|
||||||
|
};
|
||||||
|
IFrameAPI.createController(element, options, callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
var is_playing = -1;
|
||||||
|
|
||||||
|
function stop() {
|
||||||
|
$("#song-" + is_playing + " .cover-container .overlay img").attr("src", "/static/play.svg");
|
||||||
|
|
||||||
|
$("#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 playYt(song_id, yt_id) {
|
||||||
|
if (is_playing == song_id) {
|
||||||
|
stop();
|
||||||
|
} else {
|
||||||
|
stop();
|
||||||
|
|
||||||
|
is_playing = song_id;
|
||||||
|
|
||||||
|
$("#song-" + song_id + " .cover-container .overlay img").attr("src", "/static/stop.svg");
|
||||||
|
|
||||||
|
$("#yt-player").css("display", "flex");
|
||||||
|
$("#close-player").css("display", "block");
|
||||||
|
iframe_code = '<iframe src="https://www.youtube.com/embed/' + yt_id + '?autoplay=1" title="" width="640" height="360" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowFullScreen></iframe>';
|
||||||
|
$("#yt-player").html(iframe_code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function playSpfy(song_id, spfy_id) {
|
||||||
|
if (is_playing == song_id) {
|
||||||
|
stop();
|
||||||
|
} else {
|
||||||
|
stop();
|
||||||
|
|
||||||
|
is_playing = song_id;
|
||||||
|
|
||||||
|
$("#song-" + song_id + " .cover-container .overlay img").attr("src", "/static/stop.svg");
|
||||||
|
|
||||||
|
$("#spotify-player").css("display", "flex");
|
||||||
|
$("#close-player").css("display", "block");
|
||||||
|
spotify_embed_controller.loadUri("spotify:track:" + spfy_id);
|
||||||
|
spotify_embed_controller.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function openUrl(song_id, url) {
|
||||||
|
stop();
|
||||||
|
window.open(url, '_blank').focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
function vote(song_id, vote) {
|
||||||
|
var session_id = "{{ session_id }}";
|
||||||
|
|
||||||
|
no_button = $("#song-" + song_id).find(".button-no")
|
||||||
|
yes_button = $("#song-" + song_id).find(".button-yes")
|
||||||
|
neutral_button = $("#song-" + song_id).find(".button-neutral")
|
||||||
|
|
||||||
|
no_button.removeClass("selected")
|
||||||
|
yes_button.removeClass("selected")
|
||||||
|
neutral_button.removeClass("selected")
|
||||||
|
|
||||||
|
switch (vote) {
|
||||||
|
case 0:
|
||||||
|
neutral_button.addClass("selected")
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
yes_button.addClass("selected")
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
no_button.addClass("selected")
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: "/songs/" + song_id + "/vote?" + $.param({ user_id: session_id, vote: vote }),
|
||||||
|
method: "POST"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="songs"></div>
|
<h1 style="--main-color: #888888; ">Hallo :)</h1>
|
||||||
<div id="spotify-player"><div id="spotify-embed"></div></div>
|
<div class="text">Du kannst die Liederwahl jederzeit unterbrechen und zu einem späteren Zeitpunkt weitermachen.
|
||||||
<div id="yt-player"></div>
|
|
||||||
<div id="close-player"><img src="/static/no.svg"></div>
|
|
||||||
|
|
||||||
<!--<div class="song">
|
|
||||||
<div class="cover-container">
|
|
||||||
<img src="{{ url_for('static', path='/cover.jpg') }}" class="cover">
|
|
||||||
<div class="overlay"><img src="{{ url_for('static', path='/play.svg') }}"></div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="song-data">VoicePlay: In The Air Tonight</div>
|
<div id="songs">
|
||||||
<div class="categories" id="container">
|
{% for main_category, songs in songs_by_category.items() %}
|
||||||
<span class="cat-1">Ballade</span><span class="cat-2">< 90er Remake</span><span class="cat-3">Something else </span><span class="cat-4">Something else </span>
|
<h1 class="cat-{{ all_categories[main_category] }}">{{ main_category }}</h1>
|
||||||
|
{% for song in songs -%}
|
||||||
|
<div class="song" id="song-{{ song.id }}">
|
||||||
|
<div class="cover-container">
|
||||||
|
<img src="{{ song.thumbnail }}" class="cover">
|
||||||
|
<div class="overlay"
|
||||||
|
onclick="{% if song.yt_id %}playYt({{ song.id }}, '{{ song.yt_id }}'){% else %}{% if song.spfy_id %}playSpfy({{ song.id }}, '{{ song.spfy_id }}'){% else %}openUrl({{ song.id }}, '{{ song.url }}'){% endif %}{% endif %}">
|
||||||
|
<img src="/static/{% if song.yt_id or song.spfy_id %}play{% else %}open{% endif %}.svg">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="song-title">{{ song.title }}</div>
|
||||||
|
<div class="song-artist">{% if song.og_artist %}{{ song.og_artist }}{% if song.aca_artist and
|
||||||
|
song.aca_artist != song.og_artist %} / {{ song.aca_artist
|
||||||
|
}}{% endif %}{% else %}{{ song.aca_artist }}{% endif %}</div>
|
||||||
|
<div class="categories" id="container">{% for category_name, is_in_category in song.categories.items() %}{%
|
||||||
|
if is_in_category %}<span class="cat-{{ all_categories[category_name] }}">{{ category_name }}</span>{%
|
||||||
|
endif %}{% endfor %}<span style="--main-color: transparent;"> </span>
|
||||||
</div>
|
</div>
|
||||||
<div class="vote-buttons">
|
<div class="vote-buttons">
|
||||||
<div class="button button-no"><img src="{{ url_for('static', path='/no.svg') }}"></div><div class="button button-neutral"><img src="{{ url_for('static', path='/neutral.svg') }}"></div><div class="button button-yes selected"><img src="{{ url_for('static', path='/yes.svg') }}"></div>
|
<div class="button button-no {% if song.vote == -1 %}selected{% endif %}"
|
||||||
|
onmousedown="vote({{ song.id }}, -1); return false;" onclick="return false;"><img
|
||||||
|
src="/static/no.svg">
|
||||||
|
</div>
|
||||||
|
<div class="button button-neutral {% if song.vote == 0 %}selected{% endif %}"
|
||||||
|
onmousedown="vote({{ song.id }}, 0); return false;" onclick="return false;"><img
|
||||||
|
src="/static/neutral.svg"></div>
|
||||||
|
<div class="button button-yes {% if song.vote == 1 %}selected{% endif %}"
|
||||||
|
onmousedown="vote({{ song.id }}, 1); return false;" onclick="return false;"><img
|
||||||
|
src="/static/yes.svg">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="clear"></div>
|
<div class="clear"></div>
|
||||||
</div>-->
|
</div>
|
||||||
</body>
|
{% endfor %}
|
||||||
</html>
|
{% endfor %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div id="spotify-player">
|
||||||
|
<div id="spotify-embed"></div>
|
||||||
|
</div>
|
||||||
|
<div id="yt-player"></div>
|
||||||
|
<div id="close-player" onclick="stop(); return false;"><img src="/static/no.svg"></div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||