diff options
Diffstat (limited to 'libs/apprise/plugins/NotifyTelegram.py')
-rw-r--r-- | libs/apprise/plugins/NotifyTelegram.py | 120 |
1 files changed, 96 insertions, 24 deletions
diff --git a/libs/apprise/plugins/NotifyTelegram.py b/libs/apprise/plugins/NotifyTelegram.py index 4bfd2d368..3d9d718ec 100644 --- a/libs/apprise/plugins/NotifyTelegram.py +++ b/libs/apprise/plugins/NotifyTelegram.py @@ -205,13 +205,23 @@ class NotifyTelegram(NotifyBase): 'default': True, 'map_to': 'detect_owner', }, + 'silent': { + 'name': _('Silent Notification'), + 'type': 'bool', + 'default': False, + }, + 'preview': { + 'name': _('Web Page Preview'), + 'type': 'bool', + 'default': False, + }, 'to': { 'alias_of': 'targets', }, }) def __init__(self, bot_token, targets, detect_owner=True, - include_image=False, **kwargs): + include_image=False, silent=None, preview=None, **kwargs): """ Initialize Telegram Object """ @@ -229,6 +239,14 @@ class NotifyTelegram(NotifyBase): # Parse our list self.targets = parse_list(targets) + # Define whether or not we should make audible alarms + self.silent = self.template_args['silent']['default'] \ + if silent is None else bool(silent) + + # Define whether or not we should display a web page preview + self.preview = self.template_args['preview']['default'] \ + if preview is None else bool(preview) + # if detect_owner is set to True, we will attempt to determine who # the bot owner is based on the first person who messaged it. This # is not a fool proof way of doing things as over time Telegram removes @@ -513,7 +531,12 @@ class NotifyTelegram(NotifyBase): 'sendMessage' ) - payload = {} + payload = { + # Notification Audible Control + 'disable_notification': self.silent, + # Display Web Page Preview (if possible) + 'disable_web_page_preview': not self.preview, + } # Prepare Email Message if self.notify_format == NotifyFormat.MARKDOWN: @@ -524,35 +547,73 @@ class NotifyTelegram(NotifyBase): body, ) - elif self.notify_format == NotifyFormat.HTML: - payload['parse_mode'] = 'HTML' - - # HTML Spaces ( ) and tabs ( ) aren't supported - # See https://core.telegram.org/bots/api#html-style - body = re.sub(' ?', ' ', body, re.I) + else: # HTML or TEXT - # Tabs become 3 spaces - body = re.sub(' ?', ' ', body, re.I) + # Use Telegram's HTML mode + payload['parse_mode'] = 'HTML' - if title: + # Telegram's HTML support doesn't like having HTML escaped + # characters passed into it. to handle this situation, we need to + # search the body for these sequences and convert them to the + # output the user expected + telegram_escape_html_dict = { # HTML Spaces ( ) and tabs ( ) aren't supported # See https://core.telegram.org/bots/api#html-style - title = re.sub(' ?', ' ', title, re.I) + r'nbsp': ' ', # Tabs become 3 spaces - title = re.sub(' ?', ' ', title, re.I) - - payload['text'] = '{}{}'.format( - '<b>{}</b>\r\n'.format(title) if title else '', - body, - ) + r'emsp': ' ', + + # Some characters get re-escaped by the Telegram upstream + # service so we need to convert these back, + r'apos': '\'', + r'quot': '"', + } + + # Create a regular expression from the dictionary keys + html_regex = re.compile("&(%s);?" % "|".join( + map(re.escape, telegram_escape_html_dict.keys())).lower(), + re.I) + + # For each match, look-up corresponding value in dictionary + # we look +1 to ignore the & that does not appear in the index + # we only look at the first 4 characters because we don't want to + # fail on ' as it's accepted (along with &apos - no + # semi-colon) + body = html_regex.sub( # pragma: no branch + lambda mo: telegram_escape_html_dict[ + mo.string[mo.start():mo.end()][1:5]], body) - else: # TEXT - payload['parse_mode'] = 'HTML' - - # Escape content - title = NotifyTelegram.escape_html(title, whitespace=False) - body = NotifyTelegram.escape_html(body, whitespace=False) + if title: + # For each match, look-up corresponding value in dictionary + # Indexing is explained above (for how the body is parsed) + title = html_regex.sub( # pragma: no branch + lambda mo: telegram_escape_html_dict[ + mo.string[mo.start():mo.end()][1:5]], title) + + if self.notify_format == NotifyFormat.TEXT: + telegram_escape_text_dict = { + # We need to escape characters that conflict with html + # entity blocks (< and >) when displaying text + r'>': '>', + r'<': '<', + } + + # Create a regular expression from the dictionary keys + text_regex = re.compile("(%s)" % "|".join( + map(re.escape, telegram_escape_text_dict.keys())).lower(), + re.I) + + # For each match, look-up corresponding value in dictionary + body = text_regex.sub( # pragma: no branch + lambda mo: telegram_escape_text_dict[ + mo.string[mo.start():mo.end()]], body) + + if title: + # For each match, look-up corresponding value in dictionary + title = text_regex.sub( # pragma: no branch + lambda mo: telegram_escape_text_dict[ + mo.string[mo.start():mo.end()]], title) payload['text'] = '{}{}'.format( '<b>{}</b>\r\n'.format(title) if title else '', @@ -679,6 +740,8 @@ class NotifyTelegram(NotifyBase): params = { 'image': self.include_image, 'detect': 'yes' if self.detect_owner else 'no', + 'silent': 'yes' if self.silent else 'no', + 'preview': 'yes' if self.preview else 'no', } # Extend our parameters @@ -762,6 +825,15 @@ class NotifyTelegram(NotifyBase): # Store our bot token results['bot_token'] = bot_token + # Silent (Sends the message Silently); users will receive + # notification with no sound. + results['silent'] = \ + parse_bool(results['qsd'].get('silent', False)) + + # Show Web Page Preview + results['preview'] = \ + parse_bool(results['qsd'].get('preview', False)) + # Include images with our message results['include_image'] = \ parse_bool(results['qsd'].get('image', False)) |