Ejemplo n.º 1
0
 def _cleanSearchFilter(self, category, value, libtype=None):
     # check a few things before we begin
     if category not in self.ALLOWED_FILTERS:
         raise BadRequest('Unknown filter category: %s' % category)
     if category in self.BOOLEAN_FILTERS:
         return '1' if value else '0'
     if not isinstance(value, (list, tuple)):
         value = [value]
     # convert list of values to list of keys or ids
     result = set()
     choices = self.listChoices(category, libtype)
     lookup = {c.title.lower(): unquote(unquote(c.key)) for c in choices}
     allowed = set(c.key for c in choices)
     for item in value:
         item = str((item.id or item.tag
                     ) if isinstance(item, MediaTag) else item).lower()
         # find most logical choice(s) to use in url
         if item in allowed:
             result.add(item)
             continue
         if item in lookup:
             result.add(lookup[item])
             continue
         matches = [k for t, k in lookup.items() if item in t]
         if matches:
             map(result.add, matches)
             continue
         # nothing matched; use raw item value
         log.warning('Filter value not listed, using raw item value: %s' %
                     item)
         result.add(item)
     return ','.join(result)
Ejemplo n.º 2
0
 def claimToken(self):
     """ Returns a str, a new "claim-token", which you can use to register your new Plex Server instance to your
         account.
         See: https://hub.docker.com/r/plexinc/pms-docker/, https://www.plex.tv/claim/
     """
     response = self._session.get('https://plex.tv/api/claim/token.json', headers=self._headers(), timeout=TIMEOUT)
     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))
     return response.json()['token']
Ejemplo n.º 3
0
 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
Ejemplo n.º 4
0
 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
Ejemplo n.º 5
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()
Ejemplo n.º 6
0
 def __getattribute__(self, attr):
     # Dragons inside.. :-/
     value = utils.getattributeOrNone(PlexPartialObject, self, attr)
     # Check a few cases where we dont want to reload
     if attr == 'key' or attr.startswith('_'): return value
     if value not in (None, []): return value
     if self.isFullObject(): return value
     # Log warning that were reloading the object
     clsname = self.__class__.__name__
     title = self.__dict__.get('title', self.__dict__.get('name'))
     objname = "%s '%s'" % (clsname, title) if title else clsname
     log.warning("Reloading %s for attr '%s'" % (objname, attr))
     # Reload and return the value
     self.reload()
     return utils.getattributeOrNone(PlexPartialObject, self, attr)
Ejemplo n.º 7
0
    def clients(self):
        """ Returns list of all :class:`~plexapi.client.PlexClient` objects connected to server. """
        items = []
        ports = None
        for elem in self.query('/clients'):
            port = elem.attrib.get('port')
            if not port:
                log.warning('%s did not advertise a port, checking plex.tv.', elem.attrib.get('name'))
                ports = self._myPlexClientPorts() if ports is None else ports
                port = ports.get(elem.attrib.get('machineIdentifier'))
            baseurl = 'http://%s:%s' % (elem.attrib['host'], port)
            items.append(PlexClient(baseurl=baseurl, server=self,
                                    token=self._token, data=elem, connect=False))

        return items
Ejemplo n.º 8
0
    def clients(self):
        """ Returns list of all :class:`~plexapi.client.PlexClient` objects connected to server. """
        items = []
        ports = None
        for elem in self.query('/clients'):
            port = elem.attrib.get('port')
            if not port:
                log.warning('%s did not advertise a port, checking plex.tv.', elem.attrib.get('name'))
                ports = self._myPlexClientPorts() if ports is None else ports
                port = ports.get(elem.attrib.get('machineIdentifier'))
            baseurl = 'http://%s:%s' % (elem.attrib['host'], port)
            items.append(PlexClient(baseurl=baseurl, server=self,
                                    token=self._token, data=elem, connect=False))

        return items
Ejemplo n.º 9
0
 def _myPlexClientPorts(self):
     """ Sometimes the PlexServer does not properly advertise port numbers required
         to connect. This attemps to look up device port number from plex.tv.
         See issue #126: Make PlexServer.clients() more user friendly.
           https://github.com/pkkid/python-plexapi/issues/126
     """
     try:
         ports = {}
         account = self.myPlexAccount()
         for device in account.devices():
             if device.connections and ':' in device.connections[0][6:]:
                 ports[device.clientIdentifier] = device.connections[0].split(':')[-1]
         return ports
     except Exception as err:
         log.warning('Unable to fetch client ports from myPlex: %s', err)
         return ports
Ejemplo n.º 10
0
 def _myPlexClientPorts(self):
     """ Sometimes the PlexServer does not properly advertise port numbers required
         to connect. This attemps to look up device port number from plex.tv.
         See issue #126: Make PlexServer.clients() more user friendly.
           https://github.com/pkkid/python-plexapi/issues/126
     """
     try:
         ports = {}
         account = self.myPlexAccount()
         for device in account.devices():
             if device.connections and ':' in device.connections[0][6:]:
                 ports[device.clientIdentifier] = device.connections[0].split(':')[-1]
         return ports
     except Exception as err:
         log.warning('Unable to fetch client ports from myPlex: %s', err)
         return ports
Ejemplo n.º 11
0
 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):
         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
Ejemplo n.º 12
0
 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
Ejemplo n.º 13
0
 def _cleanSearchFilter(self, category, value, libtype=None):
     # check a few things before we begin
     if category not in self.ALLOWED_FILTERS:
         raise BadRequest('Unknown filter category: %s' % category)
     if category in self.BOOLEAN_FILTERS:
         return '1' if value else '0'
     if not isinstance(value, (list, tuple)):
         value = [value]
     # convert list of values to list of keys or ids
     result = set()
     choices = self.listChoices(category, libtype)
     lookup = {c.title.lower():c.key for c in choices}
     allowed = set(c.key for c in choices)
     for item in value:
         item = str(item.id if isinstance(item, MediaTag) else item).lower()
         # find most logical choice(s) to use in url
         if item in allowed: result.add(item); continue
         if item in lookup: result.add(lookup[item]); continue
         matches = [k for t,k in lookup.items() if item in t]
         if matches: map(result.add, matches); continue
         # nothing matched; use raw item value
         log.warning('Filter value not listed, using raw item value: %s' % item)
         result.add(item)    
     return ','.join(result)
Ejemplo n.º 14
0
    def updateFriend(self,
                     user,
                     server,
                     sections=None,
                     removeSections=False,
                     allowSync=None,
                     allowCameraUpload=None,
                     allowChannels=None,
                     filterMovies=None,
                     filterTelevision=None,
                     filterMusic=None):
        """ Update the specified user's share settings.

            Parameters:
                user (str): MyPlexUser, username, email of the user to be added.
                server (PlexServer): PlexServer object or machineIdentifier containing the library sections to share.
                sections: ([Section]): Library sections, names or ids to be shared (default None shares all sections).
                removeSections (Bool): Set True to remove all shares. Supersedes sections.
                allowSync (Bool): Set True to allow user to sync content.
                allowCameraUpload (Bool): Set True to allow user to upload photos.
                allowChannels (Bool): Set True to allow user to utilize installed channels.
                filterMovies (Dict): Dict containing key 'contentRating' and/or 'label' each set to a list of
                    values to be filtered. ex: {'contentRating':['G'], 'label':['foo']}
                filterTelevision (Dict): Dict containing key 'contentRating' and/or 'label' each set to a list of
                    values to be filtered. ex: {'contentRating':['G'], 'label':['foo']}
                filterMusic (Dict): Dict containing key 'label' set to a list of values to be filtered.
                    ex: {'label':['foo']}
        """
        # Update friend servers
        response_filters = ''
        response_servers = ''
        user = self.user(
            user.username if isinstance(user, MyPlexUser) else user)
        machineId = server.machineIdentifier if isinstance(
            server, PlexServer) else server
        sectionIds = self._getSectionIds(machineId, sections)
        headers = {'Content-Type': 'application/json'}
        # Determine whether user has access to the shared server.
        user_servers = [
            s for s in user.servers if s.machineIdentifier == machineId
        ]
        if user_servers and sectionIds:
            serverId = user_servers[0].id
            params = {
                'server_id': machineId,
                'shared_server': {
                    'library_section_ids': sectionIds
                }
            }
            url = self.FRIENDSERVERS.format(machineId=machineId,
                                            serverId=serverId)
        else:
            params = {
                'server_id': machineId,
                'shared_server': {
                    'library_section_ids': sectionIds,
                    "invited_id": user.id
                }
            }
            url = self.FRIENDINVITE.format(machineId=machineId)
        # Remove share sections, add shares to user without shares, or update shares
        if sectionIds:
            if removeSections is True:
                response_servers = self.query(url,
                                              self._session.delete,
                                              json=params,
                                              headers=headers)
            elif 'invited_id' in params.get('shared_server', ''):
                response_servers = self.query(url,
                                              self._session.post,
                                              json=params,
                                              headers=headers)
            else:
                response_servers = self.query(url,
                                              self._session.put,
                                              json=params,
                                              headers=headers)
        else:
            log.warning(
                'Section name, number of section object is required changing library sections'
            )
        # Update friend filters
        url = self.FRIENDUPDATE.format(userId=user.id)
        params = {}
        if isinstance(allowSync, bool):
            params['allowSync'] = '1' if allowSync else '0'
        if isinstance(allowCameraUpload, bool):
            params['allowCameraUpload'] = '1' if allowCameraUpload else '0'
        if isinstance(allowChannels, bool):
            params['allowChannels'] = '1' if allowChannels else '0'
        if isinstance(filterMovies, dict):
            params['filterMovies'] = self._filterDictToStr(
                filterMovies or {})  # '1' if allowChannels else '0'
        if isinstance(filterTelevision, dict):
            params['filterTelevision'] = self._filterDictToStr(filterTelevision
                                                               or {})
        if isinstance(allowChannels, dict):
            params['filterMusic'] = self._filterDictToStr(filterMusic or {})
        if params:
            url += joinArgs(params)
            response_filters = self.query(url, self._session.put)
        return response_servers, response_filters
Ejemplo n.º 15
0
    def updateFriend(self, user, server, sections=None, removeSections=False, allowSync=None, allowCameraUpload=None,
                     allowChannels=None, filterMovies=None, filterTelevision=None, filterMusic=None):
        """ Update the specified user's share settings.

            Parameters:
                user (str): MyPlexUser, username, email of the user to be added.
                server (PlexServer): PlexServer object or machineIdentifier containing the library sections to share.
                sections: ([Section]): Library sections, names or ids to be shared (default None shares all sections).
                removeSections (Bool): Set True to remove all shares. Supersedes sections.
                allowSync (Bool): Set True to allow user to sync content.
                allowCameraUpload (Bool): Set True to allow user to upload photos.
                allowChannels (Bool): Set True to allow user to utilize installed channels.
                filterMovies (Dict): Dict containing key 'contentRating' and/or 'label' each set to a list of
                    values to be filtered. ex: {'contentRating':['G'], 'label':['foo']}
                filterTelevision (Dict): Dict containing key 'contentRating' and/or 'label' each set to a list of
                    values to be filtered. ex: {'contentRating':['G'], 'label':['foo']}
                filterMusic (Dict): Dict containing key 'label' set to a list of values to be filtered.
                    ex: {'label':['foo']}
        """
        # Update friend servers
        response_filters = ''
        response_servers = ''
        user = self.user(user.username if isinstance(user, MyPlexUser) else user)
        machineId = server.machineIdentifier if isinstance(server, PlexServer) else server
        sectionIds = self._getSectionIds(machineId, sections)
        headers = {'Content-Type': 'application/json'}
        # Determine whether user has access to the shared server.
        user_servers = [s for s in user.servers if s.machineIdentifier == machineId]
        if user_servers and sectionIds:
            serverId = user_servers[0].id
            params = {'server_id': machineId, 'shared_server': {'library_section_ids': sectionIds}}
            url = self.FRIENDSERVERS.format(machineId=machineId, serverId=serverId)
        else:
            params = {'server_id': machineId, 'shared_server': {'library_section_ids': sectionIds,
                "invited_id": user.id}}
            url = self.FRIENDINVITE.format(machineId=machineId)
        # Remove share sections, add shares to user without shares, or update shares
        if sectionIds:
            if removeSections is True:
                response_servers = self.query(url, self._session.delete, json=params, headers=headers)
            elif 'invited_id' in params.get('shared_server', ''):
                response_servers = self.query(url, self._session.post, json=params, headers=headers)
            else:
                response_servers = self.query(url, self._session.put, json=params, headers=headers)
        else:
            log.warning('Section name, number of section object is required changing library sections')
        # Update friend filters
        url = self.FRIENDUPDATE.format(userId=user.id)
        params = {}
        if isinstance(allowSync, bool):
            params['allowSync'] = '1' if allowSync else '0'
        if isinstance(allowCameraUpload, bool):
            params['allowCameraUpload'] = '1' if allowCameraUpload else '0'
        if isinstance(allowChannels, bool):
            params['allowChannels'] = '1' if allowChannels else '0'
        if isinstance(filterMovies, dict):
            params['filterMovies'] = self._filterDictToStr(filterMovies or {})  # '1' if allowChannels else '0'
        if isinstance(filterTelevision, dict):
            params['filterTelevision'] = self._filterDictToStr(filterTelevision or {})
        if isinstance(allowChannels, dict):
            params['filterMusic'] = self._filterDictToStr(filterMusic or {})
        if params:
            url += joinArgs(params)
            response_filters = self.query(url, self._session.put)
        return response_servers, response_filters