From 2482ffa9cce50337e7f9e03e93504c55ccf62621 Mon Sep 17 00:00:00 2001 From: s4w3d0ff Date: Mon, 3 Feb 2025 08:43:11 -0700 Subject: [PATCH] fix for #2 and other tweaks --- spotifio/client.py | 4 ++-- spotifio/oauth.py | 44 ++++++++++++++++++++++---------------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/spotifio/client.py b/spotifio/client.py index 57d2677..098b617 100644 --- a/spotifio/client.py +++ b/spotifio/client.py @@ -122,9 +122,9 @@ async def _check_scope(self, method_name): if missing_scopes: raise Exception(f"Missing required scopes for {method_name}: {', '.join(missing_scopes)}") - async def login(self): + async def login(self, token=None): """ Sets up the token """ - await self.token_handler._login() + await self.token_handler._login(token) async def _request(self, method, endpoint, params=None, data=None, headers=None): """ Base Request Method for Spotify API calls """ diff --git a/spotifio/oauth.py b/spotifio/oauth.py index f1122b4..869d6c0 100644 --- a/spotifio/oauth.py +++ b/spotifio/oauth.py @@ -1,7 +1,7 @@ import aiohttp import asyncio import webbrowser -import random +import os import base64 import logging import time @@ -24,14 +24,6 @@ """ - -def randString(length=12, chars=None): - if not chars: - import string - chars = string.ascii_letters + string.digits - ranstr = ''.join(random.choice(chars) for _ in range(length)) - return ranstr - class WebServer: def __init__(self, host, port): self.app = web.Application() @@ -68,7 +60,7 @@ def __init__(self, client_id, client_secret, redirect_uri=None, scope=[], storag self.redirect_uri = redirect_uri or "http://localhost:8888/callback" self.scope = scope self.storage = storage or JSONStorage() - self._state = randString(16) + self._state = os.urandom(14).hex() self._auth_code = None self._auth_future = None self._token = None @@ -96,7 +88,7 @@ async def _callback_handler(self, request): return web.Response(text=closeBrowser, content_type='text/html', charset='utf-8') async def _get_auth_code(self): - logger.warning(f"Getting Oauth code...") + logger.warning(f"Opening browser to get Oauth code...") await self.server.start() self._auth_future = asyncio.Future() params = { @@ -107,12 +99,18 @@ async def _get_auth_code(self): } if self.scope: params['scope'] = ' '.join(self.scope) - # open webbrowser with auth link - webbrowser.open(f"https://accounts.spotify.com/authorize?{urlencode(params)}") + auth_link = f"https://accounts.spotify.com/authorize?{urlencode(params)}" + try: + # open webbrowser with auth link + webbrowser.open(auth_link) + except: + # cant open webbrowser, show auth link for user to copy/paste + logger.error(f"Couldn't open default browser!: \n{auth_link}") # wait for auth code await self._auth_future # stop webserver await self.server.stop() + logger.warning(f"Got Oauth code!") async def _token_request(self, data): """ Base token request method, used for new or refreshing tokens """ @@ -144,8 +142,8 @@ async def _refresh_token(self): async def _get_new_token(self): """ Get a new oauth token using the oauth code, get code if we dont have one yet """ - logger.warning(f"Getting new token...") await self._get_auth_code() + logger.warning(f"Getting new token...") return await self._token_request({ "grant_type": "authorization_code", "code": self._auth_code, @@ -156,10 +154,11 @@ async def _token_refresher(self): """ Waits for the time to refresh the token and refreshes """ self._running = True self._refresh_event.set() + logger.debug(f"_token_refresher started...") while self._running: time_left = self._token['expires_time'] - time.time() - logger.info(f"Token expires in {time_left} seconds...") - if time_left <= 0: + logger.debug(f"Token expires in {time_left} seconds...") + if time_left-60 <= 0: # pause 'self.get_token' self._refresh_event.clear() # refresh token @@ -167,18 +166,19 @@ async def _token_refresher(self): # resume 'self.get_token' self._refresh_event.set() continue # skip sleep to get new time_left - await asyncio.sleep(time_left+0.5) + await asyncio.sleep(time_left-60) async def _login(self, token=None): """ Checks storage for saved token, gets new token if one isnt found. Starts the token refresher task.""" self._token = token + self._refresh_task = None if not self._token: - logger.warning(f"Attempting to load saved token...") - self._refresh_task = None + logger.debug(f"Attempting to load saved token...") self._token = await self.storage.load_token(name="spotify") - if not self._token: - logger.warning(f"No token found in storage!") - self._token = await self._get_new_token() + if self._token: + logger.warning(f"Loaded saved token from storage!") + else: + self._token = await self._get_new_token() self._refresh_task = asyncio.create_task(self._token_refresher()) async def get_token(self):