98 lines
3.3 KiB
Python
98 lines
3.3 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
from typing import Any
|
|
from urllib import parse, request as urllib_request
|
|
|
|
|
|
class TelegramAPI:
|
|
def __init__(self, token: str, proxy_url: str | None = None) -> None:
|
|
self.base_url = f"https://api.telegram.org/bot{token}"
|
|
handlers = []
|
|
if proxy_url:
|
|
handlers.append(urllib_request.ProxyHandler({"https": proxy_url, "http": proxy_url}))
|
|
self.opener = urllib_request.build_opener(*handlers) if handlers else urllib_request.build_opener()
|
|
|
|
def _post(self, method: str, payload: dict[str, Any]) -> dict[str, Any]:
|
|
data = json.dumps(payload).encode("utf-8")
|
|
req = urllib_request.Request(
|
|
f"{self.base_url}/{method}",
|
|
data=data,
|
|
headers={"Content-Type": "application/json"},
|
|
method="POST",
|
|
)
|
|
with self.opener.open(req, timeout=90) as response:
|
|
return json.loads(response.read().decode("utf-8"))
|
|
|
|
def _get(self, method: str, params: dict[str, Any]) -> dict[str, Any]:
|
|
query = parse.urlencode(params)
|
|
with self.opener.open(f"{self.base_url}/{method}?{query}", timeout=90) as response:
|
|
return json.loads(response.read().decode("utf-8"))
|
|
|
|
def get_updates(self, offset: int | None, timeout: int) -> list[dict[str, Any]]:
|
|
params: dict[str, Any] = {"timeout": timeout}
|
|
if offset is not None:
|
|
params["offset"] = offset
|
|
response = self._get("getUpdates", params)
|
|
return response.get("result", [])
|
|
|
|
def send_message(
|
|
self,
|
|
chat_id: int,
|
|
text: str,
|
|
*,
|
|
parse_mode: str | None = None,
|
|
reply_markup: dict[str, Any] | None = None,
|
|
) -> int:
|
|
payload: dict[str, Any] = {"chat_id": chat_id, "text": text}
|
|
if parse_mode:
|
|
payload["parse_mode"] = parse_mode
|
|
if reply_markup:
|
|
payload["reply_markup"] = reply_markup
|
|
response = self._post("sendMessage", payload)
|
|
result = response.get("result") or {}
|
|
return int(result.get("message_id", 0))
|
|
|
|
def edit_message_text(
|
|
self,
|
|
chat_id: int,
|
|
message_id: int,
|
|
text: str,
|
|
*,
|
|
parse_mode: str | None = None,
|
|
reply_markup: dict[str, Any] | None = None,
|
|
) -> None:
|
|
try:
|
|
payload: dict[str, Any] = {
|
|
"chat_id": chat_id,
|
|
"message_id": message_id,
|
|
"text": text,
|
|
}
|
|
if parse_mode:
|
|
payload["parse_mode"] = parse_mode
|
|
if reply_markup is not None:
|
|
payload["reply_markup"] = reply_markup
|
|
self._post(
|
|
"editMessageText",
|
|
payload,
|
|
)
|
|
except Exception as exc:
|
|
if "message is not modified" in str(exc).lower():
|
|
return
|
|
raise
|
|
|
|
def send_chat_action(self, chat_id: int, action: str = "typing") -> None:
|
|
self._post(
|
|
"sendChatAction",
|
|
{
|
|
"chat_id": chat_id,
|
|
"action": action,
|
|
},
|
|
)
|
|
|
|
def answer_callback_query(self, callback_query_id: str, text: str | None = None) -> None:
|
|
payload: dict[str, Any] = {"callback_query_id": callback_query_id}
|
|
if text:
|
|
payload["text"] = text
|
|
self._post("answerCallbackQuery", payload)
|