diff --git a/lnbits/extensions/jukebox/crud.py b/lnbits/extensions/jukebox/crud.py index 5c797ab68..238ed083d 100644 --- a/lnbits/extensions/jukebox/crud.py +++ b/lnbits/extensions/jukebox/crud.py @@ -80,12 +80,11 @@ async def delete_jukebox(juke_id: str): (juke_id), ) + #####################################PAYMENTS -async def create_jukebox_payment( - song_id: str, - payment_hash: str -) -> JukeboxPayment: + +async def create_jukebox_payment(song_id: str, payment_hash: str) -> JukeboxPayment: result = await db.execute( """ INSERT INTO jukebox_payment (payment_hash, song_id, paid) @@ -102,14 +101,19 @@ async def create_jukebox_payment( return jukebox_payment -async def update_jukebox_payment(payment_hash: str, **kwargs) -> Optional[JukeboxPayment]: +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) + 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 + row = await db.fetchone( + "SELECT * FROM jukebox_payment WHERE payment_hash = ?", (payment_hash,) + ) + return JukeboxPayment(**row) if row else None diff --git a/lnbits/extensions/jukebox/migrations.py b/lnbits/extensions/jukebox/migrations.py index e81c5ecfd..53be21036 100644 --- a/lnbits/extensions/jukebox/migrations.py +++ b/lnbits/extensions/jukebox/migrations.py @@ -17,10 +17,14 @@ async def m001_initial(db): sp_device TEXT, sp_playlists TEXT, price INTEGER, - profit INTEGER + profit INTEGER, + queue TEXT, + last_checked ); """ ) + + async def m002_initial(db): """ Initial jukebox_payment table. @@ -29,8 +33,9 @@ async def m002_initial(db): """ CREATE TABLE jukebox_payment ( payment_hash TEXT PRIMARY KEY, + juke_id TEXT, song_id TEXT, paid BOOL ); """ - ) \ No newline at end of file + ) diff --git a/lnbits/extensions/jukebox/models.py b/lnbits/extensions/jukebox/models.py index 866551457..e88f5896b 100644 --- a/lnbits/extensions/jukebox/models.py +++ b/lnbits/extensions/jukebox/models.py @@ -21,16 +21,20 @@ class Jukebox(NamedTuple): sp_playlists: str price: int profit: int + queue: list + last_checked: int @classmethod def from_row(cls, row: Row) -> "Jukebox": return cls(**dict(row)) + class JukeboxPayment(NamedTuple): payment_hash: str + juke_id: str song_id: str paid: bool @classmethod def from_row(cls, row: Row) -> "JukeboxPayment": - return cls(**dict(row)) \ No newline at end of file + return cls(**dict(row)) diff --git a/lnbits/extensions/jukebox/views_api.py b/lnbits/extensions/jukebox/views_api.py index 5a0dc85c6..67d6b8e64 100644 --- a/lnbits/extensions/jukebox/views_api.py +++ b/lnbits/extensions/jukebox/views_api.py @@ -4,6 +4,8 @@ from lnurl.exceptions import InvalidUrl as LnurlInvalidUrl # type: ignore from base64 import urlsafe_b64encode import base64 import json +import time + from lnbits.decorators import api_check_wallet_key, api_validate_post_request import httpx @@ -116,9 +118,11 @@ async def api_delete_item(juke_id): ######GET ACCESS TOKEN###### -@jukebox_ext.route("/api/v1/jukebox/jb/playlist//", methods=["GET"]) -async def api_get_jukebox_son(sp_id, sp_playlist): - jukebox = await get_jukebox(sp_id) +@jukebox_ext.route( + "/api/v1/jukebox/jb/playlist//", methods=["GET"] +) +async def api_get_jukebox_son(juke_id, sp_playlist): + jukebox = await get_jukebox(juke_id) tracks = [] async with httpx.AsyncClient() as client: try: @@ -129,12 +133,12 @@ async def api_get_jukebox_son(sp_id, sp_playlist): ) if "items" not in r.json(): if r.json()["error"]["status"] == 401: - token = await api_get_token(sp_id) + token = await api_get_token(juke_id) if token == False: return False else: - return await api_get_jukebox_son(sp_id, sp_playlist) + return await api_get_jukebox_son(juke_id, sp_playlist) return r, HTTPStatus.OK for item in r.json()["items"]: tracks.append( @@ -154,8 +158,8 @@ async def api_get_jukebox_son(sp_id, sp_playlist): # return jsonify([track for track in tracks]) -async def api_get_token(sp_id): - jukebox = await get_jukebox(sp_id) +async def api_get_token(juke_id): + jukebox = await get_jukebox(juke_id) async with httpx.AsyncClient() as client: try: @@ -180,7 +184,7 @@ async def api_get_token(sp_id): return False else: await update_jukebox( - juke_id=sp_id, sp_access_token=r.json()["access_token"] + juke_id=juke_id, sp_access_token=r.json()["access_token"] ) except AssertionError: something = None @@ -190,9 +194,9 @@ async def api_get_token(sp_id): ######GET INVOICE STUFF -@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) +@jukebox_ext.route("/api/v1/jukebox/jb/invoice//", methods=["GET"]) +async def api_get_jukebox_invoice(juke_id, song_id): + jukebox = await get_jukebox(juke_id) invoice = await create_invoice( wallet_id=jukebox.wallet, @@ -207,10 +211,55 @@ async def api_get_jukebox_invoice(sp_id, song_id): @jukebox_ext.route( - "/api/v1/jukebox/jb/invoicep//", methods=["GET"] + "/api/v1/jukebox/jb/invoicep//", methods=["GET"] ) -async def api_get_jukebox_invoice_paid(payment_hash, sp_id): - jukebox = await get_jukebox(sp_id) +async def api_get_jukebox_invoice_paid(payment_hash, juke_id): + jukebox = await get_jukebox(juke_id) + print(jukebox) + paid = await check_invoice_status(jukebox.wallet, payment_hash) + if paid: + jukebox_payment = await update_jukebox_payment(payment_hash, paid=True) + else: + return jsonify({"error": "Invoice not paid"}) + + +# if not is_paid: +# return jsonify({"status": False}) +# return jsonify({"error": "Something went wrong"}) + +############################QUEUE SONG + + +async def add_to_song_queue(song_id, juke_id): + jukebox = await get_jukebox(juke_id) + queue = jukebox.queue + queue.append(song_id) + # Add song to back of queue + jukebox = await update_jukebox(juke_id=juke_id, queue=queue) + # while loop for all tracks. Check 25 secs has passsed since last check. + queued = jukebox.queue + while len(queued) > 0: + if (time.time() - jukebox.last_checked) > 25000: + song = await api_get_jukebox_currently(juke_id) + if song.track.id != queued[0]: + async with httpx.AsyncClient() as client: + r = await client.post( + "https://api.spotify.com/v1/me/player/queue?uri=spotify%3Atrack%3A" + + jukebox_payment.song_id + + "&device_id=" + + jukebox.sp_device.split("-")[1], + timeout=40, + headers={"Authorization": "Bearer " + jukebox.sp_access_token}, + ) + print(r) + else: + queued = queued[1:] + jukebox = await update_jukebox(juke_id=juke_id, queue=queued) + queued = jukebox.queue + jukebox = await update_jukebox(juke_id=juke_id, last_checked=time.time()) + + # if current track playing isnt at the front of the queue, add it to queue + print(jukebox) paid = await check_invoice_status(jukebox.wallet, payment_hash) if paid: @@ -229,27 +278,22 @@ async def api_get_jukebox_invoice_paid(payment_hash, sp_id): ) print(r) if r.json()["error"]["status"] == 401: - token = await api_get_token(sp_id) + token = await api_get_token(juke_id) if token == False: return jsonify({"error": "Something went wrong"}) else: - return await api_get_jukebox_invoice_paid(sp_id, payment_hash) + return await api_get_jukebox_invoice_paid(juke_id, payment_hash) if r.json()["error"]["status"] == 400: return jsonify({"error": "Something went wrong"}) return jsonify(r), HTTPStatus.OK -# if not is_paid: -# return jsonify({"status": False}) -# return jsonify({"error": "Something went wrong"}) - - ############################GET TRACKS -@jukebox_ext.route("/api/v1/jukebox/jb/currently/", methods=["GET"]) -async def api_get_jukebox_currently(sp_id): - jukebox = await get_jukebox(sp_id) +@jukebox_ext.route("/api/v1/jukebox/jb/currently/", methods=["GET"]) +async def api_get_jukebox_currently(juke_id): + jukebox = await get_jukebox(juke_id) async with httpx.AsyncClient() as client: try: r = await client.get( @@ -271,12 +315,12 @@ async def api_get_jukebox_currently(sp_id): something = None try: if r.json()["error"]["status"] == 401: - token = await api_get_token(sp_id) + token = await api_get_token(juke_id) if token == False: return jsonify({"error": "Something went wrong"}) else: - return await api_get_jukebox_currently(sp_id) + return await api_get_jukebox_currently(juke_id) elif r.json()["error"]["status"] == 400: return jsonify({"error": "Something went wrong"}) except ValueError: