summaryrefslogtreecommitdiffhomepage
path: root/libs/apprise/plugins/NotifyTelegram.py
diff options
context:
space:
mode:
Diffstat (limited to 'libs/apprise/plugins/NotifyTelegram.py')
-rw-r--r--libs/apprise/plugins/NotifyTelegram.py110
1 files changed, 92 insertions, 18 deletions
diff --git a/libs/apprise/plugins/NotifyTelegram.py b/libs/apprise/plugins/NotifyTelegram.py
index d5a52be60..1727fe87d 100644
--- a/libs/apprise/plugins/NotifyTelegram.py
+++ b/libs/apprise/plugins/NotifyTelegram.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-# BSD 3-Clause License
+# BSD 2-Clause License
#
# Apprise - Push Notification Library.
# Copyright (c) 2023, Chris Caron <[email protected]>
@@ -14,10 +14,6 @@
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
-# 3. Neither the name of the copyright holder nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -84,6 +80,23 @@ IS_CHAT_ID_RE = re.compile(
)
+class TelegramContentPlacement:
+ """
+ The Telegram Content Placement
+ """
+ # Before Attachments
+ BEFORE = "before"
+ # After Attachments
+ AFTER = "after"
+
+
+# Identify Placement Categories
+TELEGRAM_CONTENT_PLACEMENT = (
+ TelegramContentPlacement.BEFORE,
+ TelegramContentPlacement.AFTER,
+)
+
+
class NotifyTelegram(NotifyBase):
"""
A wrapper for Telegram Notifications
@@ -106,6 +119,9 @@ class NotifyTelegram(NotifyBase):
# Telegram uses the http protocol with JSON requests
notify_url = 'https://api.telegram.org/bot'
+ # Support attachments
+ attachment_support = True
+
# Allows the user to specify the NotifyImageSize object
image_size = NotifyImageSize.XY_256
@@ -319,11 +335,17 @@ class NotifyTelegram(NotifyBase):
'to': {
'alias_of': 'targets',
},
+ 'content': {
+ 'name': _('Content Placement'),
+ 'type': 'choice:string',
+ 'values': TELEGRAM_CONTENT_PLACEMENT,
+ 'default': TelegramContentPlacement.BEFORE,
+ },
})
def __init__(self, bot_token, targets, detect_owner=True,
include_image=False, silent=None, preview=None, topic=None,
- **kwargs):
+ content=None, **kwargs):
"""
Initialize Telegram Object
"""
@@ -349,6 +371,15 @@ class NotifyTelegram(NotifyBase):
self.preview = self.template_args['preview']['default'] \
if preview is None else bool(preview)
+ # Setup our content placement
+ self.content = self.template_args['content']['default'] \
+ if not isinstance(content, str) else content.lower()
+ if self.content and self.content not in TELEGRAM_CONTENT_PLACEMENT:
+ msg = 'The content placement specified ({}) is invalid.'\
+ .format(content)
+ self.logger.warning(msg)
+ raise TypeError(msg)
+
if topic:
try:
self.topic = int(topic)
@@ -439,11 +470,14 @@ class NotifyTelegram(NotifyBase):
# content can arrive together.
self.throttle()
+ payload = {'chat_id': chat_id}
+ if self.topic:
+ payload['message_thread_id'] = self.topic
+
try:
with open(path, 'rb') as f:
# Configure file payload (for upload)
files = {key: (file_name, f)}
- payload = {'chat_id': chat_id}
self.logger.debug(
'Telegram attachment POST URL: %s (cert_verify=%r)' % (
@@ -680,6 +714,10 @@ class NotifyTelegram(NotifyBase):
# Prepare our payload based on HTML or TEXT
payload['text'] = body
+ # Handle payloads without a body specified (but an attachment present)
+ attach_content = \
+ TelegramContentPlacement.AFTER if not body else self.content
+
# Create a copy of the chat_ids list
targets = list(self.targets)
while len(targets):
@@ -713,6 +751,20 @@ class NotifyTelegram(NotifyBase):
'Failed to send Telegram type image to {}.',
payload['chat_id'])
+ if attach and self.attachment_support and \
+ attach_content == TelegramContentPlacement.AFTER:
+ # Send our attachments now (if specified and if it exists)
+ if not self._send_attachments(
+ chat_id=payload['chat_id'], notify_type=notify_type,
+ attach=attach):
+
+ has_error = True
+ continue
+
+ if not body:
+ # Nothing more to do; move along to the next attachment
+ continue
+
# Always call throttle before any remote server i/o is made;
# Telegram throttles to occur before sending the image so that
# content can arrive together.
@@ -775,19 +827,36 @@ class NotifyTelegram(NotifyBase):
self.logger.info('Sent Telegram notification.')
- if attach:
- # Send our attachments now (if specified and if it exists)
- for attachment in attach:
- if not self.send_media(
- payload['chat_id'], notify_type,
- attach=attachment):
+ if attach and self.attachment_support \
+ and attach_content == TelegramContentPlacement.BEFORE:
+ # Send our attachments now (if specified and if it exists) as
+ # it was identified to send the content before the attachments
+ # which is now done.
+ if not self._send_attachments(
+ chat_id=payload['chat_id'],
+ notify_type=notify_type,
+ attach=attach):
- # We failed; don't continue
- has_error = True
- break
+ has_error = True
+ continue
- self.logger.info(
- 'Sent Telegram attachment: {}.'.format(attachment))
+ return not has_error
+
+ def _send_attachments(self, chat_id, notify_type, attach):
+ """
+ Sends our attachments
+ """
+ has_error = False
+ # Send our attachments now (if specified and if it exists)
+ for attachment in attach:
+ if not self.send_media(chat_id, notify_type, attach=attachment):
+
+ # We failed; don't continue
+ has_error = True
+ break
+
+ self.logger.info(
+ 'Sent Telegram attachment: {}.'.format(attachment))
return not has_error
@@ -802,6 +871,7 @@ class NotifyTelegram(NotifyBase):
'detect': 'yes' if self.detect_owner else 'no',
'silent': 'yes' if self.silent else 'no',
'preview': 'yes' if self.preview else 'no',
+ 'content': self.content,
}
if self.topic:
@@ -885,6 +955,10 @@ class NotifyTelegram(NotifyBase):
# Store our chat ids (as these are the remaining entries)
results['targets'] = entries
+ # content to be displayed 'before' or 'after' attachments
+ if 'content' in results['qsd'] and len(results['qsd']['content']):
+ results['content'] = results['qsd']['content']
+
# Support the 'to' variable so that we can support rooms this way too
# The 'to' makes it easier to use yaml configuration
if 'to' in results['qsd'] and len(results['qsd']['to']):