import base64 import json from http import HTTPStatus import httpx from fastapi import Request from fastapi.param_functions import Query from fastapi.params import Depends from starlette.exceptions import HTTPException from starlette.responses import HTMLResponse # type: ignore from lnbits.core.services import create_invoice from lnbits.core.views.api import api_payment from lnbits.decorators import WalletTypeInfo, require_admin_key from . import jukebox_ext from .crud import ( create_jukebox, create_jukebox_payment, delete_jukebox, get_jukebox, get_jukebox_payment, get_jukeboxs, update_jukebox, update_jukebox_payment, ) from .models import CreateJukeboxPayment, CreateJukeLinkData @jukebox_ext.get("/api/v1/jukebox") async def api_get_jukeboxs( req: Request, wallet: WalletTypeInfo = Depends(require_admin_key), all_wallets: bool = Query(False), ): wallet_user = wallet.wallet.user try: jukeboxs = [jukebox.dict() for jukebox in await get_jukeboxs(wallet_user)] return jukeboxs except: raise HTTPException(status_code=HTTPStatus.NO_CONTENT, detail="No Jukeboxes") ##################SPOTIFY AUTH##################### @jukebox_ext.get("/api/v1/jukebox/spotify/cb/{juke_id}", response_class=HTMLResponse) async def api_check_credentials_callbac( juke_id: str = Query(None), code: str = Query(None), access_token: str = Query(None), refresh_token: str = Query(None), ): sp_code = "" sp_access_token = "" sp_refresh_token = "" try: jukebox = await get_jukebox(juke_id) except: raise HTTPException(detail="No Jukebox", status_code=HTTPStatus.FORBIDDEN) if code: jukebox.sp_access_token = code jukebox = await update_jukebox(jukebox, juke_id=juke_id) if access_token: jukebox.sp_access_token = access_token jukebox.sp_refresh_token = refresh_token jukebox = await update_jukebox(jukebox, juke_id=juke_id) return "

Success!

You can close this window

" @jukebox_ext.get("/api/v1/jukebox/{juke_id}") async def api_check_credentials_check( juke_id: str = Query(None), wallet: WalletTypeInfo = Depends(require_admin_key) ): jukebox = await get_jukebox(juke_id) return jukebox @jukebox_ext.post("/api/v1/jukebox", status_code=HTTPStatus.CREATED) @jukebox_ext.put("/api/v1/jukebox/{juke_id}", status_code=HTTPStatus.OK) async def api_create_update_jukebox( data: CreateJukeLinkData, juke_id: str = Query(None), wallet: WalletTypeInfo = Depends(require_admin_key), ): if juke_id: jukebox = await update_jukebox(data, juke_id=juke_id) else: jukebox = await create_jukebox(data, inkey=wallet.wallet.inkey) return jukebox @jukebox_ext.delete("/api/v1/jukebox/{juke_id}") async def api_delete_item( juke_id=None, wallet: WalletTypeInfo = Depends(require_admin_key) ): await delete_jukebox(juke_id) try: return [{**jukebox} for jukebox in await get_jukeboxs(wallet.wallet.user)] except: raise HTTPException(status_code=HTTPStatus.NO_CONTENT, detail="No Jukebox") ################JUKEBOX ENDPOINTS################## ######GET ACCESS TOKEN###### @jukebox_ext.get("/api/v1/jukebox/jb/playlist/{juke_id}/{sp_playlist}") async def api_get_jukebox_song( juke_id: str = Query(None), sp_playlist: str = Query(None), retry: bool = Query(False), ): try: jukebox = await get_jukebox(juke_id) except: raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="No Jukeboxes") tracks = [] async with httpx.AsyncClient() as client: try: r = await client.get( "https://api.spotify.com/v1/playlists/" + sp_playlist + "/tracks", timeout=40, headers={"Authorization": "Bearer " + jukebox.sp_access_token}, ) if "items" not in r.json(): if r.status_code == 401: token = await api_get_token(juke_id) if token == False: return False elif retry: raise HTTPException( status_code=HTTPStatus.FORBIDDEN, detail="Failed to get auth", ) else: return await api_get_jukebox_song( juke_id, sp_playlist, retry=True ) return r 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: something = None return [track for track in tracks] async def api_get_token(juke_id=None): try: jukebox = await get_jukebox(juke_id) except: raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="No Jukeboxes") async with httpx.AsyncClient() as client: try: r = await client.post( "https://accounts.spotify.com/api/token", timeout=40, params={ "grant_type": "refresh_token", "refresh_token": jukebox.sp_refresh_token, "client_id": jukebox.sp_user, }, headers={ "Content-Type": "application/x-www-form-urlencoded", "Authorization": "Basic " + base64.b64encode( str(jukebox.sp_user + ":" + jukebox.sp_secret).encode("ascii") ).decode("ascii"), "Content-Type": "application/x-www-form-urlencoded", }, ) if "access_token" not in r.json(): return False else: jukebox.sp_access_token = r.json()["access_token"] await update_jukebox(jukebox, juke_id=juke_id) except: something = None return True ######CHECK DEVICE @jukebox_ext.get("/api/v1/jukebox/jb/{juke_id}") async def api_get_jukebox_device_check( juke_id: str = Query(None), retry: bool = Query(False) ): try: jukebox = await get_jukebox(juke_id) except: raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="No Jukeboxes") async with httpx.AsyncClient() as client: rDevice = await client.get( "https://api.spotify.com/v1/me/player/devices", timeout=40, headers={"Authorization": "Bearer " + jukebox.sp_access_token}, ) if rDevice.status_code == 204 or rDevice.status_code == 200: return json.loads(rDevice.text) elif rDevice.status_code == 401 or rDevice.status_code == 403: token = await api_get_token(juke_id) if token == False: raise HTTPException( status_code=HTTPStatus.FORBIDDEN, detail="No devices connected" ) elif retry: raise HTTPException( status_code=HTTPStatus.FORBIDDEN, detail="Failed to get auth" ) else: return api_get_jukebox_device_check(juke_id, retry=True) else: raise HTTPException( status_code=HTTPStatus.FORBIDDEN, detail="No device connected" ) ######GET INVOICE STUFF @jukebox_ext.get("/api/v1/jukebox/jb/invoice/{juke_id}/{song_id}") async def api_get_jukebox_invoice(juke_id, song_id): try: jukebox = await get_jukebox(juke_id) except: raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="No jukebox") try: devices = await api_get_jukebox_device_check(juke_id) deviceConnected = False for device in devices["devices"]: if device["id"] == jukebox.sp_device.split("-")[1]: deviceConnected = True if not deviceConnected: raise HTTPException( status_code=HTTPStatus.NOT_FOUND, detail="No device connected" ) except: raise HTTPException( status_code=HTTPStatus.NOT_FOUND, detail="No device connected" ) invoice = await create_invoice( wallet_id=jukebox.wallet, amount=jukebox.price, memo=jukebox.title, extra={"tag": "jukebox"}, ) payment_hash = invoice[0] data = CreateJukeboxPayment( invoice=invoice[1], payment_hash=payment_hash, juke_id=juke_id, song_id=song_id ) jukebox_payment = await create_jukebox_payment(data) return data @jukebox_ext.get("/api/v1/jukebox/jb/checkinvoice/{pay_hash}/{juke_id}") async def api_get_jukebox_invoice_check( pay_hash: str = Query(None), juke_id: str = Query(None) ): try: await get_jukebox(juke_id) except: raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="No jukebox") try: status = await api_payment(pay_hash) if status["paid"]: await update_jukebox_payment(pay_hash, paid=True) return {"paid": True} except: return {"paid": False} return {"paid": False} @jukebox_ext.get("/api/v1/jukebox/jb/invoicep/{song_id}/{juke_id}/{pay_hash}") async def api_get_jukebox_invoice_paid( song_id: str = Query(None), juke_id: str = Query(None), pay_hash: str = Query(None), retry: bool = Query(False), ): try: jukebox = await get_jukebox(juke_id) except: raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="No jukebox") await api_get_jukebox_invoice_check(pay_hash, juke_id) jukebox_payment = await get_jukebox_payment(pay_hash) if jukebox_payment.paid: async with httpx.AsyncClient() as client: r = await client.get( "https://api.spotify.com/v1/me/player/currently-playing?market=ES", timeout=40, headers={"Authorization": "Bearer " + jukebox.sp_access_token}, ) rDevice = await client.get( "https://api.spotify.com/v1/me/player", timeout=40, headers={"Authorization": "Bearer " + jukebox.sp_access_token}, ) isPlaying = False if rDevice.status_code == 200: isPlaying = rDevice.json()["is_playing"] if r.status_code == 204 or isPlaying == False: async with httpx.AsyncClient() as client: uri = ["spotify:track:" + song_id] r = await client.put( "https://api.spotify.com/v1/me/player/play?device_id=" + jukebox.sp_device.split("-")[1], json={"uris": uri}, timeout=40, headers={"Authorization": "Bearer " + jukebox.sp_access_token}, ) if r.status_code == 204: return jukebox_payment elif r.status_code == 401 or r.status_code == 403: token = await api_get_token(juke_id) if token == False: raise HTTPException( status_code=HTTPStatus.FORBIDDEN, detail="Invoice not paid", ) elif retry: raise HTTPException( status_code=HTTPStatus.FORBIDDEN, detail="Failed to get auth", ) else: return api_get_jukebox_invoice_paid( song_id, juke_id, pay_hash, retry=True ) else: raise HTTPException( status_code=HTTPStatus.FORBIDDEN, detail="Invoice not paid" ) elif r.status_code == 200: async with httpx.AsyncClient() as client: r = await client.post( "https://api.spotify.com/v1/me/player/queue?uri=spotify%3Atrack%3A" + song_id + "&device_id=" + jukebox.sp_device.split("-")[1], timeout=40, headers={"Authorization": "Bearer " + jukebox.sp_access_token}, ) if r.status_code == 204: return jukebox_payment elif r.status_code == 401 or r.status_code == 403: token = await api_get_token(juke_id) if token == False: raise HTTPException( status_code=HTTPStatus.FORBIDDEN, detail="Invoice not paid", ) elif retry: raise HTTPException( status_code=HTTPStatus.FORBIDDEN, detail="Failed to get auth", ) else: return await api_get_jukebox_invoice_paid( song_id, juke_id, pay_hash ) else: raise HTTPException( status_code=HTTPStatus.OK, detail="Invoice not paid" ) elif r.status_code == 401 or r.status_code == 403: token = await api_get_token(juke_id) if token == False: raise HTTPException( status_code=HTTPStatus.OK, detail="Invoice not paid" ) elif retry: raise HTTPException( status_code=HTTPStatus.FORBIDDEN, detail="Failed to get auth" ) else: return await api_get_jukebox_invoice_paid( song_id, juke_id, pay_hash ) raise HTTPException(status_code=HTTPStatus.OK, detail="Invoice not paid") ############################GET TRACKS @jukebox_ext.get("/api/v1/jukebox/jb/currently/{juke_id}") async def api_get_jukebox_currently( retry: bool = Query(False), juke_id: str = Query(None) ): try: jukebox = await get_jukebox(juke_id) except: raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="No jukebox") async with httpx.AsyncClient() as client: try: r = await client.get( "https://api.spotify.com/v1/me/player/currently-playing?market=ES", timeout=40, headers={"Authorization": "Bearer " + jukebox.sp_access_token}, ) if r.status_code == 204: raise HTTPException(status_code=HTTPStatus.OK, detail="Nothing") elif r.status_code == 200: try: response = r.json() track = { "id": response["item"]["id"], "name": response["item"]["name"], "album": response["item"]["album"]["name"], "artist": response["item"]["artists"][0]["name"], "image": response["item"]["album"]["images"][0]["url"], } return track except: raise HTTPException( status_code=HTTPStatus.NOT_FOUND, detail="Something went wrong" ) elif r.status_code == 401: token = await api_get_token(juke_id) if token == False: raise HTTPException( status_code=HTTPStatus.FORBIDDEN, detail="INvoice not paid" ) elif retry: raise HTTPException( status_code=HTTPStatus.FORBIDDEN, detail="Failed to get auth" ) else: return await api_get_jukebox_currently(retry=True, juke_id=juke_id) else: raise HTTPException( status_code=HTTPStatus.NOT_FOUND, detail="Something went wrong" ) except: raise HTTPException( status_code=HTTPStatus.NOT_FOUND, detail="Something went wrong" )