diff --git a/data/interfaces/default/css/plexpy.css b/data/interfaces/default/css/plexpy.css index d86dd165..c3350a45 100644 --- a/data/interfaces/default/css/plexpy.css +++ b/data/interfaces/default/css/plexpy.css @@ -2702,4 +2702,7 @@ table[id^='media_info_child'] table[id^='media_info_child'] thead th { color: #444; text-align: center; background-color: #2f2f2f; +} +.selectize-input input[type='text'] { + height: 20px; } \ No newline at end of file diff --git a/data/interfaces/default/settings.html b/data/interfaces/default/settings.html index a7e39b10..94bac875 100644 --- a/data/interfaces/default/settings.html +++ b/data/interfaces/default/settings.html @@ -837,11 +837,9 @@ available_notification_agents = sorted(notifiers.available_notification_agents()

Set custom arguments passed to the scripts.

- -

diff --git a/data/interfaces/default/welcome.html b/data/interfaces/default/welcome.html index 47f48a20..0b19eca1 100644 --- a/data/interfaces/default/welcome.html +++ b/data/interfaces/default/welcome.html @@ -372,41 +372,43 @@ from plexpy import common var pms_verified = false; var authenticated = false; - $("#verify-plex-server").click(function() { - var pms_ip = $("#pms_ip").val() - var pms_port = $("#pms_port").val() - var pms_identifier = $("#pms_identifier").val() - var pms_ssl = $("#pms_ssl").val() - var pms_is_remote = $("#pms_is_remote").val() - if (($("#pms_ip").val() !== '') || ($("#pms_port").val() !== '')) { - $("#pms-verify-status").html(' Validating server...'); - $('#pms-verify-status').fadeIn('fast'); - $.ajax({ - url: 'get_server_id', - data : { hostname: pms_ip, port: pms_port, identifier: pms_identifier, ssl: pms_ssl, remote: pms_is_remote }, - cache: true, - async: true, - timeout: 5000, - error: function(jqXHR, textStatus, errorThrown) { - $("#pms-verify-status").html(' This is not a Plex Server!'); - $('#pms-verify-status').fadeIn('fast'); - }, - success: function (xml) { - if ( $(xml).find('MediaContainer').attr('machineIdentifier') ) { - $("#pms_identifier").val($(xml).find('MediaContainer').attr('machineIdentifier')); - $("#pms-verify-status").html(' Server found!'); - $('#pms-verify-status').fadeIn('fast'); - pms_verified = true; - $("#pms_valid").val("valid"); - } else { + $("#verify-plex-server").click(function () { + if (!(pms_verified)) { + var pms_ip = $("#pms_ip").val().trim(); + var pms_port = $("#pms_port").val().trim(); + var pms_identifier = $("#pms_identifier").val(); + var pms_ssl = $("#pms_ssl").val(); + var pms_is_remote = $("#pms_is_remote").val(); + if ((pms_ip !== '') || (pms_port !== '')) { + $("#pms-verify-status").html(' Validating server...'); + $('#pms-verify-status').fadeIn('fast'); + $.ajax({ + url: 'get_server_id', + data: { hostname: pms_ip, port: pms_port, identifier: pms_identifier, ssl: pms_ssl, remote: pms_is_remote }, + cache: true, + async: true, + timeout: 5000, + error: function (jqXHR, textStatus, errorThrown) { $("#pms-verify-status").html(' This is not a Plex Server!'); $('#pms-verify-status').fadeIn('fast'); + }, + success: function (xml) { + if ($(xml).find('MediaContainer').attr('machineIdentifier')) { + $("#pms_identifier").val($(xml).find('MediaContainer').attr('machineIdentifier')); + $("#pms-verify-status").html(' Server found!'); + $('#pms-verify-status').fadeIn('fast'); + pms_verified = true; + $("#pms_valid").val("valid"); + } else { + $("#pms-verify-status").html(' This is not a Plex Server!'); + $('#pms-verify-status').fadeIn('fast'); + } } - } - }); - } else { - $("#pms-verify-status").html(' Please enter both fields.'); - $('#pms-verify-status').fadeIn('fast'); + }); + } else { + $("#pms-verify-status").html(' Please enter both fields.'); + $('#pms-verify-status').fadeIn('fast'); + } } }); @@ -426,20 +428,23 @@ from plexpy import common $("#pms-authenticate").click(function() { $("#pms-token-status").html(' Fetching token...'); $('#pms-token-status').fadeIn('fast'); - if (($("#pms_username").val() !== '') || ($("#pms_password").val() !== '')) { + var pms_username = $("#pms_username").val().trim(); + var pms_password = $("#pms_password").val().trim(); + if ((pms_username !== '') || (pms_password !== '')) { $.ajax({ type: "post", url: "https://plex.tv/users/sign_in.xml", dataType: 'xml', async: true, - headers: {'Content-Type': 'application/xml; charset=utf-8', - 'X-Plex-Device-Name': 'PlexPy', - 'X-Plex-Product': 'PlexPy', - 'X-Plex-Version': '${common.VERSION_NUMBER}', - 'X-Plex-Platform': '${common.PLATFORM}', - 'X-Plex-Platform-Version': '${common.PLATFORM_VERSION}', - 'X-Plex-Client-Identifier': '${config['pms_uuid']}', - 'Authorization': 'Basic ' + btoa($("#pms_username").val() + ':' + $("#pms_password").val()) + headers: { + 'Content-Type': 'application/xml; charset=utf-8', + 'X-Plex-Device-Name': 'PlexPy', + 'X-Plex-Product': 'PlexPy', + 'X-Plex-Version': '${common.VERSION_NUMBER}', + 'X-Plex-Platform': '${common.PLATFORM}', + 'X-Plex-Platform-Version': '${common.PLATFORM_VERSION}', + 'X-Plex-Client-Identifier': '${config["pms_uuid"]}', + 'Authorization': 'Basic ' + btoa(pms_username + ':' + pms_password) }, error: function(jqXHR, textStatus, errorThrown) { $("#pms-token-status").html(' Authentation failed!'); diff --git a/plexpy/notifiers.py b/plexpy/notifiers.py index d9dd7b83..bee1daab 100644 --- a/plexpy/notifiers.py +++ b/plexpy/notifiers.py @@ -2044,7 +2044,7 @@ class FacebookNotifier(object): self._post_facebook(subject + ': ' + message) def test_notify(self): - return self._post_facebook("This is a test notification from PlexPy at " + helpers.now()) + return self._post_facebook(u"PlexPy Notifiers :: This is a test notification from PlexPy at " + helpers.now()) def _get_authorization(self): return facebook.auth_url(app_id=self.app_id, @@ -2052,7 +2052,7 @@ class FacebookNotifier(object): perms=['user_managed_groups','publish_actions']) def _get_credentials(self, code): - logger.info('Requesting access token from Facebook') + logger.info(u"PlexPy Notifiers :: Requesting access token from Facebook") try: # Request user access token @@ -2072,7 +2072,7 @@ class FacebookNotifier(object): plexpy.CONFIG.FACEBOOK_TOKEN = access_token plexpy.CONFIG.write() except Exception as e: - logger.info(u"Error requesting Facebook access token: %s" % e) + logger.info(u"PlexPy Notifiers :: Error requesting Facebook access token: %s" % e) return False return True @@ -2086,21 +2086,23 @@ class FacebookNotifier(object): try: api.put_wall_post(profile_id=group_id, message=message) - logger.info(u"Facebook notifications sent.") + logger.info(u"PlexPy Notifiers :: Facebook notifications sent.") except Exception as e: - logger.info(u"Error sending Facebook post: %s" % e) + logger.info(u"PlexPy Notifiers :: Error sending Facebook post: %s" % e) return False return True else: - logger.info('Error sending Facebook post: No Facebook Group ID provided.') + logger.info(u"PlexPy Notifiers :: Error sending Facebook post: No Facebook Group ID provided.") return False def return_config_options(self): config_option = [{'label': 'Instructions', 'description': 'Facebook notifications are currently experimental!

\ - Step 1: Visit Facebook Developers to create a new app using advanced setup.
\ - Step 2: Go to Settings > Advanced and fill in Valid OAuth redirect URIs with your PlexPy URL (i.e. http://localhost:8181).
\ + Step 1: Visit \ + Facebook Developers to create a new app using advanced setup.
\ + Step 2: Go to Settings > Advanced and fill in \ + Valid OAuth redirect URIs with your PlexPy URL (i.e. http://localhost:8181).
\ Step 3: Fill in the App ID and App Secret below.
\ Step 4: Click the Request Authorization button below.', 'input_type': 'help' diff --git a/plexpy/plextv.py b/plexpy/plextv.py index 5d8c8000..d98d8e5b 100644 --- a/plexpy/plextv.py +++ b/plexpy/plextv.py @@ -139,13 +139,16 @@ class PlexTV(object): plextv_response = self.get_plex_auth(output_format='xml') if plextv_response: - xml_head = plextv_response.getElementsByTagName('user') - if not xml_head: - logger.warn("Error parsing XML for Plex.tv token") + try: + xml_head = plextv_response.getElementsByTagName('user') + if xml_head: + auth_token = xml_head[0].getAttribute('authenticationToken') + else: + logger.warn(u"PlexPy PlexTV :: Could not get Plex authentication token.") + except Exception as e: + logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_token: %s." % e) return [] - auth_token = xml_head[0].getAttribute('authenticationToken') - return auth_token else: return [] @@ -214,15 +217,15 @@ class PlexTV(object): try: xml_parse = minidom.parseString(own_account) except Exception as e: - logger.warn("Error parsing XML for Plex account details: %s" % e) + logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_full_users_list own account: %s" % e) return [] except: - logger.warn("Error parsing XML for Plex account details.") + logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_full_users_list own account.") return [] xml_head = xml_parse.getElementsByTagName('user') if not xml_head: - logger.warn("Error parsing XML for Plex account details.") + logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_full_users_list.") else: for a in xml_head: own_details = {"user_id": helpers.get_xml_attr(a, 'id'), @@ -239,13 +242,15 @@ class PlexTV(object): try: xml_parse = minidom.parseString(friends_list) except Exception as e: - logger.warn("Error parsing XML for Plex friends list: %s" % e) + logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_full_users_list friends list: %s" % e) + return [] except: - logger.warn("Error parsing XML for Plex friends list.") + logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_full_users_list friends list.") + return [] xml_head = xml_parse.getElementsByTagName('User') if not xml_head: - logger.warn("Error parsing XML for Plex friends list.") + logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_full_users_list.") else: for a in xml_head: friend = {"user_id": helpers.get_xml_attr(a, 'id'), @@ -270,16 +275,16 @@ class PlexTV(object): try: xml_parse = minidom.parseString(sync_list) except Exception as e: - logger.warn("Error parsing XML for Plex sync lists: %s" % e) + logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_synced_items: %s" % e) return [] except: - logger.warn("Error parsing XML for Plex sync lists.") + logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_synced_items.") return [] xml_head = xml_parse.getElementsByTagName('SyncList') if not xml_head: - logger.warn("Error parsing XML for Plex sync lists.") + logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_synced_items.") else: for a in xml_head: client_id = helpers.get_xml_attr(a, 'id') @@ -375,7 +380,7 @@ class PlexTV(object): if plexpy.CONFIG.PMS_IDENTIFIER: server_id = plexpy.CONFIG.PMS_IDENTIFIER else: - logger.error('PlexPy PlexTV connector :: Unable to retrieve server identity.') + logger.error(u"PlexPy PlexTV :: Unable to retrieve server identity.") return [] plextv_resources = self.get_plextv_resources(include_https=include_https) @@ -384,16 +389,16 @@ class PlexTV(object): try: xml_parse = minidom.parseString(plextv_resources) except Exception as e: - logger.warn("Error parsing XML for Plex resources: %s" % e) + logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_server_urls: %s" % e) return [] except: - logger.warn("Error parsing XML for Plex resources.") + logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_server_urls.") return [] try: xml_head = xml_parse.getElementsByTagName('Device') - except: - logger.warn("Error parsing XML for Plex resources.") + except Exception as e: + logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_server_urls: %s." % e) return [] for a in xml_head: @@ -436,8 +441,8 @@ class PlexTV(object): try: xml_head = servers.getElementsByTagName('Server') - except: - logger.warn("Error parsing XML for Plex servers.") + except Exception as e: + logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_server_times: %s." % e) return [] for a in xml_head: @@ -451,35 +456,38 @@ class PlexTV(object): def discover(self): """ Query plex for all servers online. Returns the ones you own in a selectize format """ - result = self.get_plextv_resources(include_https=True, output_format='raw') - servers = xmltodict.parse(result, process_namespaces=True, attr_prefix='') + servers = self.get_plextv_resources(include_https=True, output_format='xml') clean_servers = [] try: - if servers: - # Fix if its only one "device" - if int(servers['MediaContainer']['size']) == 1: - servers['MediaContainer']['Device'] = [servers['MediaContainer']['Device']] - - for server in servers['MediaContainer']['Device']: - # Only grab servers online and own - if server.get('presence', None) == '1' and server.get('owned', None) == '1' and server.get('provides', None) == 'server': - # If someone only has one connection.. - if isinstance(server['Connection'], dict): - server['Connection'] = [server['Connection']] - - for s in server['Connection']: - # to avoid circular ref - d = {} - d.update(s) - d.update(server) - d['label'] = d['name'] - d['value'] = d['address'] - del d['Connection'] - clean_servers.append(d) - + xml_head = servers.getElementsByTagName('MediaContainer') except Exception as e: - logger.warn('Failed to get servers from plex %s' % e) - return clean_servers + logger.warn(u"PlexPy PlexTV :: Failed to get servers from plex: %s." % e) + return [] - return json.dumps(clean_servers, indent=4) \ No newline at end of file + for a in xml_head: + if a.getAttribute('size'): + if a.getAttribute('size') == '0': + return [] + + if a.getElementsByTagName('Device'): + devices = a.getElementsByTagName('Device') + + for d in devices: + if helpers.get_xml_attr(d, 'presence') == '1' and \ + helpers.get_xml_attr(d, 'owned') == '1' and \ + helpers.get_xml_attr(d, 'provides') == 'server': + connections = d.getElementsByTagName('Connection') + + for c in connections: + server = {'httpsRequired': helpers.get_xml_attr(d, 'httpsRequired'), + 'clientIdentifier': helpers.get_xml_attr(d, 'clientIdentifier'), + 'label': helpers.get_xml_attr(d, 'name'), + 'ip': helpers.get_xml_attr(c, 'address'), + 'port': helpers.get_xml_attr(c, 'port'), + 'local': helpers.get_xml_attr(c, 'local'), + 'value': helpers.get_xml_attr(c, 'address') + } + clean_servers.append(server) + + return clean_servers \ No newline at end of file diff --git a/plexpy/pmsconnect.py b/plexpy/pmsconnect.py index c0320a08..07f60e91 100644 --- a/plexpy/pmsconnect.py +++ b/plexpy/pmsconnect.py @@ -39,6 +39,8 @@ def get_server_friendly_name(): return server_name def refresh_libraries(): + from plexpy import activity_pinger + logger.info(u"PlexPy Pmsconnect :: Requesting libraries list refresh...") library_sections = PmsConnect().get_library_details() diff --git a/plexpy/webserve.py b/plexpy/webserve.py index 89ac44dd..a34792eb 100644 --- a/plexpy/webserve.py +++ b/plexpy/webserve.py @@ -106,15 +106,16 @@ class WebInterface(object): Returns the servers that you own as a list of dicts (formatted for selectize) """ - # Need to set token so result dont return http 401 + # Need to set token so result doesn't return http 401 plexpy.CONFIG.__setattr__('PMS_TOKEN', token) plexpy.CONFIG.write() - result = plextv.PlexTV() - servers = result.discover() + plex_tv = plextv.PlexTV() + servers = plex_tv.discover() + if servers: cherrypy.response.headers['Content-type'] = 'application/json' - return servers + return json.dumps(servers) ##### Home ##### @@ -1235,7 +1236,7 @@ class WebInterface(object): if this_agent: logger.debug(u"Sending test %s notification." % this_agent['name']) - notifiers.send_notification(this_agent['id'], subject, body) + notifiers.send_notification(this_agent['id'], subject, body, **kwargs) return "Notification sent." else: logger.debug(u"Unable to send test notification, invalid notification agent ID %s." % config_id) @@ -1378,7 +1379,7 @@ class WebInterface(object): @cherrypy.expose def generateAPI(self): apikey = hashlib.sha224(str(random.getrandbits(256))).hexdigest()[0:32] - logger.info(u"New API generated") + logger.info(u"New API key generated.") return apikey @cherrypy.expose