From 04000c78e2890a000ad3b259238d69c82806f935 Mon Sep 17 00:00:00 2001 From: KnugiHK <24708955+KnugiHK@users.noreply.github.com> Date: Sun, 15 Sep 2024 10:55:43 +0800 Subject: [PATCH] Implement chat filter with group msg sender for iOS #85 --- Whatsapp_Chat_Exporter/android_handler.py | 48 +++++++++++------------ Whatsapp_Chat_Exporter/ios_handler.py | 28 ++++++++----- Whatsapp_Chat_Exporter/utility.py | 15 +++++-- 3 files changed, 54 insertions(+), 37 deletions(-) diff --git a/Whatsapp_Chat_Exporter/android_handler.py b/Whatsapp_Chat_Exporter/android_handler.py index 3ed763c..95e83a9 100644 --- a/Whatsapp_Chat_Exporter/android_handler.py +++ b/Whatsapp_Chat_Exporter/android_handler.py @@ -183,8 +183,8 @@ def messages(db, data, media_folder, timezone_offset, filter_date, filter_chat): ON messages.key_remote_jid = jid.raw_string WHERE 1=1 {f'AND timestamp {filter_date}' if filter_date is not None else ''} - {get_chat_condition(filter_chat[0], True, ["messages.key_remote_jid", "messages.remote_resource"], "jid")} - {get_chat_condition(filter_chat[1], False, ["messages.key_remote_jid", "messages.remote_resource"], "jid")}""") + {get_chat_condition(filter_chat[0], True, ["messages.key_remote_jid", "messages.remote_resource"], "jid", "android")} + {get_chat_condition(filter_chat[1], False, ["messages.key_remote_jid", "messages.remote_resource"], "jid", "android")}""") except sqlite3.OperationalError: c.execute(f"""SELECT count() @@ -197,8 +197,8 @@ def messages(db, data, media_folder, timezone_offset, filter_date, filter_chat): ON jid_group._id = message.sender_jid_row_id WHERE 1=1 {f'AND timestamp {filter_date}' if filter_date is not None else ''} - {get_chat_condition(filter_chat[0], True, ["jid.raw_string", "jid_group.raw_string"], "jid")} - {get_chat_condition(filter_chat[1], False, ["jid.raw_string", "jid_group.raw_string"], "jid")}""") + {get_chat_condition(filter_chat[0], True, ["jid.raw_string", "jid_group.raw_string"], "jid", "android")} + {get_chat_condition(filter_chat[1], False, ["jid.raw_string", "jid_group.raw_string"], "jid", "android")}""") total_row_number = c.fetchone()[0] print(f"Processing messages...(0/{total_row_number})", end="\r") @@ -254,8 +254,8 @@ def messages(db, data, media_folder, timezone_offset, filter_date, filter_chat): ON receipt_user.message_row_id = messages._id WHERE messages.key_remote_jid <> '-1' {f'AND messages.timestamp {filter_date}' if filter_date is not None else ''} - {get_chat_condition(filter_chat[0], True, ["messages.key_remote_jid", "messages.remote_resource"], "jid_global")} - {get_chat_condition(filter_chat[1], False, ["messages.key_remote_jid", "messages.remote_resource"], "jid_global")} + {get_chat_condition(filter_chat[0], True, ["messages.key_remote_jid", "messages.remote_resource"], "jid_global", "android")} + {get_chat_condition(filter_chat[1], False, ["messages.key_remote_jid", "messages.remote_resource"], "jid_global", "android")} GROUP BY messages._id ORDER BY messages.timestamp ASC;""" ) @@ -322,8 +322,8 @@ def messages(db, data, media_folder, timezone_offset, filter_date, filter_chat): ON receipt_user.message_row_id = message._id WHERE key_remote_jid <> '-1' {f'AND message.timestamp {filter_date}' if filter_date is not None else ''} - {get_chat_condition(filter_chat[0], True, ["key_remote_jid", "jid_group.raw_string"], "jid_global")} - {get_chat_condition(filter_chat[1], False, ["key_remote_jid", "jid_group.raw_string"], "jid_global")} + {get_chat_condition(filter_chat[0], True, ["key_remote_jid", "jid_group.raw_string"], "jid_global", "android")} + {get_chat_condition(filter_chat[1], False, ["key_remote_jid", "jid_group.raw_string"], "jid_global", "android")} GROUP BY message._id;""" ) except Exception as e: @@ -500,8 +500,8 @@ def media(db, data, media_folder, filter_date, filter_chat, separate_media=True) ON messages.key_remote_jid = jid.raw_string WHERE 1=1 {f'AND messages.timestamp {filter_date}' if filter_date is not None else ''} - {get_chat_condition(filter_chat[0], True, ["messages.key_remote_jid", "remote_resource"], "jid")} - {get_chat_condition(filter_chat[1], False, ["messages.key_remote_jid", "remote_resource"], "jid")}""") + {get_chat_condition(filter_chat[0], True, ["messages.key_remote_jid", "remote_resource"], "jid", "android")} + {get_chat_condition(filter_chat[1], False, ["messages.key_remote_jid", "remote_resource"], "jid", "android")}""") except sqlite3.OperationalError: c.execute(f"""SELECT count() FROM message_media @@ -515,8 +515,8 @@ def media(db, data, media_folder, filter_date, filter_chat, separate_media=True) ON jid_group._id = message.sender_jid_row_id WHERE 1=1 {f'AND message.timestamp {filter_date}' if filter_date is not None else ''} - {get_chat_condition(filter_chat[0], True, ["jid.raw_string", "jid_group.raw_string"], "jid")} - {get_chat_condition(filter_chat[1], False, ["jid.raw_string", "jid_group.raw_string"], "jid")}""") + {get_chat_condition(filter_chat[0], True, ["jid.raw_string", "jid_group.raw_string"], "jid", "android")} + {get_chat_condition(filter_chat[1], False, ["jid.raw_string", "jid_group.raw_string"], "jid", "android")}""") total_row_number = c.fetchone()[0] print(f"\nProcessing media...(0/{total_row_number})", end="\r") i = 0 @@ -538,8 +538,8 @@ def media(db, data, media_folder, filter_date, filter_chat, separate_media=True) ON messages.key_remote_jid = jid.raw_string WHERE jid.type <> 7 {f'AND messages.timestamp {filter_date}' if filter_date is not None else ''} - {get_chat_condition(filter_chat[0], True, ["messages.key_remote_jid", "remote_resource"], "jid")} - {get_chat_condition(filter_chat[1], False, ["messages.key_remote_jid", "remote_resource"], "jid")} + {get_chat_condition(filter_chat[0], True, ["messages.key_remote_jid", "remote_resource"], "jid", "android")} + {get_chat_condition(filter_chat[1], False, ["messages.key_remote_jid", "remote_resource"], "jid", "android")} ORDER BY messages.key_remote_jid ASC""" ) except sqlite3.OperationalError: @@ -564,8 +564,8 @@ def media(db, data, media_folder, filter_date, filter_chat, separate_media=True) ON jid_group._id = message.sender_jid_row_id WHERE jid.type <> 7 {f'AND message.timestamp {filter_date}' if filter_date is not None else ''} - {get_chat_condition(filter_chat[0], True, ["key_remote_jid", "jid_group.raw_string"], "jid")} - {get_chat_condition(filter_chat[1], False, ["key_remote_jid", "jid_group.raw_string"], "jid")} + {get_chat_condition(filter_chat[0], True, ["key_remote_jid", "jid_group.raw_string"], "jid", "android")} + {get_chat_condition(filter_chat[1], False, ["key_remote_jid", "jid_group.raw_string"], "jid", "android")} ORDER BY jid.raw_string ASC""" ) content = c.fetchone() @@ -627,8 +627,8 @@ def vcard(db, data, media_folder, filter_date, filter_chat): ON messages.key_remote_jid = jid.raw_string WHERE 1=1 {f'AND messages.timestamp {filter_date}' if filter_date is not None else ''} - {get_chat_condition(filter_chat[0], True, ["messages.key_remote_jid", "remote_resource"], "jid")} - {get_chat_condition(filter_chat[1], False, ["messages.key_remote_jid", "remote_resource"], "jid")} + {get_chat_condition(filter_chat[0], True, ["messages.key_remote_jid", "remote_resource"], "jid", "android")} + {get_chat_condition(filter_chat[1], False, ["messages.key_remote_jid", "remote_resource"], "jid", "android")} ORDER BY messages.key_remote_jid ASC;""" ) except sqlite3.OperationalError: @@ -647,8 +647,8 @@ def vcard(db, data, media_folder, filter_date, filter_chat): ON jid_group._id = message.sender_jid_row_id WHERE 1=1 {f'AND message.timestamp {filter_date}' if filter_date is not None else ''} - {get_chat_condition(filter_chat[0], True, ["key_remote_jid", "jid_group.raw_string"], "jid")} - {get_chat_condition(filter_chat[1], False, ["key_remote_jid", "jid_group.raw_string"], "jid")} + {get_chat_condition(filter_chat[0], True, ["key_remote_jid", "jid_group.raw_string"], "jid", "android")} + {get_chat_condition(filter_chat[1], False, ["key_remote_jid", "jid_group.raw_string"], "jid", "android")} ORDER BY message.chat_row_id ASC;""" ) @@ -684,8 +684,8 @@ def calls(db, data, timezone_offset, filter_chat): LEFT JOIN chat ON call_log.jid_row_id = chat.jid_row_id WHERE 1=1 - {get_chat_condition(filter_chat[0], True, ["jid.raw_string"], "jid")} - {get_chat_condition(filter_chat[1], False, ["jid.raw_string"], "jid")}""") + {get_chat_condition(filter_chat[0], True, ["jid.raw_string"])} + {get_chat_condition(filter_chat[1], False, ["jid.raw_string"])}""") total_row_number = c.fetchone()[0] if total_row_number == 0: return @@ -706,8 +706,8 @@ def calls(db, data, timezone_offset, filter_chat): LEFT JOIN chat ON call_log.jid_row_id = chat.jid_row_id WHERE 1=1 - {get_chat_condition(filter_chat[0], True, ["jid.raw_string"], "jid")} - {get_chat_condition(filter_chat[1], False, ["jid.raw_string"], "jid")}""" + {get_chat_condition(filter_chat[0], True, ["jid.raw_string"])} + {get_chat_condition(filter_chat[1], False, ["jid.raw_string"])}""" ) chat = ChatStore(Device.ANDROID, "WhatsApp Calls") content = c.fetchone() diff --git a/Whatsapp_Chat_Exporter/ios_handler.py b/Whatsapp_Chat_Exporter/ios_handler.py index c5aad00..2a45fde 100644 --- a/Whatsapp_Chat_Exporter/ios_handler.py +++ b/Whatsapp_Chat_Exporter/ios_handler.py @@ -78,10 +78,12 @@ def messages(db, data, media_folder, timezone_offset, filter_date, filter_chat): FROM ZWAMESSAGE INNER JOIN ZWACHATSESSION ON ZWAMESSAGE.ZCHATSESSION = ZWACHATSESSION.Z_PK + LEFT JOIN ZWAGROUPMEMBER + ON ZWAMESSAGE.ZGROUPMEMBER = ZWAGROUPMEMBER.Z_PK WHERE 1=1 {f'AND ZMESSAGEDATE {filter_date}' if filter_date is not None else ''} - {get_chat_condition(filter_chat[0], True, ["ZWACHATSESSION.ZCONTACTJID"])} - {get_chat_condition(filter_chat[1], False, ["ZWACHATSESSION.ZCONTACTJID"])}""") + {get_chat_condition(filter_chat[0], True, ["ZWACHATSESSION.ZCONTACTJID", "ZMEMBERJID"], "ZGROUPINFO", "ios")} + {get_chat_condition(filter_chat[1], False, ["ZWACHATSESSION.ZCONTACTJID", "ZMEMBERJID"], "ZGROUPINFO", "ios")}""") total_row_number = c.fetchone()[0] print(f"Processing messages...(0/{total_row_number})", end="\r") c.execute(f"""SELECT ZCONTACTJID, @@ -103,8 +105,8 @@ def messages(db, data, media_folder, timezone_offset, filter_date, filter_chat): ON ZWAMESSAGE.ZCHATSESSION = ZWACHATSESSION.Z_PK WHERE 1=1 {f'AND ZMESSAGEDATE {filter_date}' if filter_date is not None else ''} - {get_chat_condition(filter_chat[0], True, ["ZCONTACTJID"])} - {get_chat_condition(filter_chat[1], False, ["ZCONTACTJID"])} + {get_chat_condition(filter_chat[0], True, ["ZCONTACTJID", "ZMEMBERJID"], "ZGROUPINFO", "ios")} + {get_chat_condition(filter_chat[1], False, ["ZCONTACTJID", "ZMEMBERJID"], "ZGROUPINFO", "ios")} ORDER BY ZMESSAGEDATE ASC;""") i = 0 content = c.fetchone() @@ -216,10 +218,12 @@ def media(db, data, media_folder, filter_date, filter_chat, separate_media=False ON ZWAMEDIAITEM.ZMESSAGE = ZWAMESSAGE.Z_PK INNER JOIN ZWACHATSESSION ON ZWAMESSAGE.ZCHATSESSION = ZWACHATSESSION.Z_PK + LEFT JOIN ZWAGROUPMEMBER + ON ZWAMESSAGE.ZGROUPMEMBER = ZWAGROUPMEMBER.Z_PK WHERE 1=1 {f'AND ZMESSAGEDATE {filter_date}' if filter_date is not None else ''} - {get_chat_condition(filter_chat[0], True, ["ZWACHATSESSION.ZCONTACTJID"])} - {get_chat_condition(filter_chat[1], False, ["ZWACHATSESSION.ZCONTACTJID"])} + {get_chat_condition(filter_chat[0], True, ["ZWACHATSESSION.ZCONTACTJID","ZMEMBERJID"], "ZGROUPINFO", "ios")} + {get_chat_condition(filter_chat[1], False, ["ZWACHATSESSION.ZCONTACTJID", "ZMEMBERJID"], "ZGROUPINFO", "ios")} """) total_row_number = c.fetchone()[0] print(f"\nProcessing media...(0/{total_row_number})", end="\r") @@ -236,10 +240,12 @@ def media(db, data, media_folder, filter_date, filter_chat, separate_media=False ON ZWAMEDIAITEM.ZMESSAGE = ZWAMESSAGE.Z_PK INNER JOIN ZWACHATSESSION ON ZWAMESSAGE.ZCHATSESSION = ZWACHATSESSION.Z_PK + LEFT JOIN ZWAGROUPMEMBER + ON ZWAMESSAGE.ZGROUPMEMBER = ZWAGROUPMEMBER.Z_PK WHERE ZMEDIALOCALPATH IS NOT NULL {f'AND ZWAMESSAGE.ZMESSAGEDATE {filter_date}' if filter_date is not None else ''} - {get_chat_condition(filter_chat[0], True, ["ZCONTACTJID"])} - {get_chat_condition(filter_chat[1], False, ["ZCONTACTJID"])} + {get_chat_condition(filter_chat[0], True, ["ZCONTACTJID", "ZMEMBERJID"], "ZGROUPINFO", "ios")} + {get_chat_condition(filter_chat[1], False, ["ZCONTACTJID", "ZMEMBERJID"], "ZGROUPINFO", "ios")} ORDER BY ZCONTACTJID ASC""") content = c.fetchone() mime = MimeTypes() @@ -298,10 +304,12 @@ def vcard(db, data, media_folder, filter_date, filter_chat): ON ZWAMEDIAITEM.ZMESSAGE = ZWAMESSAGE.Z_PK INNER JOIN ZWACHATSESSION ON ZWAMESSAGE.ZCHATSESSION = ZWACHATSESSION.Z_PK + LEFT JOIN ZWAGROUPMEMBER + ON ZWAMESSAGE.ZGROUPMEMBER = ZWAGROUPMEMBER.Z_PK WHERE 1=1 {f'AND ZWAMESSAGE.ZMESSAGEDATE {filter_date}' if filter_date is not None else ''} - {get_chat_condition(filter_chat[0], True, ["ZCONTACTJID"])} - {get_chat_condition(filter_chat[1], False, ["ZCONTACTJID"])};""") + {get_chat_condition(filter_chat[0], True, ["ZCONTACTJID", "ZMEMBERJID"], "ZGROUPINFO", "ios")} + {get_chat_condition(filter_chat[1], False, ["ZCONTACTJID", "ZMEMBERJID"], "ZGROUPINFO", "ios")};""") contents = c.fetchall() total_row_number = len(contents) print(f"\nProcessing vCards...(0/{total_row_number})", end="\r") diff --git a/Whatsapp_Chat_Exporter/utility.py b/Whatsapp_Chat_Exporter/utility.py index 2a188ec..0ece1ee 100644 --- a/Whatsapp_Chat_Exporter/utility.py +++ b/Whatsapp_Chat_Exporter/utility.py @@ -218,18 +218,27 @@ def get_file_name(contact: str, chat: ChatStore): return sanitize_filename(file_name), name -def get_chat_condition(filter, include, columns, jid=None): +def get_chat_condition(filter, include, columns, jid=None, platform=None): if filter is not None: conditions = [] + if len(columns) < 2 and jid is not None: + raise ValueError("There must be at least two elements in argument columns if jid is not None") + if jid is not None: + if platform == "android": + is_group = f"{jid}.type == 1" + elif platform == "ios": + is_group = f"{jid} IS NOT NULL" + else: + raise ValueError("Only android and ios are supported for argument platform if jid is not None") for index, chat in enumerate(filter): if include: conditions.append(f"{' OR' if index > 0 else ''} {columns[0]} LIKE '%{chat}%'") if len(columns) > 1: - conditions.append(f" OR ({columns[1]} LIKE '%{chat}%' AND {jid}.type == 1)") + conditions.append(f" OR ({columns[1]} LIKE '%{chat}%' AND {is_group})") else: conditions.append(f"{' AND' if index > 0 else ''} {columns[0]} NOT LIKE '%{chat}%'") if len(columns) > 1: - conditions.append(f" AND ({columns[1]} NOT LIKE '%{chat}%' AND {jid}.type == 1)") + conditions.append(f" AND ({columns[1]} NOT LIKE '%{chat}%' AND {is_group})") return f"AND ({' '.join(conditions)})" else: return ""