Exemple #1
0
 def stop(self):
     """ Stop the AlertListener thread. Once the notifier is stopped, it cannot be directly
         started again. You must call :func:`~plexapi.server.PlexServer.startAlertListener`
         from a PlexServer instance.
     """
     log.info('Stopping AlertListener.')
     self._ws.close()
Exemple #2
0
 def run(self):
     # create the websocket connection
     url = self._server.url(self.key, includeToken=True).replace('http', 'ws')
     log.info('Starting AlertListener: %s', url)
     self._ws = websocket.WebSocketApp(url, on_message=self._onMessage,
                                       on_error=self._onError)
     self._ws.run_forever()
Exemple #3
0
 def connect(self, ssl=None):
     # Only check non-local connections unless we own the resource
     connections = sorted(self.connections,
                          key=lambda c: c.local,
                          reverse=True)
     if not self.owned:
         connections = [c for c in connections if c.local is False]
     # Try connecting to all known resource connections in parellel, but
     # only return the first server (in order) that provides a response.
     threads, results = [], []
     for testssl, attr in self.SSLTESTS:
         if ssl in [None, testssl]:
             for i in range(len(connections)):
                 uri = getattr(connections[i], attr)
                 args = (uri, results, len(results))
                 results.append(None)
                 threads.append(Thread(target=self._connect, args=args))
                 threads[-1].start()
     for thread in threads:
         thread.join()
     # At this point we have a list of result tuples containing (uri, PlexServer)
     # or (uri, None) in the case a connection could not be established.
     for uri, result in results:
         log.info('Testing connection: %s %s', uri,
                  'OK' if result else 'ERR')
     results = list(filter(None, [r[1] for r in results if r]))
     if not results:
         raise NotFound('Unable to connect to resource: %s' % self.name)
     log.info('Connecting to server: %s', results[0])
     return results[0]
Exemple #4
0
    def connect(self, ssl=None, timeout=None):
        """ Returns a new :class:`~server.PlexServer` or :class:`~client.PlexClient` object.
            Often times there is more than one address specified for a server or client.
            This function will prioritize local connections before remote and HTTPS before HTTP.
            After trying to connect to all available addresses for this resource and
            assuming at least one connection was successful, the PlexServer object is built and returned.

            Parameters:
                ssl (optional): Set True to only connect to HTTPS connections. Set False to
                    only connect to HTTP connections. Set None (default) to connect to any
                    HTTP or HTTPS connection.

            Raises:
                :class:`~plexapi.exceptions.NotFound`: When unable to connect to any addresses for this resource.
        """
        # Sort connections from (https, local) to (http, remote)
        # Only check non-local connections unless we own the resource
        connections = sorted(self.connections, key=lambda c: c.local, reverse=True)
        owned_or_unowned_non_local = lambda x: self.owned or (not self.owned and not x.local)
        https = [c.uri for c in connections if owned_or_unowned_non_local(c)]
        http = [c.httpuri for c in connections if owned_or_unowned_non_local(c)]
        cls = PlexServer if 'server' in self.provides else PlexClient
        # Force ssl, no ssl, or any (default)
        if ssl is True: connections = https
        elif ssl is False: connections = http
        else: connections = https + http
        # Try connecting to all known resource connections in parellel, but
        # only return the first server (in order) that provides a response.
        listargs = [[cls, url, self.accessToken, timeout] for url in connections]
        log.info('Testing %s resource connections..', len(listargs))
        results = utils.threaded(_connect, listargs)
        return _chooseConnection('Resource', self.name, results)
Exemple #5
0
 def stop(self):
     """ Stop the AlertListener thread. Once the notifier is stopped, it cannot be diractly
         started again. You must call :func:`plexapi.server.PlexServer.startAlertListener()`
         from a PlexServer instance.
     """
     log.info('Stopping AlertListener.')
     self._ws.close()
Exemple #6
0
    def connect(self):
        """ Returns a new :class:`~plexapi.client.PlexClient` object. Sometimes there is more than
            one address specified for a server or client. After trying to connect to all
            available addresses for this client and assuming at least one connection was
            successful, the PlexClient object is built and returned.

            Raises:
                :class:`~plexapi.exceptions.NotFound`: When unable to connect to any addresses for this device.
        """
        # Try connecting to all known clients in parellel, but
        # only return the first server (in order) that provides a response.
        listargs = [[c] for c in self.connections]
        results = utils.threaded(self._connect, listargs)
        # At this point we have a list of result tuples containing (url, token, PlexServer)
        # or (url, token, None) in the case a connection could not be established.
        for url, token, result in results:
            okerr = 'OK' if result else 'ERR'
            log.info('Testing device connection: %s?X-Plex-Token=%s %s', url,
                     token, okerr)
        results = [r[2] for r in results if r and r[2] is not None]
        if not results:
            raise NotFound('Unable to connect to client: %s' % self.name)
        log.info('Connecting to client: %s?X-Plex-Token=%s',
                 results[0]._baseurl, results[0]._token)
        return results[0]
Exemple #7
0
    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
Exemple #8
0
 def setWebhooks(self, urls):
     log.info('Setting webhooks: %s' % urls)
     data = self.query(self.WEBHOOKS,
                       self._session.post,
                       data={'urls[]': urls})
     self._webhooks = self.listAttrs(data, 'url', etag='webhook')
     return self._webhooks
Exemple #9
0
 def fetch_servers(cls, token):
     headers = plexapi.BASE_HEADERS
     headers['X-Plex-Token'] = token
     log.info('GET %s?X-Plex-Token=%s', cls.SERVERS, token)
     response = requests.get(cls.SERVERS, headers=headers, timeout=TIMEOUT)
     data = ElementTree.fromstring(response.text.encode('utf8'))
     return [MyPlexServer(elem) for elem in data]
Exemple #10
0
    def connect(self, ssl=None, timeout=None):
        """ Returns a new :class:`~server.PlexServer` or :class:`~client.PlexClient` object.
            Often times there is more than one address specified for a server or client.
            This function will prioritize local connections before remote and HTTPS before HTTP.
            After trying to connect to all available addresses for this resource and
            assuming at least one connection was successful, the PlexServer object is built and returned.

            Parameters:
                ssl (optional): Set True to only connect to HTTPS connections. Set False to
                    only connect to HTTP connections. Set None (default) to connect to any
                    HTTP or HTTPS connection.

            Raises:
                :class:`~plexapi.exceptions.NotFound`: When unable to connect to any addresses for this resource.
        """
        # Sort connections from (https, local) to (http, remote)
        # Only check non-local connections unless we own the resource
        connections = sorted(self.connections, key=lambda c: c.local, reverse=True)
        owned_or_unowned_non_local = lambda x: self.owned or (not self.owned and not x.local)
        https = [c.uri for c in connections if owned_or_unowned_non_local(c)]
        http = [c.httpuri for c in connections if owned_or_unowned_non_local(c)]
        cls = PlexServer if 'server' in self.provides else PlexClient
        # Force ssl, no ssl, or any (default)
        if ssl is True: connections = https
        elif ssl is False: connections = http
        else: connections = https + http
        # Try connecting to all known resource connections in parellel, but
        # only return the first server (in order) that provides a response.
        listargs = [[cls, url, self.accessToken, timeout] for url in connections]
        log.info('Testing %s resource connections..', len(listargs))
        results = utils.threaded(_connect, listargs)
        return _chooseConnection('Resource', self.name, results)
Exemple #11
0
 def connect(self, ssl=None):
     # Only check non-local connections unless we own the resource
     connections = sorted(self.connections, key=lambda c:c.local, reverse=True)
     if not self.owned:
         connections = [c for c in connections if c.local is False]
     # Try connecting to all known resource connections in parellel, but
     # only return the first server (in order) that provides a response.
     threads, results = [], []
     for testssl, attr in self.SSLTESTS:
         if ssl in [None, testssl]:
             for i in range(len(connections)):
                 uri = getattr(connections[i], attr)
                 args = (uri, results, len(results))
                 results.append(None)
                 threads.append(Thread(target=self._connect, args=args))
                 threads[-1].start()
     for thread in threads:
         thread.join()
     # At this point we have a list of result tuples containing (uri, PlexServer)
     # or (uri, None) in the case a connection could not be established.
     for uri, result in results:
         log.info('Testing connection: %s %s', uri, 'OK' if result else 'ERR')
     results = list(filter(None, [r[1] for r in results if r]))
     if not results:
         raise NotFound('Unable to connect to resource: %s' % self.name)
     log.info('Connecting to server: %s', results[0])
     return results[0]
Exemple #12
0
 def fetch_resources(cls, token):
     headers = plexapi.BASE_HEADERS
     headers['X-Plex-Token'] = token
     log.info('GET %s?X-Plex-Token=%s', cls.DEVICES, token)
     response = requests.get(cls.DEVICES, headers=headers, timeout=TIMEOUT)
     data = ElementTree.fromstring(response.text.encode('utf8'))
     return [MyPlexDevice(elem) for elem in data]
def _listItems(url, token, cls):
    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]
Exemple #14
0
    def query(self, path, method=None, headers=None, **kwargs):
        """Used to fetch relative paths to pms.

        Args:
            path (str): Relative path
            method (None, optional): requests.post etc
            headers (None, optional): Set headers manually
            **kwargs (TYPE): Passord to the http request used for filter, sorting.

        Returns:
            Element

        Raises:
            BadRequest: Http error and code
        """
        url = self.url(path)
        method = method or self.session.get
        log.info('%s %s', method.__name__.upper(), url)
        headers = dict(self.headers(), **(headers or {}))  # remove hack
        response = method(url, headers=headers, timeout=TIMEOUT, **kwargs)
        if response.status_code not in [200, 201]:
            codename = codes.get(response.status_code)[0]
            raise BadRequest('(%s) %s' % (response.status_code, codename))
        data = response.text.encode('utf8')
        return ElementTree.fromstring(data) if data else None
Exemple #15
0
 def run(self):
     # create the websocket connection
     url = self._server.url(self.key).replace('http', 'ws')
     log.info('Starting AlertListener: %s', url)
     self._ws = websocket.WebSocketApp(url,
                                       on_message=self._onMessage,
                                       on_error=self._onError)
     self._ws.run_forever()
Exemple #16
0
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]
Exemple #17
0
 def sendClientCommand(self, command, args=None):
     url = '%s%s' % (self.url(command), utils.joinArgs(args))
     log.info('GET %s', url)
     response = requests.get(url, timeout=TIMEOUT)
     if response.status_code != requests.codes.ok:
         codename = codes.get(response.status_code)[0]
         raise BadRequest('(%s) %s' % (response.status_code, codename))
     data = response.text.encode('utf8')
     return ElementTree.fromstring(data) if data else None
Exemple #18
0
 def query(self, path, method=None, **kwargs):
     url = self.url(path)
     method = method or self.session.get
     log.info('%s %s', method.__name__.upper(), url)
     response = method(url, headers=self.headers(), timeout=TIMEOUT, **kwargs)
     if response.status_code not in [200, 201]:
         codename = codes.get(response.status_code)[0]
         raise BadRequest('(%s) %s' % (response.status_code, codename))
     data = response.text.encode('utf8')
     return ElementTree.fromstring(data) if data else None
Exemple #19
0
 def query(self, path, method=requests.get):
     global TOTAL_QUERIES
     TOTAL_QUERIES += 1
     url = self.url(path)
     log.info('%s %s', method.__name__.upper(), url)
     response = method(url, headers=self.headers(), timeout=TIMEOUT)
     if response.status_code not in [200, 201]:
         codename = codes.get(response.status_code)[0]
         raise BadRequest('(%s) %s' % (response.status_code, codename))
     data = response.text.encode('utf8')
     return ElementTree.fromstring(data) if data else None
Exemple #20
0
 def query(self, path, method=requests.get):
     global TOTAL_QUERIES
     TOTAL_QUERIES += 1
     url = self.url(path)
     log.info('%s %s', method.__name__.upper(), url)
     response = method(url, headers=self.headers(), timeout=TIMEOUT)
     if response.status_code not in [200, 201]:
         codename = codes.get(response.status_code)[0]
         raise BadRequest('(%s) %s' % (response.status_code, codename))
     data = response.text.encode('utf8')
     return ElementTree.fromstring(data) if data else None
Exemple #21
0
def _chooseConnection(ctype, name, results):
    """ Chooses the first (best) connection from the given _connect results. """
    # At this point we have a list of result tuples containing (url, token, PlexServer, runtime)
    # or (url, token, None, runtime) in the case a connection could not be established.
    for url, token, result, runtime in results:
        okerr = 'OK' if result else 'ERR'
        log.info('%s connection %s (%ss): %s?X-Plex-Token=%s', ctype, okerr, runtime, url, token)
    results = [r[2] for r in results if r and r[2] is not None]
    if results:
        log.info('Connecting to %s: %s?X-Plex-Token=%s', ctype, results[0]._baseurl, results[0]._token)
        return results[0]
    raise NotFound('Unable to connect to %s: %s' % (ctype.lower(), name))
Exemple #22
0
def _chooseConnection(ctype, name, results):
    """ Chooses the first (best) connection from the given _connect results. """
    # At this point we have a list of result tuples containing (url, token, PlexServer, runtime)
    # or (url, token, None, runtime) in the case a connection could not be established.
    for url, token, result, runtime in results:
        okerr = 'OK' if result else 'ERR'
        log.info('%s connection %s (%ss): %s?X-Plex-Token=%s', ctype, okerr, runtime, url, token)
    results = [r[2] for r in results if r and r[2] is not None]
    if results:
        log.info('Connecting to %s: %s?X-Plex-Token=%s', ctype, results[0]._baseurl, results[0]._token)
        return results[0]
    raise NotFound('Unable to connect to %s: %s' % (ctype.lower(), name))
Exemple #23
0
 def _signin(self, username, password):
     auth = (username, password)
     log.info('POST %s', self.SIGNIN)
     response = requests.post(self.SIGNIN,
                              headers=plexapi.BASE_HEADERS,
                              auth=auth,
                              timeout=TIMEOUT)
     if response.status_code != requests.codes.created:
         codename = codes.get(response.status_code)[0]
         raise BadRequest('(%s) %s' % (response.status_code, codename))
     self.response = response
     data = response.text.encode('utf8')
     return ElementTree.fromstring(data)
 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)
Exemple #25
0
    def connect(self, timeout=None):
        """ Returns a new :class:`~plexapi.client.PlexClient` or :class:`~plexapi.server.PlexServer`
            Sometimes there is more than one address specified for a server or client.
            After trying to connect to all available addresses for this client and assuming
            at least one connection was successful, the PlexClient object is built and returned.

            Raises:
                :class:`~plexapi.exceptions.NotFound`: When unable to connect to any addresses for this device.
        """
        cls = PlexServer if 'server' in self.provides else PlexClient
        listargs = [[cls, url, self.token, timeout] for url in self.connections]
        log.info('Testing %s device connections..', len(listargs))
        results = utils.threaded(_connect, listargs)
        return _chooseConnection('Device', self.name, results)
Exemple #26
0
 def run(self):
     try:
         import websocket
     except ImportError:
         log.warning("Can't use the AlertListener without websocket")
         return
     # create the websocket connection
     url = self._server.url(self.key,
                            includeToken=True).replace('http', 'ws')
     log.info('Starting AlertListener: %s', url)
     self._ws = websocket.WebSocketApp(url,
                                       on_message=self._onMessage,
                                       on_error=self._onError)
     self._ws.run_forever()
Exemple #27
0
    def connect(self, timeout=None):
        """ Returns a new :class:`~plexapi.client.PlexClient` object. Sometimes there is more than
            one address specified for a server or client. After trying to connect to all available
            addresses for this client and assuming at least one connection was successful, the
            PlexClient object is built and returned.

            Raises:
                :class:`~plexapi.exceptions.NotFound`: When unable to connect to any addresses for this device.
        """
        listargs = [[PlexClient, url, self.token, timeout]
                    for url in self.connections]
        log.info('Testing %s device connections..', len(listargs))
        results = utils.threaded(_connect, listargs)
        _chooseConnection('Device', self.name, results)
 def connect(self, ssl=None):
     # Try connecting to all known resource connections in parellel, but
     # only return the first server (in order) that provides a response.
     listargs = [[c] for c in self.connections]
     results = utils.threaded(self._connect, listargs)
     # At this point we have a list of result tuples containing (url, token, PlexServer)
     # or (url, token, None) in the case a connection could not be established.
     for url, token, result in results:
         okerr = 'OK' if result else 'ERR'
         log.info('Testing device connection: %s?X-Plex-Token=%s %s', url, token, okerr)
     results = list(filter(None, [r[2] for r in results if r]))
     if not results:
         raise NotFound('Unable to connect to resource: %s' % self.name)
     log.info('Connecting to server: %s?X-Plex-Token=%s', results[0].baseurl, results[0].token)
     return results[0]
Exemple #29
0
 def save(self):
     """ Save any outstanding settnig changes to the :class:`~plexapi.server.PlexServer`. This
         performs a full reload() of Settings after complete.
     """
     params = {}
     for setting in self.all():
         if setting._setValue:
             log.info('Saving PlexServer setting %s = %s' % (setting.id, setting._setValue))
             params[setting.id] = quote(setting._setValue)
     if not params:
         raise BadRequest('No setting have been modified.')
     querystr = '&'.join(['%s=%s' % (k, v) for k, v in params.items()])
     url = '%s?%s' % (self.key, querystr)
     self._server.query(url, self._server._session.put)
     self.reload()
Exemple #30
0
 def save(self):
     """ Save any outstanding settnig changes to the :class:`~plexapi.server.PlexServer`. This
         performs a full reload() of Settings after complete.
     """
     params = {}
     for setting in self.all():
         if setting._setValue:
             log.info('Saving PlexServer setting %s = %s' % (setting.id, setting._setValue))
             params[setting.id] = quote(setting._setValue)
     if not params:
         raise BadRequest('No setting have been modified.')
     querystr = '&'.join(['%s=%s' % (k, v) for k, v in params.items()])
     url = '%s?%s' % (self.key, querystr)
     self._server.query(url, self._server._session.put)
     self.reload()
Exemple #31
0
 def sendCommand(self, command, args=None):
     url = '%s%s' % (self.url(command), utils.joinArgs(args))
     log.info('GET %s', url)
     headers = plexapi.BASE_HEADERS
     headers['X-Plex-Target-Client-Identifier'] = self.clientIdentifier
     response = requests.get(url, headers=headers, timeout=TIMEOUT)
     if response.status_code != requests.codes.ok:
         codename = codes.get(response.status_code)[0]
         raise BadRequest('(%s) %s' % (response.status_code, codename))
     data = response.text.encode('utf8')
     if data:
         try:
             return ElementTree.fromstring(data)
         except:
             pass
     return None
Exemple #32
0
 def sendCommand(self, command, args=None):
     url = '%s%s' % (self.url(command), utils.joinArgs(args))
     log.info('GET %s', url)
     headers = plexapi.BASE_HEADERS
     headers['X-Plex-Target-Client-Identifier'] = self.clientIdentifier
     response = requests.get(url, headers=headers, timeout=TIMEOUT)
     if response.status_code != requests.codes.ok:
         codename = codes.get(response.status_code)[0]
         raise BadRequest('(%s) %s' % (response.status_code, codename))
     data = response.text.encode('utf8')
     if data:
         try:
             return ElementTree.fromstring(data)
         except:
             pass
     return None
Exemple #33
0
def _listItems(url, token, cls):
    """Helper that builds list of classes from a XML response.

    Args:
        url (str): Description
        token (str): Description
        cls (class): Class to initate

    Returns:
        List: of classes
    """
    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]
Exemple #34
0
    def connect(self, ssl=None):
        """ Returns a new :class:`~server.PlexServer` object. Often times there is more than
            one address specified for a server or client. This function will prioritize local
            connections before remote and HTTPS before HTTP. After trying to connect to all
            available addresses for this resource and assuming at least one connection was
            successful, the PlexServer object is built and returned.

            Parameters:
                ssl (optional): Set True to only connect to HTTPS connections. Set False to
                    only connect to HTTP connections. Set None (default) to connect to any
                    HTTP or HTTPS connection.

            Raises:
                :class:`~plexapi.exceptions.NotFound`: When unable to connect to any addresses for this resource.
        """
        # Sort connections from (https, local) to (http, remote)
        # Only check non-local connections unless we own the resource
        forcelocal = lambda c: self.owned or c.local
        connections = sorted(self.connections,
                             key=lambda c: c.local,
                             reverse=True)
        https = [c.uri for c in self.connections if forcelocal(c)]
        http = [c.httpuri for c in self.connections if forcelocal(c)]
        # Force ssl, no ssl, or any (default)
        if ssl is True: connections = https
        elif ssl is False: connections = http
        else: connections = https + http
        # Try connecting to all known resource connections in parellel, but
        # only return the first server (in order) that provides a response.
        listargs = [[c] for c in connections]
        results = utils.threaded(self._connect, listargs)
        # At this point we have a list of result tuples containing (url, token, PlexServer)
        # or (url, token, None) in the case a connection could not be
        # established.
        for url, token, result in results:
            okerr = 'OK' if result else 'ERR'
            log.info('Testing resource connection: %s?X-Plex-Token=%s %s', url,
                     token, okerr)
        results = [r[2] for r in results if r and r[2] is not None]
        if not results:
            raise NotFound('Unable to connect to resource: %s' % self.name)
        log.info('Connecting to server: %s?X-Plex-Token=%s',
                 results[0].baseurl, results[0].token)
        return results[0]
Exemple #35
0
 def connect(self):
     # Try connecting to all known addresses in parellel to save time, but
     # only return the first server (in order) that provides a response.
     addresses = [self.address]
     if self.owned:
         addresses = self.localAddresses + [self.address]
     threads = [None] * len(addresses)
     results = [None] * len(addresses)
     for i in range(len(addresses)):
         args = (addresses[i], results, i)
         threads[i] = Thread(target=self._connect, args=args)
         threads[i].start()
     for thread in threads:
         thread.join()
     results = list(filter(None, results))
     if results:
         log.info('Connecting to server: %s', results[0])
         return results[0]
     raise NotFound('Unable to connect to server: %s' % self.name)
Exemple #36
0
 def _getSectionIds(self, server, sections):
     """ Converts a list of section objects or names to sectionIds needed for library sharing. """
     if not sections: return []
     # Get a list of all section ids for looking up each section.
     allSectionIds = {}
     machineIdentifier = server.machineIdentifier if isinstance(server, PlexServer) else server
     url = self.PLEXSERVERS.replace('{machineId}', machineIdentifier)
     data = self.query(url, self._session.get)
     for elem in data[0]:
         allSectionIds[elem.attrib.get('id', '').lower()] = elem.attrib.get('id')
         allSectionIds[elem.attrib.get('title', '').lower()] = elem.attrib.get('id')
         allSectionIds[elem.attrib.get('key', '').lower()] = elem.attrib.get('id')
     log.info(allSectionIds)
     # Convert passed in section items to section ids from above lookup
     sectionIds = []
     for section in sections:
         sectionKey = section.key if isinstance(section, LibrarySection) else section
         sectionIds.append(allSectionIds[sectionKey.lower()])
     return sectionIds
Exemple #37
0
 def connect(self):
     # Try connecting to all known addresses in parellel to save time, but
     # only return the first server (in order) that provides a response.
     addresses = [self.address]
     if self.owned:
         addresses = self.localAddresses + [self.address]
     threads = [None] * len(addresses)
     results = [None] * len(addresses)
     for i in range(len(addresses)):
         args = (addresses[i], results, i)
         threads[i] = Thread(target=self._connect, args=args)
         threads[i].start()
     for thread in threads:
         thread.join()
     results = list(filter(None, results))
     if results:
         log.info('Connecting to server: %s', results[0])
         return results[0]
     raise NotFound('Unable to connect to server: %s' % self.name)
Exemple #38
0
    def connect(self, ssl=None):
        """Connect.

        Args:
            ssl (None, optional): Use ssl.

        Returns:
            class: Plexserver

        Raises:
            NotFound: Unable to connect to resource: name
        """

        # Sort connections from (https, local) to (http, remote)
        # Only check non-local connections unless we own the resource
        forcelocal = lambda c: self.owned or c.local
        connections = sorted(self.connections,
                             key=lambda c: c.local,
                             reverse=True)
        https = [c.uri for c in self.connections if forcelocal(c)]
        http = [c.httpuri for c in self.connections if forcelocal(c)]
        connections = https + http
        # Try connecting to all known resource connections in parellel, but
        # only return the first server (in order) that provides a response.
        listargs = [[c] for c in connections]
        results = utils.threaded(self._connect, listargs)
        # At this point we have a list of result tuples containing (url, token, PlexServer)
        # or (url, token, None) in the case a connection could not be
        # established.
        for url, token, result in results:
            okerr = 'OK' if result else 'ERR'
            log.info('Testing resource connection: %s?X-Plex-Token=%s %s', url,
                     token, okerr)

        results = [r[2] for r in results if r and r is not None]
        if not results:
            raise NotFound('Unable to connect to resource: %s' % self.name)
        log.info('Connecting to server: %s?X-Plex-Token=%s',
                 results[0].baseurl, results[0].token)

        return results[0]
Exemple #39
0
def toDatetime(value, format=None):
    """ Returns a datetime object from the specified value.

        Parameters:
            value (str): value to return as a datetime
            format (str): Format to pass strftime (optional; if value is a str).
    """
    if value and value is not None:
        if format:
            try:
                value = datetime.strptime(value, format)
            except ValueError:
                log.info('Failed to parse %s to datetime, defaulting to None', value)
                return None
        else:
            # https://bugs.python.org/issue30684
            # And platform support for before epoch seems to be flaky.
            # TODO check for others errors too.
            if int(value) <= 0:
                value = 86400
            value = datetime.fromtimestamp(int(value))
    return value
 def connect(self, ssl=None):
     # Sort connections from (https, local) to (http, remote)
     # Only check non-local connections unless we own the resource
     forcelocal = lambda c: self.owned or c.local
     connections = sorted(self.connections, key=lambda c:c.local, reverse=True)
     https = [c.uri for c in self.connections if forcelocal(c)]
     http = [c.httpuri for c in self.connections if forcelocal(c)]
     connections = https + http
     # Try connecting to all known resource connections in parellel, but
     # only return the first server (in order) that provides a response.
     listargs = [[c] for c in connections]
     results = utils.threaded(self._connect, listargs)
     # At this point we have a list of result tuples containing (url, token, PlexServer)
     # or (url, token, None) in the case a connection could not be established.
     for url, token, result in results:
         okerr = 'OK' if result else 'ERR'
         log.info('Testing resource connection: %s?X-Plex-Token=%s %s', url, token, okerr)
     results = list(filter(None, [r[2] for r in results if r]))
     if not results:
         raise NotFound('Unable to connect to resource: %s' % self.name)
     log.info('Connecting to server: %s?X-Plex-Token=%s', results[0].baseurl, results[0].token)
     return results[0]
Exemple #41
0
def _findResource(resources, search, port=32400):
    """ Searches server.name """
    search = search.lower()
    log.info('Looking for server: %s', search)
    for server in resources:
        if search == server.name.lower():
            log.info('Server found: %s', server)
            return server
    log.info('Unable to find server: %s', search)
    raise NotFound('Unable to find server: %s' % search)
Exemple #42
0
def _findResource(resources, search, port=32400):
    """ Searches server.name """
    search = search.lower()
    log.info('Looking for server: %s', search)
    for server in resources:
        if search == server.name.lower():
            log.info('Server found: %s', server)
            return server
    log.info('Unable to find server: %s', search)
    raise NotFound('Unable to find server: %s' % search)
Exemple #43
0
def _findServer(servers, search, port=32400):
    """ Searches server.name, server.sourceTitle and server.host:server.port """
    search = search.lower()
    ipaddr = addrToIP(search)
    log.info('Looking for server: %s (host: %s:%s)', search, ipaddr, port)
    for server in servers:
        serverName = server.name.lower() if server.name else 'NA'
        sourceTitle = server.sourceTitle.lower() if server.sourceTitle else 'NA'
        if (search in [serverName, sourceTitle]) or (server.host == ipaddr and server.port == port):
            log.info('Server found: %s', server)
            return server
    log.info('Unable to find server: %s (host: %s:%s)', search, ipaddr, port)
    raise NotFound('Unable to find server: %s (host: %s:%s)' % (search, ipaddr, port))
Exemple #44
0
 def setWebhooks(self, urls):
     log.info('Setting webhooks: %s' % urls)
     data = self.query(self.WEBHOOKS, self._session.post, data={'urls[]': urls})
     self._webhooks = self.listAttrs(data, 'url', etag='webhook')
     return self._webhooks
Exemple #45
0
def download(url, token, filename=None, savepath=None, session=None, chunksize=4024,
             unpack=False, mocked=False, showstatus=False):
    """ Helper to download a thumb, videofile or other media item. Returns the local
        path to the downloaded file.

       Parameters:
            url (str): URL where the content be reached.
            token (str): Plex auth token to include in headers.
            filename (str): Filename of the downloaded file, default None.
            savepath (str): Defaults to current working dir.
            chunksize (int): What chunksize read/write at the time.
            mocked (bool): Helper to do evertything except write the file.
            unpack (bool): Unpack the zip file.
            showstatus(bool): Display a progressbar.

        Example:
            >>> download(a_episode.getStreamURL(), a_episode.location)
            /path/to/file
    """

    from plexapi import log
    # fetch the data to be saved
    session = session or requests.Session()
    headers = {'X-Plex-Token': token}
    response = session.get(url, headers=headers, stream=True)
    # make sure the savepath directory exists
    savepath = savepath or os.getcwd()
    compat.makedirs(savepath, exist_ok=True)

    # try getting filename from header if not specified in arguments (used for logs, db)
    if not filename and response.headers.get('Content-Disposition'):
        filename = re.findall(r'filename=\"(.+)\"', response.headers.get('Content-Disposition'))
        filename = filename[0] if filename[0] else None

    filename = os.path.basename(filename)
    fullpath = os.path.join(savepath, filename)
    # append file.ext from content-type if not already there
    extension = os.path.splitext(fullpath)[-1]
    if not extension:
        contenttype = response.headers.get('content-type')
        if contenttype and 'image' in contenttype:
            fullpath += contenttype.split('/')[1]

    # check this is a mocked download (testing)
    if mocked:
        log.debug('Mocked download %s', fullpath)
        return fullpath

    # save the file to disk
    log.info('Downloading: %s', fullpath)
    if showstatus:  # pragma: no cover
        total = int(response.headers.get('content-length', 0))
        bar = tqdm(unit='B', unit_scale=True, total=total, desc=filename)

    with open(fullpath, 'wb') as handle:
        for chunk in response.iter_content(chunk_size=chunksize):
            handle.write(chunk)
            if showstatus:
                bar.update(len(chunk))

    if showstatus:  # pragma: no cover
        bar.close()
    # check we want to unzip the contents
    if fullpath.endswith('zip') and unpack:
        with zipfile.ZipFile(fullpath, 'r') as handle:
            handle.extractall(savepath)

    return fullpath