This commit is contained in:
Ben Arc 2021-06-24 01:40:24 +01:00
parent e7824e0e8d
commit e51ef5b722
8 changed files with 449 additions and 226 deletions

View file

@ -82,7 +82,7 @@
<script> <script>
Vue.component(VueQrcode.name, VueQrcode) Vue.component(VueQrcode.name, VueQrcode)
Vue.use(VueQrcodeReader) Vue.use(VueQrcodeReader)
var mapEvents = function(obj) { var mapEvents = function (obj) {
obj.date = Quasar.utils.date.formatDate( obj.date = Quasar.utils.date.formatDate(
new Date(obj.time * 1000), new Date(obj.time * 1000),
'YYYY-MM-DD HH:mm' 'YYYY-MM-DD HH:mm'
@ -94,7 +94,7 @@
new Vue({ new Vue({
el: '#vue', el: '#vue',
mixins: [windowMixin], mixins: [windowMixin],
data: function() { data: function () {
return { return {
tickets: [], tickets: [],
ticketsTable: { ticketsTable: {
@ -119,35 +119,35 @@
} }
}, },
methods: { methods: {
hoverEmail: function(tmp) { hoverEmail: function (tmp) {
this.tickets.data.emailtemp = tmp this.tickets.data.emailtemp = tmp
}, },
closeCamera: function() { closeCamera: function () {
this.sendCamera.show = false this.sendCamera.show = false
}, },
showCamera: function() { showCamera: function () {
this.sendCamera.show = true this.sendCamera.show = true
}, },
decodeQR: function(res) { decodeQR: function (res) {
this.sendCamera.show = false this.sendCamera.show = false
var self = this var self = this
LNbits.api LNbits.api
.request('GET', '/events/api/v1/register/ticket/' + res) .request('GET', '/events/api/v1/register/ticket/' + res)
.then(function(response) { .then(function (response) {
self.$q.notify({ self.$q.notify({
type: 'positive', type: 'positive',
message: 'Registered!' message: 'Registered!'
}) })
setTimeout(function() { setTimeout(function () {
window.location.reload() window.location.reload()
}, 2000) }, 2000)
}) })
.catch(function(error) { .catch(function (error) {
LNbits.utils.notifyApiError(error) LNbits.utils.notifyApiError(error)
}) })
}, },
getEventTickets: function() { getEventTickets: function () {
var self = this var self = this
console.log('obj') console.log('obj')
LNbits.api LNbits.api
@ -155,17 +155,17 @@
'GET', 'GET',
'/events/api/v1/eventtickets/{{ wallet_id }}/{{ event_id }}' '/events/api/v1/eventtickets/{{ wallet_id }}/{{ event_id }}'
) )
.then(function(response) { .then(function (response) {
self.tickets = response.data.map(function(obj) { self.tickets = response.data.map(function (obj) {
return mapEvents(obj) return mapEvents(obj)
}) })
}) })
.catch(function(error) { .catch(function (error) {
LNbits.utils.notifyApiError(error) LNbits.utils.notifyApiError(error)
}) })
} }
}, },
created: function() { created: function () {
this.getEventTickets() this.getEventTickets()
} }
}) })

View file

@ -93,7 +93,11 @@ new Vue({
getJukeboxes() { getJukeboxes() {
self = this self = this
LNbits.api LNbits.api
.request('GET', '/jukebox/api/v1/jukebox', self.g.user.wallets[0].adminkey) .request(
'GET',
'/jukebox/api/v1/jukebox',
self.g.user.wallets[0].adminkey
)
.then(function (response) { .then(function (response) {
self.JukeboxLinks = response.data.map(mapJukebox) self.JukeboxLinks = response.data.map(mapJukebox)
}) })
@ -195,9 +199,9 @@ new Vue({
if (self.jukeboxDialog.data.sp_access_token) { if (self.jukeboxDialog.data.sp_access_token) {
self.refreshPlaylists() self.refreshPlaylists()
self.refreshDevices() self.refreshDevices()
console.log("this.devices") console.log('this.devices')
console.log(self.devices) console.log(self.devices)
console.log("this.devices") console.log('this.devices')
setTimeout(function () { setTimeout(function () {
if (self.devices.length < 1 || self.playlists.length < 1) { if (self.devices.length < 1 || self.playlists.length < 1) {
self.$q.notify({ self.$q.notify({

View file

@ -6,14 +6,9 @@ new Vue({
el: '#vue', el: '#vue',
mixins: [windowMixin], mixins: [windowMixin],
data() { data() {
return { return {}
}
}, },
computed: {}, computed: {},
methods: { methods: {},
created() {}
},
created() {
}
}) })

View file

@ -1,24 +1,33 @@
<q-card-section> <q-card-section>
To use this extension you need a Spotify client ID and client secret. You To use this extension you need a Spotify client ID and client secret. You get
get these by creating an app in the Spotify developers dashboard these by creating an app in the Spotify developers dashboard
<a style="color:#43a047" href="https://developer.spotify.com/dashboard/applications">here </a> <a
<br /><br />Select the playlists you want people to be able to pay for, style="color: #43a047"
share the frontend page, profit :) <br /><br /> href="https://developer.spotify.com/dashboard/applications"
Made by, <a style="color:#43a047" href="https://twitter.com/arcbtc">benarc</a>. Inspired by, >here
<a style="color:#43a047" href="https://twitter.com/pirosb3/status/1056263089128161280">pirosb3</a>. </a>
<br /><br />Select the playlists you want people to be able to pay for, share
the frontend page, profit :) <br /><br />
Made by,
<a style="color: #43a047" href="https://twitter.com/arcbtc">benarc</a>.
Inspired by,
<a
style="color: #43a047"
href="https://twitter.com/pirosb3/status/1056263089128161280"
>pirosb3</a
>.
</q-card-section> </q-card-section>
<q-expansion-item
group="extras"
icon="swap_vertical_circle"
label="API info"
:content-inset-level="0.5"
<q-expansion-item group="extras" icon="swap_vertical_circle" label="API info" :content-inset-level="0.5"> >
<q-expansion-item group="api" dense expand-separator label="List jukeboxes"> <q-expansion-item group="api" dense expand-separator label="List jukeboxes">
<q-card> <q-card>
<q-card-section> <q-card-section>
<code><span class="text-blue">GET</span> <code><span class="text-blue">GET</span> /jukebox/api/v1/jukebox</code>
/jukebox/api/v1/jukebox</code>
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5> <h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
<code>{"X-Api-Key": &lt;admin_key&gt;}</code><br /> <code>{"X-Api-Key": &lt;admin_key&gt;}</code><br />
<h5 class="text-caption q-mt-sm q-mb-none">Body (application/json)</h5> <h5 class="text-caption q-mt-sm q-mb-none">Body (application/json)</h5>
@ -27,7 +36,8 @@
</h5> </h5>
<code>[&lt;jukebox_object&gt;, ...]</code> <code>[&lt;jukebox_object&gt;, ...]</code>
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5> <h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
<code>curl -X GET {{ request.url_root }}api/v1/jukebox -H "X-Api-Key: {{ <code
>curl -X GET {{ request.url_root }}api/v1/jukebox -H "X-Api-Key: {{
g.user.wallets[0].adminkey }}" g.user.wallets[0].adminkey }}"
</code> </code>
</q-card-section> </q-card-section>
@ -36,8 +46,10 @@
<q-expansion-item group="api" dense expand-separator label="Get jukebox"> <q-expansion-item group="api" dense expand-separator label="Get jukebox">
<q-card> <q-card>
<q-card-section> <q-card-section>
<code><span class="text-blue">GET</span> <code
/jukebox/api/v1/jukebox/&lt;juke_id&gt;</code> ><span class="text-blue">GET</span>
/jukebox/api/v1/jukebox/&lt;juke_id&gt;</code
>
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5> <h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
<code>{"X-Api-Key": &lt;admin_key&gt;}</code><br /> <code>{"X-Api-Key": &lt;admin_key&gt;}</code><br />
<h5 class="text-caption q-mt-sm q-mb-none">Body (application/json)</h5> <h5 class="text-caption q-mt-sm q-mb-none">Body (application/json)</h5>
@ -46,36 +58,44 @@
</h5> </h5>
<code>&lt;jukebox_object&gt;</code> <code>&lt;jukebox_object&gt;</code>
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5> <h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
<code>curl -X GET {{ request.url_root }}api/v1/jukebox/&lt;juke_id&gt; -H "X-Api-Key: {{ <code
g.user.wallets[0].adminkey }}" >curl -X GET {{ request.url_root }}api/v1/jukebox/&lt;juke_id&gt; -H
"X-Api-Key: {{ g.user.wallets[0].adminkey }}"
</code> </code>
</q-card-section> </q-card-section>
</q-card> </q-card>
</q-expansion-item> </q-expansion-item>
<q-expansion-item group="api" dense expand-separator label="Create/update track"> <q-expansion-item
group="api"
dense
expand-separator
label="Create/update track"
>
<q-card> <q-card>
<q-card-section> <q-card-section>
<code><span class="text-green">POST/PUT</span> <code
/jukebox/api/v1/jukebox/</code> ><span class="text-green">POST/PUT</span>
/jukebox/api/v1/jukebox/</code
>
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5> <h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
<code>{"X-Api-Key": &lt;admin_key&gt;}</code><br /> <code>{"X-Api-Key": &lt;admin_key&gt;}</code><br />
<h5 class="text-caption q-mt-sm q-mb-none"> <h5 class="text-caption q-mt-sm q-mb-none">Body (application/json)</h5>
Body (application/json)
</h5>
<h5 class="text-caption q-mt-sm q-mb-none"> <h5 class="text-caption q-mt-sm q-mb-none">
Returns 200 OK (application/json) Returns 200 OK (application/json)
</h5> </h5>
<code>&lt;jukbox_object&gt;</code> <code>&lt;jukbox_object&gt;</code>
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5> <h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
<code>curl -X POST {{ request.url_root }}api/v1/jukebox/ -d <code
'{"user": &lt;string, user_id&gt;, >curl -X POST {{ request.url_root }}api/v1/jukebox/ -d '{"user":
"title": &lt;string&gt;, "wallet":&lt;string&gt;, "sp_user": &lt;string, user_id&gt;, "title": &lt;string&gt;,
&lt;string, spotify_user_account&gt;, "sp_secret": &lt;string, spotify_user_secret&gt;, "sp_access_token": "wallet":&lt;string&gt;, "sp_user": &lt;string,
&lt;string, not_required&gt;, "sp_refresh_token": spotify_user_account&gt;, "sp_secret": &lt;string,
&lt;string, not_required&gt;, "sp_device": &lt;string, spotify_user_secret&gt;, "sp_playlists": spotify_user_secret&gt;, "sp_access_token": &lt;string,
&lt;string, not_required&gt;, "price": not_required&gt;, "sp_refresh_token": &lt;string, not_required&gt;,
&lt;integer, not_required&gt;}' -H "Content-type: "sp_device": &lt;string, spotify_user_secret&gt;, "sp_playlists":
application/json" -H "X-Api-Key: {{g.user.wallets[0].adminkey }}" &lt;string, not_required&gt;, "price": &lt;integer, not_required&gt;}'
-H "Content-type: application/json" -H "X-Api-Key:
{{g.user.wallets[0].adminkey }}"
</code> </code>
</q-card-section> </q-card-section>
</q-card> </q-card>
@ -83,8 +103,10 @@
<q-expansion-item group="api" dense expand-separator label="Delete jukebox"> <q-expansion-item group="api" dense expand-separator label="Delete jukebox">
<q-card> <q-card>
<q-card-section> <q-card-section>
<code><span class="text-red">DELETE</span> <code
/jukebox/api/v1/jukebox/&lt;juke_id&gt;</code> ><span class="text-red">DELETE</span>
/jukebox/api/v1/jukebox/&lt;juke_id&gt;</code
>
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5> <h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
<code>{"X-Api-Key": &lt;admin_key&gt;}</code><br /> <code>{"X-Api-Key": &lt;admin_key&gt;}</code><br />
<h5 class="text-caption q-mt-sm q-mb-none">Body (application/json)</h5> <h5 class="text-caption q-mt-sm q-mb-none">Body (application/json)</h5>
@ -93,9 +115,11 @@
</h5> </h5>
<code>&lt;jukebox_object&gt;</code> <code>&lt;jukebox_object&gt;</code>
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5> <h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
<code>curl -X DELETE {{ request.url_root }}api/v1/jukebox/&lt;juke_id&gt; -H "X-Api-Key: {{ <code
g.user.wallets[0].adminkey }}" >curl -X DELETE {{ request.url_root }}api/v1/jukebox/&lt;juke_id&gt;
-H "X-Api-Key: {{ g.user.wallets[0].adminkey }}"
</code> </code>
</q-card-section> </q-card-section>
</q-card> </q-card>
</q-expansion-item> </q-expansion-item></q-expansion-item
>

View file

@ -12,7 +12,9 @@
style="font-size: 20rem" style="font-size: 20rem"
></q-icon> ></q-icon>
<h5 class="q-my-none">Ask the host to turn on the device and launch spotify</h5> <h5 class="q-my-none">
Ask the host to turn on the device and launch spotify
</h5>
<br /> <br />
</center> </center>
</q-card-section> </q-card-section>

View file

@ -4,18 +4,36 @@
<div class="col-12 col-md-7 q-gutter-y-md"> <div class="col-12 col-md-7 q-gutter-y-md">
<q-card> <q-card>
<q-card-section> <q-card-section>
<q-btn unelevated color="green-7" class="q-ma-lg" @click="openNewDialog()">Add Spotify Jukebox</q-btn> <q-btn
unelevated
color="green-7"
class="q-ma-lg"
@click="openNewDialog()"
>Add Spotify Jukebox</q-btn
>
{% raw %} {% raw %}
<q-table flat dense :data="JukeboxLinks" row-key="id" :columns="JukeboxTable.columns" <q-table
:pagination.sync="JukeboxTable.pagination" :filter="filter"> flat
dense
:data="JukeboxLinks"
row-key="id"
:columns="JukeboxTable.columns"
:pagination.sync="JukeboxTable.pagination"
:filter="filter"
>
<template v-slot:header="props"> <template v-slot:header="props">
<q-tr :props="props"> <q-tr :props="props">
<q-th auto-width></q-th> <q-th auto-width></q-th>
<q-th auto-width></q-th> <q-th auto-width></q-th>
<q-th v-for="col in props.cols" :key="col.name" :props="props" auto-width> <q-th
v-for="col in props.cols"
:key="col.name"
:props="props"
auto-width
>
<div v-if="col.name == 'id'"></div> <div v-if="col.name == 'id'"></div>
<div v-else>{{ col.label }}</div> <div v-else>{{ col.label }}</div>
</q-th> </q-th>
@ -26,18 +44,43 @@
<template v-slot:body="props"> <template v-slot:body="props">
<q-tr :props="props"> <q-tr :props="props">
<q-td auto-width> <q-td auto-width>
<q-btn unelevated dense size="xs" icon="launch" :color="($q.dark.isActive) ? 'grey-7' : 'grey-5'" <q-btn
@click="openQrCodeDialog(props.row.sp_id)"> unelevated
dense
size="xs"
icon="launch"
:color="($q.dark.isActive) ? 'grey-7' : 'grey-5'"
@click="openQrCodeDialog(props.row.sp_id)"
>
<q-tooltip> Jukebox QR </q-tooltip> <q-tooltip> Jukebox QR </q-tooltip>
</q-btn> </q-btn>
</q-td> </q-td>
<q-td auto-width> <q-td auto-width>
<q-btn flat dense size="xs" @click="updateJukebox(props.row.id)" icon="edit" color="light-blue"></q-btn> <q-btn
<q-btn flat dense size="xs" @click="deleteJukebox(props.row.id)" icon="cancel" color="pink"> flat
dense
size="xs"
@click="updateJukebox(props.row.id)"
icon="edit"
color="light-blue"
></q-btn>
<q-btn
flat
dense
size="xs"
@click="deleteJukebox(props.row.id)"
icon="cancel"
color="pink"
>
<q-tooltip> Delete Jukebox </q-tooltip> <q-tooltip> Delete Jukebox </q-tooltip>
</q-btn> </q-btn>
</q-td> </q-td>
<q-td v-for="col in props.cols" :key="col.name" :props="props" auto-width> <q-td
v-for="col in props.cols"
:key="col.name"
:props="props"
auto-width
>
<div v-if="col.name == 'id'"></div> <div v-if="col.name == 'id'"></div>
<div v-else>{{ col.value }}</div> <div v-else>{{ col.value }}</div>
</q-td> </q-td>
@ -63,23 +106,62 @@
<q-dialog v-model="jukeboxDialog.show" position="top" @hide="closeFormDialog"> <q-dialog v-model="jukeboxDialog.show" position="top" @hide="closeFormDialog">
<q-card class="q-pa-md q-pt-lg q-mt-md" style="width: 100%"> <q-card class="q-pa-md q-pt-lg q-mt-md" style="width: 100%">
<q-stepper v-model="step" active-color="green-7" inactive-color="green-10" vertical animated> <q-stepper
<q-step :name="1" title="Pick wallet, price" icon="account_balance_wallet" :done="step > 1"> v-model="step"
<q-input filled class="q-pt-md" dense v-model.trim="jukeboxDialog.data.title" label="Jukebox name"></q-input> active-color="green-7"
<q-select class="q-pb-md q-pt-md" filled dense emit-value v-model="jukeboxDialog.data.wallet" inactive-color="green-10"
:options="g.user.walletOptions" label="Wallet to use"></q-select> vertical
<q-input filled dense v-model.trim="jukeboxDialog.data.price" type="number" max="1440" label="Price per track" animated
class="q-pb-lg"> >
<q-step
:name="1"
title="Pick wallet, price"
icon="account_balance_wallet"
:done="step > 1"
>
<q-input
filled
class="q-pt-md"
dense
v-model.trim="jukeboxDialog.data.title"
label="Jukebox name"
></q-input>
<q-select
class="q-pb-md q-pt-md"
filled
dense
emit-value
v-model="jukeboxDialog.data.wallet"
:options="g.user.walletOptions"
label="Wallet to use"
></q-select>
<q-input
filled
dense
v-model.trim="jukeboxDialog.data.price"
type="number"
max="1440"
label="Price per track"
class="q-pb-lg"
>
</q-input> </q-input>
<div class="row"> <div class="row">
<div class="col-4"> <div class="col-4">
<q-btn <q-btn
v-if="jukeboxDialog.data.title != null && jukeboxDialog.data.price != null && jukeboxDialog.data.wallet != null" v-if="jukeboxDialog.data.title != null && jukeboxDialog.data.price != null && jukeboxDialog.data.wallet != null"
color="green-7" @click="step = 2">Continue</q-btn> color="green-7"
@click="step = 2"
>Continue</q-btn
>
<q-btn v-else color="green-7" disable>Continue</q-btn> <q-btn v-else color="green-7" disable>Continue</q-btn>
</div> </div>
<div class="col-8"> <div class="col-8">
<q-btn color="green-7" class="float-right" @click="closeFormDialog">Cancel</q-btn> <q-btn
color="green-7"
class="float-right"
@click="closeFormDialog"
>Cancel</q-btn
>
</div> </div>
</div> </div>
@ -90,26 +172,57 @@
<img src="/jukebox/static/spotapi.gif" /> <img src="/jukebox/static/spotapi.gif" />
To use this extension you need a Spotify client ID and client secret. To use this extension you need a Spotify client ID and client secret.
You get these by creating an app in the Spotify developers dashboard You get these by creating an app in the Spotify developers dashboard
<a target="_blank" style="color:#43a047" href="https://developer.spotify.com/dashboard/applications">here</a>. <a
<q-input filled class="q-pb-md q-pt-md" dense v-model.trim="jukeboxDialog.data.sp_user" label="Client ID"> target="_blank"
style="color: #43a047"
href="https://developer.spotify.com/dashboard/applications"
>here</a
>.
<q-input
filled
class="q-pb-md q-pt-md"
dense
v-model.trim="jukeboxDialog.data.sp_user"
label="Client ID"
>
</q-input> </q-input>
<q-input dense v-model="jukeboxDialog.data.sp_secret" filled :type="isPwd ? 'password' : 'text'" <q-input
label="Client secret"> dense
v-model="jukeboxDialog.data.sp_secret"
filled
:type="isPwd ? 'password' : 'text'"
label="Client secret"
>
<template #append> <template #append>
<q-icon :name="isPwd ? 'visibility_off' : 'visibility'" class="cursor-pointer" @click="isPwd = !isPwd"> <q-icon
:name="isPwd ? 'visibility_off' : 'visibility'"
class="cursor-pointer"
@click="isPwd = !isPwd"
>
</q-icon> </q-icon>
</template> </template>
</q-input> </q-input>
<div class="row q-mt-md"> <div class="row q-mt-md">
<div class="col-4"> <div class="col-4">
<q-btn v-if="jukeboxDialog.data.sp_secret != null && jukeboxDialog.data.sp_user != null && tokenFetched" <q-btn
color="green-7" @click="submitSpotifyKeys">Submit keys</q-btn> v-if="jukeboxDialog.data.sp_secret != null && jukeboxDialog.data.sp_user != null && tokenFetched"
<q-btn v-else color="green-7" disable color="green-7">Submit keys</q-btn> color="green-7"
@click="submitSpotifyKeys"
>Submit keys</q-btn
>
<q-btn v-else color="green-7" disable color="green-7"
>Submit keys</q-btn
>
</div> </div>
<div class="col-8"> <div class="col-8">
<q-btn color="green-7" class="float-right" @click="closeFormDialog">Cancel</q-btn> <q-btn
color="green-7"
class="float-right"
@click="closeFormDialog"
>Cancel</q-btn
>
</div> </div>
</div> </div>
@ -120,42 +233,93 @@
<img src="/jukebox/static/spotapi1.gif" /> <img src="/jukebox/static/spotapi1.gif" />
In the app go to edit-settings, set the redirect URI to this link In the app go to edit-settings, set the redirect URI to this link
<br /> <br />
<q-btn dense outline unelevated color="green-7" size="xs" <q-btn
@click="copyText(locationcb + jukeboxDialog.data.sp_id, 'Link copied to clipboard!')">{% raw %}{{ locationcb dense
}}{{ jukeboxDialog.data.sp_id }}{% endraw outline
unelevated
color="green-7"
size="xs"
@click="copyText(locationcb + jukeboxDialog.data.sp_id, 'Link copied to clipboard!')"
>{% raw %}{{ locationcb }}{{ jukeboxDialog.data.sp_id }}{% endraw
%}<q-tooltip> Click to copy URL </q-tooltip> %}<q-tooltip> Click to copy URL </q-tooltip>
</q-btn> </q-btn>
<br /> <br />
Settings can be found Settings can be found
<a target="_blank" style="color:#43a047" href="https://developer.spotify.com/dashboard/applications">here</a>. <a
target="_blank"
style="color: #43a047"
href="https://developer.spotify.com/dashboard/applications"
>here</a
>.
<div class="row q-mt-md"> <div class="row q-mt-md">
<div class="col-4"> <div class="col-4">
<q-btn v-if="jukeboxDialog.data.sp_secret != null && jukeboxDialog.data.sp_user != null && tokenFetched" <q-btn
color="green-7" @click="authAccess">Authorise access</q-btn> v-if="jukeboxDialog.data.sp_secret != null && jukeboxDialog.data.sp_user != null && tokenFetched"
<q-btn v-else color="green-7" disable color="green-7">Authorise access</q-btn> color="green-7"
@click="authAccess"
>Authorise access</q-btn
>
<q-btn v-else color="green-7" disable color="green-7"
>Authorise access</q-btn
>
</div> </div>
<div class="col-8"> <div class="col-8">
<q-btn color="green-7" class="float-right" @click="closeFormDialog">Cancel</q-btn> <q-btn
color="green-7"
class="float-right"
@click="closeFormDialog"
>Cancel</q-btn
>
</div> </div>
</div> </div>
<br /> <br />
</q-step> </q-step>
<q-step :name="4" title="Select playlists" icon="queue_music" active-color="green-8" :done="step > 4"> <q-step
<q-select class="q-pb-md q-pt-md" filled dense emit-value v-model="jukeboxDialog.data.sp_device" :name="4"
:options="devices" label="Device jukebox will play to"></q-select> title="Select playlists"
<q-select class="q-pb-md" filled dense multiple emit-value v-model="jukeboxDialog.data.sp_playlists" icon="queue_music"
:options="playlists" label="Playlists available to the jukebox"></q-select> active-color="green-8"
:done="step > 4"
>
<q-select
class="q-pb-md q-pt-md"
filled
dense
emit-value
v-model="jukeboxDialog.data.sp_device"
:options="devices"
label="Device jukebox will play to"
></q-select>
<q-select
class="q-pb-md"
filled
dense
multiple
emit-value
v-model="jukeboxDialog.data.sp_playlists"
:options="playlists"
label="Playlists available to the jukebox"
></q-select>
<div class="row q-mt-md"> <div class="row q-mt-md">
<div class="col-5"> <div class="col-5">
<q-btn v-if="jukeboxDialog.data.sp_device != null && jukeboxDialog.data.sp_playlists != null" <q-btn
color="green-7" @click="createJukebox">Create Jukebox</q-btn> v-if="jukeboxDialog.data.sp_device != null && jukeboxDialog.data.sp_playlists != null"
color="green-7"
@click="createJukebox"
>Create Jukebox</q-btn
>
<q-btn v-else color="green-7" disable>Create Jukebox</q-btn> <q-btn v-else color="green-7" disable>Create Jukebox</q-btn>
</div> </div>
<div class="col-7"> <div class="col-7">
<q-btn color="green-7" class="float-right" @click="closeFormDialog">Cancel</q-btn> <q-btn
color="green-7"
class="float-right"
@click="closeFormDialog"
>Cancel</q-btn
>
</div> </div>
</div> </div>
</q-step> </q-step>
@ -169,15 +333,28 @@
<h5 class="q-my-none">Shareable Jukebox QR</h5> <h5 class="q-my-none">Shareable Jukebox QR</h5>
</center> </center>
<q-responsive :ratio="1" class="q-mx-xl q-mb-md"> <q-responsive :ratio="1" class="q-mx-xl q-mb-md">
<qrcode :value="qrCodeDialog.data.url + '/jukebox/' + qrCodeDialog.data.id" :options="{width: 800}" <qrcode
class="rounded-borders"></qrcode> :value="qrCodeDialog.data.url + '/jukebox/' + qrCodeDialog.data.id"
:options="{width: 800}"
class="rounded-borders"
></qrcode>
</q-responsive> </q-responsive>
<div class="row q-mt-lg q-gutter-sm"> <div class="row q-mt-lg q-gutter-sm">
<q-btn outline color="grey" <q-btn
@click="copyText(qrCodeDialog.data.url + '/jukebox/' + qrCodeDialog.data.id, 'Link copied to clipboard!')"> outline
Copy jukebox link</q-btn> color="grey"
<q-btn outline color="grey" type="a" :href="qrCodeDialog.data.url + '/jukebox/' + qrCodeDialog.data.id" @click="copyText(qrCodeDialog.data.url + '/jukebox/' + qrCodeDialog.data.id, 'Link copied to clipboard!')"
target="_blank">Open jukebox</q-btn> >
Copy jukebox link</q-btn
>
<q-btn
outline
color="grey"
type="a"
:href="qrCodeDialog.data.url + '/jukebox/' + qrCodeDialog.data.id"
target="_blank"
>Open jukebox</q-btn
>
<q-btn v-close-popup flat color="grey" class="q-ml-auto">Close</q-btn> <q-btn v-close-popup flat color="grey" class="q-ml-auto">Close</q-btn>
</div> </div>
</q-card> </q-card>

View file

@ -9,7 +9,8 @@
<img style="width: 100px" :src="currentPlay.image" /> <img style="width: 100px" :src="currentPlay.image" />
</div> </div>
<div class="col-8"> <div class="col-8">
<strong style="font-size: 20px">{{ currentPlay.name }}</strong><br /> <strong style="font-size: 20px">{{ currentPlay.name }}</strong
><br />
<strong style="font-size: 15px">{{ currentPlay.artist }}</strong> <strong style="font-size: 15px">{{ currentPlay.artist }}</strong>
</div> </div>
</div> </div>
@ -19,15 +20,30 @@
<q-card class="q-mt-lg"> <q-card class="q-mt-lg">
<q-card-section> <q-card-section>
<p style="font-size: 22px">Pick a song</p> <p style="font-size: 22px">Pick a song</p>
<q-select outlined v-model="playlist" :options="playlists" label="playlists" @input="selectPlaylist()"> <q-select
outlined
v-model="playlist"
:options="playlists"
label="playlists"
@input="selectPlaylist()"
>
</q-select> </q-select>
</q-card-section> </q-card-section>
<q-card-section class="q-pa-none"> <q-card-section class="q-pa-none">
<q-separator></q-separator> <q-separator></q-separator>
<q-virtual-scroll style="max-height: 300px" :items="currentPlaylist" separator> <q-virtual-scroll
style="max-height: 300px"
:items="currentPlaylist"
separator
>
<template v-slot="{ item, index }"> <template v-slot="{ item, index }">
<q-item :key="index" dense clickable v-ripple <q-item
@click="payForSong(item.id, item.name, item.artist, item.image)"> :key="index"
dense
clickable
v-ripple
@click="payForSong(item.id, item.name, item.artist, item.image)"
>
<q-item-section> <q-item-section>
<q-item-label> <q-item-label>
{{ item.name }} - ({{ item.artist }}) {{ item.name }} - ({{ item.artist }})
@ -55,7 +71,8 @@
</q-card-section> </q-card-section>
<br /> <br />
<div class="row q-mt-lg q-gutter-sm"> <div class="row q-mt-lg q-gutter-sm">
<q-btn outline color="grey" @click="getInvoice(receive.id)">Play for {% endraw %}{{ price }}{% raw %} sats <q-btn outline color="grey" @click="getInvoice(receive.id)"
>Play for {% endraw %}{{ price }}{% raw %} sats
</q-btn> </q-btn>
</div> </div>
</q-card> </q-card>
@ -63,10 +80,16 @@
<q-dialog v-model="receive.dialogues.second" position="top"> <q-dialog v-model="receive.dialogues.second" position="top">
<q-card class="q-pa-lg lnbits__dialog-card"> <q-card class="q-pa-lg lnbits__dialog-card">
<q-responsive :ratio="1" class="q-mx-xl q-mb-md"> <q-responsive :ratio="1" class="q-mx-xl q-mb-md">
<qrcode :value="'lightning:' + receive.paymentReq" :options="{width: 800}" class="rounded-borders"></qrcode> <qrcode
:value="'lightning:' + receive.paymentReq"
:options="{width: 800}"
class="rounded-borders"
></qrcode>
</q-responsive> </q-responsive>
<div class="row q-mt-lg q-gutter-sm"> <div class="row q-mt-lg q-gutter-sm">
<q-btn outline color="grey" @click="copyText(receive.paymentReq)">Copy invoice</q-btn> <q-btn outline color="grey" @click="copyText(receive.paymentReq)"
>Copy invoice</q-btn
>
</div> </div>
</q-card> </q-card>
</q-dialog> </q-dialog>
@ -84,7 +107,7 @@
return { return {
currentPlaylist: [], currentPlaylist: [],
currentlyPlaying: {}, currentlyPlaying: {},
cancelListener: () => { }, cancelListener: () => {},
playlists: {}, playlists: {},
playlist: '', playlist: '',
heavyList: [], heavyList: [],
@ -118,7 +141,7 @@
this.paymentDialog.dismissMsg() this.paymentDialog.dismissMsg()
} }
}, },
closeReceiveDialog() { }, closeReceiveDialog() {},
payForSong(song_id, name, artist, image) { payForSong(song_id, name, artist, image) {
self = this self = this
self.receive.name = name self.receive.name = name
@ -138,7 +161,6 @@
song_id song_id
) )
.then(function (response) { .then(function (response) {
self.receive.paymentReq = response.data[0][1] self.receive.paymentReq = response.data[0][1]
self.receive.paymentHash = response.data[0][0] self.receive.paymentHash = response.data[0][0]
self.receive.dialogues.second = true self.receive.dialogues.second = true
@ -153,21 +175,27 @@
self.receive.dialogues.first = false self.receive.dialogues.first = false
self.receive.dialogues.second = false self.receive.dialogues.second = false
self.$q.notify({ self.$q.notify({
message: message: 'Processing'
'Processing',
}) })
LNbits.api LNbits.api
.request( .request(
'GET', 'GET',
'/jukebox/api/v1/jukebox/jb/invoicep/' + song_id + '/{{ juke_id }}/' + self.receive.paymentHash) '/jukebox/api/v1/jukebox/jb/invoicep/' +
song_id +
'/{{ juke_id }}/' +
self.receive.paymentHash
)
.then(function (response1) { .then(function (response1) {
if (response1.data[2] == song_id) { if (response1.data[2] == song_id) {
setTimeout(function () { self.getCurrent() }, 500) setTimeout(function () {
self.getCurrent()
}, 500)
self.$q.notify({ self.$q.notify({
color: 'green', color: 'green',
message: message:
'Success! "' + self.receive.name + '" will be played soon', 'Success! "' +
self.receive.name +
'" will be played soon',
timeout: 3000 timeout: 3000
}) })
@ -176,17 +204,14 @@
} }
}) })
.catch(err => { .catch(err => {
LNbits.utils.notifyApiError(err) LNbits.utils.notifyApiError(err)
self.paid = false self.paid = false
response1 = [] response1 = []
}) })
} }
}, 3000) }, 3000)
}) })
.catch(err => { .catch(err => {
self.$q.notify({ self.$q.notify({
color: 'warning', color: 'warning',
html: true, html: true,
@ -197,16 +222,17 @@
}) })
}, },
checkInvoice(juke_id, paymentHash) { checkInvoice(juke_id, paymentHash) {
var self = this var self = this
LNbits.api LNbits.api
.request( .request(
'GET', 'GET',
'/jukebox/api/v1/jukebox/jb/checkinvoice/' + juke_id + '/' + paymentHash, '/jukebox/api/v1/jukebox/jb/checkinvoice/' +
juke_id +
'/' +
paymentHash,
'filla' 'filla'
) )
.then(function (response) { .then(function (response) {
self.paid = response.data.paid self.paid = response.data.paid
}) })
.catch(function (error) { .catch(function (error) {
@ -214,21 +240,16 @@
}) })
}, },
getCurrent() { getCurrent() {
LNbits.api LNbits.api
.request( .request('GET', '/jukebox/api/v1/jukebox/jb/currently/{{juke_id}}')
'GET',
'/jukebox/api/v1/jukebox/jb/currently/{{juke_id}}')
.then(function (res) { .then(function (res) {
if (res.data.id) { if (res.data.id) {
self.currentlyPlaying = res.data self.currentlyPlaying = res.data
} }
}) })
.catch(function (error) { .catch(function (error) {
LNbits.utils.notifyApiError(error) LNbits.utils.notifyApiError(error)
}) })
}, },
selectPlaylist() { selectPlaylist() {
self = this self = this
@ -247,7 +268,7 @@
LNbits.utils.notifyApiError(err) LNbits.utils.notifyApiError(err)
}) })
}, },
currentSong() { } currentSong() {}
}, },
created() { created() {
this.getCurrent() this.getCurrent()

View file

@ -214,7 +214,7 @@
</div> </div>
{% endblock %} {% block scripts %} {{ window_vars(user) }} {% endblock %} {% block scripts %} {{ window_vars(user) }}
<script> <script>
var mapUserManager = function(obj) { var mapUserManager = function (obj) {
obj.date = Quasar.utils.date.formatDate( obj.date = Quasar.utils.date.formatDate(
new Date(obj.time * 1000), new Date(obj.time * 1000),
'YYYY-MM-DD HH:mm' 'YYYY-MM-DD HH:mm'
@ -228,7 +228,7 @@
new Vue({ new Vue({
el: '#vue', el: '#vue',
mixins: [windowMixin], mixins: [windowMixin],
data: function() { data: function () {
return { return {
wallets: [], wallets: [],
users: [], users: [],
@ -277,8 +277,8 @@
} }
}, },
computed: { computed: {
userOptions: function() { userOptions: function () {
return this.users.map(function(obj) { return this.users.map(function (obj) {
console.log(obj.id) console.log(obj.id)
return { return {
value: String(obj.id), value: String(obj.id),
@ -290,7 +290,7 @@
methods: { methods: {
///////////////Users//////////////////////////// ///////////////Users////////////////////////////
getUsers: function() { getUsers: function () {
var self = this var self = this
LNbits.api LNbits.api
@ -299,20 +299,20 @@
'/usermanager/api/v1/users', '/usermanager/api/v1/users',
this.g.user.wallets[0].inkey this.g.user.wallets[0].inkey
) )
.then(function(response) { .then(function (response) {
self.users = response.data.map(function(obj) { self.users = response.data.map(function (obj) {
return mapUserManager(obj) return mapUserManager(obj)
}) })
}) })
}, },
openUserUpdateDialog: function(linkId) { openUserUpdateDialog: function (linkId) {
var link = _.findWhere(this.users, {id: linkId}) var link = _.findWhere(this.users, {id: linkId})
this.userDialog.data = _.clone(link._data) this.userDialog.data = _.clone(link._data)
this.userDialog.show = true this.userDialog.show = true
}, },
sendUserFormData: function() { sendUserFormData: function () {
if (this.userDialog.data.id) { if (this.userDialog.data.id) {
} else { } else {
var data = { var data = {
@ -329,7 +329,7 @@
} }
}, },
createUser: function(data) { createUser: function (data) {
var self = this var self = this
LNbits.api LNbits.api
.request( .request(
@ -338,48 +338,48 @@
this.g.user.wallets[0].inkey, this.g.user.wallets[0].inkey,
data data
) )
.then(function(response) { .then(function (response) {
self.users.push(mapUserManager(response.data)) self.users.push(mapUserManager(response.data))
self.userDialog.show = false self.userDialog.show = false
self.userDialog.data = {} self.userDialog.data = {}
data = {} data = {}
self.getWallets() self.getWallets()
}) })
.catch(function(error) { .catch(function (error) {
LNbits.utils.notifyApiError(error) LNbits.utils.notifyApiError(error)
}) })
}, },
deleteUser: function(userId) { deleteUser: function (userId) {
var self = this var self = this
console.log(userId) console.log(userId)
LNbits.utils LNbits.utils
.confirmDialog('Are you sure you want to delete this User link?') .confirmDialog('Are you sure you want to delete this User link?')
.onOk(function() { .onOk(function () {
LNbits.api LNbits.api
.request( .request(
'DELETE', 'DELETE',
'/usermanager/api/v1/users/' + userId, '/usermanager/api/v1/users/' + userId,
self.g.user.wallets[0].inkey self.g.user.wallets[0].inkey
) )
.then(function(response) { .then(function (response) {
self.users = _.reject(self.users, function(obj) { self.users = _.reject(self.users, function (obj) {
return obj.id == userId return obj.id == userId
}) })
}) })
.catch(function(error) { .catch(function (error) {
LNbits.utils.notifyApiError(error) LNbits.utils.notifyApiError(error)
}) })
}) })
}, },
exportUsersCSV: function() { exportUsersCSV: function () {
LNbits.utils.exportCSV(this.usersTable.columns, this.users) LNbits.utils.exportCSV(this.usersTable.columns, this.users)
}, },
///////////////Wallets//////////////////////////// ///////////////Wallets////////////////////////////
getWallets: function() { getWallets: function () {
var self = this var self = this
LNbits.api LNbits.api
@ -388,19 +388,19 @@
'/usermanager/api/v1/wallets', '/usermanager/api/v1/wallets',
this.g.user.wallets[0].inkey this.g.user.wallets[0].inkey
) )
.then(function(response) { .then(function (response) {
self.wallets = response.data.map(function(obj) { self.wallets = response.data.map(function (obj) {
return mapUserManager(obj) return mapUserManager(obj)
}) })
}) })
}, },
openWalletUpdateDialog: function(linkId) { openWalletUpdateDialog: function (linkId) {
var link = _.findWhere(this.users, {id: linkId}) var link = _.findWhere(this.users, {id: linkId})
this.walletDialog.data = _.clone(link._data) this.walletDialog.data = _.clone(link._data)
this.walletDialog.show = true this.walletDialog.show = true
}, },
sendWalletFormData: function() { sendWalletFormData: function () {
if (this.walletDialog.data.id) { if (this.walletDialog.data.id) {
} else { } else {
var data = { var data = {
@ -415,7 +415,7 @@
} }
}, },
createWallet: function(data) { createWallet: function (data) {
var self = this var self = this
LNbits.api LNbits.api
.request( .request(
@ -424,43 +424,43 @@
this.g.user.wallets[0].inkey, this.g.user.wallets[0].inkey,
data data
) )
.then(function(response) { .then(function (response) {
self.wallets.push(mapUserManager(response.data)) self.wallets.push(mapUserManager(response.data))
self.walletDialog.show = false self.walletDialog.show = false
self.walletDialog.data = {} self.walletDialog.data = {}
data = {} data = {}
}) })
.catch(function(error) { .catch(function (error) {
LNbits.utils.notifyApiError(error) LNbits.utils.notifyApiError(error)
}) })
}, },
deleteWallet: function(userId) { deleteWallet: function (userId) {
var self = this var self = this
LNbits.utils LNbits.utils
.confirmDialog('Are you sure you want to delete this wallet link?') .confirmDialog('Are you sure you want to delete this wallet link?')
.onOk(function() { .onOk(function () {
LNbits.api LNbits.api
.request( .request(
'DELETE', 'DELETE',
'/usermanager/api/v1/wallets/' + userId, '/usermanager/api/v1/wallets/' + userId,
self.g.user.wallets[0].inkey self.g.user.wallets[0].inkey
) )
.then(function(response) { .then(function (response) {
self.wallets = _.reject(self.wallets, function(obj) { self.wallets = _.reject(self.wallets, function (obj) {
return obj.id == userId return obj.id == userId
}) })
}) })
.catch(function(error) { .catch(function (error) {
LNbits.utils.notifyApiError(error) LNbits.utils.notifyApiError(error)
}) })
}) })
}, },
exportWalletsCSV: function() { exportWalletsCSV: function () {
LNbits.utils.exportCSV(this.walletsTable.columns, this.wallets) LNbits.utils.exportCSV(this.walletsTable.columns, this.wallets)
} }
}, },
created: function() { created: function () {
if (this.g.user.wallets.length) { if (this.g.user.wallets.length) {
this.getUsers() this.getUsers()
this.getWallets() this.getWallets()