mirror of
https://github.com/lnbits/lnbits.git
synced 2025-06-23 15:22:13 +02:00
Creates invoice
This commit is contained in:
parent
e726d752d8
commit
f43c227b95
@ -177,8 +177,9 @@ new Vue({
|
|||||||
},
|
},
|
||||||
getSpotifyTokens() {
|
getSpotifyTokens() {
|
||||||
self = this
|
self = this
|
||||||
|
var counter = 0
|
||||||
var timerId = setInterval(function () {
|
var timerId = setInterval(function () {
|
||||||
|
counter++
|
||||||
if (!self.jukeboxDialog.data.sp_user) {
|
if (!self.jukeboxDialog.data.sp_user) {
|
||||||
clearInterval(timerId)
|
clearInterval(timerId)
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
v-model="playlist"
|
v-model="playlist"
|
||||||
:options="playlists"
|
:options="playlists"
|
||||||
label="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">
|
||||||
@ -38,7 +39,13 @@
|
|||||||
separator
|
separator
|
||||||
>
|
>
|
||||||
<template v-slot="{ item, index }">
|
<template v-slot="{ item, index }">
|
||||||
<q-item :key="index" dense clickable v-ripple>
|
<q-item
|
||||||
|
: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 }})
|
||||||
@ -62,6 +69,7 @@
|
|||||||
:key="song.id"
|
:key="song.id"
|
||||||
clickable
|
clickable
|
||||||
v-ripple
|
v-ripple
|
||||||
|
@click="payForSong(song.id, song.name, song.artist, song.image)"
|
||||||
>
|
>
|
||||||
<q-item-section prepend>
|
<q-item-section prepend>
|
||||||
<img style="width: 50px" :src="song.image" />
|
<img style="width: 50px" :src="song.image" />
|
||||||
@ -73,6 +81,43 @@
|
|||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-card>
|
</q-card>
|
||||||
</div>
|
</div>
|
||||||
|
<q-dialog v-model="receive.dialogues.first" position="top">
|
||||||
|
<q-card class="q-pa-lg lnbits__dialog-card">
|
||||||
|
<q-card-section class="q-pa-none">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-4">
|
||||||
|
<img style="width: 100px" :src="receive.image" />
|
||||||
|
</div>
|
||||||
|
<div class="col-8">
|
||||||
|
<strong style="font-size: 20px">{{ receive.name }}</strong><br />
|
||||||
|
<strong style="font-size: 15px">{{ receive.artist }}</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</q-card-section>
|
||||||
|
<br />
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
</q-card>
|
||||||
|
</q-dialog>
|
||||||
|
<q-dialog v-model="receive.dialogues.second" position="top">
|
||||||
|
<q-card class="q-pa-lg lnbits__dialog-card">
|
||||||
|
<q-responsive :ratio="1" class="q-mx-xl q-mb-md">
|
||||||
|
<qrcode
|
||||||
|
:value="'lightning:' + receive.paymentReq"
|
||||||
|
:options="{width: 800}"
|
||||||
|
class="rounded-borders"
|
||||||
|
></qrcode>
|
||||||
|
</q-responsive>
|
||||||
|
<div class="row q-mt-lg q-gutter-sm">
|
||||||
|
<q-btn outline color="grey" @click="copyText(receive.paymentReq)"
|
||||||
|
>Copy invoice</q-btn
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</q-card>
|
||||||
|
</q-dialog>
|
||||||
</div>
|
</div>
|
||||||
{% endraw %} {% endblock %} {% block scripts %}
|
{% endraw %} {% endblock %} {% block scripts %}
|
||||||
<script src="{{ url_for('static', filename='vendor/vue-qrcode@1.0.2/vue-qrcode.min.js') }}"></script>
|
<script src="{{ url_for('static', filename='vendor/vue-qrcode@1.0.2/vue-qrcode.min.js') }}"></script>
|
||||||
@ -85,20 +130,101 @@
|
|||||||
mixins: [windowMixin],
|
mixins: [windowMixin],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
currentPlaylist: JSON.parse('{{ firstPlaylist | tojson }}'),
|
currentPlaylist: {},
|
||||||
playlists: JSON.parse('{{ playlists | tojson }}'),
|
playlists: {},
|
||||||
playlist: '',
|
playlist: '',
|
||||||
heavyList: [],
|
heavyList: [],
|
||||||
queued: []
|
queued: [],
|
||||||
|
receive: {
|
||||||
|
dialogues: {
|
||||||
|
first: false,
|
||||||
|
second: false
|
||||||
|
},
|
||||||
|
paymentReq: '',
|
||||||
|
name: '',
|
||||||
|
artist: '',
|
||||||
|
image: '',
|
||||||
|
id: '',
|
||||||
|
showQR: false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {},
|
computed: {},
|
||||||
methods: {},
|
methods: {
|
||||||
|
closeReceiveDialog() {},
|
||||||
|
payForSong(song_id, name, artist, image) {
|
||||||
|
self = this
|
||||||
|
self.receive.name = name
|
||||||
|
self.receive.artist = artist
|
||||||
|
self.receive.image = image
|
||||||
|
self.receive.id = song_id
|
||||||
|
self.receive.dialogues.first = true
|
||||||
|
},
|
||||||
|
getInvoice(song_id) {
|
||||||
|
LNbits.api
|
||||||
|
.request(
|
||||||
|
'GET',
|
||||||
|
'/jukebox/api/v1/jukebox/jb/invoice/' +
|
||||||
|
'{{ juke_id }}' +
|
||||||
|
'/' +
|
||||||
|
song_id
|
||||||
|
)
|
||||||
|
.then(function (response) {
|
||||||
|
console.log(response.data)
|
||||||
|
self.receive.paymentReq = response.data[1]
|
||||||
|
self.receive.dialogues.second = true
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
LNbits.utils.notifyApiError(err)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
selectPlaylist() {
|
||||||
|
self = this
|
||||||
|
LNbits.api
|
||||||
|
.request(
|
||||||
|
'GET',
|
||||||
|
'/jukebox/api/v1/jukebox/jb/playlist/' +
|
||||||
|
'{{ juke_id }}' +
|
||||||
|
'/' +
|
||||||
|
self.playlist.split(',')[0].split('-')[1]
|
||||||
|
)
|
||||||
|
.then(function (response) {
|
||||||
|
console.log(response.data)
|
||||||
|
self.currentPlaylist = response.data
|
||||||
|
console.log(self.currentPlaylist[2].id)
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
LNbits.utils.notifyApiError(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
created() {
|
created() {
|
||||||
this.queued[0] = this.currentPlaylist[2]
|
this.playlists = JSON.parse('{{ playlists | tojson }}')
|
||||||
this.queued[1] = this.currentPlaylist[5]
|
|
||||||
this.queued[2] = this.currentPlaylist[6]
|
self = this
|
||||||
this.queued[3] = this.currentPlaylist[7]
|
console.log(
|
||||||
|
'/jukebox/api/v1/jukebox/jb/' +
|
||||||
|
'{{ juke_id }}' +
|
||||||
|
'/' +
|
||||||
|
self.playlists[0].split(',')[0].split('-')[1] +
|
||||||
|
'/'
|
||||||
|
)
|
||||||
|
LNbits.api
|
||||||
|
.request(
|
||||||
|
'GET',
|
||||||
|
'/jukebox/api/v1/jukebox/jb/playlist/' +
|
||||||
|
'{{ juke_id }}' +
|
||||||
|
'/' +
|
||||||
|
self.playlists[0].split(',')[0].split('-')[1]
|
||||||
|
)
|
||||||
|
.then(function (response) {
|
||||||
|
console.log(response.data)
|
||||||
|
self.currentPlaylist = response.data
|
||||||
|
console.log(self.currentPlaylist[2].id)
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
LNbits.utils.notifyApiError(err)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,18 +1,15 @@
|
|||||||
import time
|
import time
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from quart import g, render_template, request
|
from quart import g, render_template, request, jsonify
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
|
|
||||||
from lnbits.decorators import check_user_exists, validate_uuids
|
from lnbits.decorators import check_user_exists, validate_uuids
|
||||||
from lnbits.core.models import Payment
|
from lnbits.core.models import Payment
|
||||||
from lnbits.core.crud import get_standalone_payment
|
|
||||||
|
|
||||||
|
import json
|
||||||
from . import jukebox_ext
|
from . import jukebox_ext
|
||||||
from .crud import get_jukebox
|
from .crud import get_jukebox
|
||||||
from urllib.parse import unquote
|
from urllib.parse import unquote
|
||||||
from .views_api import (
|
|
||||||
api_get_jukebox_songs,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@jukebox_ext.route("/")
|
@jukebox_ext.route("/")
|
||||||
@ -27,13 +24,13 @@ async def print_qr_codes(juke_id):
|
|||||||
jukebox = await get_jukebox(juke_id)
|
jukebox = await get_jukebox(juke_id)
|
||||||
if not jukebox:
|
if not jukebox:
|
||||||
return "error"
|
return "error"
|
||||||
firstPlaylist = await api_get_jukebox_songs(
|
|
||||||
juke_id, jukebox.sp_playlists.split(",")[0].split("-")[1]
|
|
||||||
)
|
|
||||||
print(firstPlaylist)
|
|
||||||
|
|
||||||
return await render_template(
|
return await render_template(
|
||||||
"jukebox/jukebox.html",
|
"jukebox/jukebox.html",
|
||||||
playlists=jukebox.sp_playlists.split(","),
|
playlists=jukebox.sp_playlists.split(","),
|
||||||
firstPlaylist=firstPlaylist,
|
juke_id=juke_id,
|
||||||
|
price=jukebox.price
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ from http import HTTPStatus
|
|||||||
from lnurl.exceptions import InvalidUrl as LnurlInvalidUrl # type: ignore
|
from lnurl.exceptions import InvalidUrl as LnurlInvalidUrl # type: ignore
|
||||||
from base64 import urlsafe_b64encode
|
from base64 import urlsafe_b64encode
|
||||||
import base64
|
import base64
|
||||||
|
import json
|
||||||
|
|
||||||
from lnbits.decorators import api_check_wallet_key, api_validate_post_request
|
from lnbits.decorators import api_check_wallet_key, api_validate_post_request
|
||||||
import httpx
|
import httpx
|
||||||
@ -110,8 +111,9 @@ async def api_delete_item(juke_id):
|
|||||||
|
|
||||||
######GET ACCESS TOKEN######
|
######GET ACCESS TOKEN######
|
||||||
|
|
||||||
@jukebox_ext.route("/api/v1/jukebox/jb/<sp_id>/<sp_playlist>", methods=["GET"])
|
|
||||||
async def api_get_jukebox_songs(sp_id, sp_playlist):
|
@jukebox_ext.route("/api/v1/jukebox/jb/playlist/<sp_id>/<sp_playlist>", methods=["GET"])
|
||||||
|
async def api_get_jukebox_son(sp_id, sp_playlist):
|
||||||
jukebox = await get_jukebox(sp_id)
|
jukebox = await get_jukebox(sp_id)
|
||||||
tracks = []
|
tracks = []
|
||||||
async with httpx.AsyncClient() as client:
|
async with httpx.AsyncClient() as client:
|
||||||
@ -128,21 +130,23 @@ async def api_get_jukebox_songs(sp_id, sp_playlist):
|
|||||||
print("invalid")
|
print("invalid")
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
return await api_get_jukebox_songs(sp_id, sp_playlist)
|
return await api_get_jukebox_son(sp_id, sp_playlist)
|
||||||
return r, HTTPStatus.OK
|
return r, HTTPStatus.OK
|
||||||
for item in r.json()["items"]:
|
for item in r.json()["items"]:
|
||||||
tracks.append(
|
tracks.append(
|
||||||
{
|
{
|
||||||
"id": str(item["track"]["id"]),
|
'id': item["track"]["id"],
|
||||||
"name": str(item["track"]["name"]),
|
'name': item["track"]["name"],
|
||||||
"album": str(item["track"]["album"]["name"]),
|
'album': item["track"]["album"]["name"],
|
||||||
"artist": str(item["track"]["artists"][0]["name"]),
|
'artist': item["track"]["artists"][0]["name"],
|
||||||
"image": str(item["track"]["album"]["images"][0]["url"]),
|
'image': item["track"]["album"]["images"][0]["url"]
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
except AssertionError:
|
except AssertionError:
|
||||||
something = None
|
something = None
|
||||||
return tracks, HTTPStatus.OK
|
return jsonify([track for track in tracks])
|
||||||
|
|
||||||
|
# return jsonify([track for track in tracks])
|
||||||
|
|
||||||
|
|
||||||
async def api_get_token(sp_id):
|
async def api_get_token(sp_id):
|
||||||
@ -185,11 +189,43 @@ async def api_get_token(sp_id):
|
|||||||
|
|
||||||
######GET INVOICE
|
######GET INVOICE
|
||||||
|
|
||||||
|
@jukebox_ext.route("/api/v1/jukebox/jb/invoice/<sp_id>/<song_id>", methods=["GET"])
|
||||||
@jukebox_ext.route("/api/v1/jukebox/jb/<sp_id>/<sp_song>/", methods=["GET"])
|
async def api_get_jukebox_invoice(sp_id, song_id):
|
||||||
async def api_get_jukebox_invoice(sp_id, sp_song):
|
|
||||||
jukebox = await get_jukebox(sp_id)
|
jukebox = await get_jukebox(sp_id)
|
||||||
invoice = await create_invoice(wallet_id=jukebox.wallet,amount=jukebox.price,memo=jukebox.title)
|
invoice = await create_invoice(wallet_id=jukebox.wallet,amount=jukebox.price,memo=jukebox.title)
|
||||||
|
|
||||||
####new table needed to store payment hashes
|
####new table needed to store payment hashes
|
||||||
return invoice, HTTPStatus.OK
|
return jsonify(invoice)
|
||||||
|
|
||||||
|
|
||||||
|
@jukebox_ext.route("/api/v1/jukebox/jb/invoice/<invoice_id>", methods=["GET"])
|
||||||
|
async def api_get_jukebox_check_invoice(invoice_id):
|
||||||
|
async with httpx.AsyncClient() as client:
|
||||||
|
try:
|
||||||
|
r = await client.get(
|
||||||
|
"https://api.spotify.com/v1/me/player/queue" + sp_playlist + "/tracks",
|
||||||
|
timeout=40,
|
||||||
|
headers={"Authorization": "Bearer " + jukebox.sp_access_token},
|
||||||
|
)
|
||||||
|
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_son(sp_id, sp_playlist)
|
||||||
|
return r, HTTPStatus.OK
|
||||||
|
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(invoice)
|
Loading…
x
Reference in New Issue
Block a user