single network request function, network error exception, using requests session
closes #3
This commit is contained in:
parent
dd802a0d8f
commit
3e679d37ac
8
alarm.py
8
alarm.py
@ -41,11 +41,9 @@ def check_phone():
|
||||
if __name__ == '__main__':
|
||||
|
||||
try:
|
||||
|
||||
network = Network(NetworkUser(os.environ['SPOT_CLIENT'],
|
||||
os.environ['SPOT_SECRET'],
|
||||
os.environ['SPOT_REFRESH']))
|
||||
network.user.refresh_access_token()
|
||||
network = Network(NetworkUser(client_id=os.environ['SPOT_CLIENT'],
|
||||
client_secret=os.environ['SPOT_SECRET'],
|
||||
refresh_token=os.environ['SPOT_REFRESH'])).refresh_access_token()
|
||||
|
||||
found = False
|
||||
|
||||
|
@ -29,10 +29,9 @@ if __name__ == '__main__':
|
||||
|
||||
# try:
|
||||
|
||||
network = Network(NetworkUser(os.environ['SPOT_CLIENT'],
|
||||
os.environ['SPOT_SECRET'],
|
||||
os.environ['SPOT_REFRESH']))
|
||||
network.user.refresh_access_token()
|
||||
network = Network(NetworkUser(client_id=os.environ['SPOT_CLIENT'],
|
||||
client_secret=os.environ['SPOT_SECRET'],
|
||||
refresh_token=os.environ['SPOT_REFRESH'])).refresh_access_token()
|
||||
playlists = network.get_user_playlists()
|
||||
|
||||
for playlist in playlists:
|
||||
|
@ -122,10 +122,9 @@ def go():
|
||||
logger.critical('none to execute, terminating')
|
||||
return
|
||||
|
||||
net = Network(NetworkUser(os.environ['SPOT_CLIENT'],
|
||||
os.environ['SPOT_SECRET'],
|
||||
os.environ['SPOT_REFRESH']))
|
||||
net.user.refresh_access_token()
|
||||
net = Network(NetworkUser(client_id=os.environ['SPOT_CLIENT'],
|
||||
client_secret=os.environ['SPOT_SECRET'],
|
||||
refresh_token=os.environ['SPOT_REFRESH'])).refresh_access_token()
|
||||
|
||||
engine = PlaylistEngine(net)
|
||||
|
||||
|
@ -14,10 +14,8 @@ stream_handler.setFormatter(stream_formatter)
|
||||
logger.addHandler(stream_handler)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
network = Network(NetworkUser(os.environ['SPOT_CLIENT'],
|
||||
os.environ['SPOT_SECRET'],
|
||||
os.environ['SPOT_REFRESH']))
|
||||
network.user.refresh_access_token()
|
||||
network = Network(NetworkUser(client_id=os.environ['SPOT_CLIENT'],
|
||||
client_secret=os.environ['SPOT_SECRET'],
|
||||
refresh_token=os.environ['SPOT_REFRESH'])).refresh_access_token()
|
||||
|
||||
print(network.user.access_token)
|
||||
|
@ -39,7 +39,7 @@ def listen(verbose, client_id, client_secret, refresh_token):
|
||||
|
||||
net = Network(NetworkUser(client_id=client_id,
|
||||
client_secret=client_secret,
|
||||
refresh_token=refresh_token).refresh_access_token())
|
||||
refresh_token=refresh_token)).refresh_access_token()
|
||||
cmd = ListenCmd(net, stream_handler)
|
||||
cmd.cmdloop()
|
||||
|
||||
|
@ -28,10 +28,9 @@ logger.addHandler(stream_handler)
|
||||
|
||||
def go(playlist_name):
|
||||
|
||||
net = Network(NetworkUser(os.environ['SPOT_CLIENT'],
|
||||
os.environ['SPOT_SECRET'],
|
||||
os.environ['SPOT_REFRESH']))
|
||||
net.user.refresh_access_token()
|
||||
net = Network(NetworkUser(client_id=os.environ['SPOT_CLIENT'],
|
||||
client_secret=os.environ['SPOT_SECRET'],
|
||||
refresh_token=os.environ['SPOT_REFRESH'])).refresh_access_token()
|
||||
|
||||
engine = PlaylistEngine(net)
|
||||
engine.reorder_playlist_by_added_date(playlist_name)
|
||||
|
@ -13,10 +13,7 @@ class AbstractProcessor(ABC):
|
||||
self.playlist_uris = uris
|
||||
|
||||
def has_targets(self) -> bool:
|
||||
if self.playlist_names or self.playlist_uris:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
return bool(self.playlist_names or self.playlist_uris)
|
||||
|
||||
@abstractmethod
|
||||
def process(self, tracks: List[SimplifiedTrack]) -> List[SimplifiedTrack]:
|
||||
@ -69,5 +66,5 @@ class BatchSingleTypeAwareProcessor(BatchSingleProcessor, ABC):
|
||||
return_tracks += malformed_tracks
|
||||
|
||||
return return_tracks
|
||||
else:
|
||||
return tracks
|
||||
|
||||
return tracks
|
||||
|
@ -1,5 +1,5 @@
|
||||
from spotframework.model.track import CurrentlyPlaying
|
||||
from spotframework.net.network import Network
|
||||
from spotframework.net.network import Network, SpotifyNetworkException
|
||||
|
||||
from typing import Optional
|
||||
import logging
|
||||
@ -20,31 +20,40 @@ class Listener:
|
||||
|
||||
self.recent_tracks = []
|
||||
self.prev_now_playing: Optional[CurrentlyPlaying] = None
|
||||
self.now_playing: Optional[CurrentlyPlaying] = net.get_player()
|
||||
self.now_playing = None
|
||||
try:
|
||||
self.now_playing: Optional[CurrentlyPlaying] = net.get_player()
|
||||
except SpotifyNetworkException as e:
|
||||
logger.error(f'error occured retrieving currently playing - {e}')
|
||||
|
||||
self.on_playback_change = []
|
||||
|
||||
def update_now_playing(self):
|
||||
"""update currently playing values"""
|
||||
logger.debug('updating now playing')
|
||||
live_now_playing = self.net.get_player()
|
||||
|
||||
if self.now_playing is None and live_now_playing is None:
|
||||
return
|
||||
try:
|
||||
live_now_playing = self.net.get_player()
|
||||
if self.now_playing is None and live_now_playing is None:
|
||||
return
|
||||
|
||||
if live_now_playing != self.now_playing:
|
||||
self.prev_now_playing = self.now_playing
|
||||
self.now_playing = live_now_playing
|
||||
for func in self.on_playback_change:
|
||||
func(live_now_playing)
|
||||
else:
|
||||
self.now_playing = live_now_playing
|
||||
if live_now_playing != self.now_playing:
|
||||
self.prev_now_playing = self.now_playing
|
||||
self.now_playing = live_now_playing
|
||||
for func in self.on_playback_change:
|
||||
func(live_now_playing)
|
||||
else:
|
||||
self.now_playing = live_now_playing
|
||||
|
||||
except SpotifyNetworkException as e:
|
||||
logger.error(f'error occured retrieving currently playing - {e}')
|
||||
|
||||
def update_recent_tracks(self):
|
||||
"""retrieve recently played tracks and merge with previously stored"""
|
||||
logger.debug('updating recent tracks')
|
||||
tracks = self.net.get_recently_played_tracks(response_limit=self.request_size)
|
||||
if tracks is not None:
|
||||
|
||||
try:
|
||||
tracks = self.net.get_recently_played_tracks(response_limit=self.request_size)
|
||||
for track in tracks:
|
||||
if track.played_at not in [i.played_at for i in self.recent_tracks]:
|
||||
self.recent_tracks.append(track)
|
||||
@ -52,5 +61,6 @@ class Listener:
|
||||
self.recent_tracks.sort(key=lambda x: x.played_at)
|
||||
if self.max_recent_tracks is not None:
|
||||
self.recent_tracks = self.recent_tracks[-self.max_recent_tracks:]
|
||||
else:
|
||||
logger.error('no recent tracks returned')
|
||||
|
||||
except SpotifyNetworkException as e:
|
||||
logger.error(f'error occured retrieving recent tracks - {e}')
|
||||
|
@ -6,7 +6,3 @@ class Image:
|
||||
height: int
|
||||
width: int
|
||||
url: str
|
||||
|
||||
@staticmethod
|
||||
def wrap(**kwargs):
|
||||
return Image(**kwargs)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,26 +1,18 @@
|
||||
from __future__ import annotations
|
||||
import requests
|
||||
from spotframework.model.user import PublicUser
|
||||
from spotframework.util.console import Color
|
||||
from dataclasses import dataclass, field
|
||||
from base64 import b64encode
|
||||
import logging
|
||||
import time
|
||||
from typing import Optional, List
|
||||
from datetime import datetime, timezone
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
from typing import List
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
@dataclass
|
||||
class NetworkUser:
|
||||
|
||||
access_token: str
|
||||
refresh_token: str
|
||||
|
||||
client_id: str
|
||||
client_secret: str
|
||||
|
||||
access_token: str = None
|
||||
refresh_token: str = None
|
||||
|
||||
user: PublicUser = field(default=None, init=False)
|
||||
|
||||
last_refreshed: datetime = field(default=None, init=False)
|
||||
@ -29,93 +21,3 @@ class NetworkUser:
|
||||
on_refresh: List = field(default_factory=list, init=False)
|
||||
|
||||
refresh_counter: int = field(default=0, init=False)
|
||||
|
||||
def refresh_access_token(self) -> NetworkUser:
|
||||
|
||||
if self.refresh_token is None:
|
||||
raise NameError('no refresh token to query')
|
||||
|
||||
if self.client_id is None:
|
||||
raise NameError('no client id')
|
||||
|
||||
if self.client_secret is None:
|
||||
raise NameError('no client secret')
|
||||
|
||||
idsecret = b64encode(bytes(self.client_id + ':' + self.client_secret, "utf-8")).decode("ascii")
|
||||
headers = {'Authorization': 'Basic %s' % idsecret}
|
||||
|
||||
data = {"grant_type": "refresh_token", "refresh_token": self.refresh_token}
|
||||
|
||||
now = datetime.utcnow()
|
||||
req = requests.post('https://accounts.spotify.com/api/token', data=data, headers=headers)
|
||||
|
||||
if 200 <= req.status_code < 300:
|
||||
logger.debug('token refreshed')
|
||||
resp = req.json()
|
||||
self.access_token = resp['access_token']
|
||||
if resp.get('refresh_token', None):
|
||||
self.refresh_token = resp['refresh_token']
|
||||
self.token_expiry = resp['expires_in']
|
||||
self.last_refreshed = now
|
||||
for func in self.on_refresh:
|
||||
func(self)
|
||||
else:
|
||||
|
||||
if req.status_code == 429:
|
||||
retry_after = req.headers.get('Retry-After', None)
|
||||
|
||||
if retry_after:
|
||||
logger.warning(f'rate limit reached: retrying in {retry_after} seconds')
|
||||
time.sleep(int(retry_after) + 1)
|
||||
return self.refresh_access_token()
|
||||
else:
|
||||
logger.error('rate limit reached: cannot find Retry-After header')
|
||||
|
||||
else:
|
||||
error_text = req.json().get('error', 'n/a')
|
||||
error_description = req.json().get('error_description', 'n/a')
|
||||
logger.error(f'get {req.status_code} {error_text} - {error_description}')
|
||||
|
||||
return self
|
||||
|
||||
def refresh_info(self) -> None:
|
||||
self.user = PublicUser(**self.get_info())
|
||||
|
||||
def get_info(self) -> Optional[dict]:
|
||||
|
||||
headers = {'Authorization': 'Bearer %s' % self.access_token}
|
||||
|
||||
req = requests.get('https://api.spotify.com/v1/me', headers=headers)
|
||||
|
||||
if 200 <= req.status_code < 300:
|
||||
logger.debug(f'retrieved {req.status_code}')
|
||||
return req.json()
|
||||
else:
|
||||
|
||||
if req.status_code == 429:
|
||||
retry_after = req.headers.get('Retry-After', None)
|
||||
|
||||
if retry_after:
|
||||
logger.warning(f'rate limit reached: retrying in {retry_after} seconds')
|
||||
time.sleep(int(retry_after) + 1)
|
||||
return self.get_info()
|
||||
else:
|
||||
logger.error('rate limit reached: cannot find Retry-After header')
|
||||
|
||||
elif req.status_code == 401:
|
||||
logger.warning('access token expired, refreshing')
|
||||
self.refresh_access_token()
|
||||
if self.refresh_counter < 5:
|
||||
self.refresh_counter += 1
|
||||
return self.get_info()
|
||||
else:
|
||||
self.refresh_counter = 0
|
||||
logger.critical('refresh token limit (5) reached')
|
||||
|
||||
else:
|
||||
error = req.json().get('error', None)
|
||||
if error:
|
||||
message = error.get('message', 'n/a')
|
||||
logger.error(f'{req.status_code} {message}')
|
||||
else:
|
||||
logger.error(f'{req.status_code} no error object found')
|
||||
|
@ -1,8 +1,7 @@
|
||||
from spotframework.net.network import Network
|
||||
from spotframework.net.network import Network, SpotifyNetworkException
|
||||
from spotframework.model.track import SimplifiedTrack, Context, Device
|
||||
from spotframework.model.album import AlbumFull
|
||||
from spotframework.model.playlist import FullPlaylist
|
||||
from spotframework.model.uri import Uri
|
||||
from typing import List, Union
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -23,14 +22,20 @@ class Player:
|
||||
|
||||
@property
|
||||
def available_devices(self):
|
||||
return self.net.get_available_devices()
|
||||
try:
|
||||
return self.net.get_available_devices()
|
||||
except SpotifyNetworkException as e:
|
||||
logger.error(f'error retrieving current devices - {e}')
|
||||
|
||||
@property
|
||||
def status(self):
|
||||
new_status = self.net.get_player()
|
||||
if new_status:
|
||||
self.last_status = new_status
|
||||
return self.last_status
|
||||
try:
|
||||
new_status = self.net.get_player()
|
||||
if new_status:
|
||||
self.last_status = new_status
|
||||
return self.last_status
|
||||
except SpotifyNetworkException as e:
|
||||
logger.error(f'error retrieving current devices - {e}')
|
||||
|
||||
def play(self,
|
||||
context: Union[Context, AlbumFull, FullPlaylist] = None,
|
||||
@ -43,55 +48,76 @@ class Player:
|
||||
if searched_device:
|
||||
device = searched_device
|
||||
|
||||
if context and (tracks or uris):
|
||||
raise Exception('cant execute context and track list')
|
||||
if context:
|
||||
if device:
|
||||
self.net.play(uri=context.uri, deviceid=device.id)
|
||||
try:
|
||||
if context and (tracks or uris):
|
||||
raise Exception('cant execute context and track list')
|
||||
if context:
|
||||
if device:
|
||||
self.net.play(uri=context.uri, deviceid=device.id)
|
||||
else:
|
||||
self.net.play(uri=context.uri)
|
||||
elif tracks or uris:
|
||||
|
||||
if tracks is None:
|
||||
tracks = []
|
||||
|
||||
if uris is None:
|
||||
uris = []
|
||||
|
||||
if device:
|
||||
self.net.play(uris=[i.uri for i in tracks] + uris, deviceid=device.id)
|
||||
else:
|
||||
self.net.play(uris=[i.uri for i in tracks] + uris)
|
||||
else:
|
||||
self.net.play(uri=context.uri)
|
||||
elif tracks or uris:
|
||||
|
||||
if tracks is None:
|
||||
tracks = []
|
||||
|
||||
if uris is None:
|
||||
uris = []
|
||||
|
||||
if device:
|
||||
self.net.play(uris=[i.uri for i in tracks] + uris, deviceid=device.id)
|
||||
else:
|
||||
self.net.play(uris=[i.uri for i in tracks] + uris)
|
||||
else:
|
||||
self.net.play()
|
||||
self.net.play()
|
||||
except SpotifyNetworkException as e:
|
||||
logger.error(f'error playing - {e}')
|
||||
|
||||
def change_device(self, device: Device):
|
||||
self.net.change_playback_device(device.id)
|
||||
try:
|
||||
self.net.change_playback_device(device.id)
|
||||
except SpotifyNetworkException as e:
|
||||
logger.error(f'error changing device to {device.name} - {e}')
|
||||
|
||||
def pause(self):
|
||||
self.net.pause()
|
||||
try:
|
||||
self.net.pause()
|
||||
except SpotifyNetworkException as e:
|
||||
logger.error(f'error pausing - {e}')
|
||||
|
||||
def toggle_playback(self):
|
||||
status = self.status
|
||||
if status:
|
||||
if status.is_playing:
|
||||
self.pause()
|
||||
try:
|
||||
if status:
|
||||
if status.is_playing:
|
||||
self.pause()
|
||||
else:
|
||||
self.play()
|
||||
else:
|
||||
logger.warning('no current playback, playing')
|
||||
self.play()
|
||||
else:
|
||||
logger.warning('no current playback, playing')
|
||||
self.play()
|
||||
except SpotifyNetworkException as e:
|
||||
logger.error(f'error toggling playback - {e}')
|
||||
|
||||
def next(self):
|
||||
self.net.next()
|
||||
try:
|
||||
self.net.next()
|
||||
except SpotifyNetworkException as e:
|
||||
logger.error(f'error skipping track - {e}')
|
||||
|
||||
def previous(self):
|
||||
self.net.previous()
|
||||
try:
|
||||
self.net.previous()
|
||||
except SpotifyNetworkException as e:
|
||||
logger.error(f'error reversing track - {e}')
|
||||
|
||||
def shuffle(self, state=None):
|
||||
if state is not None:
|
||||
if isinstance(state, bool):
|
||||
self.net.set_shuffle(state)
|
||||
try:
|
||||
self.net.set_shuffle(state)
|
||||
except SpotifyNetworkException as e:
|
||||
logger.error(f'error setting shuffle - {e}')
|
||||
else:
|
||||
raise TypeError(f'{state} is not bool')
|
||||
else:
|
||||
@ -104,9 +130,12 @@ class Player:
|
||||
def volume(self, value: int, device: Device = None):
|
||||
|
||||
if 0 <= int(value) <= 100:
|
||||
if device:
|
||||
self.net.set_volume(value, deviceid=device.id)
|
||||
else:
|
||||
self.net.set_volume(value)
|
||||
try:
|
||||
if device:
|
||||
self.net.set_volume(value, deviceid=device.id)
|
||||
else:
|
||||
self.net.set_volume(value)
|
||||
except SpotifyNetworkException as e:
|
||||
logger.error(f'error setting volume to {value} - {e}')
|
||||
else:
|
||||
logger.error(f'{value} not between 0 and 100')
|
||||
|
Loading…
Reference in New Issue
Block a user