Added jukebox page

This commit is contained in:
Ben Arc
2021-05-05 23:03:22 +01:00
parent a698ba7a26
commit 396de3cfa3
4 changed files with 150 additions and 49 deletions

View File

@@ -332,6 +332,11 @@ new Vue({
},
callAuthorizationApi(body) {
self = this
console.log(btoa(
this.jukeboxDialog.data.sp_user +
':' +
this.jukeboxDialog.data.sp_secret
))
let xhr = new XMLHttpRequest()
xhr.open('POST', 'https://accounts.spotify.com/api/token', true)
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')

View File

@@ -1,24 +1,104 @@
{% extends "print.html" %} {% block page %} {% raw %}
<div class="row justify-center">
<div v-for="item in items" class="q-my-sm q-mx-lg">
<div class="text-center q-ma-none q-mb-sm">{{ item.name }}</div>
<qrcode :value="item.lnurl" :options="{margin: 0, width: 250}"></qrcode>
<div class="text-center q-ma-none q-mt-sm">{{ item.price }}</div>
{% extends "public.html" %} {% block page %} {% raw %}
<div class="row q-col-gutter-md justify-center">
<div class="col-12 col-sm-6 col-md-5 col-lg-4">
<q-card class="q-pa-lg">
<q-card-section class="q-pa-none">
<p style="font-size: 22px">Currently playing</p>
<div class="row">
<div class="col-4">
<img style="width: 100px" :src="currentPlaylist[0].image" />
</div>
<div class="col-8">
<strong style="font-size: 20px"
>{{ currentPlaylist[0].name }}</strong
><br />
<strong style="font-size: 15px"
>{{ currentPlaylist[0].artist }}</strong
>
</div>
</div>
</q-card-section>
</q-card>
<q-card class="q-mt-lg">
<q-card-section>
<p style="font-size: 22px">Pick a song</p>
<q-select
outlined
v-model="model"
:options="playlists"
label="playlists"
></q-select>
</q-card-section>
<q-card-section class="q-pa-none">
<q-separator></q-separator>
<q-virtual-scroll
style="max-height: 300px"
:items="currentPlaylist"
separator
>
<template v-slot="{ item, index }">
<q-item :key="index" dense clickable v-ripple>
<q-item-section>
<q-item-label>
{{ item.name }} - ({{ item.artist }})
</q-item-label>
</q-item-section>
</q-item>
</template>
</q-virtual-scroll>
</q-card-section>
</q-card>
</div>
<div class="col-12 col-sm-6 col-md-5 col-lg-4 q-gutter-y-md">
<q-card class="q-pa-lg">
<q-card-section class="q-pa-none">
<p style="font-size: 21px">Queued</p>
<br />
<q-list bordered separator>
<q-item
bordered
v-for="song in queued"
:key="song.id"
clickable
v-ripple
>
<q-item-section prepend>
<img style="width: 50px" :src="song.image" />
</q-item-section>
<q-item-section>{{ song.name }} ({{ song.artist }})</q-item-section>
</q-item>
</q-list>
</q-card-section>
</q-card>
</div>
</div>
{% endraw %} {% endblock %} {% block scripts %}
<script src="{{ url_for('static', filename='vendor/vue-qrcode@1.0.2/vue-qrcode.min.js') }}"></script>
<style></style>
<script>
Vue.component(VueQrcode.name, VueQrcode)
new Vue({
el: '#vue',
created: function () {
window.print()
},
data: function () {
mixins: [windowMixin],
data() {
return {
items: JSON.parse('{{items | tojson}}')
currentPlaylist: JSON.parse('{{ firstPlaylist[0] | tojson }}'),
playlists: JSON.parse('{{ playlists | tojson }}'),
heavyList: [],
queued: []
}
},
computed: {},
methods: {},
created() {
this.queued[0] = this.currentPlaylist[2]
this.queued[1] = this.currentPlaylist[5]
this.queued[2] = this.currentPlaylist[6]
this.queued[3] = this.currentPlaylist[7]
console.log(this.currentPlaylist)
}
})
</script>

View File

@@ -10,6 +10,9 @@ from lnbits.core.crud import get_standalone_payment
from . import jukebox_ext
from .crud import get_jukebox
from urllib.parse import unquote
from .views_api import (
api_get_jukebox_songs,
)
@jukebox_ext.route("/")
@@ -22,5 +25,15 @@ async def index():
@jukebox_ext.route("/<juke_id>")
async def print_qr_codes(juke_id):
jukebox = await get_jukebox(juke_id)
if not jukebox:
return "error"
firstPlaylist = await api_get_jukebox_songs(
juke_id, jukebox.sp_playlists.split(",")[0].split("-")[1]
)
print(firstPlaylist)
return await render_template("jukebox/jukebox.html", jukebox=jukebox)
return await render_template(
"jukebox/jukebox.html",
playlists=jukebox.sp_playlists.split(","),
firstPlaylist=firstPlaylist,
)

View File

@@ -109,42 +109,49 @@ async def api_delete_item(juke_id):
################JUKEBOX ENDPOINTS##################
@jukebox_ext.route("/api/v1/jukebox/jb/<sp_id>", methods=["GET"])
async def api_get_jukebox_songs(sp_id):
@jukebox_ext.route("/api/v1/jukebox/jb/<sp_id>/<sp_playlist>", methods=["GET"])
async def api_get_jukebox_songs(sp_id, sp_playlist):
jukebox = await get_jukebox(sp_id)
print(jukebox.sp_playlists.split(",")[0].split("-")[1])
tracks = []
async with httpx.AsyncClient() as client:
try:
r = await client.get(
"https://api.spotify.com/v1/playlists/"
+ jukebox.sp_playlists.split(",")[0].split("-")[1]
+ "/tracks",
"https://api.spotify.com/v1/playlists/" + sp_playlist + "/tracks",
timeout=40,
headers={"Authorization": "Bearer " + jukebox.sp_access_token},
)
if r.json()["error"]["status"] == 401:
token = await api_get_token(sp_id)
if token['error'] == 'invalid_client':
print("invalid")
return ""
else:
return await api_get_jukebox_songs(sp_id)
print(r.json()["items"])
resp = r.json()["items"][0]
print("id: " + resp["track"]["id"])
print("name: " + resp["track"]["name"])
print("album: " + resp["track"]["album"]["name"])
print("artist: " + resp["track"]["artists"][0]["name"])
print("image: " + resp["track"]["album"]["images"][0])
if "items" not in r.json():
if r.json()["error"]["status"] == 401:
token = await api_get_token(sp_id)
if token == False:
print("invalid")
return False
else:
return await api_get_jukebox_songs(sp_id, sp_playlist)
for item in r.json()["items"]:
tracks.append(
{
"id": item["track"]["id"],
"name": item["track"]["name"],
"album": item["track"]["album"]["name"],
"artist": item["track"]["artists"][0]["name"],
"image": item["track"]["album"]["images"][0]["url"],
}
)
except AssertionError:
something = None
return jsonify(jukebox._asdict()), HTTPStatus.CREATED
print(jsonify(tracks))
return tracks, HTTPStatus.OK
@jukebox_ext.route("/api/v1/jukebox/jb/<sp_id>", methods=["GET"])
async def api_get_token(sp_id):
jukebox = await get_jukebox(sp_id)
print(jukebox.sp_playlists.split(",")[0].split("-")[1])
print(
"Authorization: Bearer "
+ base64.b64encode(
str(jukebox.sp_user + ":" + jukebox.sp_secret).encode("ascii")
).decode("ascii")
)
async with httpx.AsyncClient() as client:
try:
r = await client.post(
@@ -156,24 +163,20 @@ async def api_get_token(sp_id):
"client_id": jukebox.sp_user,
},
headers={
"Authorization": "Bearer "
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": "Basic "
+ base64.b64encode(
(jukebox.sp_user + ":" + jukebox.sp_refresh_token).encode(
"utf-8"
)
str(jukebox.sp_user + ":" + jukebox.sp_secret).encode("ascii")
).decode("ascii"),
"Content-Type": "application/x-www-form-urlencoded",
},
)
print(r)
print(r.json())
if r.json()['error'] == 'invalid_client':
return r.json()
#await update_jukebox(
# juke_id=sp_id,
# sp_access_token=r.json()["access_token"],
# sp_refresh_token=r.json()["refresh_token"],
#)
if "access_token" not in r.json():
return False
else:
await update_jukebox(
juke_id=sp_id, sp_access_token=r.json()["access_token"]
)
except AssertionError:
something = None
return jsonify(jukebox._asdict()), HTTPStatus.CREATED
return True