mirror of
https://github.com/SickGear/SickGear.git
synced 2024-12-01 08:53:37 +00:00
Merge pull request #189 from JackDandy/feature/UpdatePlexNotifer
Feature/Update Plex notifer.
This commit is contained in:
commit
45c5acd88e
6 changed files with 291 additions and 195 deletions
|
@ -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
|
||||
|
|
|
@ -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"> </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"> </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"> </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"> </span>
|
||||
<span class="component-desc">host running Plex client (eg. 192.168.1.100:3000)</span>
|
||||
</label>
|
||||
<label>
|
||||
<span class="component-title"> </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"> </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"> </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"> </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">
|
||||
|
|
|
@ -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')}
|
||||
});
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue