Use Plex downloads to check for PMS updates instead of server API

* Check for PMS updates has been disabled and must be re-enabled in the
settings
This commit is contained in:
JonnyWong16 2016-06-25 18:41:18 -07:00
parent a42a1af867
commit 984e5588c8
5 changed files with 225 additions and 61 deletions

View file

@ -581,15 +581,31 @@
<div role="tabpanel" class="tab-pane" id="tabs-5"> <div role="tabpanel" class="tab-pane" id="tabs-5">
<div class="padded-header"> <div class="padded-header">
<h3>Plex Media Server <small style="color: #fff;">Version <span id="pms_version">unknown</span></small></h3> <h3>Plex Media Server <small style="color: #fff;">Version <span id="pms_version">${config['pms_version']}</span></small></h3>
</div> </div>
<p class="help-block">If you're using websocket monitoring, any server changes require a restart of PlexPy.</p> <p class="help-block">If you're using websocket monitoring, any server changes require a restart of PlexPy.</p>
<div class="checkbox"> <div class="checkbox">
<label> <label>
<input type="checkbox" id="monitor_pms_updates" name="monitor_pms_updates" value="1" ${config['monitor_pms_updates']}> Monitor Plex Updates <input type="checkbox" id="monitor_pms_updates" name="monitor_pms_updates" value="1" ${config['monitor_pms_updates']}> Monitor Plex Updates
</label> </label>
<p class="help-block">Enable to have PlexPy check if updates are available for the Plex Media Server.<br /> <p class="help-block">Enable to have PlexPy check if updates are available for the Plex Media Server.</p>
Note: The Plex updater is broken on certain Plex Pass version of Plex Media Server. PlexPy will automatically disable checking for Plex updates if one of these versions is found.</p> </div>
<div id="pms_update_options">
<div class="form-group">
<div class="row">
<div class="col-md-2">
<label for="pms_update_channel">Update Channel</label>
<select class="form-control" id="pms_update_channel" name="pms_update_channel">
<option value="public">Public</option>
</select>
</div>
<div class="col-md-5">
<label for="pms_update_distro_build">Release</label>
<select class="form-control" id="pms_update_distro_build" name="pms_update_distro_build">
</select>
</div>
</div>
</div>
</div> </div>
<div class="checkbox"> <div class="checkbox">
<label> <label>
@ -2115,6 +2131,7 @@ $(document).ready(function() {
} }
$("#http_hashed_password").val($("#http_hash_password").is(":checked") ? 1 : 0) $("#http_hashed_password").val($("#http_hash_password").is(":checked") ? 1 : 0)
getSchedulerTable(); getSchedulerTable();
loadUpdateDistros();
settingsChanged = false; settingsChanged = false;
} }
@ -2145,6 +2162,7 @@ $(document).ready(function() {
initConfigCheckbox('#https_create_cert'); initConfigCheckbox('#https_create_cert');
initConfigCheckbox('#check_github'); initConfigCheckbox('#check_github');
initConfigCheckbox('#notify_upload_posters'); initConfigCheckbox('#notify_upload_posters');
initConfigCheckbox('#monitor_pms_updates');
$("#menu_link_shutdown").click(function() { $("#menu_link_shutdown").click(function() {
$("#confirm-message").text("Are you sure you want to shutdown PlexPy?"); $("#confirm-message").text("Are you sure you want to shutdown PlexPy?");
@ -2348,6 +2366,7 @@ $(document).ready(function() {
} else { } else {
$("#pms-token-status").html('<i class="fa fa-exclamation-circle"></i> Invalid username or password.'); $("#pms-token-status").html('<i class="fa fa-exclamation-circle"></i> Invalid username or password.');
} }
loadUpdateDistros();
} }
}); });
} else { } else {
@ -2406,12 +2425,7 @@ $(document).ready(function() {
pms_logs = false; pms_logs = false;
// Checks to see if PMS server version is >= 0.9.14 with automaatically logged IP addresses // Checks to see if PMS server version is >= 0.9.14 with automaatically logged IP addresses
$.ajax({ var version = "${config['pms_version']}".split('.');
url: 'get_server_identity',
async: true,
success: function(data) {
if (data.version){ $("#pms_version").text(data.version); }
var version = (data.version ? data.version.split('.') : null);
if (version && parseInt(version[0]) >= 0 && parseInt(version[1]) >= 9 && parseInt(version[2]) >= 14) { if (version && parseInt(version[0]) >= 0 && parseInt(version[1]) >= 9 && parseInt(version[2]) >= 14) {
$("#debugLogCheck").html("IP address is automatically logged for PMS version 0.9.14 and above."); $("#debugLogCheck").html("IP address is automatically logged for PMS version 0.9.14 and above.");
$("#ip_logging_enable").attr("disabled", true); $("#ip_logging_enable").attr("disabled", true);
@ -2431,8 +2445,6 @@ $(document).ready(function() {
} }
}); });
} }
}
});
$("#pms_logs_folder").change(function() { $("#pms_logs_folder").change(function() {
checkLogsPath(); checkLogsPath();
@ -2642,6 +2654,47 @@ $(document).ready(function() {
$("#http_hashed_password").val($("#http_hash_password").is(":checked") ? 1 : 0); $("#http_hashed_password").val($("#http_hash_password").is(":checked") ? 1 : 0);
$("#http_hash_password_error").html(""); $("#http_hash_password_error").html("");
}); });
// Load PMS downloads
function loadUpdateDistros(distro_build) {
var update_params_ajax = $.getJSON('get_server_update_params', function (data) { return data; });
$.when(update_params_ajax).done(function() {
var update_params = update_params_ajax.responseJSON;
var plexpass = update_params.plexpass;
var platform = update_params.pms_platform;
var update_channel = update_params.pms_update_channel;
var update_distro_build = update_params.pms_update_distro_build;
$("#pms_update_channel option[value='plexpass']").remove();
if (plexpass) {
var selected = (update_channel == 'plexpass') ? true : false;
$('#pms_update_channel')
.append($('<option></option>')
.text('Plex Pass')
.val('plexpass')
.prop('selected', selected));
}
$.getJSON('https://plex.tv/api/downloads/1.json?channel=' + update_channel, function (downloads) {
platform_downloads = downloads.computer[platform] || downloads.nas[platform];
if (platform_downloads) {
$("#pms_update_distro_build option").remove();
$.each(platform_downloads.releases, function (index, item) {
var label = (platform_downloads.releases.length == 1) ? platform_downloads.name : platform_downloads.name + ' - ' + item.label;
var selected = (item.build == update_distro_build) ? true : false;
$('#pms_update_distro_build')
.append($('<option></option>')
.text(label)
.val(item.build)
.prop('selected', selected));
})
}
});
});
}
loadUpdateDistros();
}); });
</script> </script>
</%def> </%def>

View file

@ -24,6 +24,7 @@ import libraries
import logger import logger
import notification_handler import notification_handler
import notifiers import notifiers
import plextv
import pmsconnect import pmsconnect
@ -372,18 +373,14 @@ def check_server_updates():
with monitor_lock: with monitor_lock:
logger.info(u"PlexPy Monitor :: Checking for PMS updates...") logger.info(u"PlexPy Monitor :: Checking for PMS updates...")
pms_connect = pmsconnect.PmsConnect() plex_tv = plextv.PlexTV()
download_info = plex_tv.get_plex_downloads()
server_identity = pms_connect.get_server_identity() if download_info:
update_status = pms_connect.get_update_staus() logger.info(u"PlexPy Monitor :: Current PMS version: %s", plexpy.CONFIG.PMS_VERSION)
if server_identity and update_status: if download_info['update_available']:
version = server_identity['version'] logger.info(u"PlexPy Monitor :: PMS update available version: %s", download_info['version'])
logger.info(u"PlexPy Monitor :: Current PMS version: %s", version)
if update_status['state'] == 'available':
update_version = update_status['version']
logger.info(u"PlexPy Monitor :: PMS update available version: %s", update_version)
# Check if any notification agents have notifications enabled # Check if any notification agents have notifications enabled
if any(d['on_pmsupdate'] for d in notifiers.available_notification_agents()): if any(d['on_pmsupdate'] for d in notifiers.available_notification_agents()):

View file

@ -55,6 +55,11 @@ _CONFIG_DEFINITIONS = {
'PMS_USE_BIF': (int, 'PMS', 0), 'PMS_USE_BIF': (int, 'PMS', 0),
'PMS_UUID': (str, 'PMS', ''), 'PMS_UUID': (str, 'PMS', ''),
'PMS_TIMEOUT': (int, 'Advanced', 15), 'PMS_TIMEOUT': (int, 'Advanced', 15),
'PMS_PLEXPASS': (int, 'PMS', 0),
'PMS_PLATFORM': (str, 'PMS', ''),
'PMS_VERSION': (str, 'PMS', ''),
'PMS_UPDATE_CHANNEL': (str, 'PMS', 'public'),
'PMS_UPDATE_DISTRO_BUILD': (str, 'PMS', ''),
'TIME_FORMAT': (str, 'General', 'HH:mm'), 'TIME_FORMAT': (str, 'General', 'HH:mm'),
'ANON_REDIRECT': (str, 'General', 'http://dereferer.org/?'), 'ANON_REDIRECT': (str, 'General', 'http://dereferer.org/?'),
'API_ENABLED': (int, 'General', 0), 'API_ENABLED': (int, 'General', 0),
@ -720,3 +725,7 @@ class Config(object):
home_sections.remove('library_stats') home_sections.remove('library_stats')
self.HOME_SECTIONS = home_sections self.HOME_SECTIONS = home_sections
self.CONFIG_VERSION = '5' self.CONFIG_VERSION = '5'
if self.CONFIG_VERSION == '5':
self.MONITOR_PMS_UPDATES = 0
self.CONFIG_VERSION = '6'

View file

@ -17,6 +17,7 @@
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>. # along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
import base64 import base64
import json
from xml.dom import minidom from xml.dom import minidom
import plexpy import plexpy
@ -95,14 +96,20 @@ def get_real_pms_url():
fallback_url = 'http://' + plexpy.CONFIG.PMS_IP + ':' + str(plexpy.CONFIG.PMS_PORT) fallback_url = 'http://' + plexpy.CONFIG.PMS_IP + ':' + str(plexpy.CONFIG.PMS_PORT)
if plexpy.CONFIG.PMS_SSL: plex_tv = PlexTV()
result = PlexTV().get_server_urls(include_https=True) result = plex_tv.get_server_urls(include_https=plexpy.CONFIG.PMS_SSL)
else: plexpass = plex_tv.get_plexpass_status()
result = PlexTV().get_server_urls(include_https=False)
connections = []
if result:
plexpy.CONFIG.__setattr__('PMS_VERSION', result['version'])
plexpy.CONFIG.__setattr__('PMS_PLATFORM', result['platform'])
plexpy.CONFIG.__setattr__('PMS_PLEXPASS', plexpass)
connections = result['connections']
# Only need to retrieve PMS_URL if using SSL # Only need to retrieve PMS_URL if using SSL
if plexpy.CONFIG.PMS_SSL: if plexpy.CONFIG.PMS_SSL:
if result: if connections:
if plexpy.CONFIG.PMS_IS_REMOTE: if plexpy.CONFIG.PMS_IS_REMOTE:
# Get all remote connections # Get all remote connections
connections = [c for c in result if c['local'] == '0' and 'plex.direct' in c['uri']] connections = [c for c in result if c['local'] == '0' and 'plex.direct' in c['uri']]
@ -273,6 +280,18 @@ class PlexTV(object):
return request return request
def get_plextv_downloads(self, plexpass=False, output_format=''):
if plexpass:
uri = '/api/downloads/1.json?channel=plexpass'
else:
uri = '/api/downloads/1.json'
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): def get_full_users_list(self):
friends_list = self.get_plextv_friends() friends_list = self.get_plextv_friends()
own_account = self.get_plextv_user_details() own_account = self.get_plextv_user_details()
@ -454,7 +473,7 @@ class PlexTV(object):
server_id = plexpy.CONFIG.PMS_IDENTIFIER server_id = plexpy.CONFIG.PMS_IDENTIFIER
else: else:
logger.error(u"PlexPy PlexTV :: Unable to retrieve server identity.") logger.error(u"PlexPy PlexTV :: Unable to retrieve server identity.")
return [] return {}
plextv_resources = self.get_plextv_resources(include_https=include_https) plextv_resources = self.get_plextv_resources(include_https=include_https)
@ -462,22 +481,26 @@ class PlexTV(object):
xml_parse = minidom.parseString(plextv_resources) xml_parse = minidom.parseString(plextv_resources)
except Exception as e: except Exception as e:
logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_server_urls: %s" % e) logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_server_urls: %s" % e)
return [] return {}
except: except:
logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_server_urls.") logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_server_urls.")
return [] return {}
try: try:
xml_head = xml_parse.getElementsByTagName('Device') xml_head = xml_parse.getElementsByTagName('Device')
except Exception as e: except Exception as e:
logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_server_urls: %s." % e) logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_server_urls: %s." % e)
return [] return {}
# Function to get all connections for a device # Function to get all connections for a device
def get_connections(device): def get_connections(device):
conn = [] conn = []
connections = device.getElementsByTagName('Connection') connections = device.getElementsByTagName('Connection')
server = {"platform": helpers.get_xml_attr(device, 'platform'),
"version": helpers.get_xml_attr(device, 'productVersion')
}
for c in connections: for c in connections:
server_details = {"protocol": helpers.get_xml_attr(c, 'protocol'), server_details = {"protocol": helpers.get_xml_attr(c, 'protocol'),
"address": helpers.get_xml_attr(c, 'address'), "address": helpers.get_xml_attr(c, 'address'),
@ -487,18 +510,19 @@ class PlexTV(object):
} }
conn.append(server_details) conn.append(server_details)
return conn server['connections'] = conn
return server
server_urls = [] server = {}
# Try to match the device # Try to match the device
for a in xml_head: for a in xml_head:
if helpers.get_xml_attr(a, 'clientIdentifier') == server_id: if helpers.get_xml_attr(a, 'clientIdentifier') == server_id:
server_urls = get_connections(a) server = get_connections(a)
break break
# Else no device match found # Else no device match found
if not server_urls: if not server:
# Try to match the PMS_IP and PMS_PORT # Try to match the PMS_IP and PMS_PORT
for a in xml_head: for a in xml_head:
if helpers.get_xml_attr(a, 'provides') == 'server': if helpers.get_xml_attr(a, 'provides') == 'server':
@ -511,16 +535,16 @@ class PlexTV(object):
plexpy.CONFIG.PMS_IDENTIFIER = helpers.get_xml_attr(a, 'clientIdentifier') plexpy.CONFIG.PMS_IDENTIFIER = helpers.get_xml_attr(a, 'clientIdentifier')
plexpy.CONFIG.write() plexpy.CONFIG.write()
logger.info(u"PlexPy PlexTV :: PMS identifier changed from %s to %s." % \ logger.info(u"PlexPy PlexTV :: PMS identifier changed from %s to %s."
(server_id, plexpy.CONFIG.PMS_IDENTIFIER)) % (server_id, plexpy.CONFIG.PMS_IDENTIFIER))
server_urls = get_connections(a) server = get_connections(a)
break break
if server_urls: if server.get('connections'):
break break
return server_urls return server
def get_server_times(self): def get_server_times(self):
servers = self.get_plextv_server_list(output_format='xml') servers = self.get_plextv_server_list(output_format='xml')
@ -589,3 +613,71 @@ class PlexTV(object):
clean_servers.append(server) clean_servers.append(server)
return clean_servers return clean_servers
def get_plex_downloads(self):
logger.debug(u"PlexPy PlexTV :: Plex update channel is %s." % plexpy.CONFIG.PMS_UPDATE_CHANNEL)
plex_downloads = self.get_plextv_downloads(plexpass=(plexpy.CONFIG.PMS_UPDATE_CHANNEL == 'plexpass'))
try:
available_downloads = json.loads(plex_downloads)
except Exception as e:
logger.warn(u"PlexPy PlexTV :: Unable to load JSON for get_plex_updates.")
return {}
# Get the updates for the platform
platform_downloads = available_downloads.get('computer').get(plexpy.CONFIG.PMS_PLATFORM) or \
available_downloads.get('nas').get(plexpy.CONFIG.PMS_PLATFORM)
if not platform_downloads:
logger.error(u"PlexPy PlexTV :: Unable to retrieve Plex updates: Could not match server platform: %s."
% plexpy.CONFIG.PMS_PLATFORM)
return {}
v_old = plexpy.CONFIG.PMS_VERSION.split('-')[0].split('.')
v_new = platform_downloads.get('version', '').split('-')[0].split('.')
# Compare versions
if v_new[0] > v_old[0] or \
v_new[0] == v_old[0] and v_new[1] > v_old[1] or \
v_new[0] == v_old[0] and v_new[1] == v_old[1] and v_new[2] > v_old[2] or \
v_new[0] == v_old[0] and v_new[1] == v_old[1] and v_new[2] == v_old[2] and v_new[3] > v_old[3]:
update_available = True
else:
update_available = False
# Get proper download
releases = platform_downloads.get('releases', [])
release = next((r for r in releases if r['build'] == plexpy.CONFIG.PMS_UPDATE_DISTRO_BUILD), releases[0])
download_info = {'update_available': update_available,
'platform': platform_downloads.get('name'),
'release_date': platform_downloads.get('release_date'),
'version': platform_downloads.get('version'),
'requirements': platform_downloads.get('requirements'),
'extra_info': platform_downloads.get('extra_info'),
'changelog_added': platform_downloads.get('items_added'),
'changelog_fixed': platform_downloads.get('items_fixed'),
'label': release.get('label'),
'distro': release.get('distro'),
'distro_build': release.get('build'),
'download_url': release.get('url'),
}
return download_info
def get_plexpass_status(self):
account_data = self.get_plextv_user_details(output_format='xml')
try:
subscription = account_data.getElementsByTagName('subscription')
except Exception as e:
logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_plexpass_status: %s." % e)
return False
if subscription and helpers.get_xml_attr(subscription[0], 'active') == '1':
return True
else:
logger.debug(u"PlexPy PlexTV :: Plex Pass subscription not found.")
plexpy.CONFIG.__setattr__('PMS_PLEXPASS', 0)
plexpy.CONFIG.write()
return False

View file

@ -2606,7 +2606,8 @@ class WebInterface(object):
"group_history_tables": checked(plexpy.CONFIG.GROUP_HISTORY_TABLES), "group_history_tables": checked(plexpy.CONFIG.GROUP_HISTORY_TABLES),
"git_token": plexpy.CONFIG.GIT_TOKEN, "git_token": plexpy.CONFIG.GIT_TOKEN,
"imgur_client_id": plexpy.CONFIG.IMGUR_CLIENT_ID, "imgur_client_id": plexpy.CONFIG.IMGUR_CLIENT_ID,
"cache_images": checked(plexpy.CONFIG.CACHE_IMAGES) "cache_images": checked(plexpy.CONFIG.CACHE_IMAGES),
"pms_version": plexpy.CONFIG.PMS_VERSION,
} }
return serve_template(templatename="settings.html", title="Settings", config=config) return serve_template(templatename="settings.html", title="Settings", config=config)
@ -2769,6 +2770,18 @@ class WebInterface(object):
def get_scheduler_table(self, **kwargs): def get_scheduler_table(self, **kwargs):
return serve_template(templatename="scheduler_table.html") return serve_template(templatename="scheduler_table.html")
@cherrypy.expose
@cherrypy.tools.json_out()
@requireAuth(member_of("admin"))
def get_server_update_params(self):
plex_tv = plextv.PlexTV()
plexpass = plex_tv.get_plexpass_status()
return {'plexpass': plexpass,
'pms_platform': plexpy.CONFIG.PMS_PLATFORM,
'pms_update_channel': plexpy.CONFIG.PMS_UPDATE_CHANNEL,
'pms_update_distro_build': plexpy.CONFIG.PMS_UPDATE_DISTRO_BUILD}
@cherrypy.expose @cherrypy.expose
@cherrypy.tools.json_out() @cherrypy.tools.json_out()
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))