diff --git a/CHANGES.md b/CHANGES.md
index be2ef45a..b7912b54 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -110,6 +110,7 @@
* Add warn icon indicator of abandoned IDs to "Manage" menu bar and "Manage/Show Processes" menu item
* Add shows that have no replacement ID can be ignored at "Manage/Show Processes", the menu bar warn icon hides if all are ignored
* Change FreeBSD initscript to use command_interpreter
+* Add Slack notifier
[develop changelog]
diff --git a/gui/slick/images/notifiers/slack.png b/gui/slick/images/notifiers/slack.png
index 5efaafc0..f348c2d3 100644
Binary files a/gui/slick/images/notifiers/slack.png and b/gui/slick/images/notifiers/slack.png differ
diff --git a/gui/slick/interfaces/default/config_notifications.tmpl b/gui/slick/interfaces/default/config_notifications.tmpl
index f0ceb2d9..d912dc16 100644
--- a/gui/slick/interfaces/default/config_notifications.tmpl
+++ b/gui/slick/interfaces/default/config_notifications.tmpl
@@ -1683,77 +1683,29 @@
-
+
-
-
-
Team communication for the 21st century.
+
+
+
Team, group, and direct communication.
-
diff --git a/gui/slick/js/configNotifications.js b/gui/slick/js/configNotifications.js
index 9640c52c..d376d673 100644
--- a/gui/slick/js/configNotifications.js
+++ b/gui/slick/js/configNotifications.js
@@ -434,23 +434,30 @@
});
});
- $("#testSlack").click(function () {
- var slack_access_token = $("#slack_access_token").val();
- var slack_channel = $("#slack_channel").val();
- var slack_as_user = $("#slack_as_user").attr('checked');
- var slack_bot_name = $("#slack_bot_name").val();
- var slack_icon_url = $("#slack_icon_url").val();
- if (!slack_access_token || !slack_channel || !(slack_as_user || slack_bot_name)) {
- $("#testSlack-result").html("Please fill out the necessary fields above.");
- return;
+ $('#testSlack').click(function () {
+ var channel = '#slack_channel', slack_channel = $(channel).val(),
+ slack_as_user = $('#slack_as_user').prop('checked'),
+ slack_bot_name = $('#slack_bot_name').val(), slack_icon_url = $('#slack_icon_url').val(),
+ access_token = '#slack_access_token', slack_access_token = $(access_token).val();
+
+ $(channel + ', ' + access_token).removeClass('warning');
+ if (!slack_channel || !slack_access_token) {
+ $('#testSlack-result').html('Please fill out the necessary fields above.');
+ if (!slack_channel)
+ $(channel).addClass('warning');
+ if (!slack_access_token)
+ $(access_token).addClass('warning');
+ } else {
+ $(this).prop('disabled', true);
+ $('#testSlack-result').html(loading);
+ $.get(sbRoot + '/home/testSlack', {
+ 'channel': slack_channel, 'as_user': slack_as_user,
+ 'bot_name': slack_bot_name, 'icon_url': slack_icon_url, 'access_token': slack_access_token})
+ .done(function (data) {
+ $('#testSlack-result').html(data);
+ $('#testSlack').prop('disabled', false);
+ });
}
- $(this).prop("disabled", true);
- $("#testSlack-result").html(loading);
- $.get(sbRoot + "/home/testSlack", {'accessToken': slack_access_token, 'channel': slack_channel, 'as_user': slack_as_user, 'bot_name': slack_bot_name, 'icon_url': slack_icon_url})
- .done(function (data) {
- $("#testSlack-result").html(data);
- $("#testSlack").prop("disabled", false);
- });
});
function get_pushbullet_devices (msg) {
diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py
index bf61078a..63da291c 100755
--- a/sickbeard/__init__.py
+++ b/sickbeard/__init__.py
@@ -421,11 +421,12 @@ PUSHBULLET_DEVICE_IDEN = None
USE_SLACK = False
SLACK_NOTIFY_ONSNATCH = False
SLACK_NOTIFY_ONDOWNLOAD = False
-SLACK_ACCESS_TOKEN = None
+SLACK_NOTIFY_ONSUBTITLEDOWNLOAD = False
SLACK_CHANNEL = None
SLACK_AS_USER = False
SLACK_BOT_NAME = None
SLACK_ICON_URL = None
+SLACK_ACCESS_TOKEN = None
USE_EMAIL = False
EMAIL_OLD_SUBJECTS = None
@@ -640,7 +641,8 @@ def initialize(console_logging=True):
USE_TRAKT, TRAKT_CONNECTED_ACCOUNT, TRAKT_ACCOUNTS, TRAKT_MRU, TRAKT_VERIFY, \
TRAKT_USE_WATCHLIST, TRAKT_REMOVE_WATCHLIST, TRAKT_TIMEOUT, TRAKT_METHOD_ADD, TRAKT_START_PAUSED, \
TRAKT_SYNC, TRAKT_DEFAULT_INDEXER, TRAKT_REMOVE_SERIESLIST, TRAKT_UPDATE_COLLECTION, \
- USE_SLACK, SLACK_NOTIFY_ONSNATCH, SLACK_NOTIFY_ONDOWNLOAD, SLACK_ACCESS_TOKEN, SLACK_CHANNEL, SLACK_AS_USER, SLACK_BOT_NAME, SLACK_ICON_URL, \
+ USE_SLACK, SLACK_NOTIFY_ONSNATCH, SLACK_NOTIFY_ONDOWNLOAD, SLACK_NOTIFY_ONSUBTITLEDOWNLOAD, \
+ SLACK_CHANNEL, SLACK_AS_USER, SLACK_BOT_NAME, SLACK_ICON_URL, SLACK_ACCESS_TOKEN, \
USE_EMAIL, EMAIL_NOTIFY_ONSNATCH, EMAIL_NOTIFY_ONDOWNLOAD, EMAIL_NOTIFY_ONSUBTITLEDOWNLOAD, EMAIL_FROM, \
EMAIL_HOST, EMAIL_PORT, EMAIL_TLS, EMAIL_USER, EMAIL_PASSWORD, EMAIL_LIST, EMAIL_OLD_SUBJECTS
# Anime Settings
@@ -1046,11 +1048,12 @@ def initialize(console_logging=True):
USE_SLACK = bool(check_setting_int(CFG, 'Slack', 'use_slack', 0))
SLACK_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Slack', 'slack_notify_onsnatch', 0))
SLACK_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Slack', 'slack_notify_ondownload', 0))
- SLACK_ACCESS_TOKEN = check_setting_str(CFG, 'Slack', 'slack_access_token', '')
+ SLACK_NOTIFY_ONSUBTITLEDOWNLOAD = bool(check_setting_int(CFG, 'Slack', 'slack_notify_onsubtitledownload', 0))
SLACK_CHANNEL = check_setting_str(CFG, 'Slack', 'slack_channel', '')
SLACK_AS_USER = bool(check_setting_int(CFG, 'Slack', 'slack_as_user', 0))
SLACK_BOT_NAME = check_setting_str(CFG, 'Slack', 'slack_bot_name', '')
SLACK_ICON_URL = check_setting_str(CFG, 'Slack', 'slack_icon_url', '')
+ SLACK_ACCESS_TOKEN = check_setting_str(CFG, 'Slack', 'slack_access_token', '')
USE_EMAIL = bool(check_setting_int(CFG, 'Email', 'use_email', 0))
EMAIL_OLD_SUBJECTS = bool(check_setting_int(CFG, 'Email', 'email_old_subjects',
@@ -1844,11 +1847,12 @@ def save_config():
new_config['Slack']['use_slack'] = int(USE_SLACK)
new_config['Slack']['slack_notify_onsnatch'] = int(SLACK_NOTIFY_ONSNATCH)
new_config['Slack']['slack_notify_ondownload'] = int(SLACK_NOTIFY_ONDOWNLOAD)
- new_config['Slack']['slack_access_token'] = SLACK_ACCESS_TOKEN
+ new_config['Slack']['slack_notify_onsubtitledownload'] = int(SLACK_NOTIFY_ONSUBTITLEDOWNLOAD)
new_config['Slack']['slack_channel'] = SLACK_CHANNEL
new_config['Slack']['slack_as_user'] = int(SLACK_AS_USER)
new_config['Slack']['slack_bot_name'] = SLACK_BOT_NAME
new_config['Slack']['slack_icon_url'] = SLACK_ICON_URL
+ new_config['Slack']['slack_access_token'] = SLACK_ACCESS_TOKEN
new_config['Email'] = {}
new_config['Email']['use_email'] = int(USE_EMAIL)
diff --git a/sickbeard/notifiers/__init__.py b/sickbeard/notifiers/__init__.py
index 48ac704f..f55b2724 100644
--- a/sickbeard/notifiers/__init__.py
+++ b/sickbeard/notifiers/__init__.py
@@ -61,9 +61,9 @@ nma_notifier = nma.NMA_Notifier()
pushalot_notifier = pushalot.PushalotNotifier()
pushbullet_notifier = pushbullet.PushbulletNotifier()
# social
-slack_notifier = slack.SlackNotifier()
twitter_notifier = tweet.TwitterNotifier()
trakt_notifier = trakt.TraktNotifier()
+slack_notifier = slack.SlackNotifier()
email_notifier = emailnotify.EmailNotifier()
notifiers = [
@@ -83,9 +83,9 @@ notifiers = [
nma_notifier,
pushalot_notifier,
pushbullet_notifier,
- slack_notifier,
twitter_notifier,
trakt_notifier,
+ slack_notifier,
email_notifier,
]
diff --git a/sickbeard/notifiers/slack.py b/sickbeard/notifiers/slack.py
index 6f7c3714..3ba77f7e 100644
--- a/sickbeard/notifiers/slack.py
+++ b/sickbeard/notifiers/slack.py
@@ -2,7 +2,7 @@
#
# This file is part of SickGear.
#
-# Thanks to: mallen86
+# Thanks to: mallen86, generica
#
# SickGear is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -17,74 +17,50 @@
# You should have received a copy of the GNU General Public License
# along with SickGear. If not, see
.
-import json
import sickbeard
+from sickbeard import common, logger
-from sickbeard import logger, common
class SlackNotifier:
+ def __init__(self):
+ self.sg_logo_url = 'https://raw.githubusercontent.com/SickGear/SickGear/master' + \
+ '/gui/slick/images/ico/apple-touch-icon-precomposed.png'
- def _send_to_slack(self, message, accessToken, channel, as_user, bot_name, icon_url):
- SLACK_ENDPOINT = "https://slack.com/api/chat.postMessage"
+ def _notify(self, msg, channel='', as_user=False, bot_name='', icon_url='', access_token='', force=False):
+ custom = (force and not as_user) or (not (force or sickbeard.SLACK_AS_USER))
+ resp = (sickbeard.USE_SLACK or force) and sickbeard.helpers.getURL(
+ url='https://slack.com/api/chat.postMessage',
+ post_data=dict(
+ [('text', msg), ('token', (access_token, sickbeard.SLACK_ACCESS_TOKEN)[not access_token]),
+ ('channel', (channel, sickbeard.SLACK_CHANNEL)[not channel]), ('as_user', not custom)] +
+ ([], [('username', (bot_name, sickbeard.SLACK_BOT_NAME or 'SickGear')[not bot_name]),
+ ('icon_url', (icon_url, sickbeard.SLACK_ICON_URL or self.sg_logo_url)[not icon_url])])[custom]),
+ json=True)
- data = {}
- data["token"] = accessToken
- data["channel"] = channel
- data["username"] = bot_name
- data["text"] = message
- data["icon_url"] = icon_url
- data["as_user"] = as_user
+ result = resp and resp['ok'] or resp['error']
+ if True is not result:
+ logger.log(u'Slack failed sending message, response: "%s"' % resp['error'], logger.ERROR)
+ return result
- urlResp = sickbeard.helpers.getURL(url=SLACK_ENDPOINT, post_data=data)
- if urlResp:
- resp = json.loads(urlResp)
- else:
- return False
+ def _notify_str(self, pre_text, post_text):
+ return self._notify('%s: %s' % (common.notifyStrings[pre_text].strip('#: '), post_text))
- # if ("error" in resp):
- # raise Exception(resp["error"])
-
- if (resp["ok"] == True):
- logger.log(u"Slack: Succeeded sending message.", logger.MESSAGE)
- return True
-
- logger.log(u"Slack: Failed sending message: " + resp["error"], logger.ERROR)
- return False
-
- def _notify(self, message, accessToken='', channel='', as_user='', bot_name='', icon_url='', force=False):
- # suppress notifications if the notifier is disabled but the notify options are checked
- if not sickbeard.USE_SLACK and not force:
- return False
-
- if not accessToken:
- accessToken = sickbeard.SLACK_ACCESS_TOKEN
- if not channel:
- channel = sickbeard.SLACK_CHANNEL
- if not as_user:
- as_user = sickbeard.SLACK_AS_USER
- if not bot_name:
- bot_name = sickbeard.SLACK_BOT_NAME
- if not icon_url:
- icon_url = sickbeard.SLACK_ICON_URL
-
- return self._send_to_slack(message, accessToken, channel, as_user, bot_name, icon_url)
-
-##############################################################################
-# Public functions
-##############################################################################
+ def test_notify(self, channel, as_user, bot_name, icon_url, access_token):
+ return self._notify('This is a test notification from SickGear',
+ channel, as_user, bot_name, icon_url, access_token, force=True)
def notify_snatch(self, ep_name):
- if sickbeard.SLACK_NOTIFY_ONSNATCH:
- self._notify(common.notifyStrings[common.NOTIFY_SNATCH] + ': ' + ep_name)
+ return sickbeard.SLACK_NOTIFY_ONSNATCH and self._notify_str(common.NOTIFY_SNATCH, ep_name)
def notify_download(self, ep_name):
- if sickbeard.SLACK_NOTIFY_ONDOWNLOAD:
- self._notify(common.notifyStrings[common.NOTIFY_DOWNLOAD] + ': ' + ep_name)
+ return sickbeard.SLACK_NOTIFY_ONDOWNLOAD and self._notify_str(common.NOTIFY_DOWNLOAD, ep_name)
- def test_notify(self, accessToken, channel, as_user, bot_name, icon_url):
- return self._notify("This is a test notification from SickGear", accessToken, channel, as_user, bot_name, icon_url, force=True)
+ def notify_subtitle_download(self, ep_name, lang):
+ return sickbeard.SLACK_NOTIFY_ONSUBTITLEDOWNLOAD and \
+ self._notify_str(common.NOTIFY_SUBTITLE_DOWNLOAD, '%s: %s' % (ep_name, lang))
+
+ def notify_git_update(self, new_version='??'):
+ return self._notify_str(common.NOTIFY_GIT_UPDATE_TEXT, new_version)
- def update_library(self, ep_obj):
- pass
notifier = SlackNotifier
diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py
index bfe6f07d..5c2b53e7 100644
--- a/sickbeard/webserve.py
+++ b/sickbeard/webserve.py
@@ -1150,14 +1150,12 @@ class Home(MainHandler):
return notifiers.pushbullet_notifier.get_devices(accessToken)
- def testSlack(self, accessToken=None, channel=None, as_user=False, bot_name=None, icon_url=None):
+ def testSlack(self, access_token=None, channel=None, as_user=False, bot_name=None, icon_url=None):
self.set_header('Cache-Control', 'max-age=0,no-cache,no-store')
- result = notifiers.slack_notifier.test_notify(accessToken, channel, as_user, bot_name, icon_url)
- if result:
- return "Slack notification succeeded. Check your Slack clients to make sure it worked"
- else:
- return "Error sending Slack notification"
+ result = notifiers.slack_notifier.test_notify(channel, 'true' == as_user, bot_name, icon_url, access_token)
+ return ('Error sending notification, Slack response: "%s"' % result,
+ 'Successful test notice sent. (Note: Slack clients display icon once in a sequence)')[True is result]
def viewchanges(self):