mirror of
https://github.com/paul-nameless/tg
synced 2024-11-22 11:53:08 +00:00
Merge branch 'master' into edit-msg
This commit is contained in:
commit
36d5d8a1e3
5 changed files with 101 additions and 20 deletions
|
@ -61,6 +61,7 @@ class Controller:
|
||||||
"updateMessageContent": self.update_msg_content,
|
"updateMessageContent": self.update_msg_content,
|
||||||
"updateMessageSendSucceeded": self.update_msg_send_succeeded,
|
"updateMessageSendSucceeded": self.update_msg_send_succeeded,
|
||||||
"updateNewMessage": self.update_new_msg,
|
"updateNewMessage": self.update_new_msg,
|
||||||
|
"updateMessageContentOpened": self.update_message_content_opened,
|
||||||
}
|
}
|
||||||
self.chat_size = 0.5
|
self.chat_size = 0.5
|
||||||
signal(SIGWINCH, self.resize_handler)
|
signal(SIGWINCH, self.resize_handler)
|
||||||
|
@ -107,7 +108,6 @@ class Controller:
|
||||||
|
|
||||||
def open_current_msg(self):
|
def open_current_msg(self):
|
||||||
msg = MsgProxy(self.model.current_msg)
|
msg = MsgProxy(self.model.current_msg)
|
||||||
log.info("Open msg: %s", msg.msg)
|
|
||||||
if msg.is_text:
|
if msg.is_text:
|
||||||
with NamedTemporaryFile("w", suffix=".txt") as f:
|
with NamedTemporaryFile("w", suffix=".txt") as f:
|
||||||
f.write(msg.text_content)
|
f.write(msg.text_content)
|
||||||
|
@ -118,8 +118,9 @@ class Controller:
|
||||||
|
|
||||||
path = msg.local_path
|
path = msg.local_path
|
||||||
if path:
|
if path:
|
||||||
|
chat_id = self.model.chats.id_by_index(self.model.current_chat)
|
||||||
|
self.tg.open_message_content(chat_id, msg.msg_id)
|
||||||
with suspend(self.view) as s:
|
with suspend(self.view) as s:
|
||||||
log.info("Opening file: %s", path)
|
|
||||||
s.open_file(path)
|
s.open_file(path)
|
||||||
|
|
||||||
def present_error(self, msg: str):
|
def present_error(self, msg: str):
|
||||||
|
@ -553,3 +554,10 @@ class Controller:
|
||||||
if proxy.is_downloaded:
|
if proxy.is_downloaded:
|
||||||
self.model.downloads.pop(file_id)
|
self.model.downloads.pop(file_id)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
@handle_exception
|
||||||
|
def update_message_content_opened(self, update: Dict[str, Any]):
|
||||||
|
chat_id = update["chat_id"]
|
||||||
|
message_id = update["message_id"]
|
||||||
|
self.model.msgs.update_msg_content_opened(chat_id, message_id)
|
||||||
|
self.refresh_msgs()
|
||||||
|
|
39
tg/main.py
39
tg/main.py
|
@ -5,7 +5,7 @@ import threading
|
||||||
from curses import window, wrapper # type: ignore
|
from curses import window, wrapper # type: ignore
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from telegram.client import Telegram
|
from telegram.client import AsyncResult, Telegram
|
||||||
|
|
||||||
from tg import config, utils
|
from tg import config, utils
|
||||||
from tg.controllers import Controller
|
from tg.controllers import Controller
|
||||||
|
@ -48,7 +48,7 @@ class TelegramApi(Telegram):
|
||||||
)
|
)
|
||||||
result.wait()
|
result.wait()
|
||||||
|
|
||||||
def send_doc(self, file_path, chat_id):
|
def send_doc(self, file_path: str, chat_id: int) -> AsyncResult:
|
||||||
data = {
|
data = {
|
||||||
"@type": "sendMessage",
|
"@type": "sendMessage",
|
||||||
"chat_id": chat_id,
|
"chat_id": chat_id,
|
||||||
|
@ -59,7 +59,7 @@ class TelegramApi(Telegram):
|
||||||
}
|
}
|
||||||
return self._send_data(data)
|
return self._send_data(data)
|
||||||
|
|
||||||
def send_audio(self, file_path, chat_id):
|
def send_audio(self, file_path: str, chat_id: int) -> AsyncResult:
|
||||||
data = {
|
data = {
|
||||||
"@type": "sendMessage",
|
"@type": "sendMessage",
|
||||||
"chat_id": chat_id,
|
"chat_id": chat_id,
|
||||||
|
@ -70,7 +70,7 @@ class TelegramApi(Telegram):
|
||||||
}
|
}
|
||||||
return self._send_data(data)
|
return self._send_data(data)
|
||||||
|
|
||||||
def send_photo(self, file_path, chat_id):
|
def send_photo(self, file_path: str, chat_id: int) -> AsyncResult:
|
||||||
data = {
|
data = {
|
||||||
"@type": "sendMessage",
|
"@type": "sendMessage",
|
||||||
"chat_id": chat_id,
|
"chat_id": chat_id,
|
||||||
|
@ -81,7 +81,14 @@ class TelegramApi(Telegram):
|
||||||
}
|
}
|
||||||
return self._send_data(data)
|
return self._send_data(data)
|
||||||
|
|
||||||
def send_video(self, file_path, chat_id, width, height, duration):
|
def send_video(
|
||||||
|
self,
|
||||||
|
file_path: str,
|
||||||
|
chat_id: int,
|
||||||
|
width: int,
|
||||||
|
height: int,
|
||||||
|
duration: int,
|
||||||
|
) -> AsyncResult:
|
||||||
data = {
|
data = {
|
||||||
"@type": "sendMessage",
|
"@type": "sendMessage",
|
||||||
"chat_id": chat_id,
|
"chat_id": chat_id,
|
||||||
|
@ -95,7 +102,9 @@ class TelegramApi(Telegram):
|
||||||
}
|
}
|
||||||
return self._send_data(data)
|
return self._send_data(data)
|
||||||
|
|
||||||
def send_voice(self, file_path, chat_id, duration, waveform):
|
def send_voice(
|
||||||
|
self, file_path: str, chat_id: int, duration: int, waveform: int
|
||||||
|
):
|
||||||
data = {
|
data = {
|
||||||
"@type": "sendMessage",
|
"@type": "sendMessage",
|
||||||
"chat_id": chat_id,
|
"chat_id": chat_id,
|
||||||
|
@ -122,7 +131,7 @@ class TelegramApi(Telegram):
|
||||||
|
|
||||||
def toggle_chat_is_marked_as_unread(
|
def toggle_chat_is_marked_as_unread(
|
||||||
self, chat_id: int, is_marked_as_unread: bool
|
self, chat_id: int, is_marked_as_unread: bool
|
||||||
):
|
) -> AsyncResult:
|
||||||
data = {
|
data = {
|
||||||
"@type": "toggleChatIsMarkedAsUnread",
|
"@type": "toggleChatIsMarkedAsUnread",
|
||||||
"chat_id": chat_id,
|
"chat_id": chat_id,
|
||||||
|
@ -130,7 +139,9 @@ class TelegramApi(Telegram):
|
||||||
}
|
}
|
||||||
return self._send_data(data)
|
return self._send_data(data)
|
||||||
|
|
||||||
def toggle_chat_is_pinned(self, chat_id: int, is_pinned: bool):
|
def toggle_chat_is_pinned(
|
||||||
|
self, chat_id: int, is_pinned: bool
|
||||||
|
) -> AsyncResult:
|
||||||
data = {
|
data = {
|
||||||
"@type": "toggleChatIsPinned",
|
"@type": "toggleChatIsPinned",
|
||||||
"chat_id": chat_id,
|
"chat_id": chat_id,
|
||||||
|
@ -150,7 +161,7 @@ class TelegramApi(Telegram):
|
||||||
|
|
||||||
def view_messages(
|
def view_messages(
|
||||||
self, chat_id: int, message_ids: list, force_read: bool = True
|
self, chat_id: int, message_ids: list, force_read: bool = True
|
||||||
):
|
) -> AsyncResult:
|
||||||
data = {
|
data = {
|
||||||
"@type": "viewMessages",
|
"@type": "viewMessages",
|
||||||
"chat_id": chat_id,
|
"chat_id": chat_id,
|
||||||
|
@ -159,6 +170,16 @@ class TelegramApi(Telegram):
|
||||||
}
|
}
|
||||||
return self._send_data(data)
|
return self._send_data(data)
|
||||||
|
|
||||||
|
def open_message_content(
|
||||||
|
self, chat_id: int, message_id: int
|
||||||
|
) -> AsyncResult:
|
||||||
|
data = {
|
||||||
|
"@type": "openMessageContent",
|
||||||
|
"chat_id": chat_id,
|
||||||
|
"message_id": message_id,
|
||||||
|
}
|
||||||
|
return self._send_data(data)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
def signal_handler(sig, frame):
|
def signal_handler(sig, frame):
|
||||||
|
|
|
@ -4,6 +4,8 @@ from typing import Any, Dict, List, Optional, Set, Tuple
|
||||||
|
|
||||||
from telegram.client import Telegram
|
from telegram.client import Telegram
|
||||||
|
|
||||||
|
from tg.msg import MsgProxy
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@ -262,7 +264,22 @@ class MsgModel:
|
||||||
if msg["id"] != msg_id:
|
if msg["id"] != msg_id:
|
||||||
continue
|
continue
|
||||||
msg["content"] = message_content
|
msg["content"] = message_content
|
||||||
return True
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def update_msg_content_opened(self, chat_id: int, msg_id: int):
|
||||||
|
for message in self.msgs[chat_id]:
|
||||||
|
if message["id"] != msg_id:
|
||||||
|
continue
|
||||||
|
msg = MsgProxy(message)
|
||||||
|
if msg.type == "voice":
|
||||||
|
msg.is_listened = True
|
||||||
|
elif msg.type == "recording":
|
||||||
|
msg.is_viewed = True
|
||||||
|
# TODO: start the TTL timer for self-destructing messages
|
||||||
|
# that is the last case to implement
|
||||||
|
# https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1update_message_content_opened.html
|
||||||
|
return
|
||||||
|
|
||||||
def add_message(self, chat_id: int, message: Dict[str, Any]) -> bool:
|
def add_message(self, chat_id: int, message: Dict[str, Any]) -> bool:
|
||||||
msg_id = message["id"]
|
msg_id = message["id"]
|
||||||
|
|
36
tg/msg.py
36
tg/msg.py
|
@ -1,6 +1,6 @@
|
||||||
import logging
|
import logging
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Any, Dict
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
from tg import utils
|
from tg import utils
|
||||||
|
|
||||||
|
@ -58,8 +58,8 @@ class MsgProxy:
|
||||||
self.msg[key] = value
|
self.msg[key] = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def type(self):
|
def type(self) -> Optional[str]:
|
||||||
return self.msg["@type"]
|
return self.msg.get("@type")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def date(self) -> datetime:
|
def date(self) -> datetime:
|
||||||
|
@ -145,7 +145,35 @@ class MsgProxy:
|
||||||
return doc["local"]["is_downloading_completed"]
|
return doc["local"]["is_downloading_completed"]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def reply_msg_id(self):
|
def is_listened(self) -> Optional[bool]:
|
||||||
|
if self.type != "voice":
|
||||||
|
return None
|
||||||
|
return self.msg["content"]["is_listened"]
|
||||||
|
|
||||||
|
@is_listened.setter
|
||||||
|
def is_listened(self, value: bool):
|
||||||
|
if self.type != "voice":
|
||||||
|
return None
|
||||||
|
self.msg["content"]["is_listened"] = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_viewed(self) -> Optional[bool]:
|
||||||
|
if self.type != "recording":
|
||||||
|
return None
|
||||||
|
return self.msg["content"]["is_viewed"]
|
||||||
|
|
||||||
|
@is_viewed.setter
|
||||||
|
def is_viewed(self, value: bool):
|
||||||
|
if self.type != "recording":
|
||||||
|
return None
|
||||||
|
self.msg["content"]["is_viewed"] = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def msg_id(self) -> int:
|
||||||
|
return self.msg["id"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def reply_msg_id(self) -> Optional[int]:
|
||||||
return self.msg.get("reply_to_message_id")
|
return self.msg.get("reply_to_message_id")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -5,8 +5,7 @@ from datetime import datetime
|
||||||
from typing import Any, Dict, List, Optional, Tuple, cast
|
from typing import Any, Dict, List, Optional, Tuple, cast
|
||||||
|
|
||||||
from tg.colors import blue, cyan, get_color, magenta, reverse, white
|
from tg.colors import blue, cyan, get_color, magenta, reverse, white
|
||||||
from tg.models import MsgModel
|
from tg.models import MsgModel, UserModel
|
||||||
from tg.models import UserModel
|
|
||||||
from tg.msg import MsgProxy
|
from tg.msg import MsgProxy
|
||||||
from tg.utils import emoji_pattern, num, truncate_to_len
|
from tg.utils import emoji_pattern, num, truncate_to_len
|
||||||
|
|
||||||
|
@ -420,15 +419,23 @@ def parse_content(content: Dict[str, Any]) -> str:
|
||||||
|
|
||||||
fields = dict(
|
fields = dict(
|
||||||
name=msg.file_name,
|
name=msg.file_name,
|
||||||
duration=msg.duration,
|
|
||||||
size=msg.human_size,
|
|
||||||
download=get_download(msg.local, msg.size),
|
download=get_download(msg.local, msg.size),
|
||||||
|
size=msg.human_size,
|
||||||
|
duration=msg.duration,
|
||||||
|
listened=format_bool(msg.is_listened),
|
||||||
|
viewed=format_bool(msg.is_viewed),
|
||||||
)
|
)
|
||||||
info = ", ".join(f"{k}={v}" for k, v in fields.items() if v)
|
info = ", ".join(f"{k}={v}" for k, v in fields.items() if v)
|
||||||
|
|
||||||
return f"[{msg.content_type}: {info}]"
|
return f"[{msg.content_type}: {info}]"
|
||||||
|
|
||||||
|
|
||||||
|
def format_bool(value: Optional[bool]) -> Optional[str]:
|
||||||
|
if value is None:
|
||||||
|
return None
|
||||||
|
return "yes" if value else "no"
|
||||||
|
|
||||||
|
|
||||||
def get_download(local, size):
|
def get_download(local, size):
|
||||||
if local["is_downloading_completed"]:
|
if local["is_downloading_completed"]:
|
||||||
return "yes"
|
return "yes"
|
||||||
|
|
Loading…
Reference in a new issue