Example #1
0
        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'))
Example #2
0
 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]))
Example #3
0
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))
Example #4
0
    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()
Example #5
0
    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
Example #6
0
    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()
Example #7
0
    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')
Example #8
0
    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()