diff --git a/plexapi/client.py b/plexapi/client.py index b0821123..13495356 100644 --- a/plexapi/client.py +++ b/plexapi/client.py @@ -55,8 +55,8 @@ class PlexClient(PlexObject): TAG = 'Player' key = '/resources' - def __init__(self, server=None, data=None, initpath=None, baseurl=None, token=None, - connect=True, session=None, timeout=None): + def __init__(self, server=None, data=None, initpath=None, baseurl=None, + token=None, connect=True, session=None, timeout=None): super(PlexClient, self).__init__(server, data, initpath) self._baseurl = baseurl.strip('/') if baseurl else None self._token = logfilter.add_secret(token) diff --git a/plexapi/myplex.py b/plexapi/myplex.py index 6d8cdf9e..ac50cc59 100644 --- a/plexapi/myplex.py +++ b/plexapi/myplex.py @@ -59,13 +59,19 @@ class MyPlexAccount(PlexObject): WEBHOOKS = 'https://plex.tv/api/v2/user/webhooks' key = 'https://plex.tv/users/account' - def __init__(self, username=None, password=None, session=None, timeout=None): + def __init__(self, username=None, password=None, token=None, session=None, timeout=None): + self._token = token self._session = session or requests.Session() - self._token = None + data, initpath = self._signin(username, password, timeout) + super(MyPlexAccount, self).__init__(self, data, initpath) + + def _signin(self, username, password, timeout): + if self._token: + return self.query(self.key), self.key username = username or CONFIG.get('auth.myplex_username') password = password or CONFIG.get('auth.myplex_password') data = self.query(self.SIGNIN, method=self._session.post, auth=(username, password), timeout=timeout) - super(MyPlexAccount, self).__init__(self, data, self.SIGNIN) + return data, self.SIGNIN def _loadData(self, data): """ Load attribute values from Plex XML response. """ diff --git a/plexapi/server.py b/plexapi/server.py index 2dd68c1f..4ea48649 100644 --- a/plexapi/server.py +++ b/plexapi/server.py @@ -174,25 +174,36 @@ class PlexServer(PlexObject): data = self.query(Account.key) return Account(self, data) + def myPlexAccount(self): + """ Returns a :class:`~plexapi.myplex.MyPlexAccount` object using the same + token to access this server. If you are not the owner of this PlexServer + you're likley to recieve an authentication error calling this. + """ + from plexapi.myplex import MyPlexAccount + return MyPlexAccount(token=self._token) + + def _myPlexClientPorts(self): + 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.warn('Unable to fetch client ports from myPlex: %s', err) + return ports + def clients(self): """ Returns list of all :class:`~plexapi.client.PlexClient` objects connected to server. """ items = [] - cache_resource = None - from plexapi.myplex import MyPlexResource + ports = None for elem in self.query('/clients'): - # Some shitty clients dont include a port.. port = elem.attrib.get('port') - if port is None: - log.debug("%s didn't provide a port. Checking https://plex.tv/devices.xml" % elem.attrib.get('name')) - data = cache_resource or self._server._session.get('https://plex.tv/devices.xml?X-Plex-Token=%s' % self.token) # noqa - cache_resource = data - resources = MyPlexResource(self, data) - for resource in resources: - if resource.clientIdentifier == elem.attrib.get('machineIdentifier'): - for conn in resource.connection: - if conn.local is True: - port = conn.port - break + if not port: + log.warn('%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, data=elem, connect=False)) return items @@ -208,7 +219,12 @@ class PlexServer(PlexObject): """ for elem in self.query('/clients'): if elem.attrib.get('name').lower() == name.lower(): - baseurl = 'http://%s:%s' % (elem.attrib['host'], elem.attrib['port']) + port = elem.attrib.get('port') + if not port: + log.warn('%s did not advertise a port, checking plex.tv.', elem.attrib.get('name')) + ports = self._myPlexClientPorts() + port = ports.get(elem.attrib.get('machineIdentifier')) + baseurl = 'http://%s:%s' % (elem.attrib['host'], port) return PlexClient(baseurl=baseurl, server=self, data=elem) raise NotFound('Unknown client name: %s' % name)