From 75fcf33fda2b3a7f14fff919714327e090d52301 Mon Sep 17 00:00:00 2001
From: Cosmo
Date: Sun, 11 Jan 2026 07:06:23 -0800
Subject: [PATCH] feat: Add support for exporting message reactions
---
Whatsapp_Chat_Exporter/__main__.py | 5 +-
Whatsapp_Chat_Exporter/android_handler.py | 66 +++++++++++++++++++++++
Whatsapp_Chat_Exporter/data_model.py | 1 +
Whatsapp_Chat_Exporter/whatsapp.html | 18 +++++++
4 files changed, 89 insertions(+), 1 deletion(-)
diff --git a/Whatsapp_Chat_Exporter/__main__.py b/Whatsapp_Chat_Exporter/__main__.py
index 07a341b..c8be561 100644
--- a/Whatsapp_Chat_Exporter/__main__.py
+++ b/Whatsapp_Chat_Exporter/__main__.py
@@ -25,7 +25,10 @@ from Whatsapp_Chat_Exporter.vcards_contacts import ContactsFromVCards
logger = logging.getLogger(__name__)
-__version__ = importlib.metadata.version("whatsapp_chat_exporter")
+try:
+ __version__ = importlib.metadata.version("whatsapp_chat_exporter")
+except importlib.metadata.PackageNotFoundError:
+ __version__ = "0.13.0rc2"
WTSEXPORTER_BANNER = f"""========================================================================================================
██╗ ██╗██╗ ██╗ █████╗ ████████╗███████╗ █████╗ ██████╗ ██████╗
██║ ██║██║ ██║██╔══██╗╚══██╔══╝██╔════╝██╔══██╗██╔══██╗██╔══██╗
diff --git a/Whatsapp_Chat_Exporter/android_handler.py b/Whatsapp_Chat_Exporter/android_handler.py
index 274661b..1b11e78 100644
--- a/Whatsapp_Chat_Exporter/android_handler.py
+++ b/Whatsapp_Chat_Exporter/android_handler.py
@@ -98,6 +98,7 @@ def messages(db, data, media_folder, timezone_offset, filter_date, filter_chat,
# Fetch the next row safely
content = _fetch_row_safely(content_cursor)
+ _get_reactions(db, data)
logger.info(f"Processed {total_row_number} messages{CLEAR_LINE}")
@@ -480,6 +481,71 @@ def _format_message_text(text):
return text
+def _get_reactions(db, data):
+ """
+ Process message reactions.
+ """
+ logger.info("Processing reactions...")
+ c = db.cursor()
+
+ try:
+ # Check if tables exist
+ c.execute("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='message_add_on'")
+ if c.fetchone()[0] == 0:
+ return
+
+ c.execute("""
+ SELECT
+ message_add_on.parent_message_row_id,
+ message_add_on_reaction.reaction,
+ message_add_on.from_me,
+ jid.raw_string as sender_jid_raw,
+ chat_jid.raw_string as chat_jid_raw
+ FROM message_add_on
+ INNER JOIN message_add_on_reaction
+ ON message_add_on._id = message_add_on_reaction.message_add_on_row_id
+ LEFT JOIN jid
+ ON message_add_on.sender_jid_row_id = jid._id
+ LEFT JOIN chat
+ ON message_add_on.chat_row_id = chat._id
+ LEFT JOIN jid chat_jid
+ ON chat.jid_row_id = chat_jid._id
+ """)
+ except sqlite3.OperationalError:
+ logger.warning("Could not fetch reactions (schema might be too old or incompatible).")
+ return
+
+ row = c.fetchone()
+ while row is not None:
+ parent_id = row["parent_message_row_id"]
+ reaction = row["reaction"]
+ chat_id = row["chat_jid_raw"]
+
+ if chat_id and chat_id in data:
+ chat = data[chat_id]
+ if parent_id in chat._messages:
+ message = chat._messages[parent_id]
+
+ # Determine sender name
+ sender_name = None
+ if row["from_me"]:
+ sender_name = "You"
+ elif row["sender_jid_raw"]:
+ sender_jid = row["sender_jid_raw"]
+ if sender_jid in data:
+ sender_name = data[sender_jid].name
+ if not sender_name:
+ sender_name = sender_jid.split('@')[0] if "@" in sender_jid else sender_jid
+
+ if not sender_name:
+ sender_name = "Unknown"
+
+ message.reactions[sender_name] = reaction
+
+ row = c.fetchone()
+ logger.info(f"Reactions processed.{CLEAR_LINE}")
+
+
def media(db, data, media_folder, filter_date, filter_chat, filter_empty, separate_media=True):
"""
Process WhatsApp media files from the database.
diff --git a/Whatsapp_Chat_Exporter/data_model.py b/Whatsapp_Chat_Exporter/data_model.py
index 8747419..47034e6 100644
--- a/Whatsapp_Chat_Exporter/data_model.py
+++ b/Whatsapp_Chat_Exporter/data_model.py
@@ -338,6 +338,7 @@ class Message:
self.caption = None
self.thumb = None # Android specific
self.sticker = False
+ self.reactions = {}
def to_json(self) -> Dict[str, Any]:
"""Convert message to JSON-serializable dict."""
diff --git a/Whatsapp_Chat_Exporter/whatsapp.html b/Whatsapp_Chat_Exporter/whatsapp.html
index 2aa2b7e..b4b9c8a 100644
--- a/Whatsapp_Chat_Exporter/whatsapp.html
+++ b/Whatsapp_Chat_Exporter/whatsapp.html
@@ -287,6 +287,15 @@
{% endif %}
{{ msg.time }}
+ {% if msg.reactions %}
+
+ {% for sender, emoji in msg.reactions.items() %}
+
+ {{ emoji }}
+
+ {% endfor %}
+
+ {% endif %}
{% else %}
@@ -356,6 +365,15 @@
{{ msg.time }}
+ {% if msg.reactions %}
+
+ {% for sender, emoji in msg.reactions.items() %}
+
+ {{ emoji }}
+
+ {% endfor %}
+
+ {% endif %}