def change_shuffle_with_web_api(response): toggled_shuffle = not response.json().get('shuffle_state') self.call_web_method('me/player/shuffle', 'put', params={'state': toggled_shuffle}) send_notif( 'Shuffle toggled', 'Shuffle now {}'.format( 'enabled' if toggled_shuffle else 'disabled'))
def change_state_with_web_api(response): repeat_state = response.json().get('repeat_state') next_state = self.repeat_states[ self.repeat_states.index(repeat_state) - 1] self.call_web_method('me/player/repeat', 'put', params={'state': next_state}) send_notif( 'Repeat changed', 'Repeating is now set to: {}'.format( self.get_shuffle_and_repeat_state()[1]))
def open_bindings_file(): send_notif( 'Changing bindings', 'Please restart the Spotify Helper app after ' 'saving your changes') current_os = platform.system() if current_os == 'Darwin': # macOS subprocess.call(('open', bindings_file)) elif current_os == 'Windows': # Windows os.startfile(bindings_file) else: # Linux subprocess.call(('xdg-open', bindings_file))
def run_method(self, method): try: getattr(self.spotify, method)() except ConnectionError: send_notif('Connection Error', 'Internet connection not available') except AlreadyNotifiedException: pass except Exception as e: send_notif('Error', 'Something went wrong') logging.error('{}:{}'.format(e, traceback.format_exc())) traceback.print_exc()
def call_web_method(self, method, rest_function_name, params=None, payload=None): # 'get' functions don't have payloads. if rest_function_name == 'get': response = getattr(self.web_api, rest_function_name)(method, params=params) # get_active_devices() is here to avoid unnecessarily calls if not using the Web API when calling play(), # which has no payload. elif method == 'me/player' and rest_function_name == 'put': response = getattr(self.web_api, rest_function_name)( method, params=params, payload={ 'device_ids': [self.get_active_device().get('id')], 'play': True } if payload is None else payload) else: response = getattr(self.web_api, rest_function_name)(method, params=params, payload=payload) status_code = response.status_code # 'get' with no further method returns information about the user's playback. # 204s are usually successes, but in this case it means no active devices exist. if status_code == 204 and method == 'me/player' and rest_function_name == 'get': send_notif('Error', 'No device found') raise AlreadyNotifiedException elif 200 <= status_code <= 299: # These responses are fine return response info = response.json() # Player errors also return a reason, which we use to notify with the appropriate message from config.ini, # though it appears nearly all reasons will always be UNKNOWN, an issue with the Spotify API. if 'error' in info and 'reason' in info.get('error'): reason = info.get('error').get('reason') response = config['player_error_strings'][reason] send_notif('Player Error', response) raise AlreadyNotifiedException if status_code >= 300: logging.warning('Request {} failed with code {}'.format( response.text, status_code)) logging.warning('Fail message: {}'.format( response.json().get('error').get('message'))) raise Exception return response
def __init__(self): try: self.spotify = Spotify() except requests.exceptions.ConnectionError: send_notif('Spotify Helper closed', 'Check you have a working internet connection.') sys.exit(1) self.currently_pressed_keys = list() self.looking_for = {} self.has_released_key = True self.load_bindings_from_file(bindings_file) self.atomic_method_groups = SpotifyHelper.get_atomic_method_groups() self.method_group_thread_queues = self.get_method_group_thread_queues()
def get_access_info(self): timeout = time.time() while time.time( ) < timeout + 120: # We spend 2 minutes waiting for auth confirmation response = requests.post(self.register_user_url, json={'uuid': str(self.uuid)}) if response.status_code == 200: logging.info('initial authentication done.') send_notif('Success', 'You are now authenticated.') return response.json() time.sleep(3) send_notif('Could not authenticate', 'Spotify Helper closed.') sys.exit('Could not authenticate')
def refresh_tokens(self): payload = { 'grant_type': 'refresh_token', 'refresh_token': self.refresh_token, 'uuid': str(self.uuid) } obtained_time = time.time() try: r = requests.post(self.refresh_token_url, json=payload, timeout=4) except (requests.exceptions.ConnectionError, requests.exceptions.ReadTimeout): raise ConnectionError # 403 indicates the user UUID is not registered on the server, if r.status_code == 403: send_notif('Authentication error', 'Please re-authenticate, or try restarting the app.') self.get_auth_info() logging.warning('Authentication refresh failed, info: {}'.format( r.content)) return # Values get saved in get_auth_info() # If we need additional permissions and have added them to the scope, the # old keys will not work, and we need new authentication info. # 400-499 means there is a general user error, so we start anew with # the authentication process. if (400 <= r.status_code < 500) or \ (not set(r.json().get('scope').split(' ')).issuperset(set(self.scope_list))): self.get_auth_info() return info = r.json() if 'refresh_token' in info: self.refresh_token = info.get('refresh_token') self.save_auth_values(info.get('access_token'), self.refresh_token, obtained_time + info.get('expires_in')) self.load_auth_values()