Show chat info with <c> shortcut in msg panel

This commit is contained in:
Paul Nameless 2020-07-26 14:07:25 +08:00
parent ef09ba6e7b
commit bf266c7999
4 changed files with 167 additions and 23 deletions

View file

@ -20,13 +20,13 @@ Telegram terminal client.
- [X] message history - [X] message history
- [X] list contacts - [X] list contacts
- [X] show user status - [X] show user status
- [X] secret chats
- [X] create new chat
TODO: TODO:
- [ ] secret chats
- [ ] search - [ ] search
- [ ] show members in chat - [ ] show members in chat
- [ ] create new chat
- [ ] bots (bot keyboard) - [ ] bots (bot keyboard)
@ -245,6 +245,8 @@ For navigation arrow keys also can be used.
- `r`: read current chat - `r`: read current chat
- `c`: show list of contacts - `c`: show list of contacts
- `dd`: delete chat or remove history - `dd`: delete chat or remove history
- `ng`: create new group chat
- `ns`: create new secret chat
- `/`: search in chats - `/`: search in chats
- `?`: show help - `?`: show help
@ -277,5 +279,7 @@ For navigation arrow keys also can be used.
- `o`: open url present in message (if multiple urls, `urlview` will be opened) - `o`: open url present in message (if multiple urls, `urlview` will be opened)
- `]`: next chat - `]`: next chat
- `[`: prev 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 - `?`: show help
- `!`: open msg with custom cmd - `!`: open msg with custom cmd

View file

@ -13,7 +13,7 @@ from telegram.utils import AsyncResult
from tg import config from tg import config
from tg.models import Model from tg.models import Model
from tg.msg import MsgProxy 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 ( from tg.utils import (
get_duration, get_duration,
get_mime, get_mime,
@ -76,29 +76,25 @@ class Controller:
self.tg = tg self.tg = tg
self.chat_size = 0.5 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"]) @bind(msg_handler, ["u"])
def user_info(self) -> None: def show_user_info(self) -> None:
"""Show user profile""" """Show user profile"""
msg = MsgProxy(self.model.current_msg) msg = MsgProxy(self.model.current_msg)
user_id = msg.sender_id user_id = msg.sender_id
users = self.model.users info = self.model.get_user_info(user_id)
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,
}
with suspend(self.view) as s: with suspend(self.view) as s:
s.run_with_input( s.run_with_input(
config.VIEW_TEXT_CMD, config.VIEW_TEXT_CMD,

View file

@ -1,3 +1,4 @@
import base64
import logging import logging
import sys import sys
import time import time
@ -5,7 +6,15 @@ from collections import defaultdict, namedtuple
from typing import Any, Dict, List, Optional, Set, Tuple from typing import Any, Dict, List, Optional, Set, Tuple
from tg.msg import MsgProxy 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 from tg.utils import copy_to_clipboard, pretty_ts
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -217,6 +226,114 @@ class Model:
copy_to_clipboard("\n".join(buffer)) copy_to_clipboard("\n".join(buffer))
return True return True
def get_chat_info(self, chat: Dict[str, Any]) -> Dict[str, Any]:
chat_type = get_chat_type(chat)
if chat_type is None:
return {}
info = {}
if chat_type == ChatType.chatTypePrivate:
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)
info.update(
{
chat["title"]: status,
"Username": user.get("username", ""),
"Phone": user.get("phone_number", ""),
"Bio": user_info.get("bio", ""),
}
)
if chat_type == ChatType.chatTypeBasicGroup:
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
info.update(
{
chat["title"]: f"{basic_info['member_count']} members",
"Info": chat_info["description"],
"Share link": chat_info["invite_link"],
}
)
if chat_type == ChatType.chatTypeSupergroup:
result = self.tg.get_supergroup_full_info(
chat["type"]["supergroup_id"]
)
result.wait()
chat_info = result.update
info.update(
{
chat["title"]: f"{chat_info['member_count']} members",
"Info": chat_info["description"],
"Share link": chat_info["invite_link"],
}
)
if chat_type == ChatType.channel:
chat_info = self.tg.get_supergroup_full_info(
chat["type"]["supergroup_id"]
)
info.update(
{
chat["title"]: "subscribers",
"Info": chat_info["description"],
"Share link": chat_info["invite_link"],
}
)
if chat_type == ChatType.chatTypeSecret:
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)
info.update(
{**user_info, "State": state, "Encryption Key": hex_key}
)
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: class ChatModel:
def __init__(self, tg: Tdlib) -> None: def __init__(self, tg: Tdlib) -> None:

View file

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