Merge pull request #189 from JackDandy/feature/UpdatePlexNotifer

Feature/Update Plex notifer.
This commit is contained in:
JackDandy 2015-02-14 14:15:55 +00:00
commit 45c5acd88e
6 changed files with 291 additions and 195 deletions

View file

@ -39,6 +39,14 @@
* Remove defunct boxcar notifier
* Add sound selection for boxcar2 notifier
* Change boxcar2 notifier to use updated api scheme
* Update the Plex notifier from a port at midgetspy/sickbeard
* Add support for multiple server hosts to the updated Plex server notifier
* Change Plex Media Server settings section for multi server(s) and improve the layout in the config/notifications page
* Add logic to Plex notifier to update a single server where its TV section path matches the downloaded show. All server
libraries are updated if no single server has a download path match.
* Change the ui notifications to show the Plex Media Server(s) actioned for library updating
* Fix issue where PMS text wasn't initialised on the config/notifications page and added info about Plex clients
* Add ability to test Plex Server(s) on config/notifications page
[develop changelog]
* Change uT params from unicode to str.format as magnet URLs worked but sending files in POST bodies failed

View file

@ -1,4 +1,5 @@
#import sickbeard
#import re
#from sickbeard.helpers import anon_url
#set global $title = 'Config - Notifications'
@ -30,7 +31,7 @@
<div id="tabs-1">
<div class="component-group">
<div class="component-group-desc">
<img class="notifier-icon" src="$sbRoot/images/notifiers/xbmc.png" alt="" title="XBMC" />
<h3><a href="<%= anon_url('http://kodi.tv/') %>" rel="noreferrer" onclick="window.open(this.href, '_blank'); return false;">XBMC</a></h3>
@ -110,7 +111,7 @@
<p>only send library updates to the first active host ?</p>
</span>
</label>
</div>
</div>
<div class="field-pair">
<label for="xbmc_host">
<span class="component-title">XBMC IP:Port</span>
@ -123,7 +124,7 @@
<label>
<span class="component-title">&nbsp;</span>
<span class="component-desc">(multiple host strings must be separated by commas)</span>
</label>
</label>
</div>
<div class="field-pair">
<label for="xbmc_username">
@ -151,7 +152,7 @@
</div><!-- /content_use_xbmc //-->
</fieldset>
</div><!-- /xbmc component-group //-->
@ -160,103 +161,120 @@
<img class="notifier-icon" src="$sbRoot/images/notifiers/plex.png" alt="" title="Plex Media Server" />
<h3><a href="<%= anon_url('http://www.plexapp.com/') %>" rel="noreferrer" onclick="window.open(this.href, '_blank'); return false;">Plex Media Server</a></h3>
<p>Plex organizes all of your personal media, wherever you keep it, so you can enjoy it on any device</p>
<p class="plexinfo hide">For sending notifications to Plex Home Theater (PHT) clients, use the XBMC notifier with port <b>3005</b>.</p>
<p class="plexinfo hide"><span class="red-text">To send notifications to <span class="boldest">Plex Home Theater (PHT) clients</span>,</span> use the XBMC notifier with port <b>3005</b>.</p>
</div>
<fieldset class="component-group-list">
<div class="field-pair">
<label for="use_plex">
<span class="component-title">Enable</span>
<span class="component-desc">
<input type="checkbox" class="enabler" name="use_plex" id="use_plex" #if $sickbeard.USE_PLEX then "checked=\"checked\"" else ""# />
<input type="checkbox" class="enabler" name="use_plex" id="use_plex" #if $sickbeard.USE_PLEX then 'checked="checked" ' else ''# />
<p>should SickGear send Plex commands ?</p>
</span>
</label>
</div>
<div id="content_use_plex">
<div class="field-pair">
<label for="plex_notify_onsnatch">
<span class="component-title">Notify on snatch</span>
<span class="component-desc">
<input type="checkbox" name="plex_notify_onsnatch" id="plex_notify_onsnatch" #if $sickbeard.PLEX_NOTIFY_ONSNATCH then "checked=\"checked\"" else ""# />
<p>send a notification when a download starts ?</p>
</span>
</label>
<div class="component-group" style="padding: 0; min-height: 130px">
<div class="field-pair">
<label for="plex_username">
<span class="component-title">Server/client username</span>
<span class="component-desc">
<input type="text" name="plex_username" id="plex_username" value="$sickbeard.PLEX_USERNAME" class="form-control input-sm input250" />
<p>blank = no authentication</p>
</span>
</label>
</div>
<div class="field-pair">
<label for="plex_password">
<span class="component-title">Server/client password</span>
<span class="component-desc">
<input type="password" name="plex_password" id="plex_password" value="$sickbeard.PLEX_PASSWORD" class="form-control input-sm input250" />
<p>blank = no authentication</p>
</span>
</label>
</div>
</div>
<div class="field-pair">
<label for="plex_notify_ondownload">
<span class="component-title">Notify on download</span>
<span class="component-desc">
<input type="checkbox" name="plex_notify_ondownload" id="plex_notify_ondownload" #if $sickbeard.PLEX_NOTIFY_ONDOWNLOAD then "checked=\"checked\"" else ""# />
<p>send a notification when a download finishes ?</p>
</span>
</label>
<div class="component-group" style="padding: 0; min-height: 50px">
<div class="field-pair">
<label for="plex_update_library">
<span class="component-title">Update server library</span>
<span class="component-desc">
<input type="checkbox" class="enabler" name="plex_update_library" id="plex_update_library" #if $sickbeard.PLEX_UPDATE_LIBRARY then 'checked="checked" ' else ''#/>
<p>update Plex Media Server library when a download finishes</p>
</span>
</label>
</div>
<div id="content_plex_update_library">
<div class="field-pair">
<label for="plex_server_host">
<span class="component-title">Plex Media Server IP:Port</span>
<span class="component-desc">
<input type="text" name="plex_server_host" id="plex_server_host" value="<%= re.sub(r'\b,\b', ', ', sickbeard.PLEX_SERVER_HOST) %>" class="form-control input-sm input350" />
<div class="clear-left">
<p>one or more hosts running Plex Media Server<br />(eg. 192.168.1.1:32400, 192.168.1.2:32400)</p>
</div>
</span>
</label>
</div>
<div class="field-pair">
<div class="testNotification" id="testPMS-result">Click below to test Plex server(s)</div>
<input class="btn" type="button" value="Test Plex Server" id="testPMS" />
<input type="submit" class="config_submitter btn" value="Save Changes" />
<div class="clear-left">&nbsp;</div>
</div>
</div>
</div>
<div class="field-pair">
<label for="plex_notify_onsubtitledownload">
<span class="component-title">Notify on subtitle download</span>
<span class="component-desc">
<input type="checkbox" name="plex_notify_onsubtitledownload" id="plex_notify_onsubtitledownload" #if $sickbeard.PLEX_NOTIFY_ONSUBTITLEDOWNLOAD then "checked=\"checked\"" else ""# />
<p>send a notification when subtitles are downloaded ?</p>
</span>
</label>
</div>
<div class="field-pair">
<label for="plex_update_library">
<span class="component-title">Update library</span>
<span class="component-desc">
<input type="checkbox" name="plex_update_library" id="plex_update_library" #if $sickbeard.PLEX_UPDATE_LIBRARY then "checked=\"checked\"" else ""# />
<p>update Plex Media Server library when a download finishes ?</p>
</span>
</label>
</div>
<div class="field-pair">
<label for="plex_server_host">
<span class="component-title">Plex Media Server IP:Port</span>
<input type="text" name="plex_server_host" id="plex_server_host" value="$sickbeard.PLEX_SERVER_HOST" class="form-control input-sm input250" />
</label>
<label>
<span class="component-title">&nbsp;</span>
<span class="component-desc">host running Plex Media Server (eg. 192.168.1.100:32400)</span>
</label>
</div>
<div class="field-pair">
<label for="plex_host">
<span class="component-title">Plex client IP:Port</span>
<input type="text" name="plex_host" id="plex_host" value="$sickbeard.PLEX_HOST" class="form-control input-sm input350" />
</label>
<label>
<span class="component-title">&nbsp;</span>
<span class="component-desc">host running Plex client (eg. 192.168.1.100:3000)</span>
</label>
<label>
<span class="component-title">&nbsp;</span>
<span class="component-desc">(multiple host strings must be separated by commas)</span>
</label>
</div>
<div class="field-pair">
<label for="plex_username">
<span class="component-title">Plex client username</span>
<input type="text" name="plex_username" id="plex_username" value="$sickbeard.PLEX_USERNAME" class="form-control input-sm input250" />
</label>
<label>
<span class="component-title">&nbsp;</span>
<span class="component-desc">needed if your client / server requires authentication (blank for none)</span>
</label>
</div>
<div class="field-pair">
<label for="plex_password">
<span class="component-title">Plex client password</span>
<input type="password" name="plex_password" id="plex_password" value="$sickbeard.PLEX_PASSWORD" class="form-control input-sm input250" />
</label>
<label>
<span class="component-title">&nbsp;</span>
<span class="component-desc">needed if your client / server requires authentication (blank for none)</span>
</label>
</div>
<div class="testNotification" id="testPLEX-result">Click below to test.</div>
<input class="btn" type="button" value="Test Plex Client" id="testPLEX" />
<input type="submit" class="config_submitter btn" value="Save Changes" />
<div>
<div class="field-pair">
<label for="plex_notify_onsnatch">
<span class="component-title">Notify on snatch</span>
<span class="component-desc">
<input type="checkbox" name="plex_notify_onsnatch" id="plex_notify_onsnatch" #if $sickbeard.PLEX_NOTIFY_ONSNATCH then "checked=\"checked\"" else ""# />
<p>download start notification</p>
</span>
</label>
</div>
<div class="field-pair">
<label for="plex_notify_ondownload">
<span class="component-title">Notify on download</span>
<span class="component-desc">
<input type="checkbox" name="plex_notify_ondownload" id="plex_notify_ondownload" #if $sickbeard.PLEX_NOTIFY_ONDOWNLOAD then "checked=\"checked\"" else ""# />
<p>download finish notification</p>
</span>
</label>
</div>
<div class="field-pair">
<label for="plex_notify_onsubtitledownload">
<span class="component-title">Notify on subtitle download</span>
<span class="component-desc">
<input type="checkbox" name="plex_notify_onsubtitledownload" id="plex_notify_onsubtitledownload" #if $sickbeard.PLEX_NOTIFY_ONSUBTITLEDOWNLOAD then "checked=\"checked\"" else ""# />
<p>subtitle downloaded notification</p>
</span>
</label>
</div>
<div class="field-pair">
<label for="plex_host">
<span class="component-title">Plex client IP:Port</span>
<span class="component-desc">
<input type="text" name="plex_host" id="plex_host" value="<%= re.sub(r'\b,\b', ', ', sickbeard.PLEX_HOST) %>" class="form-control input-sm input350" />
<div class="clear-left">
<p>one or more hosts running Plex client<br />(eg. 192.168.1.100:3000, 192.168.1.101:3000)</p>
</div>
</span>
</label>
</div>
<div class="field-pair">
<div class="testNotification" id="testPMC-result">Click below to test Plex client(s)</div>
<input class="btn" type="button" value="Test Plex Client" id="testPMC" />
<input type="submit" class="config_submitter btn" value="Save Changes" />
<div class=clear-left><p>Note: some Plex clients <b class="boldest">do not</b> support notifications e.g. Plexapp for Samsung TVs</p></div>
</div>
</div><!-- /plex component-group -->
</div><!-- /content_use_plex -->
</fieldset>
@ -365,9 +383,9 @@
</label>
<label for="NMJV2_DBLOC_B">
<input type="radio" NAME="nmjv2_dbloc" VALUE="network" id="NMJV2_DBLOC_B" #if $sickbeard.NMJv2_DBLOC=="network" then "checked=\"checked\"" else ""#/>PCH Network Media
</label>
</label>
</span>
</div>
</div>
<div class="field-pair">
<label for="NMJv2db_instance">
<span class="component-title">Database instance</span>
@ -415,7 +433,7 @@
</fieldset>
</div><!-- /nmjv2 component-group //-->
<div class="component-group">
<div class="component-group-desc">
@ -430,7 +448,7 @@
<label for="use_synoindex">
<span class="component-title">Enable</span>
<span class="component-desc">
<input type="checkbox" class="enabler" name="use_synoindex" id="use_synoindex" #if $sickbeard.USE_SYNOINDEX then "checked=\"checked\"" else ""# />
<input type="checkbox" class="enabler" name="use_synoindex" id="use_synoindex" #if $sickbeard.USE_SYNOINDEX then "checked=\"checked\"" else ""# />
<p>should SickGear send Synology notifications ?</p>
</span>
</label>
@ -446,8 +464,8 @@
</fieldset>
</div><!-- /synoindex component-group //-->
<div class="component-group">
<div class="component-group-desc">
<img class="notifier-icon" src="$sbRoot/images/notifiers/synologynotifier.png" alt="" title="Synology Indexer" />
@ -563,7 +581,7 @@
</div>
<div id="tabs-2">
<div class="component-group">
<div class="component-group-desc">
@ -576,7 +594,7 @@
<label for="use_growl">
<span class="component-title">Enable</span>
<span class="component-desc">
<input type="checkbox" class="enabler" name="use_growl" id="use_growl" #if $sickbeard.USE_GROWL then "checked=\"checked\"" else ""# />
<input type="checkbox" class="enabler" name="use_growl" id="use_growl" #if $sickbeard.USE_GROWL then "checked=\"checked\"" else ""# />
<p>should SickGear send Growl notifications ?</p>
</span>
</label>
@ -587,7 +605,7 @@
<label for="growl_notify_onsnatch">
<span class="component-title">Notify on snatch</span>
<span class="component-desc">
<input type="checkbox" name="growl_notify_onsnatch" id="growl_notify_onsnatch" #if $sickbeard.GROWL_NOTIFY_ONSNATCH then "checked=\"checked\"" else ""# />
<input type="checkbox" name="growl_notify_onsnatch" id="growl_notify_onsnatch" #if $sickbeard.GROWL_NOTIFY_ONSNATCH then "checked=\"checked\"" else ""# />
<p>send a notification when a download starts ?</p>
</span>
</label>
@ -1172,7 +1190,7 @@
</div><!-- /pushbullet component-group //-->
</div>
<div id="tabs-3">
<div class="component-group">
<div class="component-group-desc">
@ -1350,7 +1368,7 @@
<span class="component-title">&nbsp;</span>
<span class="component-desc">method in which to download episodes for new show's.</span>
</label>
</div>
</div>
<div class="field-pair">
<label for="trakt_remove_watchlist">
<span class="component-title">Remove episode:</span>
@ -1359,8 +1377,8 @@
<p>remove an episode from your watchlist after it is downloaded.</p>
</span>
</label>
</div>
<div class="field-pair">
</div>
<div class="field-pair">
<label for="trakt_remove_serieslist">
<span class="component-title">Remove series:</span>
<span class="component-desc">

View file

@ -56,22 +56,41 @@ $(document).ready(function(){
});
});
$('#testPLEX').click(function () {
$('#testPMC').click(function () {
var plex_host = $.trim($('#plex_host').val());
var plex_username = $.trim($('#plex_username').val());
var plex_password = $.trim($('#plex_password').val());
if (!plex_host) {
$('#testPLEX-result').html('Please fill out the necessary fields above.');
$('#testPMC-result').html('Please fill out the necessary fields above.');
$('#plex_host').addClass('warning');
return;
}
$('#plex_host').removeClass('warning');
$(this).prop('disabled', true);
$('#testPLEX-result').html(loading);
$.get(sbRoot + '/home/testPLEX', {'host': plex_host, 'username': plex_username, 'password': plex_password})
$('#testPMC-result').html(loading);
$.get(sbRoot + '/home/testPMC', {'host': plex_host, 'username': plex_username, 'password': plex_password})
.done(function (data) {
$('#testPLEX-result').html(data);
$('#testPLEX').prop('disabled', false);
$('#testPMC-result').html(data);
$('#testPMC').prop('disabled', false);
});
});
$('#testPMS').click(function () {
var plex_server_host = $.trim($('#plex_server_host').val());
var plex_username = $.trim($('#plex_username').val());
var plex_password = $.trim($('#plex_password').val());
if (!plex_server_host) {
$('#testPMS-result').html('Please fill out the necessary fields above.');
$('#plex_server_host').addClass('warning');
return;
}
$('#plex_server_host').removeClass('warning');
$(this).prop('disabled', true);
$('#testPMS-result').html(loading);
$.get(sbRoot + '/home/testPMS', {'host': plex_server_host, 'username': plex_username, 'password': plex_password})
.done(function (data) {
$('#testPMS-result').html(data);
$('#testPMS').prop('disabled', false);
});
});
@ -158,7 +177,7 @@ $(document).ready(function(){
}
$('#testNMJ-result').html(loading);
var nmj_host = $('#nmj_host').val();
$.get(sbRoot + '/home/settingsNMJ', {'host': nmj_host},
function (data) {
if (data === null) {
@ -220,7 +239,7 @@ $(document).ready(function(){
}
var nmjv2_dbinstance=$('#NMJv2db_instance').val();
$.get(sbRoot + '/home/settingsNMJv2', {'host': nmjv2_host,'dbloc': nmjv2_dbloc,'instance': nmjv2_dbinstance},
$.get(sbRoot + '/home/settingsNMJv2', {'host': nmjv2_host,'dbloc': nmjv2_dbloc,'instance': nmjv2_dbinstance},
function (data){
if (data == null) {
$('#nmjv2_database').removeAttr('readonly');
@ -228,7 +247,7 @@ $(document).ready(function(){
var JSONData = $.parseJSON(data);
$('#testNMJv2-result').html(JSONData.message);
$('#nmjv2_database').val(JSONData.database);
if (JSONData.database)
$('#nmjv2_database').attr('readonly', true);
else
@ -379,7 +398,7 @@ $(document).ready(function(){
if(msg){
$('#testPushbullet-result').html(loading);
}
var pushbullet_api = $("#pushbullet_api").val();
if(!pushbullet_api) {
@ -417,7 +436,7 @@ $(document).ready(function(){
$('#getPushbulletDevices').click(function(){
get_pushbullet_devices("Device list updated. Please choose a device to push to.");
});
// we have to call this function on dom ready to create the devices select
get_pushbullet_devices();
@ -458,5 +477,5 @@ $(document).ready(function(){
$('.plexinfo').addClass('hide');
}
});
if ($('input[id="use_plex"]').is(':checked')) {$('.plexinfo').removeClass('hide')}
});

View file

@ -19,6 +19,7 @@
import urllib
import urllib2
import base64
import re
import sickbeard
@ -56,7 +57,7 @@ class PLEXNotifier:
password = sickbeard.PLEX_PASSWORD
if not host:
logger.log(u"PLEX: No host specified, check your settings", logger.ERROR)
logger.log(u'PLEX: No host specified, check your settings', logger.ERROR)
return False
for key in command:
@ -64,7 +65,7 @@ class PLEXNotifier:
command[key] = command[key].encode('utf-8')
enc_command = urllib.urlencode(command)
logger.log(u"PLEX: Encoded API command: " + enc_command, logger.DEBUG)
logger.log(u'PLEX: Encoded API command: ' + enc_command, logger.DEBUG)
url = 'http://%s/xbmcCmds/xbmcHttp/?%s' % (host, enc_command)
try:
@ -72,26 +73,26 @@ class PLEXNotifier:
# if we have a password, use authentication
if password:
base64string = base64.encodestring('%s:%s' % (username, password))[:-1]
authheader = "Basic %s" % base64string
req.add_header("Authorization", authheader)
logger.log(u"PLEX: Contacting (with auth header) via url: " + url, logger.DEBUG)
authheader = 'Basic %s' % base64string
req.add_header('Authorization', authheader)
logger.log(u'PLEX: Contacting (with auth header) via url: ' + url, logger.DEBUG)
else:
logger.log(u"PLEX: Contacting via url: " + url, logger.DEBUG)
logger.log(u'PLEX: Contacting via url: ' + url, logger.DEBUG)
response = urllib2.urlopen(req)
result = response.read().decode(sickbeard.SYS_ENCODING)
response.close()
logger.log(u"PLEX: HTTP response: " + result.replace('\n', ''), logger.DEBUG)
logger.log(u'PLEX: HTTP response: ' + result.replace('\n', ''), logger.DEBUG)
# could return result response = re.compile('<html><li>(.+\w)</html>').findall(result)
return 'OK'
except (urllib2.URLError, IOError), e:
logger.log(u"PLEX: Warning: Couldn't contact Plex at " + fixStupidEncodings(url) + " " + ex(e), logger.WARNING)
logger.log(u'PLEX: Warning: Couldn\'t contact Plex at ' + fixStupidEncodings(url) + ' ' + ex(e), logger.WARNING)
return False
def _notify(self, message, title="SickGear", host=None, username=None, password=None, force=False):
def _notify_pmc(self, message, title='SickGear', host=None, username=None, password=None, force=False):
"""Internal wrapper for the notify_snatch and notify_download functions
Args:
@ -121,13 +122,13 @@ class PLEXNotifier:
password = sickbeard.PLEX_PASSWORD
result = ''
for curHost in [x.strip() for x in host.split(",")]:
logger.log(u"PLEX: Sending notification to '" + curHost + "' - " + message, logger.MESSAGE)
for curHost in [x.strip() for x in host.split(',')]:
logger.log(u'PLEX: Sending notification to \'%s\' - %s' % (curHost, message), logger.MESSAGE)
command = {'command': 'ExecBuiltIn', 'parameter': 'Notification(' + title.encode("utf-8") + ',' + message.encode("utf-8") + ')'}
notifyResult = self._send_to_plex(command, curHost, username, password)
if notifyResult:
result += curHost + ':' + str(notifyResult)
command = {'command': 'ExecBuiltIn', 'parameter': 'Notification(%s,%s)' % (title.encode('utf-8'), message.encode('utf-8'))}
notify_result = self._send_to_plex(command, curHost, username, password)
if notify_result:
result += '%s:%s' % (curHost, str(notify_result))
return result
@ -145,89 +146,124 @@ class PLEXNotifier:
def notify_subtitle_download(self, ep_name, lang):
if sickbeard.PLEX_NOTIFY_ONSUBTITLEDOWNLOAD:
self._notify_pmc(ep_name + ": " + lang, common.notifyStrings[common.NOTIFY_SUBTITLE_DOWNLOAD])
self._notify_pmc(ep_name + ': ' + lang, common.notifyStrings[common.NOTIFY_SUBTITLE_DOWNLOAD])
def notify_git_update(self, new_version="??"):
def notify_git_update(self, new_version='??'):
if sickbeard.USE_PLEX:
update_text = common.notifyStrings[common.NOTIFY_GIT_UPDATE_TEXT]
title = common.notifyStrings[common.NOTIFY_GIT_UPDATE]
self._notify_pmc(update_text + new_version, title)
def test_notify(self, host, username, password):
return self._notify("This is a test notification from SickGear", "Test", host, username, password, force=True)
def test_notify_pmc(self, host, username, password):
return self._notify_pmc('This is a test notification from SickGear', 'Test', host, username, password, force=True)
def update_library(self, ep_obj=None, host=None, username=None, password=None):
def test_notify_pms(self, host, username, password):
return self.update_library(host=host, username=username, password=password, force=False)
def update_library(self, ep_obj=None, host=None, username=None, password=None, force=True):
"""Handles updating the Plex Media Server host via HTTP API
Plex Media Server currently only supports updating the whole video library and not a specific path.
Returns:
Returns True or False
Returns None for no issue, else a string of host with connection issues
"""
# fill in omitted parameters
if not host:
host = sickbeard.PLEX_SERVER_HOST
if not username:
username = sickbeard.PLEX_USERNAME
if not password:
password = sickbeard.PLEX_PASSWORD
if sickbeard.USE_PLEX and sickbeard.PLEX_UPDATE_LIBRARY:
if not sickbeard.PLEX_SERVER_HOST:
logger.log(u"PLEX: No Plex Media Server host specified, check your settings", logger.DEBUG)
logger.log(u'PLEX: No Plex Media Server host specified, check your settings', logger.DEBUG)
return False
logger.log(u"PLEX: Updating library for the Plex Media Server host: " + host, logger.MESSAGE)
if not host:
host = sickbeard.PLEX_SERVER_HOST
if not username:
username = sickbeard.PLEX_USERNAME
if not password:
password = sickbeard.PLEX_PASSWORD
# if username and password were provided, fetch the auth token from plex.tv
token_arg = ""
token_arg = ''
if username and password:
logger.log(u"PLEX: fetching credentials for Plex user: " + username, logger.DEBUG)
req = urllib2.Request("https://plex.tv/users/sign_in.xml", data="")
base64string = base64.encodestring('%s:%s' % (username, password))[:-1]
authheader = "Basic %s" % base64string
req.add_header("Authorization", authheader)
req.add_header("X-Plex-Client-Identifier", "Sick-Beard-Notifier")
logger.log(u'PLEX: fetching plex.tv credentials for user: ' + username, logger.DEBUG)
req = urllib2.Request('https://plex.tv/users/sign_in.xml', data='')
authheader = 'Basic %s' % base64.encodestring('%s:%s' % (username, password))[:-1]
req.add_header('Authorization', authheader)
req.add_header('X-Plex-Device-Name', 'SickGear')
req.add_header('X-Plex-Product', 'SickGear Notifier')
req.add_header('X-Plex-Client-Identifier', '5f48c063eaf379a565ff56c9bb2b401e')
req.add_header('X-Plex-Version', '1.0')
try:
response = urllib2.urlopen(req)
except urllib2.URLError, e:
logger.log(u"PLEX: Error fetching credentials from from plex.tv for user %s: %s" % (username, ex(e)), logger.MESSAGE)
return False
try:
auth_tree = etree.parse(response)
token = auth_tree.findall(".//authentication-token")[0].text
token_arg = "?X-Plex-Token=" + token
token = auth_tree.findall('.//authentication-token')[0].text
token_arg = '?X-Plex-Token=' + token
except urllib2.URLError as e:
logger.log(u'PLEX: Error fetching credentials from from plex.tv for user %s: %s' % (username, ex(e)), logger.MESSAGE)
except (ValueError, IndexError) as e:
logger.log(u"PLEX: Error parsing plex.tv response: " + ex(e), logger.MESSAGE)
return False
logger.log(u'PLEX: Error parsing plex.tv response: ' + ex(e), logger.MESSAGE)
url = "http://%s/library/sections%s" % (sickbeard.PLEX_SERVER_HOST, token_arg)
try:
xml_tree = etree.parse(urllib.urlopen(url))
media_container = xml_tree.getroot()
except IOError, e:
logger.log(u"PLEX: Error while trying to contact Plex Media Server: " + ex(e), logger.ERROR)
return False
file_location = '' if None is ep_obj else ep_obj.location
host_list = [x.strip() for x in host.split(',')]
hosts_all = {}
hosts_match = {}
hosts_failed = []
for cur_host in host_list:
sections = media_container.findall('.//Directory')
if not sections:
logger.log(u"PLEX: Plex Media Server not running on: " + sickbeard.PLEX_SERVER_HOST, logger.MESSAGE)
return False
url = 'http://%s/library/sections%s' % (cur_host, token_arg)
try:
xml_tree = etree.parse(urllib.urlopen(url))
media_container = xml_tree.getroot()
except IOError, e:
logger.log(u'PLEX: Error while trying to contact Plex Media Server: ' + ex(e), logger.ERROR)
hosts_failed.append(cur_host)
continue
for section in sections:
if section.attrib['type'] == "show":
url = "http://%s/library/sections/%s/refresh%s" % (sickbeard.PLEX_SERVER_HOST, section.attrib['key'], token_arg)
try:
urllib.urlopen(url)
except Exception, e:
logger.log(u"PLEX: Error updating library section for Plex Media Server: " + ex(e), logger.ERROR)
return False
sections = media_container.findall('.//Directory')
if not sections:
logger.log(u'PLEX: Plex Media Server not running on: ' + cur_host, logger.MESSAGE)
hosts_failed.append(cur_host)
continue
return True
for section in sections:
if 'show' == section.attrib['type']:
keyed_host = [(str(section.attrib['key']), cur_host)]
hosts_all.update(keyed_host)
if not file_location:
continue
for section_location in section.findall('.//Location'):
section_path = re.sub(r'[/\\]+', '/', section_location.attrib['path'].lower())
section_path = re.sub(r'^(.{,2})[/\\]', '', section_path)
location_path = re.sub(r'[/\\]+', '/', file_location.lower())
location_path = re.sub(r'^(.{,2})[/\\]', '', location_path)
if section_path in location_path:
hosts_match.update(keyed_host)
hosts_try = (hosts_all.copy(), hosts_match.copy())[len(hosts_match)]
host_list = []
for section_key, cur_host in hosts_try.items():
url = 'http://%s/library/sections/%s/refresh%s' % (cur_host, section_key, token_arg)
try:
force and urllib.urlopen(url)
host_list.append(cur_host)
except Exception, e:
logger.log(u'PLEX: Error updating library section for Plex Media Server: ' + ex(e), logger.ERROR)
hosts_failed.append(cur_host)
if len(hosts_match):
logger.log(u'PLEX: Updating hosts where TV section paths match the downloaded show: ' + ', '.join(set(host_list)), logger.MESSAGE)
else:
logger.log(u'PLEX: Updating all hosts with TV sections: ' + ', '.join(set(host_list)), logger.MESSAGE)
return (', '.join(set(hosts_failed)), None)[not len(hosts_failed)]
notifier = PLEXNotifier

View file

@ -1013,7 +1013,7 @@ class PostProcessor(object):
notifiers.xbmc_notifier.update_library(ep_obj.show.name)
# do the library update for Plex
notifiers.plex_notifier.update_library()
notifiers.plex_notifier.update_library(ep_obj)
# do the library update for NMJ
# nmj_notifier kicks off its library update when the notify_download is issued (inside notifiers)

View file

@ -2393,7 +2393,7 @@ class ConfigNotifications(MainHandler):
sickbeard.PLEX_NOTIFY_ONSUBTITLEDOWNLOAD = config.checkbox_to_value(plex_notify_onsubtitledownload)
sickbeard.PLEX_UPDATE_LIBRARY = config.checkbox_to_value(plex_update_library)
sickbeard.PLEX_HOST = config.clean_hosts(plex_host)
sickbeard.PLEX_SERVER_HOST = config.clean_host(plex_server_host)
sickbeard.PLEX_SERVER_HOST = config.clean_hosts(plex_server_host)
sickbeard.PLEX_USERNAME = plex_username
sickbeard.PLEX_PASSWORD = plex_password
@ -3412,21 +3412,37 @@ class Home(MainHandler):
return finalResult
def testPLEX(self, host=None, username=None, password=None):
def testPMC(self, host=None, username=None, password=None):
self.set_header('Cache-Control', 'max-age=0,no-cache,no-store')
finalResult = ''
for curHost in [x.strip() for x in host.split(",")]:
curResult = notifiers.plex_notifier.test_notify(urllib.unquote_plus(curHost), username, password)
if len(curResult.split(":")) > 2 and 'OK' in curResult.split(":")[2]:
finalResult += "Test Plex notice sent successfully to " + urllib.unquote_plus(curHost)
for curHost in [x.strip() for x in host.split(',')]:
curResult = notifiers.plex_notifier.test_notify_pmc(urllib.unquote_plus(curHost), username, password)
if len(curResult.split(':')) > 2 and 'OK' in curResult.split(':')[2]:
finalResult += 'Successful test notice sent to Plex client ... ' + urllib.unquote_plus(curHost)
else:
finalResult += "Test Plex notice failed to " + urllib.unquote_plus(curHost)
finalResult += "<br />\n"
finalResult += 'Test failed for Plex client ... ' + urllib.unquote_plus(curHost)
finalResult += '<br />' + "\n"
ui.notifications.message('Tested Plex client(s): ', urllib.unquote_plus(host.replace(',', ', ')))
return finalResult
def testPMS(self, host=None, username=None, password=None):
self.set_header('Cache-Control', 'max-age=0,no-cache,no-store')
finalResult = ''
curResult = notifiers.plex_notifier.test_notify_pms(urllib.unquote_plus(host), username, password)
if None is curResult:
finalResult += 'Successful test of Plex server(s) ... ' + urllib.unquote_plus(host.replace(',', ', '))
else:
finalResult += 'Test failed for Plex server(s) ... ' + urllib.unquote_plus(curResult.replace(',', ', '))
finalResult += '<br />' + "\n"
ui.notifications.message('Tested Plex Media Server host(s): ', urllib.unquote_plus(host.replace(',', ', ')))
return finalResult
def testLibnotify(self, *args, **kwargs):
self.set_header('Cache-Control', 'max-age=0,no-cache,no-store')
@ -4085,16 +4101,15 @@ class Home(MainHandler):
ui.notifications.error("Unable to contact one or more XBMC host(s): " + host)
redirect('/home/')
def updatePLEX(self, *args, **kwargs):
if notifiers.plex_notifier.update_library():
result = notifiers.plex_notifier.update_library()
if None is result:
ui.notifications.message(
"Library update command sent to Plex Media Server host: " + sickbeard.PLEX_SERVER_HOST)
'Library update command sent to', 'Plex Media Server host(s): ' + sickbeard.PLEX_SERVER_HOST.replace(',', ', '))
else:
ui.notifications.error("Unable to contact Plex Media Server host: " + sickbeard.PLEX_SERVER_HOST)
ui.notifications.error('Unable to contact', 'Plex Media Server host(s): ' + result.replace(',', ', '))
redirect('/home/')
def setStatus(self, show=None, eps=None, status=None, direct=False):
if show is None or eps is None or status is None: