Merge pull request #165 from paul-nameless/show-chat-info

Show chat info with <c> shortcut in msg panel
This commit is contained in:
Nameless 2020-07-27 20:06:18 +08:00 committed by GitHub
commit 44935ba908
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 167 additions and 23 deletions

View file

@ -20,13 +20,13 @@ Telegram terminal client.
- [X] message history
- [X] list contacts
- [X] show user status
- [X] secret chats
- [X] create new chat
TODO:
- [ ] secret chats
- [ ] search
- [ ] show members in chat
- [ ] create new chat
- [ ] bots (bot keyboard)
@ -247,6 +247,8 @@ For navigation arrow keys also can be used.
- `r`: read current chat
- `c`: show list of contacts
- `dd`: delete chat or remove history
- `ng`: create new group chat
- `ns`: create new secret chat
- `/`: search in chats
- `?`: show help
@ -279,5 +281,7 @@ For navigation arrow keys also can be used.
- `o`: open url present in message (if multiple urls, `urlview` will be opened)
- `]`: next chat
- `[`: prev chat
- `u`: show user info (username, bio, phone, etc.)
- `c`: show chat info (e.g. secret chat encryption key, chat id, state, etc.)
- `?`: show help
- `!`: open msg with custom cmd

View file

@ -13,7 +13,7 @@ from telegram.utils import AsyncResult
from tg import config
from tg.models import Model
from tg.msg import MsgProxy
from tg.tdlib import ChatAction, ChatType, Tdlib, UserType, get_chat_type
from tg.tdlib import ChatAction, ChatType, Tdlib, get_chat_type
from tg.utils import (
get_duration,
get_mime,
@ -76,29 +76,25 @@ class Controller:
self.tg = tg
self.chat_size = 0.5
@bind(msg_handler, ["c"])
def show_chat_info(self) -> None:
"""Show chat information"""
chat = self.model.chats.chats[self.model.current_chat]
info = self.model.get_chat_info(chat)
with suspend(self.view) as s:
s.run_with_input(
config.VIEW_TEXT_CMD,
"\n".join(f"{k}: {v}" for k, v in info.items() if v),
)
@bind(msg_handler, ["u"])
def user_info(self) -> None:
def show_user_info(self) -> None:
"""Show user profile"""
msg = MsgProxy(self.model.current_msg)
user_id = msg.sender_id
users = self.model.users
name = users.get_user_label(user_id)
status = users.get_status(user_id)
user = users.get_user(user_id)
user_info = users.get_user_full_info(user_id)
user_type = None
try:
user_type = UserType[user["type"]["@type"]].value
except KeyError:
pass
info = {
name: status,
"Username": user.get("username", ""),
"UserId": user_id,
"Bio": user_info.get("bio", ""),
"Phone": user.get("phone_number", ""),
"Type": user_type,
}
info = self.model.get_user_info(user_id)
with suspend(self.view) as s:
s.run_with_input(
config.VIEW_TEXT_CMD,

View file

@ -1,3 +1,4 @@
import base64
import logging
import sys
import time
@ -5,7 +6,15 @@ from collections import defaultdict, namedtuple
from typing import Any, Dict, List, Optional, Set, Tuple
from tg.msg import MsgProxy
from tg.tdlib import ChatAction, Tdlib, UserStatus
from tg.tdlib import (
ChatAction,
ChatType,
SecretChatState,
Tdlib,
UserStatus,
UserType,
get_chat_type,
)
from tg.utils import copy_to_clipboard, pretty_ts
log = logging.getLogger(__name__)
@ -217,6 +226,114 @@ class Model:
copy_to_clipboard("\n".join(buffer))
return True
def get_private_chat_info(self, chat: Dict[str, Any]) -> Dict[str, Any]:
user_id = chat["id"]
user = self.users.get_user(user_id)
user_info = self.users.get_user_full_info(user_id)
status = self.users.get_status(user_id)
return {
chat["title"]: status,
"Username": user.get("username", ""),
"Phone": user.get("phone_number", ""),
"Bio": user_info.get("bio", ""),
}
def get_basic_group_info(self, chat: Dict[str, Any]) -> Dict[str, Any]:
group_id = chat["type"]["basic_group_id"]
result = self.tg.get_basic_group_full_info(group_id)
result.wait()
chat_info = result.update
basic_info = self.tg.get_basic_group(group_id)
basic_info.wait()
basic_info = basic_info.update
return {
chat["title"]: f"{basic_info['member_count']} members",
"Info": chat_info["description"],
"Share link": chat_info["invite_link"],
}
def get_supergroup_info(self, chat: Dict[str, Any]) -> Dict[str, Any]:
result = self.tg.get_supergroup_full_info(
chat["type"]["supergroup_id"]
)
result.wait()
chat_info = result.update
return {
chat["title"]: f"{chat_info['member_count']} members",
"Info": chat_info["description"],
"Share link": chat_info["invite_link"],
}
def get_channel_info(self, chat: Dict[str, Any]) -> Dict[str, Any]:
result = self.tg.get_supergroup_full_info(
chat["type"]["supergroup_id"]
)
result.wait()
chat_info = result.update
return {
chat["title"]: "subscribers",
"Info": chat_info["description"],
"Share link": chat_info["invite_link"],
}
def get_secret_chat_info(self, chat: Dict[str, Any]) -> Dict[str, Any]:
result = self.tg.get_secret_chat(chat["type"]["secret_chat_id"])
result.wait()
chat_info = result.update
enc_key = base64.b64decode(chat_info["key_hash"])[:32].hex()
hex_key = " ".join(
[enc_key[i : i + 2] for i in range(0, len(enc_key), 2)]
)
state = "Unknown"
try:
state = SecretChatState[chat_info["state"]["@type"]].value
except KeyError:
pass
user_id = chat_info["user_id"]
user_info = self.get_user_info(user_id)
return {**user_info, "State": state, "Encryption Key": hex_key}
def get_chat_info(self, chat: Dict[str, Any]) -> Dict[str, Any]:
chat_type = get_chat_type(chat)
if chat_type is None:
return {}
handlers = {
ChatType.chatTypePrivate: self.get_private_chat_info,
ChatType.chatTypeBasicGroup: self.get_basic_group_info,
ChatType.chatTypeSupergroup: self.get_supergroup_info,
ChatType.channel: self.get_channel_info,
ChatType.chatTypeSecret: self.get_secret_chat_info,
}
info = handlers.get(chat_type, lambda _: dict())(chat)
info.update({"Type": chat_type.value, "Chat Id": chat["id"]})
return info
def get_user_info(self, user_id: int) -> Dict[str, Any]:
name = self.users.get_user_label(user_id)
status = self.users.get_status(user_id)
user = self.users.get_user(user_id)
user_info = self.users.get_user_full_info(user_id)
user_type = "Unknown"
try:
user_type = UserType[user["type"]["@type"]].value
except KeyError:
pass
info = {
name: status,
"Username": user.get("username", ""),
"Bio": user_info.get("bio", ""),
"Phone": user.get("phone_number", ""),
"User Id": user_id,
"Type": user_type,
}
return info
class ChatModel:
def __init__(self, tg: Tdlib) -> None:

View file

@ -49,6 +49,12 @@ class TextParseModeInput(Enum):
textParseModeHTML = "html"
class SecretChatState(Enum):
secretChatStatePending = "pending"
secretChatStateReady = "ready"
secretChatStateClosed = "closed"
class Tdlib(Telegram):
def parse_text_entities(
self,
@ -295,6 +301,13 @@ class Tdlib(Telegram):
}
return self._send_data(data)
def get_basic_group_full_info(self, basic_group_id: int,) -> AsyncResult:
data = {
"@type": "getBasicGroupFullInfo",
"basic_group_id": basic_group_id,
}
return self._send_data(data)
def get_supergroup(self, supergroup_id: int,) -> AsyncResult:
data = {
"@type": "getSupergroup",
@ -302,6 +315,20 @@ class Tdlib(Telegram):
}
return self._send_data(data)
def get_supergroup_full_info(self, supergroup_id: int,) -> AsyncResult:
data = {
"@type": "getSupergroupFullInfo",
"supergroup_id": supergroup_id,
}
return self._send_data(data)
def get_secret_chat(self, secret_chat_id: int,) -> AsyncResult:
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: