diff --git a/lnbits/extensions/jukebox/crud.py b/lnbits/extensions/jukebox/crud.py index fc7ddca3b..34764e3a6 100644 --- a/lnbits/extensions/jukebox/crud.py +++ b/lnbits/extensions/jukebox/crud.py @@ -1,7 +1,7 @@ from typing import List, Optional from . import db -from .models import Jukebox +from .models import Jukebox, JukeboxPayment from lnbits.helpers import urlsafe_short_hash @@ -78,3 +78,72 @@ async def delete_jukebox(juke_id: str): """, (juke_id), ) + +#####################################PAYMENTS + +async def create_jukebox_payment( + song_id: str, + payment_hash: str +) -> Jukebox: + result = await db.execute( + """ + INSERT INTO jukebox_payment (payment_hash, song_id, paid) + VALUES (?, ?, ?) + """, + ( + payment_hash, + song_id, + False, + ), + ) + jukebox_payment = await get_jukebox_payment(payment_hash) + assert jukebox_payment, "Newly created Jukebox Payment couldn't be retrieved" + return jukebox_payment + + +async def update_jukebox_payment(payment_hash: str, **kwargs) -> Optional[JukeboxPayment]: + q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()]) + await db.execute( + f"UPDATE jukebox_payment SET {q} WHERE payment_hash = ?", (*kwargs.values(), payment_hash) + ) + return await get_jukebox_payment(payment_hash) + + +async def get_jukebox_payment(payment_hash: str) -> Optional[JukeboxPayment]: + row = await db.fetchone("SELECT * FROM jukebox_payment WHERE payment_hash = ?", (payment_hash,)) + return JukeboxPayment(**row) if row else None + + +##################################SONGS QUEUED + +async def create_jukebox_queue( + song_id: str, + payment_hash: str +) -> Jukebox: + result = await db.execute( + """ + INSERT INTO jukebox_payment (payment_hash, song_id, paid) + VALUES (?, ?, ?) + """, + ( + payment_hash, + song_id, + False, + ), + ) + jukebox_payment = await get_jukebox_payment(payment_hash) + assert jukebox_payment, "Newly created Jukebox Payment couldn't be retrieved" + return jukebox_payment + + +async def update_jukebox_payment(payment_hash: str, **kwargs) -> Optional[JukeboxPayment]: + q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()]) + await db.execute( + f"UPDATE jukebox_payment SET {q} WHERE payment_hash = ?", (*kwargs.values(), payment_hash) + ) + return await get_jukebox_payment(payment_hash) + + +async def get_jukebox_payment(payment_hash: str) -> Optional[JukeboxPayment]: + row = await db.fetchone("SELECT * FROM jukebox_payment WHERE payment_hash = ?", (payment_hash,)) + return JukeboxPayment(**row) if row else None \ No newline at end of file diff --git a/lnbits/extensions/jukebox/migrations.py b/lnbits/extensions/jukebox/migrations.py index 9ca09a4a5..510f4798c 100644 --- a/lnbits/extensions/jukebox/migrations.py +++ b/lnbits/extensions/jukebox/migrations.py @@ -20,3 +20,28 @@ async def m001_initial(db): ); """ ) +async def m002_initial(db): + """ + Initial jukebox_payment table. + """ + await db.execute( + """ + CREATE TABLE jukebox_payment ( + payment_hash TEXT PRIMARY KEY, + song_id TEXT, + paid BOOL + ); + """ + ) +async def m003_initial(db): + """ + Initial jukebox_queue table. + """ + await db.execute( + """ + CREATE TABLE jukebox_queue ( + jukebox_id TEXT PRIMARY KEY, + queue TEXT + ); + """ + ) \ No newline at end of file diff --git a/lnbits/extensions/jukebox/models.py b/lnbits/extensions/jukebox/models.py index f869de4f8..04692e2b6 100644 --- a/lnbits/extensions/jukebox/models.py +++ b/lnbits/extensions/jukebox/models.py @@ -24,3 +24,20 @@ class Jukebox(NamedTuple): @classmethod def from_row(cls, row: Row) -> "Jukebox": return cls(**dict(row)) + +class JukeboxPayment(NamedTuple): + payment_hash: str + song_id: str + paid: bool + + @classmethod + def from_row(cls, row: Row) -> "JukeboxPayment": + return cls(**dict(row)) + +class JukeboxQueue(NamedTuple): + jukebox_id: str + queue: str + + @classmethod + def from_row(cls, row: Row) -> "JukeboxQueue": + return cls(**dict(row)) \ No newline at end of file diff --git a/lnbits/extensions/jukebox/templates/jukebox/jukebox.html b/lnbits/extensions/jukebox/templates/jukebox/jukebox.html index 9aac2a249..a41a1d4d1 100644 --- a/lnbits/extensions/jukebox/templates/jukebox/jukebox.html +++ b/lnbits/extensions/jukebox/templates/jukebox/jukebox.html @@ -141,6 +141,7 @@ second: false }, paymentReq: '', + paymentHash: '', name: '', artist: '', image: '', @@ -151,6 +152,13 @@ }, computed: {}, methods: { + cancelPayment: function () { + this.paymentReq = null + clearInterval(this.paymentDialog.checker) + if (this.paymentDialog.dismissMsg) { + this.paymentDialog.dismissMsg() + } + }, closeReceiveDialog() {}, payForSong(song_id, name, artist, image) { self = this @@ -161,6 +169,7 @@ self.receive.dialogues.first = true }, getInvoice(song_id) { + self = this LNbits.api .request( 'GET', @@ -170,9 +179,38 @@ song_id ) .then(function (response) { + console.log('response.data') console.log(response.data) - self.receive.paymentReq = response.data[1] + console.log('response.data') + self.receive.paymentReq = response.data[0][1] + self.receive.paymentHash = response.data[0][0] self.receive.dialogues.second = true + + pChecker = setInterval(function () { + axios + .get( + '/jukebox/api/v1/jukebox/jb/invoicecheck/' + + self.receive.paymentHash + + '/{{ juke_id }}' + ) + .then(function (res) { + console.log(res.data) + if (res.data.status == true) { + console.log('pooooooo') + // self.cancelPayment() + clearInterval(pChecker) + self.$q.notify({ + type: 'positive', + message: 'Payment received!', + icon: null + }) + self.receive.dialogues.second = false + } + }) + .catch(err => { + LNbits.utils.notifyApiError(err) + }) + }, 5000) }) .catch(err => { LNbits.utils.notifyApiError(err) diff --git a/lnbits/extensions/jukebox/views_api.py b/lnbits/extensions/jukebox/views_api.py index 1e2201ba9..7a5e69dec 100644 --- a/lnbits/extensions/jukebox/views_api.py +++ b/lnbits/extensions/jukebox/views_api.py @@ -15,9 +15,12 @@ from .crud import ( get_jukebox_by_user, get_jukeboxs, delete_jukebox, + create_jukebox_payment, + get_jukebox_payment, + update_jukebox_payment, ) from .models import Jukebox -from lnbits.core.services import create_invoice +from lnbits.core.services import create_invoice, check_invoice_status @jukebox_ext.route("/api/v1/jukebox", methods=["GET"]) @api_check_wallet_key("invoice") @@ -192,40 +195,44 @@ async def api_get_token(sp_id): @jukebox_ext.route("/api/v1/jukebox/jb/invoice//", methods=["GET"]) async def api_get_jukebox_invoice(sp_id, song_id): jukebox = await get_jukebox(sp_id) + invoice = await create_invoice(wallet_id=jukebox.wallet,amount=jukebox.price,memo=jukebox.title) + jukebox_payment = await create_jukebox_payment(song_id,invoice[0]) + print(jukebox_payment) ####new table needed to store payment hashes - return jsonify(invoice) + return jsonify(invoice, jukebox_payment) -@jukebox_ext.route("/api/v1/jukebox/jb/invoice/", 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(): +@jukebox_ext.route("/api/v1/jukebox/jb/invoicecheck//", methods=["GET"]) +async def api_get_jukebox_check_invoice(sp_id, payment_hash): + jukebox = await get_jukebox(sp_id) + status = await check_invoice_status(jukebox.wallet, payment_hash) + is_paid = not status.pending + if is_paid: + jukebox_payment = await update_jukebox_payment(payment_hash, paid = True) + print("https://api.spotify.com/v1/me/player/queue?uri=spotify%3Atrack%3A" + jukebox_payment.song_id + "&device_id=" + jukebox.sp_device) + async with httpx.AsyncClient() as client: + try: + r = await client.get( + "https://api.spotify.com/v1/me/player/queue?uri=spotify%3Atrack%3A" + jukebox_payment.song_id + "&device_id=" + jukebox.sp_device, + timeout=40, + headers={"Authorization": "Bearer " + jukebox.sp_access_token}, + ) if r.json()["error"]["status"] == 401: token = await api_get_token(sp_id) if token == False: print("invalid") - return False + return jsonify({"error": "Something went wrong"}) else: - return await api_get_jukebox_son(sp_id, sp_playlist) + return await api_get_jukebox_check_invoice(sp_id, payment_hash) + if r.json()["error"]["status"] == 400: + return jsonify({"error": "Something went wrong"}) + 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) \ No newline at end of file + except AssertionError: + something = None + return jsonify({"error": "Something went wrong"}) + if not is_paid: + return jsonify({"status": False}) + return jsonify({"error": "Something went wrong"}) \ No newline at end of file