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 query(self, path, method=None, headers=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. Parameters: path (str): Relative path to query on the server api (ex: '/search?query=HELLO') method (func): requests.method to use for this query (request.get or requests.put; defaults to get) headers (dict): Optionally include additional headers for this request. **kwargs (dict): Optionally include additional kwargs for in the specified reuqest method. These kwargs are simply passed through to method(). Raises: :class:`~plexapi.exceptions.BadRequest`: Raised when response is not in (200, 201). """ url = self.url(path) method = method or self.session.get log.info('%s %s', method.__name__.upper(), url) h = self.headers().copy() if headers: h.update(headers) response = method(url, headers=h, timeout=TIMEOUT, **kwargs) #print(response.url) if response.status_code not in [200, 201]: # pragma: no cover codename = codes.get(response.status_code)[0] raise BadRequest('(%s) %s %s' % (response.status_code, codename, response.url)) data = response.text.encode('utf8') return ElementTree.fromstring(data) if data else None
def _listItems(url, token, cls): """ Builds list of classes from a XML response. """ headers = plexapi.BASE_HEADERS headers['X-Plex-Token'] = token log.info('GET %s?X-Plex-Token=%s', url, token) response = requests.get(url, headers=headers, timeout=TIMEOUT) data = ElementTree.fromstring(response.text.encode('utf8')) return [cls(elem) for elem in data]
def query(self, url, method=None, headers=None, timeout=None, **kwargs): method = method or self._session.get timeout = timeout or TIMEOUT log.debug('%s %s %s', method.__name__.upper(), url, kwargs.get('json', '')) headers = self._headers(**headers or {}) response = method(url, headers=headers, timeout=timeout, **kwargs) if response.status_code not in (200, 201, 204): # pragma: no cover codename = codes.get(response.status_code)[0] errtext = response.text.replace('\n', ' ') raise BadRequest('(%s) %s %s; %s' % (response.status_code, codename, response.url, errtext)) data = response.text.encode('utf8') return ElementTree.fromstring(data) if data.strip() else None
def query(self, url, method=None, headers=None, timeout=None, **kwargs): method = method or self._session.get timeout = timeout or TIMEOUT log.debug('%s %s %s', method.__name__.upper(), url, kwargs.get('json', '')) headers = self._headers(**headers or {}) response = method(url, headers=headers, timeout=timeout, **kwargs) if response.status_code not in (200, 201, 204): # pragma: no cover codename = codes.get(response.status_code)[0] errtext = response.text.replace('\n', ' ') log.warning('BadRequest (%s) %s %s; %s' % (response.status_code, codename, response.url, errtext)) raise BadRequest('(%s) %s %s; %s' % (response.status_code, codename, response.url, errtext)) data = response.text.encode('utf8') return ElementTree.fromstring(data) if data.strip() else None
def query(self, url, method=None, headers=None, **kwargs): method = method or self._session.get delim = '&' if '?' in url else '?' url = '%s%sX-Plex-Token=%s' % (url, delim, self._token) log.debug('%s %s', method.__name__.upper(), url) allheaders = BASE_HEADERS.copy() allheaders.update(headers or {}) response = method(url, headers=allheaders, timeout=TIMEOUT, **kwargs) if response.status_code not in (200, 201): codename = codes.get(response.status_code)[0] log.warn('BadRequest (%s) %s %s' % (response.status_code, codename, response.url)) raise BadRequest('(%s) %s' % (response.status_code, codename)) data = response.text.encode('utf8') return ElementTree.fromstring(data) if data.strip() else None
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): codename = codes.get(response.status_code)[0] log.warn('BadRequest (%s) %s %s' % (response.status_code, codename, response.url)) raise BadRequest('(%s) %s' % (response.status_code, codename)) data = response.text.encode('utf8') return ElementTree.fromstring(data) if data.strip() else None
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): codename = codes.get(response.status_code)[0] errtext = response.text.replace('\n', ' ') log.warning('BadRequest (%s) %s %s; %s' % (response.status_code, codename, response.url, errtext)) raise BadRequest('(%s) %s; %s %s' % (response.status_code, codename, response.url, errtext)) data = response.text.encode('utf8') return ElementTree.fromstring(data) if data.strip() else None
def query(self, path, method=None, headers=None, timeout=None, **kwargs): """ Main method used to handle HTTPS requests to the Plex client. 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(path) 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 cli(username, password, server, library): """Set Plex music album covers to the corresponding front covers embedded in the contained MP3 files. USERNAME is the Plex account username to use.\n SERVER is the Plex server to connect to.\n LIBRARY is the Plex music library to work on. Password can be specified via the --password option or provided in the PLEX_PASSWORD environment variable. """ try: plex = get_plex(username, password, server) music = None try: music = plex.library.section(library) logger.info("Retrieved Plex music library.") except: logger.exception("Couldn't get Plex music library. Is the specified music library correct?") raise try: albums = music.albums() except: logger.exception("Couldn't retrieve albums from library.") raise if not albums: logger.info("No albums found.") for album in albums: logger.info("Working on: {artist} - {album}".format(artist=album.parentTitle, album=album.title)) posters_url = "{url}/posters".format(url=plex.url(album.key)) container = None try: response = plex._session.get(posters_url, headers=plex._headers()) response.raise_for_status() data = response.text.encode('utf8') container = ElementTree.fromstring(data) if data.strip() else None except: logger.exception("Couldn't fetch album convers from Plex.") raise if container and len(container) > 1: logger.info("Found multiple covers. Looking for embedded front cover...") # If we have different covers across multiple tracks in the same album # we have no good way to select one of them, therefore we'd choose a # one indiscriminately. If we are to choose a cover indiscriminately # we may as well pick the first one and avoid reading all files in the # album. So we do that. file_ = get_file_from_track(album.tracks()[0]) front_cover_pic = get_front_cover_pic(file_) if front_cover_pic: logger.info("Found an embedded cover. Updating album cover...") try: response = plex._session.post(posters_url, data=front_cover_pic, headers=plex._headers()) response.raise_for_status() logger.info("Album cover updated successfully.") except: logger.exception("Couldn't update album cover in Plex.") raise else: logger.info("No embedded front covers found.") else: logger.info("Single or no cover found. Nothing to do.") except: exit(1)