diff --git a/app/models.py b/app/models.py
index 3c2851b..195ac47 100644
--- a/app/models.py
+++ b/app/models.py
@@ -15,6 +15,7 @@ class Song(BaseModel):
aca_artist: Optional[str]
title: str
yt_url: Optional[str]
+ thumbnail: Optional[str]
is_aca: bool
arng_url: Optional[str]
categories: dict[str, bool]
diff --git a/app/routers/admin.py b/app/routers/admin.py
index 62c6f2a..40fd220 100644
--- a/app/routers/admin.py
+++ b/app/routers/admin.py
@@ -4,6 +4,8 @@ from app.dependencies import session
from app.routers.user import get_current_user
import pandas as pd
import numpy as np
+import re
+import requests
router = APIRouter(
prefix="/admin",
@@ -20,6 +22,27 @@ def get_main_category(categories) -> int:
else:
return np.argmax(categories != None, axis=0)
+def youtube_url_validation(url):
+ youtube_regex = (
+ r'(https?://)?(www\.)?'
+ '(youtube|youtu|youtube-nocookie)\.(com|be)/'
+ '(watch\?v=|embed/|v/|.+\?v=)?([^&=%\?]{11})')
+
+ youtube_regex_match = re.match(youtube_regex, url)
+ if youtube_regex_match:
+ return youtube_regex_match
+
+ return False
+
+def get_thumbnail(url):
+ m = youtube_url_validation(url)
+ if m:
+ thumbnail_url = "https://img.youtube.com/vi/" + m.group(6) + "/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):
@@ -36,6 +59,7 @@ async def create_upload_file(link_share: str):
aca_artist=row[1],
title=row[2],
yt_url=row[3],
+ thumbnail=get_thumbnail(row[3]),
is_aca=row[4] == "ja",
arng_url=row[5],
categories={n: v for n, v in zip(
diff --git a/app/sql_models.py b/app/sql_models.py
index a92a8fc..9c46f0e 100644
--- a/app/sql_models.py
+++ b/app/sql_models.py
@@ -10,6 +10,7 @@ class SqlSong(Base):
aca_artist = Column(String)
title = Column(String)
yt_url = Column(String)
+ thumbnail = Column(String)
is_aca = Column(Boolean)
arng_url = Column(String)
diff --git a/requirements.txt b/requirements.txt
index b25acae..9c7501d 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -7,4 +7,5 @@ python-jose[cryptography]
passlib[bcrypt]
python-multipart
jinja2
-openpyxl
\ No newline at end of file
+openpyxl
+requests
\ No newline at end of file
diff --git a/static/colors.css b/static/colors.css
index 9859662..4c7065e 100644
--- a/static/colors.css
+++ b/static/colors.css
@@ -1,90 +1,90 @@
.cat-1 {
- background-color: #1f77b4;
+ --main-color: #1f77b4;
}
.cat-2 {
- background-color: #ff7f0e;
+ --main-color: #ff7f0e;
}
.cat-3 {
- background-color: #2ca02c;
+ --main-color: #2ca02c;
}
.cat-4 {
- background-color: #d62728;
+ --main-color: #d62728;
}
.cat-5 {
- background-color: #9467bd;
+ --main-color: #9467bd;
}
.cat-6 {
- background-color: #8c564b;
+ --main-color: #8c564b;
}
.cat-7 {
- background-color: #e377c2;
+ --main-color: #e377c2;
}
.cat-8 {
- background-color: #7f7f7f;
+ --main-color: #7f7f7f;
}
.cat-9 {
- background-color: #bcbd22;
+ --main-color: #bcbd22;
}
.cat-10 {
- background-color: #17becf;
+ --main-color: #17becf;
}
.cat-11 {
- background-color: #a1c9f4;
+ --main-color: #a1c9f4;
}
.cat-12 {
- background-color: #ffb482;
+ --main-color: #ffb482;
}
.cat-13 {
- background-color: #8de5a1;
+ --main-color: #8de5a1;
}
.cat-14 {
- background-color: #ff9f9b;
+ --main-color: #ff9f9b;
}
.cat-15 {
- background-color: #d0bbff;
+ --main-color: #d0bbff;
}
.cat-16 {
- background-color: #debb9b;
+ --main-color: #debb9b;
}
.cat-17 {
- background-color: #fab0e4;
+ --main-color: #fab0e4;
}
.cat-18 {
- background-color: #cfcfcf;
+ --main-color: #cfcfcf;
}
.cat-19 {
- background-color: #fffea3;
+ --main-color: #fffea3;
}
.cat-20 {
- background-color: #b9f2f0;
+ --main-color: #b9f2f0;
}
.cat-21 {
- background-color: #001c7f;
+ --main-color: #001c7f;
}
.cat-22 {
- background-color: #b1400d;
+ --main-color: #b1400d;
}
.cat-23 {
- background-color: #12711c;
+ --main-color: #12711c;
}
.cat-24 {
- background-color: #8c0800;
+ --main-color: #8c0800;
}
.cat-25 {
- background-color: #591e71;
+ --main-color: #591e71;
}
.cat-26 {
- background-color: #592f0d;
+ --main-color: #592f0d;
}
.cat-27 {
- background-color: #a23582;
+ --main-color: #a23582;
}
.cat-28 {
- background-color: #3c3c3c;
+ --main-color: #3c3c3c;
}
.cat-29 {
- background-color: #b8850a;
+ --main-color: #b8850a;
}
.cat-30 {
- background-color: #006374;
+ --main-color: #006374;
}
diff --git a/static/cover.jpg b/static/cover.jpg
index 1f3d723..67e3605 100644
Binary files a/static/cover.jpg and b/static/cover.jpg differ
diff --git a/static/index.html b/static/index.html
deleted file mode 100644
index 7db222f..0000000
--- a/static/index.html
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
- Hello jQuery
-
-
-
-
-
-
-
The ID is
-
The content is
-
-
-
diff --git a/static/landing_script.js b/static/landing_script.js
index d822fbc..c9e0de0 100644
--- a/static/landing_script.js
+++ b/static/landing_script.js
@@ -5,4 +5,5 @@ $(document).ready(function () {
localStorage.setItem('session_id', s_id)
}
$('.vote-from-existing').attr('href', '?session_id=' + s_id);
+ window.location.href = "/?session_id=" + s_id;
});
diff --git a/static/site.css b/static/site.css
index 899a81d..a997bb1 100644
--- a/static/site.css
+++ b/static/site.css
@@ -2,10 +2,9 @@
box-sizing: border-box;
margin: 0;
padding: 0;
-}
-
-body {
- padding: 0.5em;
+ -webkit-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
}
@media only screen and (min-resolution: 200dpi) {
@@ -24,7 +23,8 @@ body {
border-radius: 0.5em;
width: 30em;
font-family: sans-serif;
- margin-bottom: 1em;
+ margin-bottom: 1rem;
+ margin-left: 0.5em;
}
@@ -34,12 +34,21 @@ body {
height: 6em;
float: left;
margin-right: 1em;
+ text-align: center;
+ background-color: white;
}
.cover {
display: block;
- width: 100%;
- height: auto;
+ max-width: 100%;
+ max-height: 100%;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ -webkit-transform: translate(-50%, -50%);
+ -ms-transform: translate(-50%, -50%);
+ transform: translate(-50%, -50%);
+ transition: .3s ease;
}
@@ -64,6 +73,10 @@ body {
filter: drop-shadow(0px 0px 1em black);
}
+.cover-container:hover .cover {
+ filter: brightness(0.6);
+}
+
.overlay img {
height: 50%;
position: absolute;
@@ -86,7 +99,7 @@ body {
}
.button {
- height: 2em;
+ height: 1.5em;
width: 3em;
display: inline-block;
text-align: center;
@@ -160,7 +173,7 @@ body {
white-space: nowrap;
font-size: 0.7em;
line-height: 1.2em;
- margin-top: 0.2em;
+ margin-top: 0.3em;
}
.categories span {
@@ -171,14 +184,66 @@ body {
color: white;
max-width: 10em;
overflow: clip;
+ background-color: var(--main-color);
}
.vote-buttons {
margin-top: 0.5em;
}
-.song-data {
+.song-title,
+.song-artist {
width: 100%;
overflow: clip;
white-space: nowrap;
+}
+
+.song-artist {
+ font-size: 0.7em;
+}
+
+h1 {
+ font-family: sans-serif;
+ padding: 0.1em;
+ padding-left: 0.2em;
+ margin-bottom: 1rem;
+ font-size: 1.5em;
+ background-color: color-mix(in srgb, var(--main-color) 60%, transparent);
+ border-bottom: 0.3rem solid var(--main-color);
+}
+
+#yt-player,
+#spotify-player {
+ position: fixed;
+ bottom: 0.5em;
+ right: 0.5em;
+ padding: 0;
+ display: none;
+ justify-content: center;
+ border-radius: 20px;
+}
+
+#spotify-player {
+ bottom: 0.2em;
+ background-color: blue;
+}
+
+#close-player {
+ position: absolute;
+ bottom: 320px;
+ right: 0.5em;
+ background-color: rgba(255,255,255,0.9);
+ width: 3em;
+ height: 3em;
+ border-radius: 1.5em;
+ display: none;
+}
+#close-player img {
+ position: relative;
+ left: 50%;
+ top: 50%;
+ -webkit-transform: translate(-50%, -50%);
+ -ms-transform: translate(-50%, -50%);
+ transform: translate(-50%, -50%);
+ width: 1.5em;
}
\ No newline at end of file
diff --git a/static/voting_script.js b/static/voting_script.js
index 0b76135..d472767 100644
--- a/static/voting_script.js
+++ b/static/voting_script.js
@@ -78,25 +78,36 @@ function vote(song_id, vote) {
const getQueryParameter = (param) => new URLSearchParams(document.location.search.substring(1)).get(param);
+var all_songs = {}
+
$(document).ready(function () {
var session_id = getQueryParameter("session_id");
var songTemplate = $('script[data-template="song"]').text().split(/\$\{(.+?)\}/g);
function render(props) {
- return function(tok, i) { return (i % 2) ? props[tok] : tok; };
+ return function (tok, i) { return (i % 2) ? props[tok] : tok; };
}
- song_list = {}
+
$.ajax({
- url: "/songs",
+ url: "/songs/",
data: { user_id: session_id }
}).then(function (songs) {
+ song_list = {}
+
+ cat_to_id = {}
+
$.each(songs, function (key, song) {
+ all_songs[song.id] = song;
+
var mc = song.main_category;
+ if (!song.is_aca) {
+ mc = "Wildcard"
+ }
if (!(mc in song_list)) {
song_list[mc] = ""
}
@@ -107,25 +118,102 @@ $(document).ready(function () {
if (is_cat) {
cats = cats + '' + cat_name + '';
}
+ cat_to_id[cat_name] = cat_id
cat_id += 1
});
+ cat_to_id["Wildcard"] = cat_id
+
+
+ artist = "";
+ if (song.og_artist) {
+ artist += song.og_artist;
+ if (song.aca_artist && (song.aca_artist !== song.og_artist)) {
+ artist += " / ";
+ artist += song.aca_artist;
+ }
+ } else {
+ artist = song.aca_artist;
+ }
-
var s = songTemplate.map(render({
- "id" : song.id,
- "title" : song.og_artist + ": " + song.title,
- "cover_image" : "cover.jpg",
- "no_selected" : (song.vote == -1) ? "selected" : "",
- "neutral_selected" : (song.vote == 0) ? "selected" : "",
- "yes_selected" : (song.vote == 1) ? "selected" : "",
- "categories" : cats
+ "id": song.id,
+ "title": song.title,
+ "artist": artist, //song.og_artist + ": " + song.aca_artist
+ "cover_image": song.thumbnail,
+ "no_selected": (song.vote == -1) ? "selected" : "",
+ "neutral_selected": (song.vote == 0) ? "selected" : "",
+ "yes_selected": (song.vote == 1) ? "selected" : "",
+ "categories": cats
})).join('')
song_list[mc] += s
});
- $.each(song_list, function(mc, s) {
- $('body').append("" + mc + "
");
- $('body').append(s);
+ $.each(cat_to_id, function (cat_name, cat_id) {
+ if (cat_name in song_list) {
+ $('#songs').append("" + cat_name + "
");
+ $('#songs').append(song_list[cat_name]);
+ }
});
+
+ makeScroll();
});
});
+
+var is_playing = -1;
+
+var spotify_embed_controller;
+
+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);
+ };
+
+
+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();
+
+ if (is_playing == id) {
+ is_playing = -1;
+ } else {
+ is_playing = id;
+
+ song = all_songs[id];
+ yt_id = song.yt_url.split('v=')[1]
+ spotify_id = song.yt_url.split('/track/')[1]
+
+ if (yt_id) {
+ $("#yt-player").css("display", "flex");
+ $("#close-player").css("display", "block");
+ iframe_code = '';
+ $("#yt-player").html(iframe_code);
+ }
+ else if (spotify_id) {
+ $("#spotify-player").css("display", "flex");
+ $("#close-player").css("display", "block");
+ spotify_embed_controller.loadUri("spotify:track:" + spotify_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();
+ }
+ }
+}
+
+//
+
+// https://open.spotify.com/intl-de/track/2DS7lDZNFM7safSGNm8vd4
\ No newline at end of file
diff --git a/templates/item.html b/templates/item.html
deleted file mode 100644
index 9ba6afa..0000000
--- a/templates/item.html
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
- Item Details
-
-
-
-
-
-
\ No newline at end of file
diff --git a/templates/voting.html b/templates/voting.html
index ca7298a..706cfb6 100644
--- a/templates/voting.html
+++ b/templates/voting.html
@@ -4,20 +4,22 @@
Liederwahl
+