"""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 = []