Пример #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()
Пример #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()
Пример #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]
Пример #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)
Пример #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()
Пример #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]
Пример #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
Пример #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
Пример #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]
Пример #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)
Пример #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]
Пример #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]
Пример #13
0
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]
Пример #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
Пример #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()
Пример #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]
Пример #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
Пример #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
Пример #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
Пример #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
Пример #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))
Пример #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))
Пример #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)
Пример #24
0
 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)
Пример #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)
Пример #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()
Пример #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)
Пример #28
0
 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]
Пример #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()
Пример #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()
Пример #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
Пример #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
Пример #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]
Пример #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]
Пример #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)
Пример #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
Пример #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)
Пример #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]
Пример #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
Пример #40
0
 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]
Пример #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)
Пример #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)
Пример #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))
Пример #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
Пример #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