Browse Source

Merge pull request #629 from JackDandy/feature/ChangeEmailNotif

Change refactor email notifier.
pull/632/head
JackDandy 9 years ago
parent
commit
38db11d3fe
  1. 1
      CHANGES.md
  2. 2
      gui/slick/css/dark.css
  3. 2
      gui/slick/css/light.css
  4. 92
      gui/slick/interfaces/default/config_notifications.tmpl
  5. 405
      gui/slick/js/configNotifications.js
  6. 6
      sickbeard/__init__.py
  7. 207
      sickbeard/notifiers/emailnotify.py
  8. 100
      sickbeard/webserve.py

1
CHANGES.md

@ -19,6 +19,7 @@
* Update Requests library 2.7.0 (5d6d1bc) to 2.9.1 (a1c9b84) * Update Requests library 2.7.0 (5d6d1bc) to 2.9.1 (a1c9b84)
* Update SimpleJSON library 3.8.0 (a37a9bd) to 3.8.1 (6022794) * Update SimpleJSON library 3.8.0 (a37a9bd) to 3.8.1 (6022794)
* Update Six compatibility library 1.9.0 (r400) to 1.10.0 (r405) * Update Six compatibility library 1.9.0 (r400) to 1.10.0 (r405)
* Change refactor email notifier
### 0.11.3 (2016-01-16 20:00:00 UTC) ### 0.11.3 (2016-01-16 20:00:00 UTC)

2
gui/slick/css/dark.css

@ -1178,6 +1178,7 @@ pre{
input sizing (for config pages) input sizing (for config pages)
========================================================================== */ ========================================================================== */
.showlist-select optgroup,
#pickShow optgroup, #pickShow optgroup,
#showfilter optgroup, #showfilter optgroup,
#editAProvider optgroup{ #editAProvider optgroup{
@ -1185,6 +1186,7 @@ input sizing (for config pages)
background-color:rgb(51, 51, 51) background-color:rgb(51, 51, 51)
} }
.showlist-select optgroup option,
#pickShow optgroup option, #pickShow optgroup option,
#showfilter optgroup option, #showfilter optgroup option,
#editAProvider optgroup option{ #editAProvider optgroup option{

2
gui/slick/css/light.css

@ -1142,6 +1142,7 @@ pre{
input sizing (for config pages) input sizing (for config pages)
========================================================================== */ ========================================================================== */
.showlist-select optgroup,
#pickShow optgroup, #pickShow optgroup,
#showfilter optgroup, #showfilter optgroup,
#editAProvider optgroup{ #editAProvider optgroup{
@ -1149,6 +1150,7 @@ input sizing (for config pages)
background-color:#888 background-color:#888
} }
.showlist-select optgroup option,
#pickShow optgroup option, #pickShow optgroup option,
#showfilter optgroup option, #showfilter optgroup option,
#editAProvider optgroup option{ #editAProvider optgroup option{

92
gui/slick/interfaces/default/config_notifications.tmpl

@ -1637,7 +1637,7 @@
<div class="component-group-desc"> <div class="component-group-desc">
<img class="notifier-icon" src="$sbRoot/images/notifiers/email.png" alt="" title="Email" /> <img class="notifier-icon" src="$sbRoot/images/notifiers/email.png" alt="" title="Email" />
<h3><a href="<%= anon_url('http://en.wikipedia.org/wiki/Comparison_of_webmail_providers') %>" rel="noreferrer" onclick="window.open(this.href, '_blank'); return false;">Email</a></h3> <h3><a href="<%= anon_url('http://en.wikipedia.org/wiki/Comparison_of_webmail_providers') %>" rel="noreferrer" onclick="window.open(this.href, '_blank'); return false;">Email</a></h3>
<p>Allows configuration of email notifications on a per show basis.</p> <p>Email notification settings.</p>
</div> </div>
<fieldset class="component-group-list"> <fieldset class="component-group-list">
<div class="field-pair"> <div class="field-pair">
@ -1679,94 +1679,70 @@
</label> </label>
</div> </div>
<div class="field-pair"> <div class="field-pair">
<label for="email_host">
<span class="component-title">SMTP host</span>
<input type="text" name="email_host" id="email_host" value="$sickbeard.EMAIL_HOST" class="form-control input-sm input250" />
</label>
<label>
<span class="component-title">&nbsp;</span>
<span class="component-desc">hostname of your SMTP email server.</span>
</label>
</div>
<div class="field-pair">
<label for="email_port">
<span class="component-title">SMTP port</span>
<input type="text" name="email_port" id="email_port" value="$sickbeard.EMAIL_PORT" class="form-control input-sm input75" />
</label>
<label>
<span class="component-title">&nbsp;</span>
<span class="component-desc">port number used to connect to your SMTP host.</span>
</label>
</div>
<div class="field-pair">
<label for="email_from"> <label for="email_from">
<span class="component-title">SMTP from</span> <span class="component-title">SMTP sender email address</span>
<span class="component-desc">
<input type="text" name="email_from" id="email_from" value="$sickbeard.EMAIL_FROM" class="form-control input-sm input250" /> <input type="text" name="email_from" id="email_from" value="$sickbeard.EMAIL_FROM" class="form-control input-sm input250" />
<div class="clear-left"><p>some recipient hosts require a real address</p></div>
</span>
</label> </label>
<label> <div style="margin-bottom:5px;display:inline-block">
<span class="component-title">&nbsp;</span> <span class="component-title">SMTP server hostname</span>
<span class="component-desc">sender email address, some hosts require a real address.</span> <span class="component-desc">
</label> <input type="text" name="email_host" id="email_host" value="$sickbeard.EMAIL_HOST" class="form-control input-sm input250" />
<span style="float:left;margin-right:6px">and port</span><input type="text" name="email_port" id="email_port" value="$sickbeard.EMAIL_PORT" class="form-control input-sm input75" style="width:60px" />
</span>
</div> </div>
<div class="field-pair">
<label for="email_tls"> <label for="email_tls">
<span class="component-title">Use TLS</span> <span class="component-title">Enable TLS encryption</span>
<span class="component-desc"> <span class="component-desc">
<input type="checkbox" name="email_tls" id="email_tls" #if $sickbeard.EMAIL_TLS then 'checked="checked"' else ''# /> <input type="checkbox" name="email_tls" id="email_tls" #if $sickbeard.EMAIL_TLS then 'checked="checked"' else ''# />
<p>check to use TLS encryption.</p>
</span> </span>
</label> </label>
</div>
<div class="field-pair">
<label for="email_user"> <label for="email_user">
<span class="component-title">SMTP user</span> <span class="component-title">SMTP server username</span>
<span class="component-desc">
<input type="text" name="email_user" id="email_user" value="$sickbeard.EMAIL_USER" class="form-control input-sm input250" /> <input type="text" name="email_user" id="email_user" value="$sickbeard.EMAIL_USER" class="form-control input-sm input250" />
<p>(optional)</p>
</span>
</label> </label>
<label>
<span class="component-title">&nbsp;</span>
<span class="component-desc">(optional) your SMTP server username.</span>
</label>
</div>
<div class="field-pair">
<label for="email_password"> <label for="email_password">
<span class="component-title">SMTP password</span> <span class="component-title">SMTP server password</span>
<span class="component-desc">
<input type="password" name="email_password" id="email_password" value="#echo '*' * len($sickbeard.EMAIL_PASSWORD)#" class="form-control input-sm input250" /> <input type="password" name="email_password" id="email_password" value="#echo '*' * len($sickbeard.EMAIL_PASSWORD)#" class="form-control input-sm input250" />
</label> <p>(optional)</p>
<label> </span>
<span class="component-title">&nbsp;</span>
<span class="component-desc">(optional) your SMTP server password.</span>
</label> </label>
</div> </div>
<div class="field-pair"> <div class="field-pair">
<label for="email_list"> <label for="email_list">
<span class="component-title">Global email list</span> <span class="component-title">Notify for every show</span>
<span class="component-desc">
<input type="text" name="email_list" id="email_list" value="$sickbeard.EMAIL_LIST" class="form-control input-sm input350" /> <input type="text" name="email_list" id="email_list" value="$sickbeard.EMAIL_LIST" class="form-control input-sm input350" />
</label> <div class="clear-left"><p>comma separated email list</p></div>
<label> </span>
<span class="component-title">&nbsp;</span>
<span class="component-desc">all emails here receive notifications for <b>all</b> shows.</span>
</label> </label>
</div> </div>
<div class="field-pair"> <div class="field-pair">
<label for="email_show"> <label for="email_show">
<span class="component-title">Show notification list</span> <span class="component-title">Notify on a per show basis</span>
<select name="email_show" id="email_show" class="form-control input-sm"> <select name="email_show" id="email_show" class="showlist-select form-control input-sm">
<option value="-1">-- Select a Show --</option> <option value="-1">-- Shows appear here --</option>
</select> </select>
</label> </label>
<label> <label>
<span class="component-title">&nbsp;</span> <span class="component-title">&nbsp;</span>
<input type="text" name="email_show_list" id="email_show_list" class="form-control input-sm input350" /> <span class="component-desc">
</label> <input type="text" name="show_email_list" id="show_email_list" class="form-control input-sm input350" />
<label> <input type="button" value="Save Show" id="save_show_email" class="btn" />
<span class="component-title">&nbsp;</span> <div class="clear-left"><p>comma separated email list for each show</p></div>
<span class="component-desc">configure per show notifications here.</span> </span>
</label> </label>
</div> </div>
<div class="testNotification" id="testEmail-result">Click below to test.</div> <div class="testNotification" id="testEmail-result">Click below to test.</div>
<input class="btn" type="button" value="Test Email" id="testEmail" /> <input type="button" class="btn" value="Test Email" id="testEmail" />
<input class="btn" type="submit" class="config_submitter" value="Save Changes" /> <input type="submit" class="btn config_submitter" value="Save Changes" />
</div><!-- /content_use_email //--> </div><!-- /content_use_email //-->
</fieldset> </fieldset>
</div><!-- /email component-group //--> </div><!-- /email component-group //-->

405
gui/slick/js/configNotifications.js

@ -75,6 +75,16 @@
}); });
}); });
// show instructions for plex when enabled
$('#use_plex').click(function() {
if ( $(this).is(':checked') ) {
$('.plexinfo').removeClass('hide');
} else {
$('.plexinfo').addClass('hide');
}
});
if ($('input[id="use_plex"]').is(':checked')) {$('.plexinfo').removeClass('hide')}
$('#testPMC').click(function () { $('#testPMC').click(function () {
var plex_host = $.trim($('#plex_host').val()); var plex_host = $.trim($('#plex_host').val());
var plex_username = $.trim($('#plex_username').val()); var plex_username = $.trim($('#plex_username').val());
@ -225,30 +235,6 @@
function (data) { $('#testLibnotify-result').html(data); }); function (data) { $('#testLibnotify-result').html(data); });
}); });
$('#twitterStep1').click(function() {
$('#testTwitter-result').html(loading);
$.get(sbRoot + '/home/twitterStep1', function (data) {window.open(data); })
.done(function () { $('#testTwitter-result').html('<b>Step1:</b> Confirm Authorization'); });
});
$('#twitterStep2').click(function () {
var twitter_key = $.trim($('#twitter_key').val());
if (!twitter_key) {
$('#testTwitter-result').html('Please fill out the necessary fields above.');
$('#twitter_key').addClass('warning');
return;
}
$('#twitter_key').removeClass('warning');
$('#testTwitter-result').html(loading);
$.get(sbRoot + '/home/twitterStep2', {'key': twitter_key},
function (data) { $('#testTwitter-result').html(data); });
});
$('#testTwitter').click(function() {
$.get(sbRoot + '/home/testTwitter',
function (data) { $('#testTwitter-result').html(data); });
});
$('#settingsNMJ').click(function() { $('#settingsNMJ').click(function() {
if (!$('#nmj_host').val()) { if (!$('#nmj_host').val()) {
alert('Please fill in the Popcorn IP address'); alert('Please fill in the Popcorn IP address');
@ -352,6 +338,139 @@
}); });
}); });
$('#testNMA').click(function () {
var nma_api = $.trim($('#nma_api').val());
var nma_priority = $('#nma_priority').val();
if (!nma_api) {
$('#testNMA-result').html('Please fill out the necessary fields above.');
$('#nma_api').addClass('warning');
return;
}
$('#nma_api').removeClass('warning');
$(this).prop('disabled', true);
$('#testNMA-result').html(loading);
$.get(sbRoot + '/home/testNMA', {'nma_api': nma_api, 'nma_priority': nma_priority})
.done(function (data) {
$('#testNMA-result').html(data);
$('#testNMA').prop('disabled', false);
});
});
$('#testPushalot').click(function () {
var pushalot_authorizationtoken = $.trim($('#pushalot_authorizationtoken').val());
if (!pushalot_authorizationtoken) {
$('#testPushalot-result').html('Please fill out the necessary fields above.');
$('#pushalot_authorizationtoken').addClass('warning');
return;
}
$('#pushalot_authorizationtoken').removeClass('warning');
$(this).prop('disabled', true);
$('#testPushalot-result').html(loading);
$.get(sbRoot + '/home/testPushalot', {'authorizationToken': pushalot_authorizationtoken})
.done(function (data) {
$('#testPushalot-result').html(data);
$('#testPushalot').prop('disabled', false);
});
});
$('#testPushbullet').click(function () {
var pushbullet_access_token = $.trim($('#pushbullet_access_token').val());
var pushbullet_device_iden = $('#pushbullet_device_iden').val();
if (!pushbullet_access_token) {
$('#testPushbullet-result').html('Please fill out the necessary fields above.');
$('#pushbullet_access_token').addClass('warning');
return;
}
$('#pushbullet_access_token').removeClass('warning');
$(this).prop('disabled', true);
$('#testPushbullet-result').html(loading);
$.get(sbRoot + '/home/testPushbullet', {'accessToken': pushbullet_access_token, 'device_iden': pushbullet_device_iden})
.done(function (data) {
$('#testPushbullet-result').html(data);
$('#testPushbullet').prop('disabled', false);
});
});
function get_pushbullet_devices (msg) {
var pushbullet_access_token = $.trim($('#pushbullet_access_token').val());
if (!pushbullet_access_token) {
$('#testPushbullet-result').html('Please fill out the necessary fields above.');
$('#pushbullet_access_token').addClass('warning');
return;
}
$(this).prop("disabled", true);
if (msg) {
$('#testPushbullet-result').html(loading);
}
var current_pushbullet_device = $('#pushbullet_device_iden').val();
$.get(sbRoot + '/home/getPushbulletDevices', {'accessToken': pushbullet_access_token})
.done(function (data) {
var devices = jQuery.parseJSON(data || '{}').devices;
var error = jQuery.parseJSON(data || '{}').error;
$('#pushbullet_device_list').html('');
if (devices) {
// add default option to send to all devices
$('#pushbullet_device_list').append('<option value="" selected="selected">-- All Devices --</option>');
for (var i = 0; i < devices.length; i++) {
// only list active device targets
if (devices[i].active == true) {
// if a device in the list matches our current iden, select it
if (current_pushbullet_device == devices[i].iden) {
$('#pushbullet_device_list').append('<option value="' + devices[i].iden + '" selected="selected">' + devices[i].manufacturer + ' ' + devices[i].nickname + '</option>');
} else {
$('#pushbullet_device_list').append('<option value="' + devices[i].iden + '">' + devices[i].manufacturer + ' ' + devices[i].nickname + '</option>');
}
}
}
}
$('#getPushbulletDevices').prop('disabled', false);
if (msg) {
if (error.message) {
$('#testPushbullet-result').html(error.message);
} else {
$('#testPushbullet-result').html(msg);
}
}
});
$('#pushbullet_device_list').change(function () {
$('#pushbullet_device_iden').val($('#pushbullet_device_list').val());
$('#testPushbullet-result').html('Don\'t forget to save your new Pushbullet settings.');
});
}
$('#getPushbulletDevices').click(function () {
get_pushbullet_devices('Device list updated. Select specific device to use.');
});
if ($('#use_pushbullet').prop('checked')) {
get_pushbullet_devices();
}
$('#twitterStep1').click(function() {
$('#testTwitter-result').html(loading);
$.get(sbRoot + '/home/twitterStep1', function (data) {window.open(data); })
.done(function () { $('#testTwitter-result').html('<b>Step1:</b> Confirm Authorization'); });
});
$('#twitterStep2').click(function () {
var twitter_key = $.trim($('#twitter_key').val());
if (!twitter_key) {
$('#testTwitter-result').html('Please fill out the necessary fields above.');
$('#twitter_key').addClass('warning');
return;
}
$('#twitter_key').removeClass('warning');
$('#testTwitter-result').html(loading);
$.get(sbRoot + '/home/twitterStep2', {'key': twitter_key},
function (data) { $('#testTwitter-result').html(data); });
});
$('#testTwitter').click(function() {
$.get(sbRoot + '/home/testTwitter',
function (data) { $('#testTwitter-result').html(data); });
});
var elTraktAuth = $('#trakt-authenticate'), elTraktAuthResult = $('#trakt-authentication-result'); var elTraktAuth = $('#trakt-authenticate'), elTraktAuthResult = $('#trakt-authentication-result');
function trakt_send_auth(){ function trakt_send_auth(){
@ -510,187 +629,101 @@
}); });
}); });
$('#testEmail').click(function () { function load_show_notify_lists() {
var status, host, port, tls, from, user, pwd, err, to; $.get(sbRoot + '/home/loadShowNotifyLists', function (data) {
status = $('#testEmail-result'); var list, html, item, len= 0, el;
status.html(loading); list = $.parseJSON(data);
host = $('#email_host').val(); html = [];
host = host.length > 0 ? host : null; for (item in list) {
port = $('#email_port').val(); for (var k in list[item]) {
port = port.length > 0 ? port : null; if ($.isArray(list[item][k])) {
tls = $('#email_tls').attr('checked') !== undefined ? 1 : 0; len += list[item][k].length;
from = $('#email_from').val(); html.push('\t<optgroup label="' + k + '">');
from = from.length > 0 ? from : 'root@localhost'; for (var show in list[item][k]) {
user = $('#email_user').val().trim(); html.push('\t\t<option value="' + list[item][k][show].id + '"'
pwd = $('#email_password').val(); + ' data="' + list[item][k][show].list + '"'
err = ''; + '>' + list[item][k][show].name + '</option>');
if (host === null) {
err += '<li style="color: red;">You must specify an SMTP hostname!</li>';
}
if (port === null) {
err += '<li style="color: red;">You must specify an SMTP port!</li>';
} else if (port.match(/^\d+$/) === null || parseInt(port, 10) > 65535) {
err += '<li style="color: red;">SMTP port must be between 0 and 65535!</li>';
}
if (err.length > 0) {
err = '<ol>' + err + '</ol>';
status.html(err);
} else {
to = prompt('Enter an email address to send the test to:', null);
if (to === null || to.length === 0 || to.match(/.*@.*/) === null) {
status.html('<p style="color: red;">You must provide a recipient email address!</p>');
} else {
$.get(sbRoot + '/home/testEmail', {host: host, port: port, smtp_from: from, use_tls: tls, user: user, pwd: pwd, to: to},
function (msg) { $('#testEmail-result').html(msg); });
} }
html.push('\t</optgroup>');
} }
});
$('#testNMA').click(function () {
var nma_api = $.trim($('#nma_api').val());
var nma_priority = $('#nma_priority').val();
if (!nma_api) {
$('#testNMA-result').html('Please fill out the necessary fields above.');
$('#nma_api').addClass('warning');
return;
} }
$('#nma_api').removeClass('warning');
$(this).prop('disabled', true);
$('#testNMA-result').html(loading);
$.get(sbRoot + '/home/testNMA', {'nma_api': nma_api, 'nma_priority': nma_priority})
.done(function (data) {
$('#testNMA-result').html(data);
$('#testNMA').prop('disabled', false);
});
});
$('#testPushalot').click(function () {
var pushalot_authorizationtoken = $.trim($('#pushalot_authorizationtoken').val());
if (!pushalot_authorizationtoken) {
$('#testPushalot-result').html('Please fill out the necessary fields above.');
$('#pushalot_authorizationtoken').addClass('warning');
return;
} }
$('#pushalot_authorizationtoken').removeClass('warning');
$(this).prop('disabled', true);
$('#testPushalot-result').html(loading);
$.get(sbRoot + '/home/testPushalot', {'authorizationToken': pushalot_authorizationtoken})
.done(function (data) {
$('#testPushalot-result').html(data);
$('#testPushalot').prop('disabled', false);
});
});
$('#testPushbullet').click(function () { if (len) {
var pushbullet_access_token = $.trim($('#pushbullet_access_token').val()); el = $('#email_show');
var pushbullet_device_iden = $('#pushbullet_device_iden').val(); el.html('<option value="-1">-- Select show --</option>'
if (!pushbullet_access_token) { + html.join('\n'));
$('#testPushbullet-result').html('Please fill out the necessary fields above.');
$('#pushbullet_access_token').addClass('warning');
return;
}
$('#pushbullet_access_token').removeClass('warning');
$(this).prop('disabled', true);
$('#testPushbullet-result').html(loading);
$.get(sbRoot + '/home/testPushbullet', {'accessToken': pushbullet_access_token, 'device_iden': pushbullet_device_iden})
.done(function (data) {
$('#testPushbullet-result').html(data);
$('#testPushbullet').prop('disabled', false);
});
});
function get_pushbullet_devices (msg) { $('#show_email_list').val('');
var pushbullet_access_token = $.trim($('#pushbullet_access_token').val());
if (!pushbullet_access_token) {
$('#testPushbullet-result').html('Please fill out the necessary fields above.');
$('#pushbullet_access_token').addClass('warning');
return;
}
$(this).prop("disabled", true);
if (msg) {
$('#testPushbullet-result').html(loading);
}
var current_pushbullet_device = $('#pushbullet_device_iden').val();
$.get(sbRoot + '/home/getPushbulletDevices', {'accessToken': pushbullet_access_token})
.done(function (data) {
var devices = jQuery.parseJSON(data || '{}').devices;
var error = jQuery.parseJSON(data || '{}').error;
$('#pushbullet_device_list').html('');
if (devices) {
// add default option to send to all devices
$('#pushbullet_device_list').append('<option value="" selected="selected">-- All Devices --</option>');
for (var i = 0; i < devices.length; i++) {
// only list active device targets
if (devices[i].active == true) {
// if a device in the list matches our current iden, select it
if (current_pushbullet_device == devices[i].iden) {
$('#pushbullet_device_list').append('<option value="' + devices[i].iden + '" selected="selected">' + devices[i].manufacturer + ' ' + devices[i].nickname + '</option>');
} else {
$('#pushbullet_device_list').append('<option value="' + devices[i].iden + '">' + devices[i].manufacturer + ' ' + devices[i].nickname + '</option>');
}
}
}
}
$('#getPushbulletDevices').prop('disabled', false);
if (msg) {
if (error.message) {
$('#testPushbullet-result').html(error.message);
} else {
$('#testPushbullet-result').html(msg);
}
}
});
$('#pushbullet_device_list').change(function () { el.change(function () {
$('#pushbullet_device_iden').val($('#pushbullet_device_list').val()); $('#show_email_list').val(
$('#testPushbullet-result').html('Don\'t forget to save your new Pushbullet settings.'); $(this).find('option[value="' + $(this).val() + '"]').attr('data'))
}); });
} }
$('#getPushbulletDevices').click(function () {
get_pushbullet_devices('Device list updated. Select specific device to use.');
}); });
if ($('#use_pushbullet').prop('checked')) {
get_pushbullet_devices();
} }
// Load the per show notify lists everytime this page is loaded
$('#email_show').change(function () { load_show_notify_lists();
var key = parseInt($('#email_show').val(), 10);
$('#email_show_list').val(key >= 0 ? notify_data[key.toString()].list : '');
});
// Update the internal data struct anytime settings are saved to the server // Update the internal data struct anytime settings are saved to the server
$('#email_show').bind('notify', function () { load_show_notify_lists(); }); $('#email_show').bind('notify', function () { load_show_notify_lists(); });
function load_show_notify_lists() { $('#save_show_email').click(
$.get(sbRoot + "/home/loadShowNotifyLists", function (data) { function(){
var list, html, s; var show = $('#email_show').val();
list = $.parseJSON(data); if ('-1' == show) {
notify_data = list; $('#testEmail-result').html('No show selected for save.');
if (list._size === 0) { return
return;
}
html = '<option value="-1">-- Select --</option>';
for (s in list) {
if (s.charAt(0) !== '_') {
html += '<option value="' + list[s].id + '">' + $('<div/>').text(list[s].name).html() + '</option>';
}
} }
$('#email_show').html(html); $.post(sbRoot + '/home/save_show_email', {
$('#email_show_list').val(''); show: show,
}); emails: $('#show_email_list').val()},
} function (data){
// Load the per show notify lists everytime this page is loaded // Reload the per show notify lists to reflect changes
load_show_notify_lists(); load_show_notify_lists();
var result = $.parseJSON(data),
show = $('#email_show').find('option[value="' + result.id + '"]').text();
$('#testEmail-result').html(result.success
? 'Success. Notify list updated for show "' + show + '". Click below to test.'
: 'Error saving notify list for show %s' % show);
});
});
// show instructions for plex when enabled $('#testEmail').click(function () {
$('#use_plex').click(function() { var status, host, port, tls, from, user, pwd, err, to;
if ( $(this).is(':checked') ) { status = $('#testEmail-result');
$('.plexinfo').removeClass('hide'); status.html(loading);
host = $('#email_host').val();
host = host.length > 0 ? host : null;
port = $('#email_port').val();
port = port.length > 0 ? port : null;
tls = $('#email_tls').attr('checked') !== undefined ? 1 : 0;
from = $('#email_from').val();
from = from.length > 0 ? from : 'root@localhost';
user = $('#email_user').val().trim();
pwd = $('#email_password').val();
err = [];
if (null == host) {
err.push('SMTP server hostname');
}
if (null == port) {
err.push('SMTP server host port');
} else if (null == port.match(/^\d+$/) || parseInt(port, 10) > 65535) {
err.push('SMTP server host port must be between 0 and 65535');
}
if (0 < err.length) {
status.html('Required: ' + err.join(', '));
} else { } else {
$('.plexinfo').addClass('hide'); to = prompt('Enter an email address to send the test to:', '');
if (null == to || 0 == to.length || null == to.match(/.*@.*/)) {
status.html('Required: A valid address for email test');
} else {
$.get(sbRoot + '/home/testEmail',
{host:host, port:port, smtp_from:from, use_tls:tls, user:user, pwd:pwd, to:to},
function(msg) {$('#testEmail-result').html(msg);});
}
} }
}); });
if ($('input[id="use_plex"]').is(':checked')) {$('.plexinfo').removeClass('hide')}
}); });

6
sickbeard/__init__.py

@ -393,6 +393,7 @@ PUSHBULLET_ACCESS_TOKEN = None
PUSHBULLET_DEVICE_IDEN = None PUSHBULLET_DEVICE_IDEN = None
USE_EMAIL = False USE_EMAIL = False
EMAIL_OLD_SUBJECTS = None
EMAIL_NOTIFY_ONSNATCH = False EMAIL_NOTIFY_ONSNATCH = False
EMAIL_NOTIFY_ONDOWNLOAD = False EMAIL_NOTIFY_ONDOWNLOAD = False
EMAIL_NOTIFY_ONSUBTITLEDOWNLOAD = False EMAIL_NOTIFY_ONSUBTITLEDOWNLOAD = False
@ -511,7 +512,7 @@ def initialize(consoleLogging=True):
USE_PUSHOVER, PUSHOVER_USERKEY, PUSHOVER_APIKEY, PUSHOVER_NOTIFY_ONDOWNLOAD, PUSHOVER_NOTIFY_ONSUBTITLEDOWNLOAD, PUSHOVER_NOTIFY_ONSNATCH, PUSHOVER_PRIORITY, PUSHOVER_DEVICE, PUSHOVER_SOUND, \ USE_PUSHOVER, PUSHOVER_USERKEY, PUSHOVER_APIKEY, PUSHOVER_NOTIFY_ONDOWNLOAD, PUSHOVER_NOTIFY_ONSUBTITLEDOWNLOAD, PUSHOVER_NOTIFY_ONSNATCH, PUSHOVER_PRIORITY, PUSHOVER_DEVICE, PUSHOVER_SOUND, \
USE_LIBNOTIFY, LIBNOTIFY_NOTIFY_ONSNATCH, LIBNOTIFY_NOTIFY_ONDOWNLOAD, LIBNOTIFY_NOTIFY_ONSUBTITLEDOWNLOAD, USE_NMJ, NMJ_HOST, NMJ_DATABASE, NMJ_MOUNT, USE_NMJv2, NMJv2_HOST, NMJv2_DATABASE, NMJv2_DBLOC, USE_SYNOINDEX, \ USE_LIBNOTIFY, LIBNOTIFY_NOTIFY_ONSNATCH, LIBNOTIFY_NOTIFY_ONDOWNLOAD, LIBNOTIFY_NOTIFY_ONSUBTITLEDOWNLOAD, USE_NMJ, NMJ_HOST, NMJ_DATABASE, NMJ_MOUNT, USE_NMJv2, NMJv2_HOST, NMJv2_DATABASE, NMJv2_DBLOC, USE_SYNOINDEX, \
USE_SYNOLOGYNOTIFIER, SYNOLOGYNOTIFIER_NOTIFY_ONSNATCH, SYNOLOGYNOTIFIER_NOTIFY_ONDOWNLOAD, SYNOLOGYNOTIFIER_NOTIFY_ONSUBTITLEDOWNLOAD, \ USE_SYNOLOGYNOTIFIER, SYNOLOGYNOTIFIER_NOTIFY_ONSNATCH, SYNOLOGYNOTIFIER_NOTIFY_ONDOWNLOAD, SYNOLOGYNOTIFIER_NOTIFY_ONSUBTITLEDOWNLOAD, \
USE_EMAIL, EMAIL_HOST, EMAIL_PORT, EMAIL_TLS, EMAIL_USER, EMAIL_PASSWORD, EMAIL_FROM, EMAIL_NOTIFY_ONSNATCH, EMAIL_NOTIFY_ONDOWNLOAD, EMAIL_NOTIFY_ONSUBTITLEDOWNLOAD, EMAIL_LIST, \ USE_EMAIL, EMAIL_OLD_SUBJECTS, EMAIL_HOST, EMAIL_PORT, EMAIL_TLS, EMAIL_USER, EMAIL_PASSWORD, EMAIL_FROM, EMAIL_NOTIFY_ONSNATCH, EMAIL_NOTIFY_ONDOWNLOAD, EMAIL_NOTIFY_ONSUBTITLEDOWNLOAD, EMAIL_LIST, \
METADATA_XBMC, METADATA_XBMC_12PLUS, METADATA_MEDIABROWSER, METADATA_PS3, METADATA_KODI, metadata_provider_dict, \ METADATA_XBMC, METADATA_XBMC_12PLUS, METADATA_MEDIABROWSER, METADATA_PS3, METADATA_KODI, metadata_provider_dict, \
GIT_PATH, MOVE_ASSOCIATED_FILES, POSTPONE_IF_SYNC_FILES, recentSearchScheduler, NFO_RENAME, \ GIT_PATH, MOVE_ASSOCIATED_FILES, POSTPONE_IF_SYNC_FILES, recentSearchScheduler, NFO_RENAME, \
GUI_NAME, DEFAULT_HOME, HOME_LAYOUT, HISTORY_LAYOUT, DISPLAY_SHOW_SPECIALS, EPISODE_VIEW_LAYOUT, EPISODE_VIEW_SORT, EPISODE_VIEW_DISPLAY_PAUSED, EPISODE_VIEW_MISSED_RANGE, FUZZY_DATING, TRIM_ZERO, DATE_PRESET, TIME_PRESET, TIME_PRESET_W_SECONDS, THEME_NAME, \ GUI_NAME, DEFAULT_HOME, HOME_LAYOUT, HISTORY_LAYOUT, DISPLAY_SHOW_SPECIALS, EPISODE_VIEW_LAYOUT, EPISODE_VIEW_SORT, EPISODE_VIEW_DISPLAY_PAUSED, EPISODE_VIEW_MISSED_RANGE, FUZZY_DATING, TRIM_ZERO, DATE_PRESET, TIME_PRESET, TIME_PRESET_W_SECONDS, THEME_NAME, \
@ -922,6 +923,8 @@ def initialize(consoleLogging=True):
PUSHBULLET_DEVICE_IDEN = check_setting_str(CFG, 'Pushbullet', 'pushbullet_device_iden', '') PUSHBULLET_DEVICE_IDEN = check_setting_str(CFG, 'Pushbullet', 'pushbullet_device_iden', '')
USE_EMAIL = bool(check_setting_int(CFG, 'Email', 'use_email', 0)) USE_EMAIL = bool(check_setting_int(CFG, 'Email', 'use_email', 0))
EMAIL_OLD_SUBJECTS = bool(check_setting_int(CFG, 'Email', 'email_old_subjects',
None is not EMAIL_HOST and any(EMAIL_HOST)))
EMAIL_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Email', 'email_notify_onsnatch', 0)) EMAIL_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Email', 'email_notify_onsnatch', 0))
EMAIL_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Email', 'email_notify_ondownload', 0)) EMAIL_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Email', 'email_notify_ondownload', 0))
EMAIL_NOTIFY_ONSUBTITLEDOWNLOAD = bool(check_setting_int(CFG, 'Email', 'email_notify_onsubtitledownload', 0)) EMAIL_NOTIFY_ONSUBTITLEDOWNLOAD = bool(check_setting_int(CFG, 'Email', 'email_notify_onsubtitledownload', 0))
@ -1740,6 +1743,7 @@ def save_config():
new_config['Email'] = {} new_config['Email'] = {}
new_config['Email']['use_email'] = int(USE_EMAIL) new_config['Email']['use_email'] = int(USE_EMAIL)
new_config['Email']['email_old_subjects'] = int(EMAIL_OLD_SUBJECTS)
new_config['Email']['email_notify_onsnatch'] = int(EMAIL_NOTIFY_ONSNATCH) new_config['Email']['email_notify_onsnatch'] = int(EMAIL_NOTIFY_ONSNATCH)
new_config['Email']['email_notify_ondownload'] = int(EMAIL_NOTIFY_ONDOWNLOAD) new_config['Email']['email_notify_ondownload'] = int(EMAIL_NOTIFY_ONDOWNLOAD)
new_config['Email']['email_notify_onsubtitledownload'] = int(EMAIL_NOTIFY_ONSUBTITLEDOWNLOAD) new_config['Email']['email_notify_onsubtitledownload'] = int(EMAIL_NOTIFY_ONSUBTITLEDOWNLOAD)

207
sickbeard/notifiers/emailnotify.py

@ -19,191 +19,186 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with SickGear. If not, see <http://www.gnu.org/licenses/>. # along with SickGear. If not, see <http://www.gnu.org/licenses/>.
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import re import re
import sickbeard import sickbeard
import smtplib
from sickbeard import logger, common
from sickbeard import db from sickbeard import db
from sickbeard.exceptions import ex from sickbeard import logger
from sickbeard.common import notifyStrings, NOTIFY_SNATCH, NOTIFY_DOWNLOAD, NOTIFY_SUBTITLE_DOWNLOAD
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import formatdate
class EmailNotifier: class EmailNotifier:
def __init__(self): def __init__(self):
self.last_err = None self.last_err = None
def test_notify(self, host, port, smtp_from, use_tls, user, pwd, to): def test_notify(self, host, port, smtp_from, use_tls, user, pwd, to):
msg = MIMEText('This is a test message from SickGear. If you\'re reading this, the test succeeded.')
msg['Subject'] = 'SickGear: Test Message' msg = MIMEText('Success. This is a SickGear test message. Typically sent on, %s' %
notifyStrings[NOTIFY_DOWNLOAD])
msg['Subject'] = 'SickGear: Test message'
msg['From'] = smtp_from msg['From'] = smtp_from
msg['To'] = to msg['To'] = to
msg['Date'] = formatdate(localtime=True)
return self._sendmail(host, port, smtp_from, use_tls, user, pwd, [to], msg, True) return self._sendmail(host, port, smtp_from, use_tls, user, pwd, [to], msg, True)
def notify_snatch(self, ep_name, title='Snatched:'): def _send_email(self, title, ep_name, lang='', extra='', force=False):
"""
Send a notification that an episode was snatched if not sickbeard.USE_EMAIL and not force:
return
ep_name: The name of the episode that was snatched
title: The title of the notification (optional)
"""
ep_name = ep_name.encode('utf-8', 'replace') ep_name = ep_name.encode('utf-8', 'replace')
show = self._parse_ep(ep_name)
to = self._generate_recipients(show)
if not any(to):
logger.log(u'No email recipients to notify, skipping', logger.WARNING)
return
if sickbeard.EMAIL_NOTIFY_ONSNATCH:
show = self._parseEp(ep_name)
to = self._generate_recepients(show)
if len(to) == 0:
logger.log('Skipping email notification because there are no configured recepients', logger.WARNING)
else:
try: try:
msg = MIMEMultipart('alternative') msg = MIMEMultipart('alternative')
msg.attach(MIMEText( msg.attach(MIMEText(
"<body style='font-family:Helvetica, Arial, sans-serif;'><h3>SickGear Notification - Snatched</h3>\n<p>Show: <b>" + re.search( '<body style="font-family:Helvetica, Arial, sans-serif;">' +
'(.+?) -.+', ep_name).group(1) + '</b></p>\n<p>Episode: <b>' + re.search( '<h3>SickGear Notification - %s</h3>\n' % title +
'.+ - (.+?-.+) -.+', ep_name).group( '<p>Show: <b>' + re.search('(.+?) -.+', ep_name).group(1) +
1) + "</b></p>\n\n<footer style='margin-top: 2.5em; padding: .7em 0; color: #777; border-top: #BBB solid 1px;'>Powered by SickGear.</footer></body>", '</b></p>\n<p>Episode: <b>' + re.search('.+ - (.+?-.+) -.+', ep_name).group(1) +
extra +
'</b></p>\n\n' +
'<footer style="margin-top:2.5em;padding:.7em 0;color:#777;border-top:#BBB solid 1px;">' +
'Powered by SickGear.</footer></body>',
'html')) 'html'))
except: except:
try:
msg = MIMEText(ep_name) msg = MIMEText(ep_name)
except:
msg = MIMEText('Episode %s' % title)
msg['Subject'] = 'Snatched: ' + ep_name msg['Subject'] = '%s%s: %s' % (lang, title, ep_name)
msg['From'] = sickbeard.EMAIL_FROM msg['From'] = sickbeard.EMAIL_FROM
msg['To'] = ','.join(to) msg['To'] = ','.join(to)
msg['Date'] = formatdate(localtime=True)
if self._sendmail(sickbeard.EMAIL_HOST, sickbeard.EMAIL_PORT, sickbeard.EMAIL_FROM, sickbeard.EMAIL_TLS, if self._sendmail(sickbeard.EMAIL_HOST, sickbeard.EMAIL_PORT, sickbeard.EMAIL_FROM, sickbeard.EMAIL_TLS,
sickbeard.EMAIL_USER, sickbeard.EMAIL_PASSWORD, to, msg): sickbeard.EMAIL_USER, sickbeard.EMAIL_PASSWORD, to, msg):
logger.log('Snatch notification sent to [%s] for "%s"' % (to, ep_name), logger.DEBUG) logger.log(u'%s notification sent to [%s] for "%s"' % (title, to, ep_name), logger.DEBUG)
else: else:
logger.log('Snatch notification ERROR: %s' % self.last_err, logger.ERROR) logger.log(u'%s notification ERROR: %s' % (title, self.last_err), logger.ERROR)
def notify_download(self, ep_name, title='Completed:'): def notify_snatch(self, ep_name, title=notifyStrings[NOTIFY_SNATCH]):
"""
Send a notification that an episode was snatched
:param ep_name: The name of the episode that was snatched
:param title: The title of the notification (optional)
"""
if sickbeard.EMAIL_NOTIFY_ONSNATCH:
title = sickbeard.EMAIL_OLD_SUBJECTS and 'Snatched' or title
self._send_email(title, ep_name)
def notify_download(self, ep_name, title=notifyStrings[NOTIFY_DOWNLOAD]):
""" """
Send a notification that an episode was downloaded Send a notification that an episode was downloaded
ep_name: The name of the episode that was downloaded :param ep_name: The name of the episode that was downloaded
title: The title of the notification (optional) :param title: The title of the notification (optional)
""" """
ep_name = ep_name.encode('utf-8', 'replace')
if sickbeard.EMAIL_NOTIFY_ONDOWNLOAD: if sickbeard.EMAIL_NOTIFY_ONDOWNLOAD:
show = self._parseEp(ep_name) title = sickbeard.EMAIL_OLD_SUBJECTS and 'Downloaded' or title
to = self._generate_recepients(show) self._send_email(title, ep_name)
if len(to) == 0:
logger.log('Skipping email notification because there are no configured recepients', logger.WARNING)
else:
try:
msg = MIMEMultipart('alternative')
msg.attach(MIMEText(
"<body style='font-family:Helvetica, Arial, sans-serif;'><h3>SickGear Notification - Downloaded</h3>\n<p>Show: <b>" + re.search(
'(.+?) -.+', ep_name).group(1) + '</b></p>\n<p>Episode: <b>' + re.search(
'.+ - (.+?-.+) -.+', ep_name).group(
1) + "</b></p>\n\n<footer style='margin-top: 2.5em; padding: .7em 0; color: #777; border-top: #BBB solid 1px;'>Powered by SickGear.</footer></body>",
'html'))
except:
msg = MIMEText(ep_name)
msg['Subject'] = 'Downloaded: ' + ep_name
msg['From'] = sickbeard.EMAIL_FROM
msg['To'] = ','.join(to)
if self._sendmail(sickbeard.EMAIL_HOST, sickbeard.EMAIL_PORT, sickbeard.EMAIL_FROM, sickbeard.EMAIL_TLS,
sickbeard.EMAIL_USER, sickbeard.EMAIL_PASSWORD, to, msg):
logger.log('Download notification sent to [%s] for "%s"' % (to, ep_name), logger.DEBUG)
else:
logger.log('Download notification ERROR: %s' % self.last_err, logger.ERROR)
def notify_subtitle_download(self, ep_name, lang, title='Downloaded subtitle:'): def notify_subtitle_download(self, ep_name, lang, title=notifyStrings[NOTIFY_SUBTITLE_DOWNLOAD]):
""" """
Send a notification that an subtitle was downloaded Send a notification that a subtitle was downloaded
ep_name: The name of the episode that was downloaded :param ep_name: The name of the episode that was downloaded
lang: Subtitle language wanted :param lang: Subtitle language
:param title: The title of the notification (optional)
""" """
ep_name = ep_name.encode('utf-8', 'replace')
if sickbeard.EMAIL_NOTIFY_ONSUBTITLEDOWNLOAD: if sickbeard.EMAIL_NOTIFY_ONSUBTITLEDOWNLOAD:
show = self._parseEp(ep_name) title = sickbeard.EMAIL_OLD_SUBJECTS and 'Subtitle Downloaded' or title
to = self._generate_recepients(show) self._send_email(title, ep_name, '%s ' % lang, '</b></p>\n<p>Language: <b>%s' % lang)
if len(to) == 0:
logger.log('Skipping email notification because there are no configured recepients', logger.WARNING)
else:
try:
msg = MIMEMultipart('alternative')
msg.attach(MIMEText(
"<body style='font-family:Helvetica, Arial, sans-serif;'><h3>SickGear Notification - Subtitle Downloaded</h3>\n<p>Show: <b>" + re.search(
'(.+?) -.+', ep_name).group(1) + '</b></p>\n<p>Episode: <b>' + re.search(
'.+ - (.+?-.+) -.+', ep_name).group(
1) + '</b></p>\n<p>Language: <b>' + lang + "</b></p>\n\n<footer style='margin-top: 2.5em; padding: .7em 0; color: #777; border-top: #BBB solid 1px;'>Powered by SickGear.</footer></body>",
'html'))
except:
msg = MIMEText(ep_name + ': ' + lang)
msg['Subject'] = lang + ' Subtitle Downloaded: ' + ep_name
msg['From'] = sickbeard.EMAIL_FROM
msg['To'] = ','.join(to)
if self._sendmail(sickbeard.EMAIL_HOST, sickbeard.EMAIL_PORT, sickbeard.EMAIL_FROM, sickbeard.EMAIL_TLS,
sickbeard.EMAIL_USER, sickbeard.EMAIL_PASSWORD, to, msg):
logger.log('Download notification sent to [%s] for "%s"' % (to, ep_name), logger.DEBUG)
else:
logger.log('Download notification ERROR: %s' % self.last_err, logger.ERROR)
def notify_git_update(self, new_version='??'): def notify_git_update(self, new_version='??'):
pass pass
def _generate_recepients(self, show): @staticmethod
def _generate_recipients(show):
addrs = [] addrs = []
# Grab the global recipients # Grab the global recipients
if sickbeard.EMAIL_LIST:
for addr in sickbeard.EMAIL_LIST.split(','): for addr in sickbeard.EMAIL_LIST.split(','):
if (len(addr.strip()) > 0): if any(addr.strip()):
addrs.append(addr) addrs.append(addr)
# Grab the recipients for the show # Grab the recipients for the show
myDB = db.DBConnection() if None is not show:
for s in show: my_db = db.DBConnection()
for subs in myDB.select('SELECT notify_list FROM tv_shows WHERE show_name = ?', (s,)): for name in show:
for subs in my_db.select('SELECT notify_list FROM tv_shows WHERE show_name = ?', (name,)):
if subs['notify_list']: if subs['notify_list']:
for addr in subs['notify_list'].split(','): for addr in subs['notify_list'].split(','):
if (len(addr.strip()) > 0): if any(addr.strip()):
addrs.append(addr) addrs.append(addr)
addrs = set(addrs) addrs = set(addrs)
logger.log('Notification recepients: %s' % addrs, logger.DEBUG) logger.log(u'Email recipients to notify: %s' % addrs, logger.DEBUG)
return addrs return addrs
def _sendmail(self, host, port, smtp_from, use_tls, user, pwd, to, msg, smtpDebug=False): def _sendmail(self, host, port, smtp_from, use_tls, user, pwd, to, msg, smtp_debug=False):
logger.log('HOST: %s; PORT: %s; FROM: %s, TLS: %s, USER: %s, PWD: %s, TO: %s' % (
host, port, smtp_from, use_tls, user, pwd, to), logger.DEBUG) use_tls = 1 == sickbeard.helpers.tryInt(use_tls)
login = any(user) and any(pwd)
logger.log(u'Sendmail HOST: %s; PORT: %s; LOGIN: %s, TLS: %s, USER: %s, FROM: %s, TO: %s' % (
host, port, login, use_tls, user, smtp_from, to), logger.DEBUG)
try: try:
srv = smtplib.SMTP(host, int(port)) srv = smtplib.SMTP(host, int(port))
if smtpDebug: if smtp_debug:
srv.set_debuglevel(1) srv.set_debuglevel(1)
if (use_tls == '1' or use_tls == True) or (len(user) > 0 and len(pwd) > 0):
if use_tls or login:
srv.ehlo() srv.ehlo()
logger.log('Sent initial EHLO command!', logger.DEBUG) logger.log(u'Sent initial EHLO command', logger.DEBUG)
if use_tls == '1' or use_tls == True:
if use_tls:
srv.starttls() srv.starttls()
logger.log('Sent STARTTLS command!', logger.DEBUG) srv.ehlo()
if len(user) > 0 and len(pwd) > 0: logger.log(u'Sent STARTTLS and EHLO command', logger.DEBUG)
if login:
srv.login(user, pwd) srv.login(user, pwd)
logger.log('Sent LOGIN command!', logger.DEBUG) logger.log(u'Sent LOGIN command', logger.DEBUG)
srv.sendmail(smtp_from, to, msg.as_string()) srv.sendmail(smtp_from, to, msg.as_string())
srv.quit() srv.quit()
return True
except Exception as e: except Exception as e:
self.last_err = '%s' % e self.last_err = '%s' % e
return False return False
def _parseEp(self, ep_name): return True
ep_name = ep_name.encode('utf-8', 'replace')
@staticmethod
def _parse_ep(ep_name):
ep_name = ep_name.encode('utf-8', 'replace')
sep = ' - ' sep = ' - '
titles = ep_name.split(sep) titles = ep_name.split(sep)
titles.sort(key=len, reverse=True) titles.sort(key=len, reverse=True)
logger.log('TITLES: %s' % titles, logger.DEBUG) logger.log(u'TITLES: %s' % titles, logger.DEBUG)
return titles return titles

100
sickbeard/webserve.py

@ -937,16 +937,38 @@ class Home(MainHandler):
def loadShowNotifyLists(self, *args, **kwargs): def loadShowNotifyLists(self, *args, **kwargs):
self.set_header('Cache-Control', 'max-age=0,no-cache,no-store') self.set_header('Cache-Control', 'max-age=0,no-cache,no-store')
myDB = db.DBConnection() my_db = db.DBConnection()
rows = myDB.select('SELECT show_id, show_name, notify_list FROM tv_shows ORDER BY show_name ASC') rows = my_db.select('SELECT indexer_id, indexer, notify_list FROM tv_shows ' +
'WHERE notify_list NOTNULL and notify_list != ""')
notify_lists = {}
for r in filter(lambda x: x['notify_list'].strip(), rows):
notify_lists['%s_%s' % (r['indexer'], r['indexer_id'])] = r['notify_list']
sorted_show_lists = self.sorted_show_lists()
response = []
for current_group in sorted_show_lists:
data = []
for current_show in current_group[1]:
uid = '%s_%s' % (current_show.indexer, current_show.indexerid)
data.append({'id': uid, 'name': current_show.name,
'list': '' if uid not in notify_lists else notify_lists[uid]})
if data:
response.append({current_group[0]: data})
return json.dumps(response)
@staticmethod
def save_show_email(show=None, emails=None):
# self.set_header('Cache-Control', 'max-age=0,no-cache,no-store')
data = {} my_db = db.DBConnection()
size = 0 success = False
for r in rows: parse = show.split('_')
data[r['show_id']] = {'id': r['show_id'], 'name': r['show_name'], 'list': r['notify_list']} if 1 < len(parse) and \
size += 1 my_db.action('UPDATE tv_shows SET notify_list = ? WHERE indexer = ? AND indexer_id = ?',
data['_size'] = size [emails, parse[0], parse[1]]):
return json.dumps(data) success = True
return json.dumps({'id': show, 'success': success})
def testEmail(self, host=None, port=None, smtp_from=None, use_tls=None, user=None, pwd=None, to=None): def testEmail(self, host=None, port=None, smtp_from=None, use_tls=None, user=None, pwd=None, to=None):
self.set_header('Cache-Control', 'max-age=0,no-cache,no-store') self.set_header('Cache-Control', 'max-age=0,no-cache,no-store')
@ -956,8 +978,7 @@ class Home(MainHandler):
host = config.clean_host(host) host = config.clean_host(host)
if notifiers.email_notifier.test_notify(host, port, smtp_from, use_tls, user, pwd, to): if notifiers.email_notifier.test_notify(host, port, smtp_from, use_tls, user, pwd, to):
return 'Test email sent successfully! Check inbox.' return 'Success. Test email sent. Check inbox.'
else:
return 'ERROR: %s' % notifiers.email_notifier.last_err return 'ERROR: %s' % notifiers.email_notifier.last_err
def testNMA(self, nma_api=None, nma_priority=0): def testNMA(self, nma_api=None, nma_priority=0):
@ -1217,32 +1238,11 @@ class Home(MainHandler):
display_seasons += [1] display_seasons += [1]
display_seasons += [highest_season] display_seasons += [highest_season]
def titler(x): t.sortedShowLists = self.sorted_show_lists()
return (remove_article(x), x)[not x or sickbeard.SORT_ARTICLE]
if sickbeard.SHOWLIST_TAGVIEW == 'custom':
t.sortedShowLists = []
for tag in sickbeard.SHOW_TAGS:
results = filter(lambda x: x.tag == tag, sickbeard.showList)
if results:
t.sortedShowLists.append([tag, sorted(results, lambda x, y: cmp(titler(x.name), titler(y.name)))])
elif sickbeard.SHOWLIST_TAGVIEW == 'anime':
shows = []
anime = []
for show in sickbeard.showList:
if show.is_anime:
anime.append(show)
else:
shows.append(show)
t.sortedShowLists = [['Shows', sorted(shows, lambda x, y: cmp(titler(x.name), titler(y.name)))],
['Anime', sorted(anime, lambda x, y: cmp(titler(x.name), titler(y.name)))]]
else:
t.sortedShowLists = [
['Show List', sorted(sickbeard.showList, lambda x, y: cmp(titler(x.name), titler(y.name)))]]
tvshows = [] tvshows = []
tvshow_names = [] tvshow_names = []
cur_sel = None
for tvshow_types in t.sortedShowLists: for tvshow_types in t.sortedShowLists:
for tvshow in tvshow_types[1]: for tvshow in tvshow_types[1]:
tvshows.append(tvshow.indexerid) tvshows.append(tvshow.indexerid)
@ -1252,6 +1252,9 @@ class Home(MainHandler):
t.tvshow_id_csv = ','.join(str(x) for x in tvshows) t.tvshow_id_csv = ','.join(str(x) for x in tvshows)
last_item = len(tvshow_names) last_item = len(tvshow_names)
t.prev_title = ''
t.next_title = ''
if cur_sel:
t.prev_title = 'Prev show, %s' % tvshow_names[(cur_sel - 2, last_item - 1)[1 == cur_sel]] t.prev_title = 'Prev show, %s' % tvshow_names[(cur_sel - 2, last_item - 1)[1 == cur_sel]]
t.next_title = 'Next show, %s' % tvshow_names[(cur_sel, 0)[last_item == cur_sel]] t.next_title = 'Next show, %s' % tvshow_names[(cur_sel, 0)[last_item == cur_sel]]
@ -1276,6 +1279,35 @@ class Home(MainHandler):
return t.respond() return t.respond()
@staticmethod
def sorted_show_lists():
def titler(x):
return (remove_article(x), x)[not x or sickbeard.SORT_ARTICLE]
if 'custom' == sickbeard.SHOWLIST_TAGVIEW:
sorted_show_lists = []
for tag in sickbeard.SHOW_TAGS:
results = filter(lambda x: x.tag == tag, sickbeard.showList)
if results:
sorted_show_lists.append([tag, sorted(results, lambda x, y: cmp(titler(x.name), titler(y.name)))])
elif 'anime' == sickbeard.SHOWLIST_TAGVIEW:
shows = []
anime = []
for show in sickbeard.showList:
if show.is_anime:
anime.append(show)
else:
shows.append(show)
sorted_show_lists = [['Shows', sorted(shows, lambda x, y: cmp(titler(x.name), titler(y.name)))],
['Anime', sorted(anime, lambda x, y: cmp(titler(x.name), titler(y.name)))]]
else:
sorted_show_lists = [
['Show List', sorted(sickbeard.showList, lambda x, y: cmp(titler(x.name), titler(y.name)))]]
return sorted_show_lists
def plotDetails(self, show, season, episode): def plotDetails(self, show, season, episode):
myDB = db.DBConnection() myDB = db.DBConnection()
result = myDB.select( result = myDB.select(

Loading…
Cancel
Save