generated from exteraGramPlugins/pluginBase
Rename to Extended Media Forwards and forward rich message media
Publish plugin / publish (push) Successful in 5s
Publish plugin / publish (push) Successful in 5s
Rename the plugin (id extended_media_forwards) and add the Forward button to media opened from rich messages, both single media and carousels. Rich message media opens PhotoViewer through ChatActivity's ChatArticlePageBlocksAdapter, whose parent object is the MessageObject rather than a WebPage, so the article-only check hid the button. The re-sent media links back to the message when it lives in a channel or supergroup; elsewhere it is sent without a caption. FileLoader now gets the parent object so expired file references can be refreshed. Instant View carousels already worked: slideshow items are flattened into the article's photo list. Findings are in docs/media-viewer-notes.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
05c5212a8a
commit
46503f24a0
9 files changed
+317
-36
No files matched your search
+101
-1
@@ -116,6 +116,42 @@ class FakeWebPage:
|
||||
self.display_url = display_url
|
||||
|
||||
|
||||
class FakeRichMessage:
|
||||
"""Stand-in for TL_iv.RichMessage."""
|
||||
|
||||
|
||||
class FakeMessage:
|
||||
def __init__(self, rich_message=None):
|
||||
self.rich_message = rich_message
|
||||
|
||||
|
||||
class FakeMessageObject:
|
||||
def __init__(self, msg_id, dialog_id, rich_message=None):
|
||||
self.messageOwner = FakeMessage(rich_message)
|
||||
self._id = msg_id
|
||||
self._dialog_id = dialog_id
|
||||
|
||||
def getId(self):
|
||||
return self._id
|
||||
|
||||
def getDialogId(self):
|
||||
return self._dialog_id
|
||||
|
||||
|
||||
class FakeChat:
|
||||
def __init__(self, chat_id, channel, username=None):
|
||||
self.id = chat_id
|
||||
self.channel = channel
|
||||
self.username = username
|
||||
|
||||
|
||||
FAKE_CHATS = {
|
||||
100: FakeChat(100, channel=True, username="publicchan"),
|
||||
200: FakeChat(200, channel=True),
|
||||
300: FakeChat(300, channel=False),
|
||||
}
|
||||
|
||||
|
||||
def install_fakes() -> None:
|
||||
base_plugin_mod = types.ModuleType("base_plugin")
|
||||
base_plugin_mod.BasePlugin = BasePlugin
|
||||
@@ -158,6 +194,22 @@ def install_fakes() -> None:
|
||||
),
|
||||
)
|
||||
tgnet_mod.TLRPC = tlrpc
|
||||
tgnet_mod.__path__ = []
|
||||
tgnet_tl_mod = types.ModuleType("org.telegram.tgnet.tl")
|
||||
tgnet_tl_mod.TL_iv = types.SimpleNamespace(RichMessage=FakeRichMessage)
|
||||
tgnet_mod.tl = tgnet_tl_mod
|
||||
sys.modules["org.telegram.tgnet.tl"] = tgnet_tl_mod
|
||||
|
||||
messenger_mod = types.ModuleType("org.telegram.messenger")
|
||||
messenger_mod.MessageObject = FakeMessageObject
|
||||
messenger_mod.ChatObject = types.SimpleNamespace(
|
||||
isChannel=lambda chat: chat.channel,
|
||||
getPublicUsername=lambda chat: chat.username,
|
||||
)
|
||||
messenger_mod.MessagesController = types.SimpleNamespace(
|
||||
getInstance=lambda account: types.SimpleNamespace(getChat=FAKE_CHATS.get)
|
||||
)
|
||||
sys.modules["org.telegram.messenger"] = messenger_mod
|
||||
|
||||
# `java.util.ArrayList` only ever gets add()ed to and iterated.
|
||||
java_mod = types.ModuleType("java")
|
||||
@@ -346,11 +398,32 @@ def main(argv=None) -> int:
|
||||
plugin.allows(other) and not plugin.allows(no_page),
|
||||
)
|
||||
|
||||
rich_msg = FakeAdapter(FakeMessageObject(5, -1000000000200, FakeRichMessage()))
|
||||
rich_bare = FakeAdapter(FakeRichMessage())
|
||||
plain_msg = FakeAdapter(FakeMessageObject(5, -1000000000200, None))
|
||||
check(
|
||||
"settings expose the rich_messages switch",
|
||||
any(getattr(row, "key", None) == "rich_messages" for row in rows),
|
||||
)
|
||||
check(
|
||||
"rich message media is accepted by default (with or without a message)",
|
||||
plugin.allows(rich_msg) and plugin.allows(rich_bare),
|
||||
)
|
||||
check(
|
||||
"message parent without a rich message is rejected",
|
||||
not plugin.allows(plain_msg),
|
||||
)
|
||||
plugin.set_setting("rich_messages", False)
|
||||
check(
|
||||
"rich_messages setting off rejects rich message media",
|
||||
not plugin.allows(rich_msg) and not plugin.allows(rich_bare),
|
||||
)
|
||||
|
||||
ivmedia = ns.get("ivmedia")
|
||||
sender = ns.get("sender")
|
||||
caption = getattr(sender, "CAPTION_TEXT", None)
|
||||
link_entities = getattr(sender, "_link_entities", None)
|
||||
entities = link_entities("https://telegra.ph/x") if link_entities else []
|
||||
entities = link_entities(caption, "https://telegra.ph/x") if link_entities and caption else []
|
||||
entity = entities[0] if entities else None
|
||||
check(
|
||||
"caption is a single text_url entity covering the whole caption",
|
||||
@@ -363,6 +436,33 @@ def main(argv=None) -> int:
|
||||
f"got caption={caption!r} entities={entities!r}",
|
||||
)
|
||||
|
||||
message_link = getattr(ivmedia, "message_link", None)
|
||||
if message_link is not None:
|
||||
# Channel dialog ids are -(chat id) in this fake, like getDialogId().
|
||||
links = (
|
||||
message_link(0, FakeMessageObject(7, -100)),
|
||||
message_link(0, FakeMessageObject(8, -200)),
|
||||
message_link(0, FakeMessageObject(9, -300)),
|
||||
message_link(0, FakeMessageObject(9, 12345)),
|
||||
message_link(0, FakeMessageObject(-1, -100)),
|
||||
message_link(0, FakeRichMessage()),
|
||||
)
|
||||
else:
|
||||
links = None
|
||||
check(
|
||||
"message_link: public/private channels linked; groups, DMs, local and bare rich messages not",
|
||||
links
|
||||
== (
|
||||
"https://t.me/publicchan/7",
|
||||
"https://t.me/c/200/8",
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
),
|
||||
f"got {links!r}",
|
||||
)
|
||||
|
||||
media_at = getattr(ivmedia, "media_at", None)
|
||||
no_media = getattr(ivmedia, "NoMedia", None)
|
||||
raised = False
|
||||
|
||||
Reference in new issue
Block a user