From c2fcf374984776155621ebe04796cde7961e56b8 Mon Sep 17 00:00:00 2001 From: Brett Pemberton Date: Thu, 14 Sep 2017 04:39:54 +0100 Subject: [PATCH 1/2] Add Slack Notifications. --- gui/slick/images/notifiers/slack.png | Bin 0 -> 15154 bytes .../default/config_notifications.tmpl | 92 ++++++++++++++++++ gui/slick/js/configNotifications.js | 19 ++++ sickbeard/__init__.py | 31 +++++- sickbeard/notifiers/__init__.py | 3 + sickbeard/notifiers/slack.py | 90 +++++++++++++++++ sickbeard/webserve.py | 22 ++++- 7 files changed, 254 insertions(+), 3 deletions(-) create mode 100644 gui/slick/images/notifiers/slack.png create mode 100644 sickbeard/notifiers/slack.py diff --git a/gui/slick/images/notifiers/slack.png b/gui/slick/images/notifiers/slack.png new file mode 100644 index 0000000000000000000000000000000000000000..5efaafc0f934461b0a365daebcce80c06aaa56ab GIT binary patch literal 15154 zcmeI3e{>U77RRTBN(myA9~JiKnv)idKsqz|(KKTcPH9?F+jP4n*q~<%lVp;PO)_a_ zYSI*u0#?>NM=LDIR&?EM5q~dr5wPr$Mf?G~9Ctx%cX2`JdddPTtio~-QFbOtlh-um z=^p=lIVYLh_rCYuH=ldo>-;l6udP`$S@t6thGCN{t(H3RI!pTI-X#8>44bZqmx)2^ zQXa!5O_#n|Sl1R&QBug-9fHGFO}RLK5$)!jOi{!i6xA4JTo4J;t|ms1I~gwgUVV1gXOb4Xz0Wl}T>LXg7oa5!8P))a9eFHRZ^2AojiYPCvKsQA`^ zKu1&oz91fCIF5zkT_H9ouv|bc#igBGi(pbHq(sS2;=cUBWTF6{U?)<-GCHrsjq6 zheQMkq!~SVdux!v>lmJE3Avc^hs0Yc$aMDt>q!-7L?mfu%(XKSb__RZChit%g?NRG z;=NL3A%+&Xke%av=6ILY4kMJ8mBqSBuB>MRZZ6E!#FNr^Z9*2^B+<1{I;!x>W{^UZW~;8fel$JDrT%8G~rEf$pP1TR2yXv|AFP-QP1b z;65t!PeQDC($PLZBdz}XrpORxR4OaWi~ZRO^sU&vv9oM3(>!u?c*4iV&ZHn6;u&ej znH0lYE_sM0&nU?!wsR@kC7otwm$V@mw-FyPnp#%UGvUVmzXgoP2i(Wb5pHAxH`-9~ zP%+imL3qw1gy|4d>J@w9yX^IN)RAuK;f=U-`uo_Cg@})itj}=Aj;^OsI@Bn!7sPeZ zu^Ny@eAHMfb6oF`YU*o=>Gf(t{NSYYn{WlE(_NR|*cF^kcTIUN39y1$oye9p40uT= zZ~RzTEIuSK=3<>rqch^^!|5KiY=rSSEUdVHd8sSa+JsN~L`KJ@V>tp73CDP;fPd$) zO2$XUhXwID1y4Sxj4X0;BmBTd>W+Tkz+gC(1f&7A5iTeqP=IiOG@v%Z1w{l35H64g z)JC|Vh(H0t1=4`p2p1F)C_uPC8c-YIf+7M12p32LY9m}wM4$lS0%<^PgbRuY6d+t6 z4XBN9K@ouhgbSnrwGl2TB2a*Efi$2t!UaVH3J@-k2GmBlpol;L!UfWR+6WgE5hy^o zKpIdR;esLp1qc^N18O5&P(+{r;R0zuZG;Po2oxY(APuOEa6u7)0)z{s0ksh>C?ZgR zaDgAm+n^U0Aj4Idi5$!XZKuHe zpQ6;aDes7m#~j^_jXksavQ>m^-)&r|zte2imvlu3`!{Sk{nv?RWntE9b3Cn+3$0jZ zMbDKMefg^oSI<^9&y3Fh`=f=IhX#)J&3)?Lw_olYzkiu-oh%PK!ulT{I#n~b?u)~b z3niyM?AkGXS3yCQvAOqZ=@V7i)9Ma)bZ8Hp*mq*b{sYwqpSgcBL8b>PKG&(0PCoi#6fzJ*aPzqj{TgW!B*&y+v6 zMNQ}Dw_fdk>B%SQlezktU!PQ#T=q4udTu^(QS&Ne zAaDNdrB%OqZRMXf^sCw?Jbm_or|vm-u)gdg>)tT4gIf8=x8AvL+}!Om&TV~pxBZ19 zRrXWdz`LjZQ2$1I^|mR-ZLieNu}{{0y8mDE`n!L3XvXhX)GVl<{%oYX>C0W^8$VmU zz1Oj>Zr8PWk8ghvYrJ(~Q}4%XZhGu&`n8bw`IZJ0IEMKl$s6UhJ;j W*Iv)+CdHn`u*&ip%j*l5ul^q`(ALKQ literal 0 HcmV?d00001 diff --git a/gui/slick/interfaces/default/config_notifications.tmpl b/gui/slick/interfaces/default/config_notifications.tmpl index 03009cfb..f0ceb2d9 100644 --- a/gui/slick/interfaces/default/config_notifications.tmpl +++ b/gui/slick/interfaces/default/config_notifications.tmpl @@ -1683,6 +1683,98 @@ +
+
+ +

Slack

+

Team communication for the 21st century.

+
+
+
+ + +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ +
+
Click below to test.
+ + +
+ +
+
+
diff --git a/gui/slick/js/configNotifications.js b/gui/slick/js/configNotifications.js index bb064cc7..9640c52c 100644 --- a/gui/slick/js/configNotifications.js +++ b/gui/slick/js/configNotifications.js @@ -434,6 +434,25 @@ }); }); + $("#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; + } + $(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) { var pushbullet_access_token = $.trim($('#pushbullet_access_token').val()); if (!pushbullet_access_token) { diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py index dc25093b..bf61078a 100755 --- a/sickbeard/__init__.py +++ b/sickbeard/__init__.py @@ -418,6 +418,15 @@ PUSHBULLET_NOTIFY_ONSUBTITLEDOWNLOAD = False PUSHBULLET_ACCESS_TOKEN = None PUSHBULLET_DEVICE_IDEN = None +USE_SLACK = False +SLACK_NOTIFY_ONSNATCH = False +SLACK_NOTIFY_ONDOWNLOAD = False +SLACK_ACCESS_TOKEN = None +SLACK_CHANNEL = None +SLACK_AS_USER = False +SLACK_BOT_NAME = None +SLACK_ICON_URL = None + USE_EMAIL = False EMAIL_OLD_SUBJECTS = None EMAIL_NOTIFY_ONSNATCH = False @@ -631,6 +640,7 @@ 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_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 @@ -640,7 +650,7 @@ def initialize(console_logging=True): return False for stanza in ('General', 'Blackhole', 'SABnzbd', 'NZBget', 'Emby', 'Kodi', 'XBMC', 'PLEX', - 'Growl', 'Prowl', 'Twitter', 'Boxcar2', 'NMJ', 'NMJv2', 'Synology', 'SynologyNotifier', + 'Growl', 'Prowl', 'Twitter', 'Slack', 'Boxcar2', 'NMJ', 'NMJv2', 'Synology', 'SynologyNotifier', 'pyTivo', 'NMA', 'Pushalot', 'Pushbullet', 'Subtitles'): CheckSection(CFG, stanza) @@ -1033,6 +1043,15 @@ def initialize(console_logging=True): PUSHBULLET_ACCESS_TOKEN = check_setting_str(CFG, 'Pushbullet', 'pushbullet_access_token', '') PUSHBULLET_DEVICE_IDEN = check_setting_str(CFG, 'Pushbullet', 'pushbullet_device_iden', '') + 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_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', '') + 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))) @@ -1821,6 +1840,16 @@ def save_config(): new_config['Pushbullet']['pushbullet_access_token'] = PUSHBULLET_ACCESS_TOKEN new_config['Pushbullet']['pushbullet_device_iden'] = PUSHBULLET_DEVICE_IDEN + new_config['Slack'] = {} + 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_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['Email'] = {} new_config['Email']['use_email'] = int(USE_EMAIL) new_config['Email']['email_old_subjects'] = int(EMAIL_OLD_SUBJECTS) diff --git a/sickbeard/notifiers/__init__.py b/sickbeard/notifiers/__init__.py index 7faf5685..48ac704f 100644 --- a/sickbeard/notifiers/__init__.py +++ b/sickbeard/notifiers/__init__.py @@ -36,6 +36,7 @@ import nma import pushalot import pushbullet +import slack import tweet from lib import libtrakt import emailnotify @@ -60,6 +61,7 @@ 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() email_notifier = emailnotify.EmailNotifier() @@ -81,6 +83,7 @@ notifiers = [ nma_notifier, pushalot_notifier, pushbullet_notifier, + slack_notifier, twitter_notifier, trakt_notifier, email_notifier, diff --git a/sickbeard/notifiers/slack.py b/sickbeard/notifiers/slack.py new file mode 100644 index 00000000..6f7c3714 --- /dev/null +++ b/sickbeard/notifiers/slack.py @@ -0,0 +1,90 @@ +# coding=utf-8 +# +# This file is part of SickGear. +# +# Thanks to: mallen86 +# +# SickGear is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# SickGear is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# 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 logger, common + +class SlackNotifier: + + def _send_to_slack(self, message, accessToken, channel, as_user, bot_name, icon_url): + SLACK_ENDPOINT = "https://slack.com/api/chat.postMessage" + + data = {} + data["token"] = accessToken + data["channel"] = channel + data["username"] = bot_name + data["text"] = message + data["icon_url"] = icon_url + data["as_user"] = as_user + + urlResp = sickbeard.helpers.getURL(url=SLACK_ENDPOINT, post_data=data) + if urlResp: + resp = json.loads(urlResp) + else: + return False + + # 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 notify_snatch(self, ep_name): + if sickbeard.SLACK_NOTIFY_ONSNATCH: + self._notify(common.notifyStrings[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) + + 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 update_library(self, ep_obj): + pass + +notifier = SlackNotifier diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index 31486cf1..bfe6f07d 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -1150,6 +1150,15 @@ 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): + 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" + def viewchanges(self): t = PageTemplate(headers=self.request.headers, file='viewchanges.tmpl') @@ -5750,7 +5759,8 @@ class ConfigNotifications(Config): use_email=None, email_notify_onsnatch=None, email_notify_ondownload=None, email_notify_onsubtitledownload=None, email_host=None, email_port=25, email_from=None, email_tls=None, email_user=None, email_password=None, email_list=None, email_show_list=None, - email_show=None, **kwargs): + email_show=None, use_slack=None, slack_notify_onsnatch=None, slack_notify_ondownload=None, + slack_access_token=None, slack_channel=None, slack_as_user=None, slack_bot_name=None, slack_icon_url=None, **kwargs): results = [] @@ -5889,6 +5899,15 @@ class ConfigNotifications(Config): # sickbeard.TRAKT_REMOVE_SERIESLIST = config.checkbox_to_value(trakt_remove_serieslist) # sickbeard.TRAKT_START_PAUSED = config.checkbox_to_value(trakt_start_paused) + sickbeard.USE_SLACK = config.checkbox_to_value(use_slack) + sickbeard.SLACK_NOTIFY_ONSNATCH = config.checkbox_to_value(slack_notify_onsnatch) + sickbeard.SLACK_NOTIFY_ONDOWNLOAD = config.checkbox_to_value(slack_notify_ondownload) + sickbeard.SLACK_ACCESS_TOKEN = slack_access_token + sickbeard.SLACK_CHANNEL = slack_channel + sickbeard.SLACK_AS_USER = config.checkbox_to_value(slack_as_user) + sickbeard.SLACK_BOT_NAME = slack_bot_name + sickbeard.SLACK_ICON_URL = slack_icon_url + sickbeard.USE_EMAIL = config.checkbox_to_value(use_email) sickbeard.EMAIL_NOTIFY_ONSNATCH = config.checkbox_to_value(email_notify_onsnatch) sickbeard.EMAIL_NOTIFY_ONDOWNLOAD = config.checkbox_to_value(email_notify_ondownload) @@ -6323,4 +6342,3 @@ class CachedImages(MainHandler): self.set_header('Content-Type', mime_type) with open(static_image_path, 'rb') as img: return img.read() - From 87ac49322a983ba661cfd14e7cdbc033070a2ecc Mon Sep 17 00:00:00 2001 From: JackDandy Date: Sat, 16 Sep 2017 00:27:23 +0100 Subject: [PATCH 2/2] Change improve Slack notifier. --- CHANGES.md | 1 + gui/slick/images/notifiers/slack.png | Bin 15154 -> 1152 bytes .../default/config_notifications.tmpl | 134 ++++++++++-------- gui/slick/js/configNotifications.js | 39 ++--- sickbeard/__init__.py | 12 +- sickbeard/notifiers/__init__.py | 4 +- sickbeard/notifiers/slack.py | 88 +++++------- sickbeard/webserve.py | 10 +- 8 files changed, 144 insertions(+), 144 deletions(-) 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 5efaafc0f934461b0a365daebcce80c06aaa56ab..f348c2d3971fbf464d4e5cbd8d4ae3d5925e1ea4 100644 GIT binary patch delta 1132 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 W*Iv)+CdHn`u*&ip%j*l5ul^q`(ALKQ 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 @@
-
+
- -

Slack

-

Team communication for the 21st century.

+ +

Slack

+

Team, group, and direct communication.

- -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
@@ -1762,16 +1714,78 @@
+
+ +
+ +
+ +
+
+ +
+
+
+ +
+
+ +
+
+
+ +
Click below to test.
-
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):