Files
messageLogger/src/hooks/comments.py
T
lyuksovannyyandClaude Opus 5.5 a2e4075a03
Publish plugin / publish (push) Successful in 4s
Message Logger: comments of deleted channel posts
The comments button of a deleted post opens the app's own comments section
(discussion thread), its history request answered locally from the logged
comments; the input bar is replaced by a "Viewing deleted comments" notice.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 13:46:11 +02:00

122 lines
4.2 KiB
Python

"""The comments button of a deleted channel post opens its logged comments
(views/comments.py) instead of the app's discussion, which Telegram deleted
with the post ("message doesn't exist").
ChatActivity$ChatMessageCellDelegate.didPressCommentButton(ChatMessageCell)
handles the button; an album's comments hang on any of its messages.
ConnectionsManager.sendRequestInternal (where every sendRequest overload
ends) is where the opened thread's getReplies is answered locally, and
ChatActivity.updateBottomOverlay where its input bar is kept hidden.
"""
from base_plugin import MethodHook
import diag
import store
from jutil import field, hook_methods, in_background, java_list
from views import comments as comments_view
DELEGATE = "org.telegram.ui.ChatActivity$ChatMessageCellDelegate"
CONNECTIONS = "org.telegram.tgnet.ConnectionsManager"
def _deleted_post(cell):
"""The deleted message of the cell (or its album), else None."""
message = cell.getMessageObject()
if message is None:
return None
candidates = [message]
group = cell.getCurrentMessagesGroup()
if group is not None:
candidates += java_list(group.messages)
for candidate in candidates:
if candidate is not None and int(candidate.getId()) > 0 and store.is_deleted(
int(candidate.currentAccount),
int(candidate.getDialogId()),
int(candidate.getId()),
):
return candidate
return None
class CommentsButton:
def __init__(self, plugin, open_comments):
self.plugin = plugin
self.open_comments = open_comments
self.handles = []
def install(self):
button = self
class BeforePress(MethodHook):
def before_hooked_method(self, param):
try:
post = _deleted_post(param.args[0])
if post is not None:
param.setResult(None)
button.open_comments(post)
except Exception as exc:
diag.error("comments.press", exc)
self.handles += hook_methods(
self.plugin, DELEGATE, "didPressCommentButton", BeforePress()
)
class BeforeSend(MethodHook):
def before_hooked_method(self, param):
try:
button.answer_locally(param)
except Exception as exc:
diag.error("comments.request", exc)
self.handles += hook_methods(
self.plugin, CONNECTIONS, "sendRequestInternal", BeforeSend()
)
class AfterOverlay(MethodHook):
def after_hooked_method(self, param):
try:
chat = param.thisObject
if int(chat.getClassGuid()) in comments_view.read_only:
comments_view.make_read_only(chat)
except Exception as exc:
diag.error("comments.overlay", exc)
self.handles += hook_methods(
self.plugin, "org.telegram.ui.ChatActivity", "updateBottomOverlay", AfterOverlay()
)
def answer_locally(self, param):
"""A thread opened by views/comments.py asks for its replies: answer
from the logged comments instead of Telegram (the thread is gone)."""
request = param.args[0]
if request is None or type(request).__name__ != "TLRPC$TL_messages_getReplies":
return
account = int(field(param.thisObject, "currentAccount") or 0)
response = comments_view.answer(account, request)
if response is None:
return
delegate, timestamped = param.args[1], param.args[2]
if param.method.getReturnType().getName() == "void":
param.setResult(None)
else:
from java import jint
param.setResult(jint(0))
def deliver():
if delegate is not None:
delegate.run(response, None)
elif timestamped is not None:
timestamped.run(response, None, 0)
in_background(deliver)
def uninstall(self):
for handle in self.handles:
try:
self.plugin.unhook_method(handle)
except Exception:
pass
self.handles = []