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