22 Commits
0.8.0 ... 0.8.5

Author SHA1 Message Date
KnugiHK
77ceaa25dd Bump version 2023-01-31 17:52:34 +08:00
KnugiHK
e09f18e2f2 Minor fix 2023-01-31 17:52:12 +08:00
KnugiHK
23114572bd Forgot to change the variable lol 2023-01-31 17:52:12 +08:00
KnugiHK
2f04b69f38 A more concrete way to determine database offset 2023-01-31 17:52:12 +08:00
KnugiHK
e7c246822b Link to the file intead of showing the path directly
Not tested
Ref: https://github.com/KnugiHK/Whatsapp-Chat-Exporter/issues/15
2023-01-31 17:52:12 +08:00
KnugiHK
2a215d024f Bug fix
Duplicated folder creation
https://github.com/KnugiHK/Whatsapp-Chat-Exporter/issues/14
2023-01-31 17:52:12 +08:00
KnugiHK
f267f53007 Remove unused dependencies 2023-01-31 17:52:12 +08:00
KnugiHK
3a30dfc800 Bump version 2023-01-31 17:52:12 +08:00
Knugi
580eaddb24 Delete old_README.md 2022-10-24 03:59:42 +00:00
Knugi
77b4b784d3 Update README.md 2022-10-24 03:59:24 +00:00
KnugiHK
507e88d9c3 Merge branch 'dev' 2022-05-09 18:31:03 +08:00
KnugiHK
60e1e7d3eb Bump version 2022-05-09 18:28:13 +08:00
Knugi
774fb6d781 Merge pull request #11 from asla9709/dev
Fixed bug where blank VCard media_name would crash the program.
2022-05-09 10:03:04 +00:00
Aakif Aslam
3ef3b02230 Fixed bug where blank VCard media_name would crash the program. 2022-04-24 18:01:32 -04:00
Knugi
07cc0f3571 Update README.md 2022-04-04 07:57:12 +00:00
KnugiHK
a1319eb835 Exclude default conversation from results 2022-04-01 17:17:43 +08:00
KnugiHK
8cbb0af43a Oh. I missed this change 2022-03-04 14:06:19 +08:00
KnugiHK
28c4a7b99f Prepare for new function 2022-03-04 14:03:15 +08:00
KnugiHK
e4c9d42927 Update __init__.py 2022-03-04 13:48:12 +08:00
KnugiHK
c274b6b1c0 Merge branch 'dev' 2022-03-04 13:47:54 +08:00
KnugiHK
eec739d7cf Add crypt15 dependency to android_backup 2022-03-04 13:47:17 +08:00
Knugi
3d7dca0682 Delete _config.yml 2022-02-25 08:57:31 +00:00
10 changed files with 31 additions and 55 deletions

View File

@@ -7,7 +7,9 @@ A customizable Android and iPhone Whatsapp database parser that will give you th
**If you plan to uninstall WhatsApp or delete your WhatsApp account, please make a backup of your WhatsApp database. You may want to use this exporter again on the same database in the future as the exporter develops** **If you plan to uninstall WhatsApp or delete your WhatsApp account, please make a backup of your WhatsApp database. You may want to use this exporter again on the same database in the future as the exporter develops**
# Usage # Usage
**If you want to use the old release (< 0.5) of the exporter, please follow the [old usage guide](https://github.com/KnugiHK/Whatsapp-Chat-Exporter/blob/main/old_README.md#usage)** **Usage in README may be removed in the future. Check the usage in [Wiki](https://github.com/KnugiHK/Whatsapp-Chat-Exporter/wiki)**.
**If you want to use the old release (< 0.5) of the exporter, please follow the [old usage guide](https://github.com/KnugiHK/Whatsapp-Chat-Exporter/wiki/Old-Usage#usage)**.
First, install the exporter by: First, install the exporter by:
```shell ```shell

View File

@@ -1 +1 @@
__version__ = "0.8.0" __version__ = "0.8.5"

View File

@@ -78,6 +78,13 @@ def main():
dest="template", dest="template",
default=None, default=None,
help="Path to custom HTML template") help="Path to custom HTML template")
parser.add_option(
"-e",
"--embedded",
dest="embedded",
default=False,
action='store_true',
help="Embed media into HTML file")
(options, args) = parser.parse_args() (options, args) = parser.parse_args()
if options.android and options.iphone: if options.android and options.iphone:
@@ -167,7 +174,7 @@ def main():
messages(db, data) messages(db, data)
media(db, data, options.media) media(db, data, options.media)
vcard(db, data) vcard(db, data)
create_html(data, options.output, options.template) create_html(data, options.output, options.template, options.embedded)
else: else:
print( print(
"The message database does not exist. You may specify the path " "The message database does not exist. You may specify the path "

View File

@@ -4,10 +4,8 @@ import sqlite3
import json import json
import jinja2 import jinja2
import os import os
import requests
import shutil import shutil
import re import re
import pkgutil
import io import io
import hmac import hmac
from pathlib import Path from pathlib import Path
@@ -114,7 +112,8 @@ def decrypt_backup(database, key, output, crypt=Crypt.CRYPT14):
raise ValueError("The crypt15 file must be at least 131 bytes") raise ValueError("The crypt15 file must be at least 131 bytes")
t1 = t2 = None t1 = t2 = None
iv = database[8:24] iv = database[8:24]
db_ciphertext = database[131:] db_offset = database[0] + 2 # Skip protobuf + protobuf size and backup type
db_ciphertext = database[db_offset:]
if t1 != t2: if t1 != t2:
raise ValueError("The signature of key file and backup file mismatch") raise ValueError("The signature of key file and backup file mismatch")
@@ -215,7 +214,8 @@ def messages(db, data):
messages.media_caption messages.media_caption
FROM messages FROM messages
LEFT JOIN messages_quotes LEFT JOIN messages_quotes
ON messages.quoted_row_id = messages_quotes._id;""") ON messages.quoted_row_id = messages_quotes._id
WHERE messages.key_remote_jid <> '-1';""")
i = 0 i = 0
content = c.fetchone() content = c.fetchone()
while content is not None: while content is not None:
@@ -414,12 +414,13 @@ def vcard(db, data):
if not os.path.isdir(base): if not os.path.isdir(base):
Path(base).mkdir(parents=True, exist_ok=True) Path(base).mkdir(parents=True, exist_ok=True)
for index, row in enumerate(rows): for index, row in enumerate(rows):
file_name = "".join(x for x in row[3] if x.isalnum()) media_name = row[3] if row[3] else ""
file_name = "".join(x for x in media_name if x.isalnum())
file_path = f"{base}/{file_name}.vcf" file_path = f"{base}/{file_name}.vcf"
if not os.path.isfile(file_path): if not os.path.isfile(file_path):
with open(file_path, "w", encoding="utf-8") as f: with open(file_path, "w", encoding="utf-8") as f:
f.write(row[2]) f.write(row[2])
data[row[1]]["messages"][row[0]]["data"] = row[3] + \ data[row[1]]["messages"][row[0]]["data"] = media_name + \
"The vCard file cannot be displayed here, " \ "The vCard file cannot be displayed here, " \
f"however it should be located at {file_path}" f"however it should be located at {file_path}"
data[row[1]]["messages"][row[0]]["mime"] = "text/x-vcard" data[row[1]]["messages"][row[0]]["mime"] = "text/x-vcard"
@@ -427,7 +428,7 @@ def vcard(db, data):
print(f"Gathering vCards...({index + 1}/{total_row_number})", end="\r") print(f"Gathering vCards...({index + 1}/{total_row_number})", end="\r")
def create_html(data, output_folder, template=None): def create_html(data, output_folder, template=None, embedded=False):
if template is None: if template is None:
template_dir = os.path.dirname(__file__) template_dir = os.path.dirname(__file__)
template_file = "whatsapp.html" template_file = "whatsapp.html"

View File

@@ -4,9 +4,7 @@ import sqlite3
import json import json
import jinja2 import jinja2
import os import os
import requests
import shutil import shutil
import pkgutil
from pathlib import Path from pathlib import Path
from bleach import clean as sanitize from bleach import clean as sanitize
from markupsafe import Markup from markupsafe import Markup
@@ -230,7 +228,7 @@ def vcard(db, data):
print(f"Gathering vCards...({index + 1}/{total_row_number})", end="\r") print(f"Gathering vCards...({index + 1}/{total_row_number})", end="\r")
def create_html(data, output_folder, template=None): def create_html(data, output_folder, template=None, embedded=False):
if template is None: if template is None:
template_dir = os.path.dirname(__file__) template_dir = os.path.dirname(__file__)
template_file = "whatsapp.html" template_file = "whatsapp.html"

View File

@@ -115,7 +115,10 @@ def extract_media(base_dir):
folder = hashes[:2] folder = hashes[:2]
flags = row[2] flags = row[2]
if flags == 2: if flags == 2:
os.mkdir(destination) try:
os.mkdir(destination)
except FileExistsError:
pass
elif flags == 1: elif flags == 1:
shutil.copyfile(f"{base_dir}/{folder}/{hashes}", destination) shutil.copyfile(f"{base_dir}/{folder}/{hashes}", destination)
i += 1 i += 1

View File

@@ -92,7 +92,7 @@
</video> </video>
{% elif "/" in msg.mime %} {% elif "/" in msg.mime %}
<div style="text-align: center;" class="w3-panel w3-border-blue w3-pale-blue w3-rightbar w3-leftbar"> <div style="text-align: center;" class="w3-panel w3-border-blue w3-pale-blue w3-rightbar w3-leftbar">
<p>The file cannot be displayed here, however it should be located at {{ msg.data }}</p> <p>The file cannot be displayed here, however it should be located at <a href="./{{ msg.data }}">here</a></p>
</div> </div>
{% else %} {% else %}
{% filter escape %}{{ msg.data }}{% endfilter %} {% filter escape %}{{ msg.data }}{% endfilter %}
@@ -148,7 +148,7 @@
</video> </video>
{% elif "/" in msg.mime %} {% elif "/" in msg.mime %}
<div style="text-align: center;" class="w3-panel w3-border-blue w3-pale-blue w3-rightbar w3-leftbar"> <div style="text-align: center;" class="w3-panel w3-border-blue w3-pale-blue w3-rightbar w3-leftbar">
<p>The file cannot be displayed here, however it should be located at {{ msg.data }}</p> <p>The file cannot be displayed here, however it should be located at <a href="./{{ msg.data }}">here</a></p>
</div> </div>
{% else %} {% else %}
{% filter escape %}{{ msg.data }}{% endfilter %} {% filter escape %}{{ msg.data }}{% endfilter %}

View File

@@ -1 +0,0 @@
theme: jekyll-theme-cayman

View File

@@ -1,34 +0,0 @@
# Whatsapp-Chat-Exporter
A Whatsapp database parser that will give you the history of your Whatsapp conversations in HTML and JSON
**If you plan to uninstall WhatsApp or delete your WhatsApp account, please make a backup of your WhatsApp database. You may want to use this exporter again on the same database in the future as the exporter develops**
# Usage
First, clone this repo, and copy all py and html files to a working directory if you want to do so.
```shell
git clone https://github.com/KnugiHK/Whatsapp-Chat-Exporter.git
```
Then, ready your WhatsApp database, place them in the root of working directory.
* For Android, it is called msgstore.db. If you want name of your contacts, get the contact database, which is called wa.db.
* For iPhone, it is called 7c7fba66680ef796b916b067077cc246adacf01d (YES, a hash).
Next, ready your media folder, place it in the root of working directory.
* For Android, copy the WhatsApp directory from your phone directly.
* For iPhone, run the extract_iphone_media.py, and you will get a folder called Message.
```
python extract_iphone_media.py "C:\Users\[Username]\AppData\Roaming\Apple Computer\MobileSync\Backup\[device id]"
```
And now, you should have something like this:
![Folder structure](imgs/structure.png)
Last, run the script regarding the type of phone.
```
python extract.py & :: Android
python extract_iphone.py & :: iPhone
```
And you will get these:
#### Private Message
![Private Message](imgs/pm.png)
#### Group Message
![Group Message](imgs/group.png)

View File

@@ -37,13 +37,13 @@ setuptools.setup(
], ],
python_requires='>=3.7', python_requires='>=3.7',
install_requires=[ install_requires=[
'jinja2', 'jinja2',
'bleach' 'bleach'
], ],
extras_require={ extras_require={
'android_backup': ["pycryptodome"], 'android_backup': ["pycryptodome", "javaobj-py3"],
'crypt12': ["pycryptodome"],
'crypt12': ["pycryptodome"], 'crypt12': ["pycryptodome"],
'crypt14': ["pycryptodome"],
'crypt15': ["pycryptodome", "javaobj-py3"] 'crypt15': ["pycryptodome", "javaobj-py3"]
}, },
entry_points={ entry_points={