mm-telegram 0.1.1__py3-none-any.whl → 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mm_telegram/__init__.py +4 -1
- mm_telegram/bot.py +81 -0
- mm_telegram/message.py +62 -0
- mm_telegram-0.2.0.dist-info/METADATA +6 -0
- mm_telegram-0.2.0.dist-info/RECORD +7 -0
- mm_telegram/simple_message.py +0 -32
- mm_telegram-0.1.1.dist-info/METADATA +0 -5
- mm_telegram-0.1.1.dist-info/RECORD +0 -6
- {mm_telegram-0.1.1.dist-info → mm_telegram-0.2.0.dist-info}/WHEEL +0 -0
mm_telegram/__init__.py
CHANGED
mm_telegram/bot.py
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
import logging
|
2
|
+
from typing import Any
|
3
|
+
|
4
|
+
from telegram import Update
|
5
|
+
from telegram.ext import (
|
6
|
+
Application,
|
7
|
+
ApplicationBuilder,
|
8
|
+
ApplicationHandlerStop,
|
9
|
+
BaseHandler,
|
10
|
+
CallbackContext,
|
11
|
+
CommandHandler,
|
12
|
+
ContextTypes,
|
13
|
+
ExtBot,
|
14
|
+
MessageHandler,
|
15
|
+
filters,
|
16
|
+
)
|
17
|
+
|
18
|
+
logger = logging.getLogger(__name__)
|
19
|
+
|
20
|
+
|
21
|
+
type TelegramHandler = BaseHandler[Any, CallbackContext[ExtBot[None], dict[Any, Any], dict[Any, Any], dict[Any, Any]], Any]
|
22
|
+
|
23
|
+
|
24
|
+
async def ping(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
25
|
+
if update.effective_chat is not None:
|
26
|
+
await context.bot.send_message(chat_id=update.effective_chat.id, text="pong")
|
27
|
+
|
28
|
+
|
29
|
+
async def unknown(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
30
|
+
if update.effective_chat is not None:
|
31
|
+
await context.bot.send_message(chat_id=update.effective_chat.id, text="Sorry, I didn't understand that command.")
|
32
|
+
|
33
|
+
|
34
|
+
async def is_admin(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
35
|
+
admins: list[int] = context.bot_data.get("admins", [])
|
36
|
+
|
37
|
+
if update.effective_user is None or update.message is None:
|
38
|
+
raise ApplicationHandlerStop
|
39
|
+
|
40
|
+
if update.effective_user.id not in admins:
|
41
|
+
logger.warning("is not admin", extra={"telegram_user_id": update.effective_user.id})
|
42
|
+
await update.message.reply_text("Who are you?")
|
43
|
+
raise ApplicationHandlerStop
|
44
|
+
|
45
|
+
|
46
|
+
class TelegramBot:
|
47
|
+
app: Application[Any, Any, Any, Any, Any, Any] | None
|
48
|
+
|
49
|
+
def __init__(self, handlers: list[TelegramHandler], bot_data: dict[str, object]) -> None:
|
50
|
+
self.handlers = handlers
|
51
|
+
self.bot_data = bot_data
|
52
|
+
self.app = None
|
53
|
+
|
54
|
+
async def start(self, token: str, admins: list[int]) -> None:
|
55
|
+
if not admins:
|
56
|
+
raise ValueError("No admins provided")
|
57
|
+
logger.debug("Starting telegram bot...")
|
58
|
+
app = ApplicationBuilder().token(token).build()
|
59
|
+
for key, value in self.bot_data.items():
|
60
|
+
app.bot_data[key] = value
|
61
|
+
app.bot_data["admins"] = admins
|
62
|
+
|
63
|
+
for handler in self.handlers:
|
64
|
+
app.add_handler(handler)
|
65
|
+
|
66
|
+
app.add_handler(CommandHandler("ping", ping))
|
67
|
+
app.add_handler(MessageHandler(filters.COMMAND, unknown))
|
68
|
+
|
69
|
+
await app.initialize()
|
70
|
+
await app.start()
|
71
|
+
if app.updater is not None:
|
72
|
+
await app.updater.start_polling()
|
73
|
+
logger.debug("Telegram bot started.")
|
74
|
+
|
75
|
+
self.app = app
|
76
|
+
|
77
|
+
async def shutdown(self) -> None:
|
78
|
+
if self.app is not None:
|
79
|
+
await self.app.shutdown()
|
80
|
+
self.app = None
|
81
|
+
logger.debug("Telegram bot stopped.")
|
mm_telegram/message.py
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
import asyncio
|
2
|
+
|
3
|
+
from mm_std import Result, http_request
|
4
|
+
|
5
|
+
|
6
|
+
async def send_message(
|
7
|
+
bot_token: str,
|
8
|
+
chat_id: int,
|
9
|
+
message: str,
|
10
|
+
timeout: float = 5,
|
11
|
+
inter_message_delay_seconds: int = 3,
|
12
|
+
) -> Result[list[int]]:
|
13
|
+
"""
|
14
|
+
Sends a message to a Telegram chat.
|
15
|
+
|
16
|
+
If the message exceeds the Telegram character limit (4096),
|
17
|
+
it will be split into multiple messages and sent sequentially
|
18
|
+
with a delay between each part.
|
19
|
+
|
20
|
+
Args:
|
21
|
+
bot_token: The Telegram bot token.
|
22
|
+
chat_id: The target chat ID.
|
23
|
+
message: The message text to send.
|
24
|
+
timeout: The HTTP request timeout in seconds. Defaults to 5.
|
25
|
+
inter_message_delay_seconds: The delay in seconds between sending
|
26
|
+
parts of a long message. Defaults to 3.
|
27
|
+
|
28
|
+
Returns:
|
29
|
+
A Result object containing a list of message IDs for the sent messages
|
30
|
+
on success, or an error details on failure. The 'extra' field in the
|
31
|
+
Result contains the raw responses from the Telegram API.
|
32
|
+
"""
|
33
|
+
messages = _split_string(message, 4096)
|
34
|
+
responses = []
|
35
|
+
result_message_ids = []
|
36
|
+
while True:
|
37
|
+
text_part = messages.pop(0)
|
38
|
+
params = {"chat_id": chat_id, "text": text_part}
|
39
|
+
res = await http_request(
|
40
|
+
f"https://api.telegram.org/bot{bot_token}/sendMessage", method="post", json=params, timeout=timeout
|
41
|
+
)
|
42
|
+
responses.append(res.to_dict())
|
43
|
+
if res.is_err():
|
44
|
+
return Result.err(res.error or "error sending message", extra={"responses": responses})
|
45
|
+
|
46
|
+
message_id = res.parse_json_body("result.message_id", none_on_error=True)
|
47
|
+
if message_id:
|
48
|
+
result_message_ids.append(message_id)
|
49
|
+
else:
|
50
|
+
# Log the unexpected response for debugging?
|
51
|
+
return Result.err("unknown_response_structure", extra={"responses": responses})
|
52
|
+
|
53
|
+
if len(messages):
|
54
|
+
await asyncio.sleep(inter_message_delay_seconds)
|
55
|
+
else:
|
56
|
+
break
|
57
|
+
return Result.ok(result_message_ids, extra={"responses": responses})
|
58
|
+
|
59
|
+
|
60
|
+
def _split_string(text: str, chars_per_string: int) -> list[str]:
|
61
|
+
"""Splits a string into a list of strings, each with a maximum length."""
|
62
|
+
return [text[i : i + chars_per_string] for i in range(0, len(text), chars_per_string)]
|
@@ -0,0 +1,7 @@
|
|
1
|
+
mm_telegram/__init__.py,sha256=MfDt-Y42ew8LaQW34MElvgrpkPcs_RWCW_coQSyFYOE,142
|
2
|
+
mm_telegram/bot.py,sha256=ZQeKONCiFkmuinCpgvbfYc1clvd2lB26YR9NAuL8eMs,2614
|
3
|
+
mm_telegram/message.py,sha256=nbBWG58PjKU74NYqxwMANBLax0HJqgJ0B6r3FOAeVxg,2285
|
4
|
+
mm_telegram/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
+
mm_telegram-0.2.0.dist-info/METADATA,sha256=o0WxxaffFumRugRsp9zfbrXpNy8-fUn0QipGaCupXjw,150
|
6
|
+
mm_telegram-0.2.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
7
|
+
mm_telegram-0.2.0.dist-info/RECORD,,
|
mm_telegram/simple_message.py
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
import asyncio
|
2
|
-
|
3
|
-
from mm_std import Result, http_request
|
4
|
-
|
5
|
-
|
6
|
-
async def send_message(bot_token: str, chat_id: int, message: str, long_message_delay: int = 3) -> Result[list[int]]:
|
7
|
-
messages = _split_string(message, 4096)
|
8
|
-
responses = []
|
9
|
-
result = []
|
10
|
-
while True:
|
11
|
-
text = messages.pop(0)
|
12
|
-
params = {"chat_id": chat_id, "text": text}
|
13
|
-
res = await http_request(f"https://api.telegram.org/bot{bot_token}/sendMessage", method="post", json=params)
|
14
|
-
responses.append(res.to_dict())
|
15
|
-
if res.is_err():
|
16
|
-
return Result.err(res.error or "error", extra={"responses": [responses]})
|
17
|
-
|
18
|
-
message_id = res.parse_json_body("result.message_id", none_on_error=True)
|
19
|
-
if message_id:
|
20
|
-
result.append(message_id)
|
21
|
-
else:
|
22
|
-
return Result.err("unknown_response", extra={"responses": responses})
|
23
|
-
|
24
|
-
if len(messages):
|
25
|
-
await asyncio.sleep(long_message_delay)
|
26
|
-
else:
|
27
|
-
break
|
28
|
-
return Result.ok(result, extra={"responses": responses})
|
29
|
-
|
30
|
-
|
31
|
-
def _split_string(text: str, chars_per_string: int) -> list[str]:
|
32
|
-
return [text[i : i + chars_per_string] for i in range(0, len(text), chars_per_string)]
|
@@ -1,6 +0,0 @@
|
|
1
|
-
mm_telegram/__init__.py,sha256=Nl5I50id12u28Q0H_uHziyd2t_bjySeZAH1etBOVW3A,57
|
2
|
-
mm_telegram/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
|
-
mm_telegram/simple_message.py,sha256=fT0zhmUPqq_w2EvTdOKLC0JhVMh3nZmthApY8dmY_fk,1193
|
4
|
-
mm_telegram-0.1.1.dist-info/METADATA,sha256=8Iusxz_r-QCJMu7dN8BNW9VN2EFNUZBxO3G0NwNYnEc,108
|
5
|
-
mm_telegram-0.1.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
6
|
-
mm_telegram-0.1.1.dist-info/RECORD,,
|
File without changes
|