def query(self, key, method=None, headers=None, timeout=None, **kwargs): """ Main method used to handle HTTPS requests to the Plex server. This method helps by encoding the response to utf-8 and parsing the returned XML into and ElementTree object. Returns None if no data exists in the response. """ url = self.url(key) method = method or self._session.get timeout = timeout or TIMEOUT log.debug('%s %s', method.__name__.upper(), url) headers = self._headers(**headers or {}) response = method(url, headers=headers, timeout=timeout, **kwargs) if response.status_code not in (200, 201, 204): codename = codes.get(response.status_code)[0] errtext = response.text.replace('\n', ' ') message = '(%s) %s; %s %s' % (response.status_code, codename, response.url, errtext) if response.status_code == 401: raise Unauthorized(message) elif response.status_code == 404: raise NotFound(message) else: raise BadRequest(message) data = response.text.encode('utf8') return ElementTree.fromstring(data) if data.strip() else None
def signin(cls, username=None, password=None, session=None): """ Returns a new :class:`~myplex.MyPlexAccount` object by connecting to MyPlex with the specified username and password. This is essentially logging into MyPlex and often the very first entry point to using this API. Parameters: username (str): Your MyPlex.tv username. If not specified, it will check the config.ini file. password (str): Your MyPlex.tv password. If not specified, it will check the config.ini file. Raises: :class:`~plexapi.exceptions.Unauthorized`: (401) If the username or password are invalid. :class:`~plexapi.exceptions.BadRequest`: If any other errors occured not allowing us to log into MyPlex.tv. """ if 'X-Plex-Token' in plexapi.BASE_HEADERS: del plexapi.BASE_HEADERS['X-Plex-Token'] username = username or CONFIG.get('authentication.username') password = password or CONFIG.get('authentication.password') auth = (username, password) log.info('POST %s', cls.SIGNIN) sess = session or requests.Session() response = sess.post(cls.SIGNIN, headers=plexapi.BASE_HEADERS, auth=auth, timeout=TIMEOUT) if response.status_code != requests.codes.created: codename = codes.get(response.status_code)[0] if response.status_code == 401: raise Unauthorized('(%s) %s' % (response.status_code, codename)) raise BadRequest('(%s) %s' % (response.status_code, codename)) data = ElementTree.fromstring(response.text.encode('utf8')) return MyPlexAccount(data, cls.SIGNIN, session=sess)
def signin(cls, username, password): """Summary Args: username (str): username password (str): password Returns: class: MyPlexAccount Raises: BadRequest: (HTTPCODE) http codename Unauthorized: (HTTPCODE) http codename """ if 'X-Plex-Token' in plexapi.BASE_HEADERS: del plexapi.BASE_HEADERS['X-Plex-Token'] auth = (username, password) log.info('POST %s', cls.SIGNIN) response = requests.post(cls.SIGNIN, headers=plexapi.BASE_HEADERS, auth=auth, timeout=TIMEOUT) if response.status_code != requests.codes.created: codename = codes.get(response.status_code)[0] if response.status_code == 401: raise Unauthorized('(%s) %s' % (response.status_code, codename)) raise BadRequest('(%s) %s' % (response.status_code, codename)) data = ElementTree.fromstring(response.text.encode('utf8')) return cls(data, cls.SIGNIN)
def __init__(self, bot, **kwargs): """ Initializes Plex resources Connects to Plex library and sets up all asyncronous communications. Args: bot: discord.ext.command.Bot, bind for cogs base_url: str url to Plex server plex_token: str X-Token of Plex server lib_name: str name of Plex library to search through Raises: plexapi.exceptions.Unauthorized: Invalid Plex token Returns: None """ self.bot = bot self.base_url = kwargs["base_url"] self.plex_token = kwargs["plex_token"] self.library_name = kwargs["lib_name"] self.bot_prefix = bot.command_prefix if kwargs["lyrics_token"]: self.genius = lyricsgenius.Genius(kwargs["lyrics_token"]) else: plex_log.warning("No lyrics token specified, lyrics disabled") self.genius = None # Log fatal invalid plex token try: self.pms = PlexServer(self.base_url, self.plex_token) except Unauthorized: plex_log.fatal("Invalid Plex token, stopping...") raise Unauthorized("Invalid Plex token") self.music = self.pms.library.section(self.library_name) plex_log.debug("Connected to plex library: %s", self.library_name) # Initialize necessary vars self.voice_channel = None self.current_track = None self.np_message_id = None self.ctx = None # Initialize events self.play_queue = asyncio.Queue() self.play_next_event = asyncio.Event() bot_log.info("Started bot successfully") self.bot.loop.create_task(self._audio_player_task())
def signin(cls, username, password): if 'X-Plex-Token' in plexapi.BASE_HEADERS: del plexapi.BASE_HEADERS['X-Plex-Token'] auth = (username, password) log.info('POST %s', cls.SIGNIN) response = requests.post(cls.SIGNIN, headers=plexapi.BASE_HEADERS, auth=auth, timeout=TIMEOUT) if response.status_code != requests.codes.created: codename = codes.get(response.status_code)[0] if response.status_code == 401: raise Unauthorized('(%s) %s' % (response.status_code, codename)) raise BadRequest('(%s) %s' % (response.status_code, codename)) data = ElementTree.fromstring(response.text.encode('utf8')) return cls(data, cls.SIGNIN)
def connect(self): """Connect to a Plex server directly, obtaining direct URL if necessary.""" config_entry_update_needed = False def _connect_with_token(): available_servers = [(x.name, x.clientIdentifier) for x in self.account.resources() if "server" in x.provides and x.presence] if not available_servers: raise NoServersFound if not self._server_name and len(available_servers) > 1: raise ServerNotSpecified(available_servers) self.server_choice = (self._server_name if self._server_name else available_servers[0][0]) self._plex_server = self.account.resource( self.server_choice).connect(timeout=10) def _connect_with_url(): session = None if self._url.startswith("https") and not self._verify_ssl: session = Session() session.verify = False self._plex_server = plexapi.server.PlexServer( self._url, self._token, session) def _update_plexdirect_hostname(): matching_servers = [ x.name for x in self.account.resources() if x.clientIdentifier == self._server_id ] if matching_servers: self._plex_server = self.account.resource( matching_servers[0]).connect(timeout=10) return True _LOGGER.error("Attempt to update plex.direct hostname failed") return False if self._url: try: _connect_with_url() except requests.exceptions.SSLError as error: while error and not isinstance(error, ssl.SSLCertVerificationError): error = error.__context__ if isinstance(error, ssl.SSLCertVerificationError): domain = urlparse(self._url).netloc.split(":")[0] if domain.endswith( "plex.direct") and error.args[0].startswith( f"hostname '{domain}' doesn't match"): _LOGGER.warning( "Plex SSL certificate's hostname changed, updating" ) if _update_plexdirect_hostname(): config_entry_update_needed = True else: raise Unauthorized( # pylint: disable=raise-missing-from "New certificate cannot be validated with provided token" ) else: raise else: raise else: _connect_with_token() try: system_accounts = self._plex_server.systemAccounts() shared_users = self.account.users() if self.account else [] except Unauthorized: _LOGGER.warning( "Plex account has limited permissions, shared account filtering will not be available" ) else: self._accounts = [] for user in shared_users: for shared_server in user.servers: if shared_server.machineIdentifier == self.machine_identifier: self._accounts.append(user.title) _LOGGER.debug("Linked accounts: %s", self.accounts) owner_account = next( (account.name for account in system_accounts if account.accountID == 1), None, ) if owner_account: self._owner_username = owner_account self._accounts.append(owner_account) _LOGGER.debug("Server owner found: '%s'", self._owner_username) self._version = self._plex_server.version if config_entry_update_needed: raise ShouldUpdateConfigEntry