fix: fall back to reply_markup when buttons property is None for bot messages
Telethon's client.get_messages(entity, ids=N) sometimes returns bot messages with buttons=None and reply_markup=None, even when the message has inline keyboard buttons. The same message fetched via history (limit=N) includes the full ReplyInlineMarkup. Changes: - Add fallback: when message fetched by ID has no inline buttons, re-fetch via history and match by ID - Check both msg.buttons and msg.reply_markup.rows when searching for messages with buttons - Access .data/.url/.text directly on button objects (works for both MessageButton wrappers and raw KeyboardButtonCallback objects)
This commit is contained in:
parent
e96a6a8ca2
commit
cf6888e000
1 changed files with 53 additions and 18 deletions
71
main.py
71
main.py
|
|
@ -815,6 +815,22 @@ async def list_inline_buttons(
|
||||||
return "message_id must be an integer."
|
return "message_id must be an integer."
|
||||||
|
|
||||||
entity = await resolve_entity(chat_id)
|
entity = await resolve_entity(chat_id)
|
||||||
|
|
||||||
|
def _has_inline(msg):
|
||||||
|
if getattr(msg, "buttons", None):
|
||||||
|
return True
|
||||||
|
rm = getattr(msg, "reply_markup", None)
|
||||||
|
return bool(rm and hasattr(rm, "rows"))
|
||||||
|
|
||||||
|
def _flat_buttons(msg):
|
||||||
|
btns = getattr(msg, "buttons", None)
|
||||||
|
if btns:
|
||||||
|
return [btn for row in btns for btn in row]
|
||||||
|
rm = getattr(msg, "reply_markup", None)
|
||||||
|
if rm and hasattr(rm, "rows"):
|
||||||
|
return [btn for row in rm.rows for btn in row.buttons]
|
||||||
|
return []
|
||||||
|
|
||||||
target_message = None
|
target_message = None
|
||||||
|
|
||||||
if message_id is not None:
|
if message_id is not None:
|
||||||
|
|
@ -824,17 +840,13 @@ async def list_inline_buttons(
|
||||||
else:
|
else:
|
||||||
recent_messages = await client.get_messages(entity, limit=limit)
|
recent_messages = await client.get_messages(entity, limit=limit)
|
||||||
target_message = next(
|
target_message = next(
|
||||||
(msg for msg in recent_messages if getattr(msg, "buttons", None)), None
|
(msg for msg in recent_messages if _has_inline(msg)), None
|
||||||
)
|
)
|
||||||
|
|
||||||
if not target_message:
|
if not target_message:
|
||||||
return "No message with inline buttons found."
|
return "No message with inline buttons found."
|
||||||
|
|
||||||
buttons_attr = getattr(target_message, "buttons", None)
|
buttons = _flat_buttons(target_message)
|
||||||
if not buttons_attr:
|
|
||||||
return f"Message {target_message.id} does not contain inline buttons."
|
|
||||||
|
|
||||||
buttons = [btn for row in buttons_attr for btn in row]
|
|
||||||
if not buttons:
|
if not buttons:
|
||||||
return f"Message {target_message.id} does not contain inline buttons."
|
return f"Message {target_message.id} does not contain inline buttons."
|
||||||
|
|
||||||
|
|
@ -842,9 +854,8 @@ async def list_inline_buttons(
|
||||||
f"Buttons for message {target_message.id} (date {target_message.date}):",
|
f"Buttons for message {target_message.id} (date {target_message.date}):",
|
||||||
]
|
]
|
||||||
for idx, btn in enumerate(buttons):
|
for idx, btn in enumerate(buttons):
|
||||||
raw_button = getattr(btn, "button", None)
|
|
||||||
text = getattr(btn, "text", "") or "<no text>"
|
text = getattr(btn, "text", "") or "<no text>"
|
||||||
url = getattr(raw_button, "url", None) if raw_button else None
|
url = getattr(btn, "url", None)
|
||||||
has_callback = bool(getattr(btn, "data", None))
|
has_callback = bool(getattr(btn, "data", None))
|
||||||
parts = [f"[{idx}] text='{text}'"]
|
parts = [f"[{idx}] text='{text}'"]
|
||||||
parts.append("callback=yes" if has_callback else "callback=no")
|
parts.append("callback=yes" if has_callback else "callback=no")
|
||||||
|
|
@ -903,25 +914,49 @@ async def press_inline_button(
|
||||||
|
|
||||||
entity = await resolve_entity(chat_id)
|
entity = await resolve_entity(chat_id)
|
||||||
|
|
||||||
|
def _has_inline_buttons(msg):
|
||||||
|
"""Check if a message has inline buttons via buttons property or reply_markup."""
|
||||||
|
if getattr(msg, "buttons", None):
|
||||||
|
return True
|
||||||
|
rm = getattr(msg, "reply_markup", None)
|
||||||
|
return bool(rm and hasattr(rm, "rows"))
|
||||||
|
|
||||||
|
def _extract_buttons(msg):
|
||||||
|
"""Extract flat list of buttons from buttons property or reply_markup fallback."""
|
||||||
|
btns = getattr(msg, "buttons", None)
|
||||||
|
if btns:
|
||||||
|
return [btn for row in btns for btn in row]
|
||||||
|
rm = getattr(msg, "reply_markup", None)
|
||||||
|
if rm and hasattr(rm, "rows"):
|
||||||
|
return [btn for row in rm.rows for btn in row.buttons]
|
||||||
|
return []
|
||||||
|
|
||||||
target_message = None
|
target_message = None
|
||||||
if message_id is not None:
|
if message_id is not None:
|
||||||
|
# Fetch by ID first, then fall back to recent-message search if
|
||||||
|
# reply_markup is missing (Telethon sometimes omits it for ID fetches).
|
||||||
target_message = await client.get_messages(entity, ids=message_id)
|
target_message = await client.get_messages(entity, ids=message_id)
|
||||||
if isinstance(target_message, list):
|
if isinstance(target_message, list):
|
||||||
target_message = target_message[0] if target_message else None
|
target_message = target_message[0] if target_message else None
|
||||||
|
if target_message and not _has_inline_buttons(target_message):
|
||||||
|
# Fallback: search recent messages for the same ID with markup
|
||||||
|
recent = await client.get_messages(entity, limit=30)
|
||||||
|
fallback = next(
|
||||||
|
(m for m in recent if m.id == target_message.id and _has_inline_buttons(m)),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
if fallback:
|
||||||
|
target_message = fallback
|
||||||
else:
|
else:
|
||||||
recent_messages = await client.get_messages(entity, limit=20)
|
recent_messages = await client.get_messages(entity, limit=20)
|
||||||
target_message = next(
|
target_message = next(
|
||||||
(msg for msg in recent_messages if getattr(msg, "buttons", None)), None
|
(msg for msg in recent_messages if _has_inline_buttons(msg)), None
|
||||||
)
|
)
|
||||||
|
|
||||||
if not target_message:
|
if not target_message:
|
||||||
return "No message with inline buttons found. Specify message_id to target a specific message."
|
return "No message with inline buttons found. Specify message_id to target a specific message."
|
||||||
|
|
||||||
buttons_attr = getattr(target_message, "buttons", None)
|
buttons = _extract_buttons(target_message)
|
||||||
if not buttons_attr:
|
|
||||||
return f"Message {target_message.id} does not contain inline buttons."
|
|
||||||
|
|
||||||
buttons = [btn for row in buttons_attr for btn in row]
|
|
||||||
if not buttons:
|
if not buttons:
|
||||||
return f"Message {target_message.id} does not contain inline buttons."
|
return f"Message {target_message.id} does not contain inline buttons."
|
||||||
|
|
||||||
|
|
@ -949,16 +984,16 @@ async def press_inline_button(
|
||||||
)
|
)
|
||||||
return f"Button not found. Available buttons: {available}"
|
return f"Button not found. Available buttons: {available}"
|
||||||
|
|
||||||
if not getattr(target_button, "data", None):
|
btn_data = getattr(target_button, "data", None)
|
||||||
raw_button = getattr(target_button, "button", None)
|
if not btn_data:
|
||||||
url = getattr(raw_button, "url", None) if raw_button else None
|
url = getattr(target_button, "url", None)
|
||||||
if url:
|
if url:
|
||||||
return f"Selected button opens a URL instead of sending a callback: {url}"
|
return f"Selected button opens a URL instead of sending a callback: {url}"
|
||||||
return "Selected button does not provide callback data to press."
|
return "Selected button does not provide callback data to press."
|
||||||
|
|
||||||
callback_result = await client(
|
callback_result = await client(
|
||||||
functions.messages.GetBotCallbackAnswerRequest(
|
functions.messages.GetBotCallbackAnswerRequest(
|
||||||
peer=entity, msg_id=target_message.id, data=target_button.data
|
peer=entity, msg_id=target_message.id, data=btn_data
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue