def device_auth(): code_data = get_device_code() if not code_data: logger.error('Failed device auth.') sys.exit(1) logger.info(f"Verification URL: {code_data['verification_url']}") logger.info(f"User Code: {code_data['user_code']}") notify("Open {verification_url} in your browser and enter this code: " "{user_code}".format(**code_data), timeout=60, stdout=True) webbrowser.open(code_data['verification_url']) start = time.time() while time.time() - start < code_data['expires_in']: token_data = get_device_token(code_data['device_code']) if not token_data: logger.debug('Waiting for user to authorize the app.') time.sleep(int(code_data['interval'])) else: notify('App authorized successfully.', stdout=True) logger.info('Device auth successful.') break else: logger.error('Timed out during auth.') return token_data
def merge_categories(root: dict, user, default=True, parents=[]): """Merge data from user config with default categories""" if not isinstance(user, (dict, bool)): logger.error(f"Invalid value {user} for category {'.'.join(parents)}") return if isinstance(user, dict): # check for extra keys not present in existing categories extra = set(user.keys()).difference(root) if extra: msg = f"Extra categor{'ies' if len(extra) > 1 else 'y'}" if parents: msg += f" under {'.'.join(parents)}" msg += f": {', '.join(extra)}" logger.warning(msg) for k, v in root.items(): value = user if isinstance(user, bool) else user.get(k, default) if v: # recurse for sub-categories parents.append(k) merge_categories(v, value, default) parents.pop() elif isinstance(value, bool): root[k] = value else: logger.error( f"Expected bool(true/false) but found {value} for category " f"{'.'.join(parents + [k])}" )
def autoload_cfg(cls): template = getattr(cls, 'CONFIG_TEMPLATE', None) monitor_cfg = config['players'][cls.name].get(template) auto_keys = {k for k, v in monitor_cfg.items() if v == "auto-detect"} if not auto_keys: return monitor_cfg try: loaders = getattr(cls, "read_player_cfg")(auto_keys) except AttributeError: logger.debug(f"Auto val not found for {', '.join(auto_keys)}") logger.error(f"Autoload not supported for {cls.name}.") raise AutoloadError except FileNotFoundError as e: raise AutoloadError(src=e.filename) while auto_keys: param = auto_keys.pop() try: param_loader = loaders[param] except KeyError: logger.error(f"Autoload not supported for '{param}'.") raise AutoloadError(param) try: monitor_cfg[param] = param_loader() logger.debug( f"Autoloaded {cls.name} {param} = {monitor_cfg[param]}") except FileNotFoundError as e: raise AutoloadError(src=e.filename) return monitor_cfg
def refresh_token(self): if self._refresh_retries == self._REFRESH_RETRIES_LIMIT: self.token_data = {} self._refresh_retries = 0 logger.critical("Too many failed refreshes. Clearing token.") notify("Trakt token expired. Couldn't auto-refresh token.", stdout=True) self.device_auth() return exchange_params = { "url": API_URL + '/oauth/token', "headers": {"Content-Type": "application/json"}, "json": { "refresh_token": self.token_data['refresh_token'], "client_id": self.CLIENT_ID, "client_secret": self.CLIENT_SECRET, "redirect_uri": "urn:ietf:wg:oauth:2.0:oob", "grant_type": "refresh_token" } } self._refresh_retries += 1 exchange_resp = safe_request('post', exchange_params) if exchange_resp and exchange_resp.status_code == 200: self.token_data = exchange_resp.json() self._refresh_retries = 0 logger.info('Refreshed access token.') else: logger.error("Error refreshing token.")
def device_auth(self): code_data = self.get_device_code() if not code_data: logger.error("Could not get device code.") return logger.info(f"Verification URL: {code_data['verification_url']}") logger.info(f"User Code: {code_data['user_code']}") notify( "Open {verification_url} in your browser and enter this code: " "{user_code}".format(**code_data), timeout=30, stdout=True, category="trakt") # automatically open the url in the default browser # but we don't want to use terminal-based browsers - most likely not # what the user wants term_bak = os.environ.pop("TERM", None) webbrowser.open(code_data['verification_url']) if term_bak is not None: os.environ["TERM"] = term_bak start = time.time() while time.time() - start < code_data['expires_in']: if self.get_device_token(code_data['device_code']): notify('App authorized successfully.', stdout=True, category="trakt") logger.info('App authorized successfully.') break logger.debug('Waiting for user to authorize the app.') time.sleep(int(code_data['interval'])) else: logger.error('Timed out during auth.')
def device_auth(self): code_data = self.get_device_code() if not code_data: logger.error("Could not get device code.") return logger.info(f"Verification URL: {code_data['verification_url']}") logger.info(f"User Code: {code_data['user_code']}") notify("Open {verification_url} in your browser and enter this code: " "{user_code}".format(**code_data), timeout=30, stdout=True, category="trakt") webbrowser.open(code_data['verification_url']) start = time.time() while time.time() - start < code_data['expires_in']: if self.get_device_token(code_data['device_code']): notify('App authorized successfully.', stdout=True, category="trakt") logger.info('App authorized successfully.') break logger.debug('Waiting for user to authorize the app.') time.sleep(int(code_data['interval'])) else: logger.error('Timed out during auth.')
def __new__(cls, *args, **kwargs): try: cls.config = cls.autoload_cfg() except AutoloadError as e: logger.debug(str(e)) logger.error(f"Config value autoload failed for {cls.name}.") except Exception: logger.exception(f"Config value autoload failed for {cls.name}.") else: return super().__new__(cls)
def __new__(cls, *args, **kwargs): try: cls.inject_base_config() cls.config = cls.autoload_cfg() except AutoloadError as e: logger.debug(str(e)) logger.error(f"Config value autoload failed for {cls.name}.") notify(f"Check log file. {e!s}", category="exception") except Exception: msg = f"Config value autoload failed for {cls.name}." logger.exception(msg) notify(f"{msg} Check log file.", category="exception") else: return super().__new__(cls)
def get_token(self): logger.info("Retrieving plex token") login = self.ask("Plex login ID:") pwd = self.secret("Plex password:"******"user"]["authToken"] elif resp is not None: err_msg = resp.json().get("error", resp.text) self.line(err_msg, "error") logger.error(err_msg) return None else: logger.error("Unable to get access token") return None
def __init__(self, scrobble_queue): try: self.token = get_token() self.URL = self.URL.format(**self.config) except KeyError: logger.exception("Check config for correct Plex params.") return if not self.token: logger.error("Unable to retrieve plex token.") return super().__init__(scrobble_queue) self.sess.headers["Accept"] = "application/json" self.sess.headers["X-Plex-Token"] = self.token self.session_url = self.URL + "/status/sessions" self.media_info_cache = {}
def handle_cmd_response(self, resp): command = self.sent_commands.pop(resp['request_id']) if resp['error'] != 'success': logger.error(f'Error with command {command!s}. Response: {resp!s}') return elif command[0] != 'get_property': return param = command[1] data = resp['data'] if param == 'pause': self.vars['state'] = 1 if data else 2 if param in self.WATCHED_PROPS: self.vars[param] = data self.updated_props_count += 1 if self.updated_props_count == len(self.WATCHED_PROPS): self.update_status()
def get_access_token(): global token_data if not token_data: logger.info("Access token not found in config. " "Initiating device authentication.") token_data = device_auth() write_json(token_data, TRAKT_TOKEN_PATH) elif token_data['created_at'] + token_data['expires_in'] - \ time.time() < 86400: logger.info("Access token about to expire. Refreshing.") token_data = refresh_token(token_data) write_json(token_data, TRAKT_TOKEN_PATH) if not token_data: logger.error("Unable to get access token. " f"Try deleting {TRAKT_TOKEN_PATH!s} and retry.") notify("Failed to authorize application.", stdout=True) sys.exit(1) return token_data['access_token']
def run(self): while True: try: self.update_status() except requests.ConnectionError: logger.info(f'Unable to connect to {self.name}. Ensure that ' 'the web interface is running.') self.status = {} except requests.HTTPError as e: logger.error(f"Error while getting data from {self.name}: {e}") break if not self.status.get("filepath") and not self.status.get( "media_info"): self.status = {} self.handle_status_update() time.sleep(self.poll_interval) logger.warning(f"{self.name} monitor stopped")
def get_token(): global token_data if not token_data: logger.info("Retrieving plex token") login = input("Plex login ID: ") pwd = getpass() resp = plex_token_auth(login, pwd) if resp.ok: token_data = {"token": resp.json()["user"]["authToken"]} write_json(token_data, PLEX_TOKEN_PATH) logger.info(f"Saved plex token to {PLEX_TOKEN_PATH}") elif resp is not None: print(resp.json().get("error", resp.text)) return None else: logger.error("Unable to get access token. " f"Try deleting {PLEX_TOKEN_PATH!s} and retry.") return None return token_data['token']
def get_device_token(device_code): token_request_params = { "url": API_URL + "/oauth/device/token", "headers": {"Content-Type": "application/json"}, "json": { "code": device_code, "client_id": CLIENT_ID, "client_secret": CLIENT_SECRET } } token_resp = safe_request('post', token_request_params) if not token_resp: return elif token_resp.status_code == 400: return elif token_resp.status_code == 200: return token_resp.json() else: logger.error('Invalid status code of token response.') sys.exit(1)