From 101e698a86a5cf4349e9c5e1931330654139ff14 Mon Sep 17 00:00:00 2001
From: JackDandy
Date: Sun, 17 Jan 2016 18:50:26 +0000
Subject: [PATCH] Change refactor email notifier.
---
CHANGES.md | 1 +
gui/slick/css/dark.css | 6 +-
gui/slick/css/light.css | 2 +
.../default/config_notifications.tmpl | 110 ++---
gui/slick/js/configNotifications.js | 405 ++++++++++--------
sickbeard/__init__.py | 6 +-
sickbeard/notifiers/emailnotify.py | 239 +++++------
sickbeard/webserve.py | 106 +++--
8 files changed, 460 insertions(+), 415 deletions(-)
diff --git a/CHANGES.md b/CHANGES.md
index 2953b7d1..52e8fafc 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -19,6 +19,7 @@
* 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 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)
diff --git a/gui/slick/css/dark.css b/gui/slick/css/dark.css
index 49977547..5b898c67 100644
--- a/gui/slick/css/dark.css
+++ b/gui/slick/css/dark.css
@@ -1177,14 +1177,16 @@ pre{
/* =======================================================================
input sizing (for config pages)
========================================================================== */
-
+
+.showlist-select optgroup,
#pickShow optgroup,
#showfilter optgroup,
#editAProvider optgroup{
color:#eee;
background-color:rgb(51, 51, 51)
}
-
+
+.showlist-select optgroup option,
#pickShow optgroup option,
#showfilter optgroup option,
#editAProvider optgroup option{
diff --git a/gui/slick/css/light.css b/gui/slick/css/light.css
index eb79039e..f5f2cd23 100644
--- a/gui/slick/css/light.css
+++ b/gui/slick/css/light.css
@@ -1142,6 +1142,7 @@ pre{
input sizing (for config pages)
========================================================================== */
+.showlist-select optgroup,
#pickShow optgroup,
#showfilter optgroup,
#editAProvider optgroup{
@@ -1149,6 +1150,7 @@ input sizing (for config pages)
background-color:#888
}
+.showlist-select optgroup option,
#pickShow optgroup option,
#showfilter optgroup option,
#editAProvider optgroup option{
diff --git a/gui/slick/interfaces/default/config_notifications.tmpl b/gui/slick/interfaces/default/config_notifications.tmpl
index 242fd89e..1de8e626 100644
--- a/gui/slick/interfaces/default/config_notifications.tmpl
+++ b/gui/slick/interfaces/default/config_notifications.tmpl
@@ -1637,7 +1637,7 @@
-
Allows configuration of email notifications on a per show basis.
+
Email notification settings.
@@ -1678,95 +1678,71 @@
-
-
- SMTP host
-
-
-
-
- hostname of your SMTP email server.
-
-
-
-
- SMTP port
-
-
-
-
- port number used to connect to your SMTP host.
-
-
-
-
-
- SMTP user
-
-
-
-
- (optional) your SMTP server username.
-
-
-
-
- SMTP password
-
-
-
-
- (optional) your SMTP server password.
-
-
Click below to test.
-
-
+
+
diff --git a/gui/slick/js/configNotifications.js b/gui/slick/js/configNotifications.js
index 9bfde006..d616e3c3 100644
--- a/gui/slick/js/configNotifications.js
+++ b/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 () {
var plex_host = $.trim($('#plex_host').val());
var plex_username = $.trim($('#plex_username').val());
@@ -224,30 +234,6 @@
$.get(sbRoot + '/home/testLibnotify',
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('Step1: 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() {
if (!$('#nmj_host').val()) {
@@ -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('-- All Devices -- ');
+ 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('' + devices[i].manufacturer + ' ' + devices[i].nickname + ' ');
+ } else {
+ $('#pushbullet_device_list').append('' + devices[i].manufacturer + ' ' + devices[i].nickname + ' ');
+ }
+ }
+ }
+ }
+ $('#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('Step1: 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');
function trakt_send_auth(){
@@ -510,6 +629,67 @@
});
});
+ function load_show_notify_lists() {
+ $.get(sbRoot + '/home/loadShowNotifyLists', function (data) {
+ var list, html, item, len= 0, el;
+ list = $.parseJSON(data);
+ html = [];
+ for (item in list) {
+ for (var k in list[item]) {
+ if ($.isArray(list[item][k])) {
+ len += list[item][k].length;
+ html.push('\t');
+ for (var show in list[item][k]) {
+ html.push('\t\t' + list[item][k][show].name + ' ');
+ }
+ html.push('\t ');
+ }
+ }
+ }
+
+ if (len) {
+ el = $('#email_show');
+ el.html('-- Select show -- '
+ + html.join('\n'));
+
+ $('#show_email_list').val('');
+
+ el.change(function () {
+ $('#show_email_list').val(
+ $(this).find('option[value="' + $(this).val() + '"]').attr('data'))
+ });
+ }
+ });
+ }
+ // Load the per show notify lists everytime this page is loaded
+ load_show_notify_lists();
+
+ // Update the internal data struct anytime settings are saved to the server
+ $('#email_show').bind('notify', function () { load_show_notify_lists(); });
+
+ $('#save_show_email').click(
+ function(){
+ var show = $('#email_show').val();
+ if ('-1' == show) {
+ $('#testEmail-result').html('No show selected for save.');
+ return
+ }
+ $.post(sbRoot + '/home/save_show_email', {
+ show: show,
+ emails: $('#show_email_list').val()},
+ function (data){
+ // Reload the per show notify lists to reflect changes
+ 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);
+ });
+ });
+
$('#testEmail').click(function () {
var status, host, port, tls, from, user, pwd, err, to;
status = $('#testEmail-result');
@@ -523,174 +703,27 @@
from = from.length > 0 ? from : 'root@localhost';
user = $('#email_user').val().trim();
pwd = $('#email_password').val();
- err = '';
- if (host === null) {
- err += 'You must specify an SMTP hostname! ';
+ err = [];
+ if (null == host) {
+ err.push('SMTP server hostname');
}
- if (port === null) {
- err += 'You must specify an SMTP port! ';
- } else if (port.match(/^\d+$/) === null || parseInt(port, 10) > 65535) {
- err += 'SMTP port must be between 0 and 65535! ';
+ 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 (err.length > 0) {
- err = '' + err + ' ';
- status.html(err);
+ if (0 < err.length) {
+ status.html('Required: ' + err.join(', '));
} else {
- to = prompt('Enter an email address to send the test to:', null);
- if (to === null || to.length === 0 || to.match(/.*@.*/) === null) {
- status.html('You must provide a recipient email address!
');
+ 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); });
+ $.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);});
}
}
});
- $('#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('-- All Devices -- ');
- 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('' + devices[i].manufacturer + ' ' + devices[i].nickname + ' ');
- } else {
- $('#pushbullet_device_list').append('' + devices[i].manufacturer + ' ' + devices[i].nickname + ' ');
- }
- }
- }
- }
- $('#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();
- }
-
- $('#email_show').change(function () {
- 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
- $('#email_show').bind('notify', function () { load_show_notify_lists(); });
-
- function load_show_notify_lists() {
- $.get(sbRoot + "/home/loadShowNotifyLists", function (data) {
- var list, html, s;
- list = $.parseJSON(data);
- notify_data = list;
- if (list._size === 0) {
- return;
- }
- html = '-- Select -- ';
- for (s in list) {
- if (s.charAt(0) !== '_') {
- html += '' + $('
').text(list[s].name).html() + ' ';
- }
- }
- $('#email_show').html(html);
- $('#email_show_list').val('');
- });
- }
- // Load the per show notify lists everytime this page is loaded
- load_show_notify_lists();
-
- // 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')}
});
diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py
index 7fd8c7ab..ceb58feb 100755
--- a/sickbeard/__init__.py
+++ b/sickbeard/__init__.py
@@ -393,6 +393,7 @@ PUSHBULLET_ACCESS_TOKEN = None
PUSHBULLET_DEVICE_IDEN = None
USE_EMAIL = False
+EMAIL_OLD_SUBJECTS = None
EMAIL_NOTIFY_ONSNATCH = False
EMAIL_NOTIFY_ONDOWNLOAD = 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_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_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, \
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, \
@@ -922,6 +923,8 @@ def initialize(consoleLogging=True):
PUSHBULLET_DEVICE_IDEN = check_setting_str(CFG, 'Pushbullet', 'pushbullet_device_iden', '')
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_ONDOWNLOAD = bool(check_setting_int(CFG, 'Email', 'email_notify_ondownload', 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']['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_ondownload'] = int(EMAIL_NOTIFY_ONDOWNLOAD)
new_config['Email']['email_notify_onsubtitledownload'] = int(EMAIL_NOTIFY_ONSUBTITLEDOWNLOAD)
diff --git a/sickbeard/notifiers/emailnotify.py b/sickbeard/notifiers/emailnotify.py
index 164aca57..badf794e 100644
--- a/sickbeard/notifiers/emailnotify.py
+++ b/sickbeard/notifiers/emailnotify.py
@@ -19,191 +19,186 @@
# You should have received a copy of the GNU General Public License
# along with SickGear. If not, see .
-import smtplib
-from email.mime.multipart import MIMEMultipart
-from email.mime.text import MIMEText
-
import re
import sickbeard
+import smtplib
-from sickbeard import logger, common
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:
+
def __init__(self):
+
self.last_err = None
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['To'] = to
+ msg['Date'] = formatdate(localtime=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):
+
+ if not sickbeard.USE_EMAIL and not force:
+ return
+
+ 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
+
+ try:
+ msg = MIMEMultipart('alternative')
+ msg.attach(MIMEText(
+ '' +
+ 'SickGear Notification - %s \n' % title +
+ 'Show: ' + re.search('(.+?) -.+', ep_name).group(1) +
+ '
\nEpisode: ' + re.search('.+ - (.+?-.+) -.+', ep_name).group(1) +
+ extra +
+ '
\n\n' +
+ '' +
+ 'Powered by SickGear. ',
+ 'html'))
+ except:
+ try:
+ msg = MIMEText(ep_name)
+ except:
+ msg = MIMEText('Episode %s' % title)
+
+ msg['Subject'] = '%s%s: %s' % (lang, title, ep_name)
+ msg['From'] = sickbeard.EMAIL_FROM
+ msg['To'] = ','.join(to)
+ msg['Date'] = formatdate(localtime=True)
+ 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(u'%s notification sent to [%s] for "%s"' % (title, to, ep_name), logger.DEBUG)
+ else:
+ logger.log(u'%s notification ERROR: %s' % (title, self.last_err), logger.ERROR)
+
+ def notify_snatch(self, ep_name, title=notifyStrings[NOTIFY_SNATCH]):
"""
Send a notification that an episode was snatched
- ep_name: The name of the episode that was snatched
- title: The title of the notification (optional)
+ :param ep_name: The name of the episode that was snatched
+ :param title: The title of the notification (optional)
"""
- ep_name = ep_name.encode('utf-8', 'replace')
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:
- msg = MIMEMultipart('alternative')
- msg.attach(MIMEText(
- "SickGear Notification - Snatched \nShow: " + re.search(
- '(.+?) -.+', ep_name).group(1) + '
\nEpisode: ' + re.search(
- '.+ - (.+?-.+) -.+', ep_name).group(
- 1) + "
\n\n",
- 'html'))
- except:
- msg = MIMEText(ep_name)
+ title = sickbeard.EMAIL_OLD_SUBJECTS and 'Snatched' or title
+ self._send_email(title, ep_name)
- msg['Subject'] = 'Snatched: ' + 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('Snatch notification sent to [%s] for "%s"' % (to, ep_name), logger.DEBUG)
- else:
- logger.log('Snatch notification ERROR: %s' % self.last_err, logger.ERROR)
-
- def notify_download(self, ep_name, title='Completed:'):
+ def notify_download(self, ep_name, title=notifyStrings[NOTIFY_DOWNLOAD]):
"""
Send a notification that an episode was downloaded
- ep_name: The name of the episode that was downloaded
- title: The title of the notification (optional)
+ :param ep_name: The name of the episode that was downloaded
+ :param title: The title of the notification (optional)
"""
- ep_name = ep_name.encode('utf-8', 'replace')
if sickbeard.EMAIL_NOTIFY_ONDOWNLOAD:
- 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:
- msg = MIMEMultipart('alternative')
- msg.attach(MIMEText(
- "SickGear Notification - Downloaded \nShow: " + re.search(
- '(.+?) -.+', ep_name).group(1) + '
\nEpisode: ' + re.search(
- '.+ - (.+?-.+) -.+', ep_name).group(
- 1) + "
\n\n",
- 'html'))
- except:
- msg = MIMEText(ep_name)
+ title = sickbeard.EMAIL_OLD_SUBJECTS and 'Downloaded' or title
+ self._send_email(title, 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
- lang: Subtitle language wanted
+ :param ep_name: The name of the episode that was downloaded
+ :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:
- 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:
- msg = MIMEMultipart('alternative')
- msg.attach(MIMEText(
- "SickGear Notification - Subtitle Downloaded \nShow: " + re.search(
- '(.+?) -.+', ep_name).group(1) + '
\nEpisode: ' + re.search(
- '.+ - (.+?-.+) -.+', ep_name).group(
- 1) + '
\nLanguage: ' + lang + "
\n\n",
- '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)
-
+ title = sickbeard.EMAIL_OLD_SUBJECTS and 'Subtitle Downloaded' or title
+ self._send_email(title, ep_name, '%s ' % lang, '
\nLanguage: %s' % lang)
def notify_git_update(self, new_version='??'):
+
pass
- def _generate_recepients(self, show):
+ @staticmethod
+ def _generate_recipients(show):
+
addrs = []
# Grab the global recipients
- for addr in sickbeard.EMAIL_LIST.split(','):
- if (len(addr.strip()) > 0):
- addrs.append(addr)
+ if sickbeard.EMAIL_LIST:
+ for addr in sickbeard.EMAIL_LIST.split(','):
+ if any(addr.strip()):
+ addrs.append(addr)
# Grab the recipients for the show
- myDB = db.DBConnection()
- for s in show:
- for subs in myDB.select('SELECT notify_list FROM tv_shows WHERE show_name = ?', (s,)):
- if subs['notify_list']:
- for addr in subs['notify_list'].split(','):
- if (len(addr.strip()) > 0):
- addrs.append(addr)
+ if None is not show:
+ my_db = db.DBConnection()
+ for name in show:
+ for subs in my_db.select('SELECT notify_list FROM tv_shows WHERE show_name = ?', (name,)):
+ if subs['notify_list']:
+ for addr in subs['notify_list'].split(','):
+ if any(addr.strip()):
+ addrs.append(addr)
addrs = set(addrs)
- logger.log('Notification recepients: %s' % addrs, logger.DEBUG)
+ logger.log(u'Email recipients to notify: %s' % addrs, logger.DEBUG)
+
return addrs
- def _sendmail(self, host, port, smtp_from, use_tls, user, pwd, to, msg, smtpDebug=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)
+ def _sendmail(self, host, port, smtp_from, use_tls, user, pwd, to, msg, smtp_debug=False):
+
+ 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:
srv = smtplib.SMTP(host, int(port))
- if smtpDebug:
+ if smtp_debug:
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()
- logger.log('Sent initial EHLO command!', logger.DEBUG)
- if use_tls == '1' or use_tls == True:
- srv.starttls()
- logger.log('Sent STARTTLS command!', logger.DEBUG)
- if len(user) > 0 and len(pwd) > 0:
- srv.login(user, pwd)
- logger.log('Sent LOGIN command!', logger.DEBUG)
+ logger.log(u'Sent initial EHLO command', logger.DEBUG)
+
+ if use_tls:
+ srv.starttls()
+ srv.ehlo()
+ logger.log(u'Sent STARTTLS and EHLO command', logger.DEBUG)
+
+ if login:
+ srv.login(user, pwd)
+ logger.log(u'Sent LOGIN command', logger.DEBUG)
+
srv.sendmail(smtp_from, to, msg.as_string())
srv.quit()
- return True
+
except Exception as e:
self.last_err = '%s' % e
return False
- def _parseEp(self, ep_name):
- ep_name = ep_name.encode('utf-8', 'replace')
+ return True
+ @staticmethod
+ def _parse_ep(ep_name):
+
+ ep_name = ep_name.encode('utf-8', 'replace')
sep = ' - '
titles = ep_name.split(sep)
titles.sort(key=len, reverse=True)
- logger.log('TITLES: %s' % titles, logger.DEBUG)
+ logger.log(u'TITLES: %s' % titles, logger.DEBUG)
+
return titles
diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py
index 5248d58d..10686384 100644
--- a/sickbeard/webserve.py
+++ b/sickbeard/webserve.py
@@ -937,16 +937,38 @@ class Home(MainHandler):
def loadShowNotifyLists(self, *args, **kwargs):
self.set_header('Cache-Control', 'max-age=0,no-cache,no-store')
- myDB = db.DBConnection()
- rows = myDB.select('SELECT show_id, show_name, notify_list FROM tv_shows ORDER BY show_name ASC')
+ my_db = db.DBConnection()
+ 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']
- data = {}
- size = 0
- for r in rows:
- data[r['show_id']] = {'id': r['show_id'], 'name': r['show_name'], 'list': r['notify_list']}
- size += 1
- data['_size'] = size
- return json.dumps(data)
+ 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')
+
+ my_db = db.DBConnection()
+ success = False
+ parse = show.split('_')
+ if 1 < len(parse) and \
+ my_db.action('UPDATE tv_shows SET notify_list = ? WHERE indexer = ? AND indexer_id = ?',
+ [emails, parse[0], parse[1]]):
+ 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):
self.set_header('Cache-Control', 'max-age=0,no-cache,no-store')
@@ -956,9 +978,8 @@ class Home(MainHandler):
host = config.clean_host(host)
if notifiers.email_notifier.test_notify(host, port, smtp_from, use_tls, user, pwd, to):
- return 'Test email sent successfully! Check inbox.'
- else:
- return 'ERROR: %s' % notifiers.email_notifier.last_err
+ return 'Success. Test email sent. Check inbox.'
+ return 'ERROR: %s' % notifiers.email_notifier.last_err
def testNMA(self, nma_api=None, nma_priority=0):
self.set_header('Cache-Control', 'max-age=0,no-cache,no-store')
@@ -1217,32 +1238,11 @@ class Home(MainHandler):
display_seasons += [1]
display_seasons += [highest_season]
- def titler(x):
- 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)))]]
+ t.sortedShowLists = self.sorted_show_lists()
tvshows = []
tvshow_names = []
+ cur_sel = None
for tvshow_types in t.sortedShowLists:
for tvshow in tvshow_types[1]:
tvshows.append(tvshow.indexerid)
@@ -1252,8 +1252,11 @@ class Home(MainHandler):
t.tvshow_id_csv = ','.join(str(x) for x in tvshows)
last_item = len(tvshow_names)
- 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.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.next_title = 'Next show, %s' % tvshow_names[(cur_sel, 0)[last_item == cur_sel]]
t.bwl = None
if showObj.is_anime:
@@ -1276,6 +1279,35 @@ class Home(MainHandler):
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):
myDB = db.DBConnection()
result = myDB.select(