mirror of
https://github.com/KnugiHK/WhatsApp-Chat-Exporter.git
synced 2026-04-27 16:24:53 +00:00
Add date filter for Android #82
This commit is contained in:
@@ -12,6 +12,7 @@ from Whatsapp_Chat_Exporter import extract, extract_iphone_media
|
|||||||
from Whatsapp_Chat_Exporter.data_model import ChatStore
|
from Whatsapp_Chat_Exporter.data_model import ChatStore
|
||||||
from Whatsapp_Chat_Exporter.utility import Crypt, DbType, check_update, import_from_json
|
from Whatsapp_Chat_Exporter.utility import Crypt, DbType, check_update, import_from_json
|
||||||
from argparse import ArgumentParser, SUPPRESS
|
from argparse import ArgumentParser, SUPPRESS
|
||||||
|
from datetime import datetime
|
||||||
from sys import exit
|
from sys import exit
|
||||||
try:
|
try:
|
||||||
from .__init__ import __version__
|
from .__init__ import __version__
|
||||||
@@ -207,6 +208,18 @@ def main():
|
|||||||
choices=range(-12, 15),
|
choices=range(-12, 15),
|
||||||
help="Offset in hours (-12 to 14) for time displayed in the output"
|
help="Offset in hours (-12 to 14) for time displayed in the output"
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--date",
|
||||||
|
dest="filter_date",
|
||||||
|
default=None,
|
||||||
|
help="The date filter in specific format (inclusive)"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--date-format",
|
||||||
|
dest="filter_date_format",
|
||||||
|
default="%Y-%m-%d %H:%M",
|
||||||
|
help="The date format for the date filter."
|
||||||
|
)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# Check for updates
|
# Check for updates
|
||||||
@@ -232,6 +245,22 @@ def main():
|
|||||||
if args.android and args.business:
|
if args.android and args.business:
|
||||||
print("WhatsApp Business is only available on iOS for now.")
|
print("WhatsApp Business is only available on iOS for now.")
|
||||||
exit(1)
|
exit(1)
|
||||||
|
if args.filter_date is not None:
|
||||||
|
if " - " in args.filter_date:
|
||||||
|
start, end = args.filter_date.split(" - ")
|
||||||
|
start = int(datetime.strptime(start, args.filter_date_format).timestamp())
|
||||||
|
end = int(datetime.strptime(end, args.filter_date_format).timestamp())
|
||||||
|
args.filter_date = f"BETWEEN {start}000 AND {end}000"
|
||||||
|
else:
|
||||||
|
_timestamp = int(datetime.strptime(args.filter_date[2:], args.filter_date_format).timestamp())
|
||||||
|
if args.filter_date[:2] == "> ":
|
||||||
|
args.filter_date = f">= {_timestamp}000"
|
||||||
|
elif args.filter_date[:2] == "< ":
|
||||||
|
args.filter_date = f"<= {_timestamp}000"
|
||||||
|
else:
|
||||||
|
print("Unsupported date format. See https://wts.knugi.dev/filter.html")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
data = {}
|
data = {}
|
||||||
|
|
||||||
@@ -338,9 +367,9 @@ def main():
|
|||||||
if os.path.isfile(msg_db):
|
if os.path.isfile(msg_db):
|
||||||
with sqlite3.connect(msg_db) as db:
|
with sqlite3.connect(msg_db) as db:
|
||||||
db.row_factory = sqlite3.Row
|
db.row_factory = sqlite3.Row
|
||||||
messages(db, data, args.media, args.timezone_offset)
|
messages(db, data, args.media, args.timezone_offset, args.filter_date)
|
||||||
media(db, data, args.media)
|
media(db, data, args.media, args.filter_date)
|
||||||
vcard(db, data, args.media)
|
vcard(db, data, args.media, args.filter_date)
|
||||||
if args.android:
|
if args.android:
|
||||||
extract.calls(db, data, args.timezone_offset)
|
extract.calls(db, data, args.timezone_offset)
|
||||||
if not args.no_html:
|
if not args.no_html:
|
||||||
|
|||||||
@@ -165,18 +165,18 @@ def contacts(db, data):
|
|||||||
row = c.fetchone()
|
row = c.fetchone()
|
||||||
|
|
||||||
|
|
||||||
def messages(db, data, media_folder, timezone_offset):
|
def messages(db, data, media_folder, timezone_offset, range):
|
||||||
# Get message history
|
# Get message history
|
||||||
c = db.cursor()
|
c = db.cursor()
|
||||||
try:
|
try:
|
||||||
c.execute("""SELECT count() FROM messages""")
|
c.execute(f"""SELECT count() FROM messages {f'WHERE timestamp {range}' if range is not None else ''}""")
|
||||||
except sqlite3.OperationalError:
|
except sqlite3.OperationalError:
|
||||||
c.execute("""SELECT count() FROM message""")
|
c.execute(f"""SELECT count() FROM message {f'WHERE timestamp {range}' if range is not None else ''}""")
|
||||||
total_row_number = c.fetchone()[0]
|
total_row_number = c.fetchone()[0]
|
||||||
print(f"Processing messages...(0/{total_row_number})", end="\r")
|
print(f"Processing messages...(0/{total_row_number})", end="\r")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
c.execute("""SELECT messages.key_remote_jid,
|
c.execute(f"""SELECT messages.key_remote_jid,
|
||||||
messages._id,
|
messages._id,
|
||||||
messages.key_from_me,
|
messages.key_from_me,
|
||||||
messages.timestamp,
|
messages.timestamp,
|
||||||
@@ -226,12 +226,13 @@ def messages(db, data, media_folder, timezone_offset):
|
|||||||
LEFT JOIN receipt_user
|
LEFT JOIN receipt_user
|
||||||
ON receipt_user.message_row_id = messages._id
|
ON receipt_user.message_row_id = messages._id
|
||||||
WHERE messages.key_remote_jid <> '-1'
|
WHERE messages.key_remote_jid <> '-1'
|
||||||
|
{f'AND messages.timestamp {range}' if range is not None else ''}
|
||||||
GROUP BY messages._id
|
GROUP BY messages._id
|
||||||
ORDER BY messages.timestamp ASC;"""
|
ORDER BY messages.timestamp ASC;"""
|
||||||
)
|
)
|
||||||
except sqlite3.OperationalError:
|
except sqlite3.OperationalError:
|
||||||
try:
|
try:
|
||||||
c.execute("""SELECT jid_global.raw_string as key_remote_jid,
|
c.execute(f"""SELECT jid_global.raw_string as key_remote_jid,
|
||||||
message._id,
|
message._id,
|
||||||
message.from_me as key_from_me,
|
message.from_me as key_from_me,
|
||||||
message.timestamp,
|
message.timestamp,
|
||||||
@@ -291,6 +292,7 @@ def messages(db, data, media_folder, timezone_offset):
|
|||||||
LEFT JOIN receipt_user
|
LEFT JOIN receipt_user
|
||||||
ON receipt_user.message_row_id = message._id
|
ON receipt_user.message_row_id = message._id
|
||||||
WHERE key_remote_jid <> '-1'
|
WHERE key_remote_jid <> '-1'
|
||||||
|
{f'AND message.timestamp {range}' if range is not None else ''}
|
||||||
GROUP BY message._id;"""
|
GROUP BY message._id;"""
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -455,15 +457,26 @@ def messages(db, data, media_folder, timezone_offset):
|
|||||||
print(f"Processing messages...({total_row_number}/{total_row_number})", end="\r")
|
print(f"Processing messages...({total_row_number}/{total_row_number})", end="\r")
|
||||||
|
|
||||||
|
|
||||||
def media(db, data, media_folder):
|
def media(db, data, media_folder, range):
|
||||||
# Get media
|
# Get media
|
||||||
c = db.cursor()
|
c = db.cursor()
|
||||||
c.execute("""SELECT count() FROM message_media""")
|
try:
|
||||||
|
c.execute(f"""SELECT count()
|
||||||
|
FROM message_media
|
||||||
|
INNER JOIN messages
|
||||||
|
ON message_media.message_row_id = messages._id
|
||||||
|
{f'WHERE messages.timestamp {range}' if range is not None else ''}""")
|
||||||
|
except sqlite3.OperationalError:
|
||||||
|
c.execute(f"""SELECT count()
|
||||||
|
FROM message_media
|
||||||
|
INNER JOIN message
|
||||||
|
ON message_media.message_row_id = message._id
|
||||||
|
{f'WHERE message.timestamp {range}' if range is not None else ''}""")
|
||||||
total_row_number = c.fetchone()[0]
|
total_row_number = c.fetchone()[0]
|
||||||
print(f"\nProcessing media...(0/{total_row_number})", end="\r")
|
print(f"\nProcessing media...(0/{total_row_number})", end="\r")
|
||||||
i = 0
|
i = 0
|
||||||
try:
|
try:
|
||||||
c.execute("""SELECT messages.key_remote_jid,
|
c.execute(f"""SELECT messages.key_remote_jid,
|
||||||
message_row_id,
|
message_row_id,
|
||||||
file_path,
|
file_path,
|
||||||
message_url,
|
message_url,
|
||||||
@@ -477,10 +490,11 @@ def media(db, data, media_folder):
|
|||||||
LEFT JOIN media_hash_thumbnail
|
LEFT JOIN media_hash_thumbnail
|
||||||
ON message_media.file_hash = media_hash_thumbnail.media_hash
|
ON message_media.file_hash = media_hash_thumbnail.media_hash
|
||||||
WHERE jid.type <> 7
|
WHERE jid.type <> 7
|
||||||
|
{f'AND messages.timestamp {range}' if range is not None else ''}
|
||||||
ORDER BY messages.key_remote_jid ASC"""
|
ORDER BY messages.key_remote_jid ASC"""
|
||||||
)
|
)
|
||||||
except sqlite3.OperationalError:
|
except sqlite3.OperationalError:
|
||||||
c.execute("""SELECT jid.raw_string as key_remote_jid,
|
c.execute(f"""SELECT jid.raw_string as key_remote_jid,
|
||||||
message_row_id,
|
message_row_id,
|
||||||
file_path,
|
file_path,
|
||||||
message_url,
|
message_url,
|
||||||
@@ -498,6 +512,7 @@ def media(db, data, media_folder):
|
|||||||
LEFT JOIN media_hash_thumbnail
|
LEFT JOIN media_hash_thumbnail
|
||||||
ON message_media.file_hash = media_hash_thumbnail.media_hash
|
ON message_media.file_hash = media_hash_thumbnail.media_hash
|
||||||
WHERE jid.type <> 7
|
WHERE jid.type <> 7
|
||||||
|
{f'AND message.timestamp {range}' if range is not None else ''}
|
||||||
ORDER BY jid.raw_string ASC"""
|
ORDER BY jid.raw_string ASC"""
|
||||||
)
|
)
|
||||||
content = c.fetchone()
|
content = c.fetchone()
|
||||||
@@ -547,20 +562,21 @@ def media(db, data, media_folder):
|
|||||||
f"Processing media...({total_row_number}/{total_row_number})", end="\r")
|
f"Processing media...({total_row_number}/{total_row_number})", end="\r")
|
||||||
|
|
||||||
|
|
||||||
def vcard(db, data, media_folder):
|
def vcard(db, data, media_folder, range):
|
||||||
c = db.cursor()
|
c = db.cursor()
|
||||||
try:
|
try:
|
||||||
c.execute("""SELECT message_row_id,
|
c.execute(f"""SELECT message_row_id,
|
||||||
messages.key_remote_jid,
|
messages.key_remote_jid,
|
||||||
vcard,
|
vcard,
|
||||||
messages.media_name
|
messages.media_name
|
||||||
FROM messages_vcards
|
FROM messages_vcards
|
||||||
INNER JOIN messages
|
INNER JOIN messages
|
||||||
ON messages_vcards.message_row_id = messages._id
|
ON messages_vcards.message_row_id = messages._id
|
||||||
|
{f'WHERE messages.timestamp {range}' if range is not None else ''}
|
||||||
ORDER BY messages.key_remote_jid ASC;"""
|
ORDER BY messages.key_remote_jid ASC;"""
|
||||||
)
|
)
|
||||||
except sqlite3.OperationalError:
|
except sqlite3.OperationalError:
|
||||||
c.execute("""SELECT message_row_id,
|
c.execute(f"""SELECT message_row_id,
|
||||||
jid.raw_string as key_remote_jid,
|
jid.raw_string as key_remote_jid,
|
||||||
vcard,
|
vcard,
|
||||||
message.text_data as media_name
|
message.text_data as media_name
|
||||||
@@ -571,6 +587,7 @@ def vcard(db, data, media_folder):
|
|||||||
ON chat._id = message.chat_row_id
|
ON chat._id = message.chat_row_id
|
||||||
INNER JOIN jid
|
INNER JOIN jid
|
||||||
ON jid._id = chat.jid_row_id
|
ON jid._id = chat.jid_row_id
|
||||||
|
{f'WHERE message.timestamp {range}' if range is not None else ''}
|
||||||
ORDER BY message.chat_row_id ASC;"""
|
ORDER BY message.chat_row_id ASC;"""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
12
Whatsapp_Chat_Exporter/filter.html
Normal file
12
Whatsapp_Chat_Exporter/filter.html
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="refresh" content="0; url='https://github.com/KnugiHK/WhatsApp-Chat-Exporter/wiki/Filters'" />
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.location.href = "https://github.com/KnugiHK/WhatsApp-Chat-Exporter/wiki/Filters"
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>If the redirection doesn't work, you can find the documentation on filters at <a href="https://github.com/KnugiHK/WhatsApp-Chat-Exporter/wiki/Filters">https://github.com/KnugiHK/WhatsApp-Chat-Exporter/wiki/Filters</a>.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user