mirror of
https://github.com/KnugiHK/WhatsApp-Chat-Exporter.git
synced 2026-04-24 23:11:35 +00:00
feat: Add support for exporting message reactions
This commit is contained in:
@@ -25,7 +25,10 @@ from Whatsapp_Chat_Exporter.vcards_contacts import ContactsFromVCards
|
|||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
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"""========================================================================================================
|
WTSEXPORTER_BANNER = f"""========================================================================================================
|
||||||
██╗ ██╗██╗ ██╗ █████╗ ████████╗███████╗ █████╗ ██████╗ ██████╗
|
██╗ ██╗██╗ ██╗ █████╗ ████████╗███████╗ █████╗ ██████╗ ██████╗
|
||||||
██║ ██║██║ ██║██╔══██╗╚══██╔══╝██╔════╝██╔══██╗██╔══██╗██╔══██╗
|
██║ ██║██║ ██║██╔══██╗╚══██╔══╝██╔════╝██╔══██╗██╔══██╗██╔══██╗
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ def messages(db, data, media_folder, timezone_offset, filter_date, filter_chat,
|
|||||||
# Fetch the next row safely
|
# Fetch the next row safely
|
||||||
content = _fetch_row_safely(content_cursor)
|
content = _fetch_row_safely(content_cursor)
|
||||||
|
|
||||||
|
_get_reactions(db, data)
|
||||||
logger.info(f"Processed {total_row_number} messages{CLEAR_LINE}")
|
logger.info(f"Processed {total_row_number} messages{CLEAR_LINE}")
|
||||||
|
|
||||||
|
|
||||||
@@ -480,6 +481,71 @@ def _format_message_text(text):
|
|||||||
return 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):
|
def media(db, data, media_folder, filter_date, filter_chat, filter_empty, separate_media=True):
|
||||||
"""
|
"""
|
||||||
Process WhatsApp media files from the database.
|
Process WhatsApp media files from the database.
|
||||||
|
|||||||
@@ -338,6 +338,7 @@ class Message:
|
|||||||
self.caption = None
|
self.caption = None
|
||||||
self.thumb = None # Android specific
|
self.thumb = None # Android specific
|
||||||
self.sticker = False
|
self.sticker = False
|
||||||
|
self.reactions = {}
|
||||||
|
|
||||||
def to_json(self) -> Dict[str, Any]:
|
def to_json(self) -> Dict[str, Any]:
|
||||||
"""Convert message to JSON-serializable dict."""
|
"""Convert message to JSON-serializable dict."""
|
||||||
|
|||||||
@@ -287,6 +287,15 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
<p class="text-[10px] text-[#667781] text-right mt-1">{{ msg.time }}</p>
|
<p class="text-[10px] text-[#667781] text-right mt-1">{{ msg.time }}</p>
|
||||||
|
{% if msg.reactions %}
|
||||||
|
<div class="flex flex-wrap gap-1 mt-1 justify-end">
|
||||||
|
{% for sender, emoji in msg.reactions.items() %}
|
||||||
|
<div class="bg-white rounded-full px-1.5 py-0.5 text-xs shadow-sm border border-gray-200 cursor-help" title="{{ sender }}">
|
||||||
|
{{ emoji }}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
@@ -356,6 +365,15 @@
|
|||||||
<span class="flex-grow min-w-[4px]"></span>
|
<span class="flex-grow min-w-[4px]"></span>
|
||||||
<span class="flex-shrink-0">{{ msg.time }}</span>
|
<span class="flex-shrink-0">{{ msg.time }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
{% if msg.reactions %}
|
||||||
|
<div class="flex flex-wrap gap-1 mt-1 justify-start">
|
||||||
|
{% for sender, emoji in msg.reactions.items() %}
|
||||||
|
<div class="bg-gray-100 rounded-full px-1.5 py-0.5 text-xs shadow-sm border border-gray-200 cursor-help" title="{{ sender }}">
|
||||||
|
{{ emoji }}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="opacity-0 group-hover:opacity-100 transition-opacity duration-200 relative ml-2">
|
<!-- <div class="opacity-0 group-hover:opacity-100 transition-opacity duration-200 relative ml-2">
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
|
|||||||
Reference in New Issue
Block a user