diff --git a/Whatsapp_Chat_Exporter/android_handler.py b/Whatsapp_Chat_Exporter/android_handler.py index f56c531..5c0b2ab 100644 --- a/Whatsapp_Chat_Exporter/android_handler.py +++ b/Whatsapp_Chat_Exporter/android_handler.py @@ -92,6 +92,7 @@ def messages(db, data, media_folder, timezone_offset, filter_date, filter_chat, _process_single_message(data, content, table_message, timezone_offset) pbar.update(1) total_time = pbar.format_dict['elapsed'] + _get_reactions(db, data) logger.info(f"Processed {total_row_number} messages in {convert_time_unit(total_time)}{CLEAR_LINE}") # Helper functions for message processing @@ -495,6 +496,76 @@ def _format_message_text(text): return text +def _get_reactions(db, data): + """ + Process message reactions. Only new schema is supported. + Chat filter is not applied here at the moment. Maybe in the future. + """ + c = db.cursor() + + try: + # Check if tables exist, old schema might not have reactions or in somewhere else + c.execute("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='message_add_on'") + if c.fetchone()[0] == 0: + return + + logger.info("Processing reactions...\r") + + 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(f"Could not fetch reactions (schema might be too old or incompatible){CLEAR_LINE}") + return + + rows = c.fetchall() + total_row_number = len(rows) + + with tqdm(total=total_row_number, desc="Processing reactions", unit="reaction", leave=False) as pbar: + for row in rows: + 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 + pbar.update(1) + total_time = pbar.format_dict['elapsed'] + logger.info(f"Processed {total_row_number} reactions in {convert_time_unit(total_time)}{CLEAR_LINE}") + + def media(db, data, media_folder, filter_date, filter_chat, filter_empty, separate_media=True, fix_dot_files=False): """ Process WhatsApp media files from the database. diff --git a/Whatsapp_Chat_Exporter/data_model.py b/Whatsapp_Chat_Exporter/data_model.py index b63ed01..9ea0d7b 100644 --- a/Whatsapp_Chat_Exporter/data_model.py +++ b/Whatsapp_Chat_Exporter/data_model.py @@ -337,6 +337,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 a52601c..6ef972b 100644 --- a/Whatsapp_Chat_Exporter/whatsapp.html +++ b/Whatsapp_Chat_Exporter/whatsapp.html @@ -230,7 +230,7 @@ -