From 8d20a7976d5006dcb6fd914c7ec10528c545d5a3 Mon Sep 17 00:00:00 2001 From: JackDandy Date: Thu, 30 Jan 2020 00:43:31 +0000 Subject: [PATCH] Add Telegram notifier. --- CHANGES.md | 1 + gui/slick/images/notifiers/telegram.png | Bin 0 -> 588 bytes .../interfaces/default/config_notifications.tmpl | 85 ++++++++++++++++++++- gui/slick/js/configNotifications.js | 43 +++++++++++ lib/apprise/URLBase.py | 6 +- lib/apprise/plugins/NotifyTelegram.py | 15 ++-- sickbeard/__init__.py | 26 +++++++ sickbeard/notifiers/__init__.py | 3 +- sickbeard/notifiers/telegram.py | 61 +++++++++++++++ sickbeard/webserve.py | 18 +++++ 10 files changed, 246 insertions(+), 12 deletions(-) create mode 100644 gui/slick/images/notifiers/telegram.png create mode 100644 sickbeard/notifiers/telegram.py diff --git a/CHANGES.md b/CHANGES.md index 6b495b3..1adbceb 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -16,6 +16,7 @@ * Update Six compatibility library 1.13.0 (ec58185) to 1.14.0 (3a3db75) * Update Tornado_py3 Web Server 6.0.3 (ff985fe) to 6.0.xx (18b653c) * Update urllib3 release 1.25.6 (4a6c288) to 1.25.7 (37ba61a) +* Add Telegram notifier [develop changelog] diff --git a/gui/slick/images/notifiers/telegram.png b/gui/slick/images/notifiers/telegram.png new file mode 100644 index 0000000000000000000000000000000000000000..41a2cb1761697bf07a6a7ee97c31b2503bf53546 GIT binary patch literal 588 zcmV-S0<-;zP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0pUqRK~zXfwU$py z0znwY_tux_9;Dx)Lx+wXI&|&Up+l$WR<}Muc#6bbupshKAPC{1K!_p$~8GP_g zxk!%1E}vPY)?lgPJJn{m1fk;+yC_td96b~88e9>Ai-o-#c9=F`3O{*xJFJV~$uqDv};#f|b}UJITF@QOfaD{Srnn z@788^t~)$zTnW%n9+@3j9?WPXanG8q@Akh|AhGNr({qV1i$vx{B*QcQ+f6>SEjt4R z@9uB&YYhNQm!f%5&|a~B{z&!(eG_1>V~3O~pKUvLpe9sb&^G}Slack + @@ -1814,7 +1815,7 @@
-

Gitter

+

Gitter

Gitter chat and networking platform.

@@ -1883,6 +1884,88 @@
+ +

Telegram

+

Mobile and desktop messaging with a focus on security and speed.

+
+
+
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
Click below to test
+ + +
+
+
+ + +
+

Email

Email notification settings.

diff --git a/gui/slick/js/configNotifications.js b/gui/slick/js/configNotifications.js index 24a50d7..7fa8067 100644 --- a/gui/slick/js/configNotifications.js +++ b/gui/slick/js/configNotifications.js @@ -2,6 +2,7 @@ /** @namespace JSONData.account_name */ /** @namespace JSONData.error_message */ /** @namespace JSONData.num_accounts */ +/** @namespace JSONData.chatid */ $(document).ready(function(){ var loading = ''; @@ -509,6 +510,48 @@ $(document).ready(function(){ } }); + $('#test-telegram').click(function () { + var telegramSendIcon = $('#telegram-send-icon').prop('checked'), + accessToken = '#telegram-access-token', telegramAccessToken = $(accessToken).val().replace(/\s/g, ''), + chatid = '#telegram-chatid', telegramChatid = $(chatid).val().replace(/\s/g, ''); + + $(accessToken + ', ' + chatid).removeClass('warning'); + if (!telegramAccessToken) { + $('#test-telegram-result').html('Please fill out the necessary fields above.'); + $(accessToken).addClass('warning'); + } else { + $(this).prop('disabled', !0); + $('#test-telegram-result').html(loading); + $.getJSON(sbRoot + '/home/test-telegram', + {send_icon: telegramSendIcon, access_token: telegramAccessToken, chatid: telegramChatid}) + .done(function (JSONdata) { + $('#test-telegram-result').html(JSONdata.result); + if ('' === telegramChatid) { + if ('' === JSONdata.chatid) { + $(chatid).addClass('warning'); + } else { + $(chatid).val(JSONdata.chatid); + } + } + $('#test-telegram').prop('disabled', !1); + }); + } + }); + + $('.config_submitter').click(function (e) { + if ($('#use-telegram').prop('checked')){ + var chatid$ = $('#telegram-chatid'); + if ('' === chatid$.val().replace(/\s/g, '')){ + chatid$.addClass('warning'); + alert('Cannot save, Telegram is enabled and the chat id field needs attention'); + e.preventDefault(); + return !1; + } else { + chatid$.removeClass('warning'); + } + } + }); + function getPushbulletDevices (msg) { var pushbulletAccessToken = $.trim($('#pushbullet-access-token').val()); if (!pushbulletAccessToken) { diff --git a/lib/apprise/URLBase.py b/lib/apprise/URLBase.py index 4d62b82..9d245cb 100644 --- a/lib/apprise/URLBase.py +++ b/lib/apprise/URLBase.py @@ -47,6 +47,8 @@ from .utils import parse_url from .utils import parse_bool from .utils import parse_list +from six import iteritems + # Used to break a path list into parts PATHSPLIT_LIST_DELIM = re.compile(r'[ \t\r\n,\\/]+') @@ -378,7 +380,7 @@ class URLBase(object): pass in an empty variable, set it to an empty string. Args: - query (str): The dictionary to encode + query (dict): The dictionary to encode doseq (:obj:`bool`, optional): Handle sequences safe (:obj:`str`): non-ascii characters and URI specific ones that you do not wish to escape (if detected). Setting this string @@ -391,7 +393,7 @@ class URLBase(object): str: The escaped parameters returned as a string """ # Tidy query by eliminating any records set to None - _query = {k: v for (k, v) in query.items() if v is not None} + _query = {k: v for (k, v) in iteritems(query) if v is not None} try: # Python v3.x return _urlencode( diff --git a/lib/apprise/plugins/NotifyTelegram.py b/lib/apprise/plugins/NotifyTelegram.py index 73bdf65..8166a91 100644 --- a/lib/apprise/plugins/NotifyTelegram.py +++ b/lib/apprise/plugins/NotifyTelegram.py @@ -87,6 +87,8 @@ class NotifyTelegram(NotifyBase): # The services URL service_url = 'https://telegram.org/' + icon_path = None + # The default secure protocol secure_protocol = 'tgram' @@ -182,7 +184,6 @@ class NotifyTelegram(NotifyBase): 'name': _('Target Chat ID'), 'type': 'string', 'map_to': 'targets', - 'map_to': 'targets', 'regex': (r'^((-?[0-9]{1,32})|([a-z_-][a-z0-9_-]+))$', 'i'), }, 'targets': { @@ -264,7 +265,6 @@ class NotifyTelegram(NotifyBase): # Our function name and payload are determined on the path function_name = 'SendPhoto' key = 'photo' - path = None if isinstance(attach, AttachBase): if not attach: @@ -295,7 +295,8 @@ class NotifyTelegram(NotifyBase): return True # Take on specified attachent as path - path = attach + # hack in self.icon_path to use alt icon as nothing on homepage docs shows how) + path = self.icon_path or attach file_name = os.path.basename(path) url = '%s%s/%s' % ( @@ -385,9 +386,6 @@ class NotifyTelegram(NotifyBase): 'Telegram User Detection POST URL: %s (cert_verify=%r)' % ( url, self.verify_certificate)) - # Track our response object - response = None - try: r = requests.post( url, @@ -427,6 +425,7 @@ class NotifyTelegram(NotifyBase): return 0 + # Track our response object # Load our response and attempt to fetch our userid response = loads(r.content) @@ -577,7 +576,7 @@ class NotifyTelegram(NotifyBase): # Define our path if not self.send_media(payload['chat_id'], notify_type): # We failed to send the image associated with our - notify_type + # notify_type self.logger.warning( 'Failed to send Telegram type image to {}.', payload['chat_id']) @@ -683,7 +682,7 @@ class NotifyTelegram(NotifyBase): args=NotifyTelegram.urlencode(args)) @staticmethod - def parse_url(url): + def parse_url(url, **kwargs): """ Parses the URL and returns enough arguments that can allow us to substantiate this object. diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py index 8879d30..56680b0 100755 --- a/sickbeard/__init__.py +++ b/sickbeard/__init__.py @@ -453,6 +453,14 @@ GITTER_NOTIFY_ONSUBTITLEDOWNLOAD = False GITTER_ROOM = None GITTER_ACCESS_TOKEN = None +USE_TELEGRAM = False +TELEGRAM_NOTIFY_ONSNATCH = False +TELEGRAM_NOTIFY_ONDOWNLOAD = False +TELEGRAM_NOTIFY_ONSUBTITLEDOWNLOAD = False +TELEGRAM_SEND_ICON = True +TELEGRAM_ACCESS_TOKEN = None +TELEGRAM_CHATID = None + USE_EMAIL = False EMAIL_OLD_SUBJECTS = False EMAIL_NOTIFY_ONSNATCH = False @@ -701,6 +709,8 @@ def init_stage_1(console_logging): DISCORDAPP_AS_AUTHED, DISCORDAPP_USERNAME, DISCORDAPP_ICON_URL, DISCORDAPP_AS_TTS, DISCORDAPP_ACCESS_TOKEN,\ USE_GITTER, GITTER_NOTIFY_ONSNATCH, GITTER_NOTIFY_ONDOWNLOAD, GITTER_NOTIFY_ONSUBTITLEDOWNLOAD,\ GITTER_ROOM, GITTER_ACCESS_TOKEN, \ + USE_TELEGRAM, TELEGRAM_NOTIFY_ONSNATCH, TELEGRAM_NOTIFY_ONDOWNLOAD, TELEGRAM_NOTIFY_ONSUBTITLEDOWNLOAD, \ + TELEGRAM_SEND_ICON, TELEGRAM_ACCESS_TOKEN, TELEGRAM_CHATID, \ 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 @@ -1154,6 +1164,15 @@ def init_stage_1(console_logging): GITTER_ROOM = check_setting_str(CFG, 'Gitter', 'gitter_room', '') GITTER_ACCESS_TOKEN = check_setting_str(CFG, 'Gitter', 'gitter_access_token', '') + USE_TELEGRAM = bool(check_setting_int(CFG, 'Telegram', 'use_telegram', 0)) + TELEGRAM_NOTIFY_ONSNATCH = bool(check_setting_int(CFG, 'Telegram', 'telegram_notify_onsnatch', 0)) + TELEGRAM_NOTIFY_ONDOWNLOAD = bool(check_setting_int(CFG, 'Telegram', 'telegram_notify_ondownload', 0)) + TELEGRAM_NOTIFY_ONSUBTITLEDOWNLOAD = bool(check_setting_int( + CFG, 'Telegram', 'telegram_notify_onsubtitledownload', 0)) + TELEGRAM_SEND_ICON = bool(check_setting_int(CFG, 'Telegram', 'telegram_send_icon', 1)) + TELEGRAM_ACCESS_TOKEN = check_setting_str(CFG, 'Telegram', 'telegram_access_token', '') + TELEGRAM_CHATID = check_setting_str(CFG, 'Telegram', 'telegram_chatid', '') + 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))) @@ -2022,6 +2041,12 @@ def save_config(): ('room', GITTER_ROOM), ('access_token', GITTER_ACCESS_TOKEN), ]), + ('Telegram', [ + ('use_%s', int(USE_TELEGRAM)), + ('send_icon', int(TELEGRAM_SEND_ICON)), + ('access_token', TELEGRAM_ACCESS_TOKEN), + ('chatid', TELEGRAM_CHATID), + ]), ('Email', [ ('use_%s', int(USE_EMAIL)), ('old_subjects', int(EMAIL_OLD_SUBJECTS)), @@ -2063,6 +2088,7 @@ def save_config(): ('Slack', SLACK_NOTIFY_ONSNATCH, SLACK_NOTIFY_ONDOWNLOAD, SLACK_NOTIFY_ONSUBTITLEDOWNLOAD), ('Discordapp', DISCORDAPP_NOTIFY_ONSNATCH, DISCORDAPP_NOTIFY_ONDOWNLOAD, DISCORDAPP_NOTIFY_ONSUBTITLEDOWNLOAD), ('Gitter', GITTER_NOTIFY_ONSNATCH, GITTER_NOTIFY_ONDOWNLOAD, GITTER_NOTIFY_ONSUBTITLEDOWNLOAD), + ('Telegram', TELEGRAM_NOTIFY_ONSNATCH, TELEGRAM_NOTIFY_ONDOWNLOAD, TELEGRAM_NOTIFY_ONSUBTITLEDOWNLOAD), ('Email', EMAIL_NOTIFY_ONSNATCH, EMAIL_NOTIFY_ONDOWNLOAD, EMAIL_NOTIFY_ONSUBTITLEDOWNLOAD), ]: if any([onsnatch, ondownload, onsubtitledownload]): diff --git a/sickbeard/notifiers/__init__.py b/sickbeard/notifiers/__init__.py index 650db29..918ffed 100644 --- a/sickbeard/notifiers/__init__.py +++ b/sickbeard/notifiers/__init__.py @@ -23,7 +23,7 @@ import re # from lib import libtrakt from . import emby, kodi, plex, xbmc, \ boxcar2, nmj, nmjv2, pushbullet, pushover, pytivo, synoindex, synologynotifier, \ - discordapp, emailnotify, gitter, libnotify, growl, prowl, slack, trakt + discordapp, emailnotify, gitter, libnotify, growl, prowl, slack, telegram, trakt import sickbeard # noinspection PyPep8Naming @@ -61,6 +61,7 @@ class NotifierFactory(object): SLACK=slack.SlackNotifier, DISCORDAPP=discordapp.DiscordappNotifier, GITTER=gitter.GitterNotifier, + TELEGRAM=telegram.TelegramNotifier, EMAIL=emailnotify.EmailNotifier, ) diff --git a/sickbeard/notifiers/telegram.py b/sickbeard/notifiers/telegram.py new file mode 100644 index 0000000..afa65b1 --- /dev/null +++ b/sickbeard/notifiers/telegram.py @@ -0,0 +1,61 @@ +# coding=utf-8 +# +# This file is part of SickGear. +# +# 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 os +from .generic import Notifier +import sickbeard + +# noinspection PyPep8Naming +import encodingKludge as ek +from exceptions_helper import ex +from lib.apprise.plugins.NotifyTelegram import NotifyTelegram + + +class TelegramNotifier(Notifier): + + def __init__(self): + super(TelegramNotifier, self).__init__() + + def _notify(self, title, body, send_icon='', access_token='', chatid='', **kwargs): + result = None + cid = '' + use_icon = bool(self._choose(send_icon, sickbeard.TELEGRAM_SEND_ICON)) + try: + tg = NotifyTelegram( + bot_token=self._choose(access_token, sickbeard.TELEGRAM_ACCESS_TOKEN), + targets=self._choose(chatid, sickbeard.TELEGRAM_CHATID), + include_image=use_icon + ) + cid = chatid or isinstance(tg.targets, list) and 1 == len(tg.targets) and tg.targets[0] or '' + if use_icon: + tg.icon_path = ek.ek(os.path.join, sickbeard.PROG_DIR, 'gui', 'slick', + 'images', 'ico', 'apple-touch-icon-76x76.png') + tg.image_size = '72x72' + result = tg.send(body, title=title) + except (BaseException, Exception) as e: + if 'No chat_id' in ex(e): + result = 'a chat id is not set, and a msg has not been sent to the bot to auto detect one.' + + if True is not result: + self._log_error('Failed to send message, %s' % result) + + return dict(chatid=cid, + result=self._choose(('Successful test notice sent.', + 'Error sending notification, %s' % result)[True is not result], result)) + + +notifier = TelegramNotifier diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index a2b4e72..b31c35e 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -1772,6 +1772,13 @@ class Home(MainHandler): return notifiers.NotifierFactory().get('GITTER').test_notify( room_name=room_name, access_token=access_token) + def test_telegram(self, send_icon=False, access_token=None, chatid=None): + self.set_header('Cache-Control', 'max-age=0,no-cache,no-store') + + r = notifiers.NotifierFactory().get('TELEGRAM').test_notify( + send_icon=bool(config.checkbox_to_value(send_icon)), access_token=access_token, chatid=chatid) + return json.dumps(r) + def test_email(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') @@ -7255,6 +7262,9 @@ class ConfigNotifications(Config): discordapp_as_tts=None, use_gitter=None, gitter_notify_onsnatch=None, gitter_notify_ondownload=None, gitter_notify_onsubtitledownload=None, gitter_access_token=None, gitter_room=None, + use_telegram=None, telegram_notify_onsnatch=None, telegram_notify_ondownload=None, + telegram_notify_onsubtitledownload=None, telegram_access_token=None, telegram_chatid=None, + telegram_send_icon=None, 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, @@ -7410,6 +7420,14 @@ class ConfigNotifications(Config): sickbeard.GITTER_ACCESS_TOKEN = gitter_access_token sickbeard.GITTER_ROOM = gitter_room + sickbeard.USE_TELEGRAM = config.checkbox_to_value(use_telegram) + sickbeard.TELEGRAM_NOTIFY_ONSNATCH = config.checkbox_to_value(telegram_notify_onsnatch) + sickbeard.TELEGRAM_NOTIFY_ONDOWNLOAD = config.checkbox_to_value(telegram_notify_ondownload) + sickbeard.TELEGRAM_NOTIFY_ONSUBTITLEDOWNLOAD = config.checkbox_to_value(telegram_notify_onsubtitledownload) + sickbeard.TELEGRAM_ACCESS_TOKEN = telegram_access_token + sickbeard.TELEGRAM_CHATID = telegram_chatid + sickbeard.TELEGRAM_SEND_ICON = config.checkbox_to_value(telegram_send_icon) + 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)