diff --git a/lnbits/extensions/jukebox/crud.py b/lnbits/extensions/jukebox/crud.py index 99d1c4cd..da27e74d 100644 --- a/lnbits/extensions/jukebox/crud.py +++ b/lnbits/extensions/jukebox/crud.py @@ -11,15 +11,16 @@ async def create_jukebox( price: int, sp_user: str, sp_secret: str, - sp_token: Optional[str] = "", + sp_access_token: Optional[str] = "", + sp_refresh_token: Optional[str] = "", sp_device: Optional[str] = "", sp_playlists: Optional[str] = "", ) -> Jukebox: juke_id = urlsafe_short_hash() result = await db.execute( """ - INSERT INTO jukebox (id, title, wallet, sp_user, sp_secret, sp_token, sp_device, sp_playlists, price) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) + INSERT INTO jukebox (id, title, wallet, sp_user, sp_secret, sp_access_token, sp_refresh_token, sp_device, sp_playlists, price) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, ( juke_id, @@ -27,7 +28,8 @@ async def create_jukebox( wallet, sp_user, sp_secret, - sp_token, + sp_access_token, + sp_refresh_token, sp_device, sp_playlists, int(price), diff --git a/lnbits/extensions/jukebox/migrations.py b/lnbits/extensions/jukebox/migrations.py index 365f13e5..86f675fe 100644 --- a/lnbits/extensions/jukebox/migrations.py +++ b/lnbits/extensions/jukebox/migrations.py @@ -10,7 +10,8 @@ async def m001_initial(db): wallet TEXT, sp_user TEXT NOT NULL, sp_secret TEXT NOT NULL, - sp_token TEXT, + sp_access_token TEXT, + sp_refresh_token TEXT, sp_device TEXT, sp_playlists TEXT, price INTEGER diff --git a/lnbits/extensions/jukebox/models.py b/lnbits/extensions/jukebox/models.py index 9f3ec629..dddebbc5 100644 --- a/lnbits/extensions/jukebox/models.py +++ b/lnbits/extensions/jukebox/models.py @@ -13,7 +13,8 @@ class Jukebox(NamedTuple): wallet: str sp_user: str sp_secret: str - sp_token: str + sp_access_token: str + sp_refresh_token: str sp_device: str sp_playlists: str price: int diff --git a/lnbits/extensions/jukebox/static/js/index.js b/lnbits/extensions/jukebox/static/js/index.js index 07498053..fa5fd390 100644 --- a/lnbits/extensions/jukebox/static/js/index.js +++ b/lnbits/extensions/jukebox/static/js/index.js @@ -13,11 +13,12 @@ new Vue({ return { isPwd: true, tokenFetched: true, - device: [], + devices: [], jukebox: {}, playlists: [], step: 1, locationcbPath: "", + locationcb: "", jukeboxDialog: { show: false, data: {} @@ -55,22 +56,26 @@ new Vue({ .then(response => { if(response.data){ var timerId = setInterval(function(){ + console.log(response.data) if(!self.jukeboxDialog.data.sp_user){ clearInterval(timerId); } + self.jukeboxDialog.data.sp_id = response.data.id LNbits.api - .request('GET', '/jukebox/api/v1/jukebox/spotify/' + self.jukeboxDialog.data.sp_user, self.g.user.wallets[0].inkey) + .request('GET', '/jukebox/api/v1/jukebox/spotify/' + self.jukeboxDialog.data.sp_id, self.g.user.wallets[0].inkey) .then(response => { - if(response.data.sp_token){ - console.log(response.data.sp_token) - + if(response.data.sp_access_token){ + self.jukeboxDialog.data.sp_access_token = response.data.sp_access_token self.step = 3 - clearInterval(timerId); - self.refreshPlaylists() - self.$q.notify({ - message: 'Success! App is now linked!', - timeout: 3000 - }) + self.fetchAccessToken() + + clearInterval(timerId) + + // self.refreshPlaylists(response.data.sp_token) +// self.$q.notify({ +// message: 'Success! App is now linked!', +// timeout: 3000 +// }) //set devices, playlists } }) @@ -86,13 +91,12 @@ new Vue({ }, requestAuthorization(){ self = this - let url = 'https://accounts.spotify.com/authorize' - url += '?scope=user-modify-playback-state%20user-read-playback-position' - url += '%20user-library-read%20streaming%20user-read-playback-state' - url += '%20user-read-recently-played%20playlist-read-private&response_type=code' - url += '&redirect_uri=' + encodeURIComponent(self.locationcbPath) + self.jukeboxDialog.data.sp_user - url += '&client_id=' + self.jukeboxDialog.data.sp_user - url += '&show_dialog=true' + var url = 'https://accounts.spotify.com/authorize' + url += '?client_id=' + self.jukeboxDialog.data.sp_user + url += '&response_type=code' + url += '&redirect_uri=' + encodeURI(self.locationcbPath + self.jukeboxDialog.data.sp_user) + url += "&show_dialog=true" + url += '&scope=user-read-private user-read-email user-modify-playback-state user-read-playback-position user-library-read streaming user-read-playback-state user-read-recently-played playlist-read-private' console.log(url) window.open(url) }, @@ -105,47 +109,96 @@ new Vue({ let item = this.jukebox.items.find(item => item.id === itemId) this.jukeboxDialog.data = item }, + createJukebox(){ + self = this - callApi(method, url, body, callback){ + LNbits.api.request( + 'PUT', + '/jukebox/api/v1/jukebox/' + this.jukeboxDialog.data.sp_id, + self.g.user.wallets[0].adminkey, + self.jukeboxDialog.data + ) + .then(response => { + console.log(response.data) + + }) + .catch(err => { + LNbits.utils.notifyApiError(err) + }) + }, + + playlistApi(method, url, body){ + self = this let xhr = new XMLHttpRequest() xhr.open(method, url, true) xhr.setRequestHeader('Content-Type', 'application/json') - xhr.setRequestHeader('Authorization', 'Bearer ' + self.jukeboxDialog.data.sp_token) + xhr.setRequestHeader('Authorization', 'Bearer ' + this.jukeboxDialog.data.sp_access_token) xhr.send(body) - xhr.onload = callback + xhr.onload = function() { + let responseObj = JSON.parse(xhr.response) + console.log(responseObj.items) + var i; + for (i = 0; i < responseObj.items.length; i++) { + self.playlists.push(responseObj.items[i].name + "-" + responseObj.items[i].id) + } + } }, refreshPlaylists(){ - console.log("sdfvasdv") - callApi( "GET", "https://api.spotify.com/v1/me/playlists", null, handlePlaylistsResponse ) + self = this + self.playlistApi( "GET", "https://api.spotify.com/v1/me/playlists", null) }, - handlePlaylistsResponse(){ - console.log("data") - if ( this.status == 200 ){ - var data = JSON.parse(this.responseText) - console.log(data) - } - else if ( this.status == 401 ){ - refreshAccessToken() - } - else { - console.log(this.responseText) - alert(this.responseText) + deviceApi(method, url, body){ + self = this + let xhr = new XMLHttpRequest() + xhr.open(method, url, true) + xhr.setRequestHeader('Content-Type', 'application/json') + xhr.setRequestHeader('Authorization', 'Bearer ' + this.jukeboxDialog.data.sp_access_token) + xhr.send(body) + xhr.onload = function() { + let responseObj = xhr.response + alert(responseObj) + var i; + for (i = 0; i < responseObj.items.length; i++) { + self.devices.push(responseObj.items[i].name + "-" + responseObj.items[i].id) + } } }, + refreshDevices(){ + self = this + self.deviceApi( "GET", "https://api.spotify.com/v1/me/player/devices", null) + }, + fetchAccessToken( ){ + self = this + let body = "grant_type=authorization_code" + body += "&code=" + self.jukeboxDialog.data.sp_access_token + body += '&redirect_uri=' + encodeURI(self.locationcbPath + self.jukeboxDialog.data.sp_user) + this.callAuthorizationApi(body) + }, refreshAccessToken(){ - refresh_token = localStorage.getItem("refresh_token") + self = this let body = "grant_type=refresh_token" - body += "&refresh_token=" + self.jukeboxDialog.data.sp_token + body += "&refresh_token=" + self.jukeboxDialog.data.sp_refresh_token body += "&client_id=" + self.jukeboxDialog.data.sp_user - callAuthorizationApi(body) + this.callAuthorizationApi(body) }, callAuthorizationApi(body){ + self = this let xhr = new XMLHttpRequest() - xhr.open("POST", TOKEN, true) + xhr.open("POST", "https://accounts.spotify.com/api/token", true) xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded') - xhr.setRequestHeader('Authorization', 'Basic ' + btoa(self.jukeboxDialog.data.sp_user + ":" + self.jukeboxDialog.data.sp_secret)) + xhr.setRequestHeader('Authorization', 'Basic ' + btoa(this.jukeboxDialog.data.sp_user + ":" + this.jukeboxDialog.data.sp_secret)) xhr.send(body) - xhr.onload = handleAuthorizationResponse + console.log(('Authorization', 'Basic ' + btoa(this.jukeboxDialog.data.sp_user + ":" + this.jukeboxDialog.data.sp_secret))) + xhr.onload = function() { + let responseObj = JSON.parse(xhr.response) + alert(responseObj.access_token) + alert(responseObj.refresh_token) + self.jukeboxDialog.data.sp_access_token = responseObj.access_token + self.jukeboxDialog.data.sp_refresh_token = responseObj.refresh_token + console.log(self.jukeboxDialog.data) + self.refreshPlaylists() + self.refreshDevices() + } }, }, created() { @@ -156,5 +209,7 @@ new Vue({ window.location.host, '/jukebox/api/v1/jukebox/spotify/cb/' ].join('')) + console.log(this.locationcbPath) + this.locationcb = this.locationcbPath } }) diff --git a/lnbits/extensions/jukebox/templates/jukebox/index.html b/lnbits/extensions/jukebox/templates/jukebox/index.html index ab056931..07e06ebd 100644 --- a/lnbits/extensions/jukebox/templates/jukebox/index.html +++ b/lnbits/extensions/jukebox/templates/jukebox/index.html @@ -174,7 +174,7 @@ >here.
In the app go to edit-settings, set the redirect URI to this link - (replacing the CLIENT-ID with your own) {% raw %}{{ locationcbPath + (replacing the CLIENT-ID with your own) {% raw %}{{ locationcb }}CLIENT-ID{% endraw %}
- Create Jukebox + Create Jukebox
/", methods=["GET"]) +@jukebox_ext.route("/api/v1/jukebox/spotify/cb/", methods=["GET"]) async def api_check_credentials_callbac(sp_user): + sp_code = "" + sp_access_token = "" + sp_refresh_token = "" + print(request.args) jukebox = await get_jukebox_by_user(sp_user) - jukebox = await update_jukebox( - sp_user=sp_user, sp_secret=jukebox.sp_secret, sp_token=request.args.get('code') - ) + if request.args.get('code'): + sp_code = request.args.get('code') + jukebox = await update_jukebox( + sp_user=sp_user, sp_secret=jukebox.sp_secret, sp_access_token=sp_code + ) + if request.args.get('access_token'): + sp_access_token = request.args.get('access_token') + sp_refresh_token = request.args.get('refresh_token') + jukebox = await update_jukebox( + sp_user=sp_user, sp_secret=jukebox.sp_secret, sp_access_token=sp_access_token, sp_refresh_token=sp_refresh_token + ) return "

Success!

You can close this window

" -@jukebox_ext.route("/api/v1/jukebox/spotify/", methods=["GET"]) +@jukebox_ext.route("/api/v1/jukebox/spotify/", methods=["GET"]) @api_check_wallet_key("invoice") -async def api_check_credentials_check(sp_user): - jukebox = await get_jukebox_by_user(sp_user) +async def api_check_credentials_check(sp_id): + jukebox = await get_jukebox(sp_id) return jsonify(jukebox._asdict()), HTTPStatus.CREATED @@ -49,14 +61,16 @@ async def api_check_credentials_check(sp_user): "wallet": {"type": "string", "empty": False, "required": True}, "sp_user": {"type": "string", "empty": False, "required": True}, "sp_secret": {"type": "string", "required": True}, - "sp_token": {"type": "string", "required": False}, + "sp_access_token": {"type": "string", "required": False}, + "sp_refresh_token": {"type": "string", "required": False}, "sp_device": {"type": "string", "required": False}, "sp_playlists": {"type": "string", "required": False}, "price": {"type": "string", "required": True}, } ) async def api_create_update_jukebox(item_id=None): - print(g.data) + if item_id: + jukebox = await update_jukebox(**g.data) jukebox = await create_jukebox(**g.data) return jsonify(jukebox._asdict()), HTTPStatus.CREATED