arigram/arigram/tdlib.py
Ari Archer 9bfc08f357
[CORE] improved code, formatting and fixed some bugs
- Added a better `.gitignore`
- Formatted the `do` script better, made it better in general
- Improved instalation and upgrading instructons
- Removed arrow key support
- Imrproved `README.md` formatting
- Improved the runtime (`__main__.py`) script, improved formatting,
  handling of arguments and added docstrings
- Renamed `colors` to `colours`
- Added type hints to the config file and improved how it handles some
  things
- Improved chat action strings (e.g `uploading video` -> `is uploading a video`)
- Made `COPY_CMD` deprecated, using `pyperclip` instead
- Changed dependency for stability from dynamic to exact
  (`python-telegram>=....` to `python-telegram==....`)

Signed-off-by: Ari Archer <truncateddinosour@gmail.com>
2022-01-01 03:21:24 +02:00

561 lines
15 KiB
Python

from enum import Enum
from typing import Any, Dict, List, Optional, Union
from telegram.client import AsyncResult, Telegram
class ChatAction(Enum):
chatActionTyping = "is typing"
chatActionCancel = "cancel"
chatActionRecordingVideo = "is recording a video"
chatActionUploadingVideo = "is uploading a video"
chatActionRecordingVoiceNote = "is recording a voice message"
chatActionUploadingVoiceNote = "is uploading a voice message"
chatActionUploadingPhoto = "is uploading a photo"
chatActionUploadingDocument = "is uploading a document"
chatActionChoosingLocation = "is choosing a location"
chatActionChoosingContact = "is choosing a contact"
chatActionStartPlayingGame = "started playing a game"
chatActionRecordingVideoNote = "is recording a video"
chatActionUploadingVideoNote = "is uploading a video"
chatActionChoosingSticker = "is choosing a sticker"
class ChatType(Enum):
chatTypePrivate = "private"
chatTypeBasicGroup = "group"
chatTypeSupergroup = "supergroup"
channel = "channel"
chatTypeSecret = "secret"
class UserStatus(Enum):
userStatusEmpty = ""
userStatusOnline = "online"
userStatusOffline = "offline"
userStatusRecently = "recently"
userStatusLastWeek = "last week"
userStatusLastMonth = "last month"
class UserType(Enum):
userTypeRegular = ""
userTypeDeleted = "deleted"
userTypeBot = "bot"
userTypeUnknown = "unknownn"
class TextParseModeInput(Enum):
textParseModeMarkdown = "markdown"
textParseModeHTML = "html"
class SecretChatState(Enum):
secretChatStatePending = "pending"
secretChatStateReady = "ready"
secretChatStateClosed = "closed"
class Tdlib(Telegram):
def __init__(self, extra_headers, *args, **kwargs) -> None: # type: ignore
self.extra_headers = extra_headers
super().__init__(*args, **kwargs)
def _parse_data(self, data: Dict[Any, Any]) -> Dict[Any, Any]:
_tmp_data = data.copy()
_tmp_data.update(self.extra_headers)
return _tmp_data
def parse_text_entities(
self,
text: str,
parse_mode: TextParseModeInput = TextParseModeInput.textParseModeMarkdown,
version: int = 2,
) -> AsyncResult:
"""Offline synchronous method which returns parsed entities"""
data = self._parse_data(
{
"@type": "parseTextEntities",
"text": text,
"parse_mode": {"@type": parse_mode.name, "version": version},
}
)
return self._send_data(data)
def send_message(self, chat_id: int, msg: str) -> AsyncResult:
text = {"@type": "formattedText", "text": msg}
result = self.parse_text_entities(msg)
result.wait()
if not result.error:
text = result.update
data = self._parse_data(
{
"@type": "sendMessage",
"chat_id": chat_id,
"input_message_content": {
"@type": "inputMessageText",
"text": text,
},
}
)
return self._send_data(data)
def download_file(
self,
file_id: int,
priority: int = 16,
offset: int = 0,
limit: int = 0,
synchronous: bool = False,
) -> None:
data = self._parse_data(
{
"@type": "downloadFile",
"file_id": file_id,
"priority": priority,
"offset": offset,
"limit": limit,
"synchronous": synchronous,
}
)
return self._send_data(data)
def reply_message(
self, chat_id: int, reply_to_message_id: int, text: str
) -> AsyncResult:
data = self._parse_data(
{
"@type": "sendMessage",
"chat_id": chat_id,
"reply_to_message_id": reply_to_message_id,
"input_message_content": {
"@type": "inputMessageText",
"text": {"@type": "formattedText", "text": text},
},
}
)
return self._send_data(data)
def search_contacts(self, target: str, limit: int = 10) -> AsyncResult:
data = self._parse_data(
{"@type": "searchChats", "query": target, "limit": limit}
)
return self._send_data(data, block=True)
def send_doc(self, file_path: str, chat_id: int) -> AsyncResult:
data = self._parse_data(
{
"@type": "sendMessage",
"chat_id": chat_id,
"input_message_content": {
"@type": "inputMessageDocument",
"document": {"@type": "inputFileLocal", "path": file_path},
},
}
)
return self._send_data(data)
def send_audio(self, file_path: str, chat_id: int) -> AsyncResult:
data = self._parse_data(
{
"@type": "sendMessage",
"chat_id": chat_id,
"input_message_content": {
"@type": "inputMessageAudio",
"audio": {"@type": "inputFileLocal", "path": file_path},
},
}
)
return self._send_data(data)
def send_animation(self, file_path: str, chat_id: int) -> AsyncResult:
data = self._parse_data(
{
"@type": "sendMessage",
"chat_id": chat_id,
"input_message_content": {
"@type": "inputMessageAnimation",
"animation": {
"@type": "inputFileLocal",
"path": file_path,
},
},
}
)
return self._send_data(data)
def send_photo(self, file_path: str, chat_id: int) -> AsyncResult:
data = self._parse_data(
{
"@type": "sendMessage",
"chat_id": chat_id,
"input_message_content": {
"@type": "inputMessagePhoto",
"photo": {"@type": "inputFileLocal", "path": file_path},
},
}
)
return self._send_data(data)
def send_video(
self,
file_path: str,
chat_id: int,
width: int,
height: int,
duration: int,
) -> AsyncResult:
data = self._parse_data(
{
"@type": "sendMessage",
"chat_id": chat_id,
"input_message_content": {
"@type": "inputMessageVideo",
"width": width,
"height": height,
"duration": duration,
"video": {"@type": "inputFileLocal", "path": file_path},
},
}
)
return self._send_data(data)
def send_voice(
self, file_path: str, chat_id: int, duration: int, waveform: str
) -> AsyncResult:
data = self._parse_data(
{
"@type": "sendMessage",
"chat_id": chat_id,
"input_message_content": {
"@type": "inputMessageVoiceNote",
"duration": duration,
"waveform": waveform,
"voice_note": {
"@type": "inputFileLocal",
"path": file_path,
},
},
}
)
return self._send_data(data)
def edit_message_text(
self, chat_id: int, message_id: int, text: str
) -> AsyncResult:
data = self._parse_data(
{
"@type": "editMessageText",
"message_id": message_id,
"chat_id": chat_id,
"input_message_content": {
"@type": "inputMessageText",
"text": {"@type": "formattedText", "text": text},
},
}
)
return self._send_data(data)
def toggle_chat_is_marked_as_unread(
self, chat_id: int, is_marked_as_unread: bool
) -> AsyncResult:
data = self._parse_data(
{
"@type": "toggleChatIsMarkedAsUnread",
"chat_id": chat_id,
"is_marked_as_unread": is_marked_as_unread,
}
)
return self._send_data(data)
def toggle_chat_is_pinned(
self, chat_id: int, is_pinned: bool
) -> AsyncResult:
data = self._parse_data(
{
"@type": "toggleChatIsPinned",
"chat_id": chat_id,
"is_pinned": is_pinned,
}
)
return self._send_data(data)
def set_chat_nottification_settings(
self, chat_id: int, notification_settings: dict
) -> AsyncResult:
data = self._parse_data(
{
"@type": "setChatNotificationSettings",
"chat_id": chat_id,
"notification_settings": notification_settings,
}
)
return self._send_data(data)
def view_messages(
self, chat_id: int, message_ids: list, force_read: bool = True
) -> AsyncResult:
data = self._parse_data(
{
"@type": "viewMessages",
"chat_id": chat_id,
"message_ids": message_ids,
"force_read": force_read,
}
)
return self._send_data(data)
def open_message_content(
self, chat_id: int, message_id: int
) -> AsyncResult:
data = self._parse_data(
{
"@type": "openMessageContent",
"chat_id": chat_id,
"message_id": message_id,
}
)
return self._send_data(data)
def forward_messages(
self,
chat_id: int,
from_chat_id: int,
message_ids: List[int],
as_album: bool = False,
send_copy: bool = False,
remove_caption: bool = False,
options: Dict[str, Any] = {},
) -> AsyncResult:
data = self._parse_data(
{
"@type": "forwardMessages",
"chat_id": chat_id,
"from_chat_id": from_chat_id,
"message_ids": message_ids,
"as_album": as_album,
"send_copy": send_copy,
"remove_caption": remove_caption,
"options": options,
}
)
return self._send_data(data)
def get_basic_group(
self,
basic_group_id: int,
) -> AsyncResult:
data = self._parse_data(
{
"@type": "getBasicGroup",
"basic_group_id": basic_group_id,
}
)
return self._send_data(data)
def get_basic_group_full_info(
self,
basic_group_id: int,
) -> AsyncResult:
data = self._parse_data(
{
"@type": "getBasicGroupFullInfo",
"basic_group_id": basic_group_id,
}
)
return self._send_data(data)
def get_supergroup(
self,
supergroup_id: int,
) -> AsyncResult:
data = self._parse_data(
{
"@type": "getSupergroup",
"supergroup_id": supergroup_id,
}
)
return self._send_data(data)
def get_supergroup_full_info(
self,
supergroup_id: int,
) -> AsyncResult:
data = self._parse_data(
{
"@type": "getSupergroupFullInfo",
"supergroup_id": supergroup_id,
}
)
return self._send_data(data)
def get_secret_chat(
self,
secret_chat_id: int,
) -> AsyncResult:
data = self._parse_data(
{
"@type": "getSecretChat",
"secret_chat_id": secret_chat_id,
}
)
return self._send_data(data)
def send_chat_action(
self, chat_id: int, action: ChatAction, progress: int = None
) -> AsyncResult:
data = self._parse_data(
{
"@type": "sendChatAction",
"chat_id": chat_id,
"action": {"@type": action.name, "progress": progress},
}
)
return self._send_data(data)
def get_contacts(self) -> AsyncResult:
data = self._parse_data(
{
"@type": "getContacts",
}
)
return self._send_data(data)
def leave_chat(self, chat_id: int) -> AsyncResult:
data = self._parse_data(
{
"@type": "leaveChat",
"chat_id": chat_id,
}
)
return self._send_data(data)
def join_chat(self, chat_id: int) -> AsyncResult:
data = self._parse_data(
{
"@type": "joinChat",
"chat_id": chat_id,
}
)
return self._send_data(data)
def close_secret_chat(self, secret_chat_id: int) -> AsyncResult:
data = self._parse_data(
{
"@type": "closeSecretChat",
"secret_chat_id": secret_chat_id,
}
)
return self._send_data(data)
def create_new_secret_chat(self, user_id: int) -> AsyncResult:
data = self._parse_data(
{
"@type": "createNewSecretChat",
"user_id": user_id,
}
)
return self._send_data(data)
def create_new_basic_group_chat(
self, user_ids: List[int], title: str
) -> AsyncResult:
data = self._parse_data(
{
"@type": "createNewBasicGroupChat",
"user_ids": user_ids,
"title": title,
}
)
return self._send_data(data)
def delete_chat_history(
self, chat_id: int, remove_from_chat_list: bool, revoke: bool = False
) -> AsyncResult:
"""
revoke: Pass true to try to delete chat history for all users
"""
data = self._parse_data(
{
"@type": "deleteChatHistory",
"chat_id": chat_id,
"remove_from_chat_list": remove_from_chat_list,
"revoke": revoke,
}
)
return self._send_data(data)
def get_user(self, user_id: int) -> AsyncResult:
data = self._parse_data(
{
"@type": "getUser",
"user_id": user_id,
}
)
return self._send_data(data)
def get_user_full_info(self, user_id: int) -> AsyncResult:
data = self._parse_data(
{
"@type": "getUserFullInfo",
"user_id": user_id,
}
)
return self._send_data(data)
def get_chat_type(chat: Dict[str, Any]) -> Optional[ChatType]:
try:
chat_type = ChatType[chat["type"]["@type"]]
if (
chat_type == ChatType.chatTypeSupergroup
and chat["type"]["is_channel"]
):
chat_type = ChatType.channel
return chat_type
except KeyError:
pass
return None
def is_group(chat_type: Union[str, ChatType]) -> bool:
return chat_type in (
ChatType.chatTypeSupergroup,
ChatType.chatTypeBasicGroup,
)