diff --git a/data/interfaces/default/config.html b/data/interfaces/default/config.html index b2c18b47..e592a6e8 100644 --- a/data/interfaces/default/config.html +++ b/data/interfaces/default/config.html @@ -146,6 +146,17 @@

Set your preferred time format. Click here to see the parameter list.

+
+
+

Plex.tv Authentication

+
+
+ + +

Token for Plex.tv authentication.

+
+

Fetch Token

+

@@ -154,21 +165,25 @@

Plex Media Server

- - -

IP Address for Plex Media Server.

+ + +

IP Address or hostname for Plex Media Server.

+
+
+ Remote Server +

Check this is your Plex Server is not on the same local network as PlexPy.

+
+
+ Force SSL +

Force PlexPy to connect to your Plex Server via SSL. Your server needs to have remote access enabled.

- - + +

Port that Plex Media Server is listening on.

-
- - -

Token for Plex.tv authentication.

-
-

Fetch Token

+ + Verify
@@ -181,12 +196,6 @@

If you have media indexing enabled on your server, use these on the activity pane.

-
-
- Force SSL -

Force PlexPy to connect to your Plex Server via SSL.

-
-

Plex Logs

@@ -825,15 +834,56 @@ $(document).ready(function () { var configForm = $("#configUpdate"); $('.save-button').click(function() { - if (configForm.parsley().validate()) { - doAjaxCall('configUpdate',$(this),'tabs',true); - return false; + if ($("#pms_identifier").val() == "") { + showMsg(' Please verify your server.',false,true,2000) } else { - showMsg(' Please verify your settings.',false,true,2000) + if (configForm.parsley().validate()) { + doAjaxCall('configUpdate',$(this),'tabs',true); + return false; + } else { + showMsg(' Please verify your settings.',false,true,2000) + } } }); }); + $( ".pms-settings" ).change(function() { + $("#pms_identifier").val(""); + $("#pms-verify-status").html(""); + }); + + $("#verify-plex-server").click(function() { + var pms_ip = $("#pms_ip").val() + var pms_port = $("#pms_port").val() + if (($("#pms_ip").val() !== '') || ($("#pms_port").val() !== '')) { + $("#pms-verify-status").html(' Verifying server...'); + $('#pms-verify-status').fadeIn('fast'); + $.ajax({ + url: 'http://' + pms_ip + ':' + pms_port + '/identity', + 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 verified!'); + $('#pms-verify-status').fadeIn('fast'); + } else { + $("#pms-verify-status").html(' This is not a Plex Server!'); + $('#pms-verify-status').fadeIn('fast'); + } + } + }); + } else { + $("#pms-verify-status").html(' Please enter IP and port number.'); + $('#pms-verify-status').fadeIn('fast'); + } + }); + // Plex.tv auth token fetch $("#get-pms-auth-token").click(function() { $("#pms-token-status").html(' Fetching token...'); diff --git a/data/interfaces/default/welcome.html b/data/interfaces/default/welcome.html index 3fa324bc..571c4c6d 100644 --- a/data/interfaces/default/welcome.html +++ b/data/interfaces/default/welcome.html @@ -57,9 +57,16 @@ from plexpy import version
+
+ Server uses SSL +
+
+ Remote Server +
+ Verify @@ -160,6 +167,14 @@ from plexpy import version +
+

Setup Complete!

+
+

Setup is now complete. For more configuration options please visit the Settings menu on the home page.

+
+ Just configuring a few things, please wait... + +
@@ -185,6 +200,8 @@ from plexpy import version wizard.show(); wizard.on("submit", function(wizard) { + // Probably should not success before we know, but hopefully validation is good enough. + wizard.submitSuccess(); $.ajax({ url: "configUpdate", type: "POST", @@ -194,7 +211,7 @@ from plexpy import version complete: function (data) { setTimeout(function(){ location.reload(); - }, 3000); + }, 5000); } }) }); @@ -293,6 +310,7 @@ from plexpy import version }, 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; diff --git a/plexpy/__init__.py b/plexpy/__init__.py index ce658cff..36bd552f 100644 --- a/plexpy/__init__.py +++ b/plexpy/__init__.py @@ -159,9 +159,13 @@ def initialize(config_file): else: LATEST_VERSION = CURRENT_VERSION + # Get the real PMS urls for SSL and remote access + if CONFIG.PMS_TOKEN and CONFIG.PMS_IP and CONFIG.PMS_PORT: + plextv.get_real_pms_url() + # Refresh the users list on startup if CONFIG.PMS_TOKEN and CONFIG.REFRESH_USERS_ON_STARTUP: - plextv.refresh_users() + threading.Thread(target=plextv.refresh_users).start() # Store the original umask UMASK = os.umask(0) @@ -268,6 +272,7 @@ def initialize_scheduler(): seconds = 0 if CONFIG.PMS_IP: + schedule_job(plextv.get_real_pms_url, 'Refresh Plex Server URLs', hours=12, minutes=0, seconds=0) schedule_job(monitor.check_active_sessions, 'Check for active sessions', hours=0, minutes=0, seconds=seconds) # Refresh the users list diff --git a/plexpy/config.py b/plexpy/config.py index 55033cf9..b7f51e73 100644 --- a/plexpy/config.py +++ b/plexpy/config.py @@ -22,12 +22,15 @@ _CONFIG_DEFINITIONS = { 'GROUPING_USER_HISTORY': (int, 'PlexWatch', 0), 'GROUPING_CHARTS': (int, 'PlexWatch', 0), 'PLEXWATCH_DATABASE': (str, 'PlexWatch', ''), + 'PMS_IDENTIFIER': (str, 'PMS', ''), 'PMS_IP': (str, 'PMS', '127.0.0.1'), + 'PMS_IS_REMOTE': (int, 'PMS', 0), 'PMS_LOGS_FOLDER': (str, 'PMS', ''), 'PMS_PORT': (int, 'PMS', 32400), 'PMS_PASSWORD': (str, 'PMS', ''), 'PMS_TOKEN': (str, 'PMS', ''), 'PMS_SSL': (int, 'General', 0), + 'PMS_URL': (str, 'PMS', ''), 'PMS_USERNAME': (str, 'PMS', ''), 'PMS_USE_BIF': (int, 'PMS', 0), 'PMS_UUID': (str, 'PMS', ''), diff --git a/plexpy/datafactory.py b/plexpy/datafactory.py index 9186e832..1f4ea71a 100644 --- a/plexpy/datafactory.py +++ b/plexpy/datafactory.py @@ -173,7 +173,7 @@ class DataFactory(object): search_regex=search_regex, custom_where=custom_where, group_by='', - join_type=['JOIN', 'JOIN', 'JOIN'], + join_type=['LEFT OUTER JOIN', 'JOIN', 'JOIN'], join_table=[t3, t2, t4], join_evals=[[t1 + '.user_id', t3 + '.user_id'], [t1 + '.id', t2 + '.id'], diff --git a/plexpy/http_handler.py b/plexpy/http_handler.py index e073e723..a03db388 100644 --- a/plexpy/http_handler.py +++ b/plexpy/http_handler.py @@ -70,6 +70,11 @@ class HTTPHandler(object): except IOError, e: logger.warn(u"Failed to access uri endpoint %s with error %s" % (uri, e)) return None + except Exception, e: + logger.warn(u"Failed to access uri endpoint %s. Is your server maybe accepting SSL connections only?" % uri) + return None + except: + logger.warn(u"Failed to access uri endpoint %s with Uncaught exception." % uri) if request_status == 200: if output_format == 'dict': diff --git a/plexpy/plextv.py b/plexpy/plextv.py index 6469e934..4f60131c 100644 --- a/plexpy/plextv.py +++ b/plexpy/plextv.py @@ -43,6 +43,42 @@ def refresh_users(): else: logger.warn("Unable to refresh users list.") +def get_real_pms_url(): + logger.info("Requesting URLs for server...") + + # Reset any current PMS_URL value + plexpy.CONFIG.__setattr__('PMS_URL', '') + plexpy.CONFIG.write() + + if plexpy.CONFIG.PMS_SSL: + result = PlexTV().get_server_urls(include_https=True) + process_urls = True + elif plexpy.CONFIG.PMS_IS_REMOTE: + result = PlexTV().get_server_urls(include_https=False) + process_urls = True + else: + real_url = 'http://' + plexpy.CONFIG.PMS_IP + ':' + str(plexpy.CONFIG.PMS_PORT) + process_urls = False + + if process_urls: + if len(result) > 0: + for item in result: + if plexpy.CONFIG.PMS_IS_REMOTE and item['local'] == '0': + real_url = item['uri'] + else: + real_url = item['uri'] + + plexpy.CONFIG.__setattr__('PMS_URL', real_url) + plexpy.CONFIG.write() + logger.info("Server URL retrieved.") + else: + fallback_url = 'http://' + plexpy.CONFIG.PMS_IP + ':' + str(plexpy.CONFIG.PMS_PORT) + plexpy.CONFIG.__setattr__('PMS_URL', fallback_url) + plexpy.CONFIG.write() + logger.warn("Unable to retrieve server URLs. Using user-defined value.") + else: + plexpy.CONFIG.__setattr__('PMS_URL', real_url) + plexpy.CONFIG.write() class PlexTV(object): """ @@ -137,6 +173,18 @@ class PlexTV(object): return request + def get_plextv_resources(self, include_https=False, output_format=''): + if include_https: + uri = '/api/resources?includeHttps=1' + else: + uri = '/api/resources' + request = self.request_handler.make_request(uri=uri, + proto=self.protocol, + request_type='GET', + output_format=output_format) + + return request + def get_full_users_list(self): friends_list = self.get_plextv_friends() own_account = self.get_plextv_user_details() @@ -299,4 +347,45 @@ class PlexTV(object): synced_items.append(sync_details) - return synced_items \ No newline at end of file + return synced_items + + def get_server_urls(self, include_https=True): + + if plexpy.CONFIG.PMS_IDENTIFIER: + server_id = plexpy.CONFIG.PMS_IDENTIFIER + else: + logger.error('PlexPy PlexTV connector :: Unable to retrieve server identity.') + return [] + + plextv_resources = self.get_plextv_resources(include_https=include_https) + server_urls = [] + + try: + xml_parse = minidom.parseString(plextv_resources) + except Exception, e: + logger.warn("Error parsing XML for Plex resources: %s" % e) + return [] + except: + logger.warn("Error parsing XML for Plex resources.") + return [] + + try: + xml_head = xml_parse.getElementsByTagName('Device') + except: + logger.warn("Error parsing XML for Plex resources.") + return [] + + for a in xml_head: + if helpers.get_xml_attr(a, 'clientIdentifier') == server_id: + connections = a.getElementsByTagName('Connection') + for connection in connections: + server_details = {"protocol": helpers.get_xml_attr(connection, 'protocol'), + "address": helpers.get_xml_attr(connection, 'address'), + "port": helpers.get_xml_attr(connection, 'port'), + "uri": helpers.get_xml_attr(connection, 'uri'), + "local": helpers.get_xml_attr(connection, 'local') + } + + server_urls.append(server_details) + + return server_urls \ No newline at end of file diff --git a/plexpy/pmsconnect.py b/plexpy/pmsconnect.py index 53317725..29d73516 100644 --- a/plexpy/pmsconnect.py +++ b/plexpy/pmsconnect.py @@ -14,6 +14,7 @@ # along with PlexPy. If not, see . from plexpy import logger, helpers, datafactory, http_handler +from urlparse import urlparse import plexpy @@ -24,12 +25,18 @@ class PmsConnect(object): """ def __init__(self): - if plexpy.CONFIG.PMS_SSL: - self.protocol = 'HTTPS' + if plexpy.CONFIG.PMS_URL: + url_parsed = urlparse(plexpy.CONFIG.PMS_URL) + hostname = url_parsed.hostname + port = url_parsed.port + self.protocol = url_parsed.scheme else: - self.protocol = 'HTTP' - self.request_handler = http_handler.HTTPHandler(host=plexpy.CONFIG.PMS_IP, - port=plexpy.CONFIG.PMS_PORT, + hostname = plexpy.CONFIG.PMS_IP + port = plexpy.CONFIG.PMS_PORT + self.protocol = 'http' + + self.request_handler = http_handler.HTTPHandler(host=hostname, + port=port, token=plexpy.CONFIG.PMS_TOKEN) """ diff --git a/plexpy/webserve.py b/plexpy/webserve.py index b238563c..964493e5 100644 --- a/plexpy/webserve.py +++ b/plexpy/webserve.py @@ -71,9 +71,12 @@ class WebInterface(object): config = { "launch_browser": checked(plexpy.CONFIG.LAUNCH_BROWSER), "refresh_users_on_startup": checked(plexpy.CONFIG.REFRESH_USERS_ON_STARTUP), + "pms_identifier": plexpy.CONFIG.PMS_IDENTIFIER, "pms_ip": plexpy.CONFIG.PMS_IP, + "pms_is_remote": checked(plexpy.CONFIG.PMS_IS_REMOTE), "pms_port": plexpy.CONFIG.PMS_PORT, "pms_token": plexpy.CONFIG.PMS_TOKEN, + "pms_ssl": checked(plexpy.CONFIG.PMS_SSL), "pms_uuid": plexpy.CONFIG.PMS_UUID, "tv_notify_enable": checked(plexpy.CONFIG.TV_NOTIFY_ENABLE), "movie_notify_enable": checked(plexpy.CONFIG.MOVIE_NOTIFY_ENABLE), @@ -364,6 +367,7 @@ class WebInterface(object): "email_smtp_password": plexpy.CONFIG.EMAIL_SMTP_PASSWORD, "email_smtp_port": int(plexpy.CONFIG.EMAIL_SMTP_PORT), "email_tls": checked(plexpy.CONFIG.EMAIL_TLS), + "pms_identifier": plexpy.CONFIG.PMS_IDENTIFIER, "pms_ip": plexpy.CONFIG.PMS_IP, "pms_logs_folder": plexpy.CONFIG.PMS_LOGS_FOLDER, "pms_port": plexpy.CONFIG.PMS_PORT, @@ -395,7 +399,8 @@ class WebInterface(object): "ip_logging_enable": checked(plexpy.CONFIG.IP_LOGGING_ENABLE), "video_logging_enable": checked(plexpy.CONFIG.VIDEO_LOGGING_ENABLE), "music_logging_enable": checked(plexpy.CONFIG.MUSIC_LOGGING_ENABLE), - "logging_ignore_interval": plexpy.CONFIG.LOGGING_IGNORE_INTERVAL + "logging_ignore_interval": plexpy.CONFIG.LOGGING_IGNORE_INTERVAL, + "pms_is_remote": checked(plexpy.CONFIG.PMS_IS_REMOTE) } return serve_template(templatename="config.html", title="Settings", config=config) @@ -416,7 +421,7 @@ class WebInterface(object): "tv_notify_on_start", "movie_notify_on_start", "music_notify_on_start", "tv_notify_on_stop", "movie_notify_on_stop", "music_notify_on_stop", "tv_notify_on_pause", "movie_notify_on_pause", "music_notify_on_pause", "refresh_users_on_startup", - "ip_logging_enable", "video_logging_enable", "music_logging_enable" + "ip_logging_enable", "video_logging_enable", "music_logging_enable", "pms_is_remote" ] for checked_config in checked_configs: if checked_config not in kwargs: @@ -441,6 +446,8 @@ class WebInterface(object): # Reconfigure scheduler plexpy.initialize_scheduler() + plextv.get_real_pms_url() + # Refresh users table. Probably shouldn't do this on every config save, will improve this later. threading.Thread(target=plextv.refresh_users).start()