Optimize quoted message lookups via global in-memory mapping

This change replaces the inefficient N+1 SQL query pattern with a pre-computed hash map. By fetching `ZSTANZAID` and `ZTEXT` pairs globally before processing, the exporter can resolve quoted message content in O(1) time.

Crucially, this maintains parity with the Android exporter by ensuring that replies to messages outside the current date or chat filters are still correctly rendered, providing full conversational context without the performance penalty of repeated database hits.
This commit is contained in:
KnugiHK
2026-01-06 20:51:29 +08:00
parent 8f29fa0505
commit 5a20953a81

View File

@@ -178,6 +178,10 @@ def messages(db, data, media_folder, timezone_offset, filter_date, filter_chat,
""" """
c.execute(messages_query) c.execute(messages_query)
reply_query = """SELECT ZSTANZAID, ZTEXT FROM ZWAMESSAGE WHERE ZTEXT IS NOT NULL"""
cursor2.execute(reply_query)
message_map = {row[0][:17]: row[1] for row in cursor2.fetchall() if row[0]}
# Process each message # Process each message
i = 0 i = 0
content = c.fetchone() content = c.fetchone()
@@ -207,7 +211,7 @@ def messages(db, data, media_folder, timezone_offset, filter_date, filter_chat,
) )
# Process message data # Process message data
invalid = process_message_data(message, content, is_group_message, data, cursor2, no_reply) invalid = process_message_data(message, content, is_group_message, data, message_map, no_reply)
# Add valid messages to chat # Add valid messages to chat
if not invalid: if not invalid:
@@ -221,7 +225,7 @@ def messages(db, data, media_folder, timezone_offset, filter_date, filter_chat,
logger.info(f"Processed {total_row_number} messages{CLEAR_LINE}") logger.info(f"Processed {total_row_number} messages{CLEAR_LINE}")
def process_message_data(message, content, is_group_message, data, cursor2, no_reply): def process_message_data(message, content, is_group_message, data, message_map, no_reply):
"""Process and set message data from content row.""" """Process and set message data from content row."""
# Handle group sender info # Handle group sender info
if is_group_message and content["ZISFROMME"] == 0: if is_group_message and content["ZISFROMME"] == 0:
@@ -247,14 +251,7 @@ def process_message_data(message, content, is_group_message, data, cursor2, no_r
if content["ZMETADATA"] is not None and content["ZMETADATA"].startswith(b"\x2a\x14") and not no_reply: if content["ZMETADATA"] is not None and content["ZMETADATA"].startswith(b"\x2a\x14") and not no_reply:
quoted = content["ZMETADATA"][2:19] quoted = content["ZMETADATA"][2:19]
message.reply = quoted.decode() message.reply = quoted.decode()
cursor2.execute(f"""SELECT ZTEXT message.quoted_data = message_map.get(message.reply)
FROM ZWAMESSAGE
WHERE ZSTANZAID LIKE '{message.reply}%'""")
quoted_content = cursor2.fetchone()
if quoted_content and "ZTEXT" in quoted_content:
message.quoted_data = quoted_content["ZTEXT"]
else:
message.quoted_data = None
# Handle stickers # Handle stickers
if content["ZMESSAGETYPE"] == 15: if content["ZMESSAGETYPE"] == 15: