Comply with PEP8 with some exception

E501 and F401 are not fully enforced
This commit is contained in:
KnugiHK
2021-01-18 15:55:21 +08:00
parent cfb180220c
commit 1d614eafb7
3 changed files with 217 additions and 108 deletions

View File

@@ -1,11 +1,9 @@
#!/usr/bin/python3
import sqlite3
import sys
import json
import jinja2
import os
import base64
import requests
import shutil
import re
@@ -21,6 +19,7 @@ def determine_day(last, current):
else:
return current
def contacts(db, data):
# Get contacts
c = db.cursor()
@@ -31,9 +30,10 @@ def contacts(db, data):
c.execute("""SELECT jid, display_name FROM wa_contacts; """)
row = c.fetchone()
while row is not None:
data[row[0]] = {"name": row[1], "messages":{}}
data[row[0]] = {"name": row[1], "messages": {}}
row = c.fetchone()
def messages(db, data):
# Get message history
c = db.cursor()
@@ -42,7 +42,25 @@ def messages(db, data):
print(f"Gathering messages...(0/{total_row_number})", end="\r")
phone_number_re = re.compile(r"[0-9]+@s.whatsapp.net")
c.execute("""SELECT messages.key_remote_jid, messages._id, messages.key_from_me, messages.timestamp, messages.data, messages.status, messages.edit_version, messages.thumb_image, messages.remote_resource, messages.media_wa_type, messages.latitude, messages.longitude, messages_quotes.key_id as quoted, messages.key_id, messages_quotes.data, messages.media_caption FROM messages LEFT JOIN messages_quotes ON messages.quoted_row_id = messages_quotes._id; """)
c.execute("""SELECT messages.key_remote_jid,
messages._id,
messages.key_from_me,
messages.timestamp,
messages.data,
messages.status,
messages.edit_version,
messages.thumb_image,
messages.remote_resource,
messages.media_wa_type,
messages.latitude,
messages.longitude,
messages_quotes.key_id as quoted,
messages.key_id,
messages_quotes.data,
messages.media_caption
FROM messages
LEFT JOIN messages_quotes
ON messages.quoted_row_id = messages_quotes._id;""")
i = 0
content = c.fetchone()
while content is not None:
@@ -65,30 +83,33 @@ def messages(db, data):
fallback = None
else:
fallback = None
data[content[0]]["messages"][content[1]]["sender"] = name or fallback
data[content[0]]["messages"][content[1]
]["sender"] = name or fallback
else:
data[content[0]]["messages"][content[1]]["sender"] = None
if content[12] is not None:
data[content[0]]["messages"][content[1]]["reply"] = content[12]
data[content[0]]["messages"][content[1]]["quoted_data"] = content[14]
data[content[0]]["messages"][content[1]
]["quoted_data"] = content[14]
else:
data[content[0]]["messages"][content[1]]["reply"] = None
if content[15] is not None:
data[content[0]]["messages"][content[1]]["caption"] = content[15]
else:
data[content[0]]["messages"][content[1]]["caption"] = None
if content[5] == 6:
if "-" in content[0]:
# Is Group
if content[4] is not None:
try:
int(content[4])
except:
data[content[0]]["messages"][content[1]]["data"] = "{The group name changed to "f"{content[4]}"" }"
except ValueError:
msg = "{The group name changed to "f"{content[4]}"" }"
data[content[0]]["messages"][content[1]]["data"] = msg
else:
del data[content[0]]["messages"][content[1]]
else:
@@ -96,7 +117,8 @@ def messages(db, data):
if thumb_image is not None:
if b"\x00\x00\x01\x74\x00\x1A" in thumb_image:
# Add user
added = phone_number_re.search(thumb_image.decode("unicode_escape"))[0]
added = phone_number_re.search(
thumb_image.decode("unicode_escape"))[0]
if added in data:
name_right = data[added]["name"]
else:
@@ -106,14 +128,15 @@ def messages(db, data):
name_left = data[content[8]]["name"]
else:
name_left = content[8].split('@')[0]
data[content[0]]["messages"][content[1]]["data"] = "{"f"{name_left}"f" added {name_right or 'You'}""}"
msg = "{"f"{name_left}"f" added {name_right or 'You'}""}"
else:
data[content[0]]["messages"][content[1]]["data"] = "{"f"Added {name_right or 'You'}""}"
if b"\xac\xed\x00\x05\x74\x00" in thumb_image:
msg = "{"f"Added {name_right or 'You'}""}"
elif b"\xac\xed\x00\x05\x74\x00" in thumb_image:
# Changed number
original = content[8].split('@')[0]
changed = thumb_image[7:].decode().split('@')[0]
data[content[0]]["messages"][content[1]]["data"] = "{"f"{original} changed to {changed}""}"
msg = "{"f"{original} changed to {changed}""}"
data[content[0]]["messages"][content[1]]["data"] = msg
else:
if content[4] is None:
del data[content[0]]["messages"][content[1]]
@@ -121,30 +144,34 @@ def messages(db, data):
# Private chat
if content[4] is None and content[7] is None:
del data[content[0]]["messages"][content[1]]
else:
if content[2] == 1:
if content[5] == 5 and content[6] == 7:
data[content[0]]["messages"][content[1]]["data"] = "{Message deleted}"
msg = "{Message deleted}"
else:
if content[9] == "5":
data[content[0]]["messages"][content[1]]["data"] = "{ Location shared: "f"{content[10], content[11]}"" }"
msg = "{ Location shared: "f"{content[10], content[11]}"" }"
else:
data[content[0]]["messages"][content[1]]["data"] = content[4]
msg = content[4]
else:
if content[5] == 0 and content[6] == 7:
data[content[0]]["messages"][content[1]]["data"] = "{Message deleted}"
msg = "{Message deleted}"
else:
if content[9] == "5":
data[content[0]]["messages"][content[1]]["data"] = "{ Location shared: "f"{content[10], content[11]}"" }"
msg = "{ Location shared: "f"{content[10], content[11]}"" }"
else:
data[content[0]]["messages"][content[1]]["data"] = content[4]
msg = content[4]
data[content[0]]["messages"][content[1]]["data"] = msg
i += 1
if i % 1000 == 0:
print(f"Gathering messages...({i}/{total_row_number})", end="\r")
content = c.fetchone()
print(f"Gathering messages...({total_row_number}/{total_row_number})", end="\r")
print(
f"Gathering messages...({total_row_number}/{total_row_number})", end="\r")
def media(db, data, media_folder):
# Get media
@@ -153,7 +180,16 @@ def media(db, data, media_folder):
total_row_number = c.fetchone()[0]
print(f"\nGathering media...(0/{total_row_number})", end="\r")
i = 0
c.execute("""SELECT messages.key_remote_jid, message_row_id, file_path, message_url, mime_type, media_key FROM message_media INNER JOIN messages ON message_media.message_row_id = messages._id ORDER BY messages.key_remote_jid ASC""")
c.execute("""SELECT messages.key_remote_jid,
message_row_id,
file_path,
message_url,
mime_type,
media_key
FROM message_media
INNER JOIN messages
ON message_media.message_row_id = messages._id
ORDER BY messages.key_remote_jid ASC""")
content = c.fetchone()
mime = MimeTypes()
while content is not None:
@@ -171,26 +207,36 @@ def media(db, data, media_folder):
data[content[0]]["messages"][content[1]]["mime"] = content[4]
else:
# if "https://mmg" in content[4]:
# try:
# r = requests.get(content[3])
# if r.status_code != 200:
# raise RuntimeError()
# except:
# data[content[0]]["messages"][content[1]]["data"] = "{The media is missing}"
# data[content[0]]["messages"][content[1]]["media"] = True
# data[content[0]]["messages"][content[1]]["mime"] = "media"
# try:
# r = requests.get(content[3])
# if r.status_code != 200:
# raise RuntimeError()
# except:
# data[content[0]]["messages"][content[1]]["data"] = "{The media is missing}"
# data[content[0]]["messages"][content[1]]["media"] = True
# data[content[0]]["messages"][content[1]]["mime"] = "media"
# else:
data[content[0]]["messages"][content[1]]["data"] = "{The media is missing}"
data[content[0]]["messages"][content[1]
]["data"] = "{The media is missing}"
data[content[0]]["messages"][content[1]]["mime"] = "media"
i += 1
if i % 100 == 0:
print(f"Gathering media...({i}/{total_row_number})", end="\r")
content = c.fetchone()
print(f"Gathering media...({total_row_number}/{total_row_number})", end="\r")
print(
f"Gathering media...({total_row_number}/{total_row_number})", end="\r")
def vcard(db, data):
c = db.cursor()
c.execute("""SELECT message_row_id, messages.key_remote_jid, vcard, messages.media_name FROM messages_vcards INNER JOIN messages ON messages_vcards.message_row_id = messages._id ORDER BY messages.key_remote_jid ASC""")
c.execute("""SELECT message_row_id,
messages.key_remote_jid,
vcard,
messages.media_name
FROM messages_vcards
INNER JOIN messages
ON messages_vcards.message_row_id = messages._id
ORDER BY messages.key_remote_jid ASC;""")
rows = c.fetchall()
total_row_number = len(rows)
print(f"\nGathering vCards...(0/{total_row_number})", end="\r")
@@ -203,10 +249,13 @@ def vcard(db, data):
if not os.path.isfile(file_path):
with open(file_path, "w", encoding="utf-8") as f:
f.write(row[2])
data[row[1]]["messages"][row[0]]["data"] = row[3] + "{ The vCard file cannot be displayed here, however it should be located at " + file_path + "}"
data[row[1]]["messages"][row[0]]["data"] = row[3] + \
"{ The vCard file cannot be displayed here, however it " \
"should be located at " + file_path + "}"
data[row[1]]["messages"][row[0]]["mime"] = "x-vcard"
print(f"Gathering vCards...({index + 1}/{total_row_number})", end="\r")
def create_html(data, output_folder):
templateLoader = jinja2.FileSystemLoader(searchpath="./")
templateEnv = jinja2.Environment(loader=templateLoader)
@@ -224,11 +273,11 @@ def create_html(data, output_folder):
if len(data[i]["messages"]) == 0:
continue
phone_number = i.split('@')[0]
if "-"in i:
if "-" in i:
file_name = ""
else:
file_name = phone_number
if data[i]["name"] is not None:
if file_name != "":
file_name += "-"
@@ -237,12 +286,14 @@ def create_html(data, output_folder):
else:
name = phone_number
safe_file_name = ''
safe_file_name = "".join(x for x in file_name if x.isalnum() or x in "- ")
safe_file_name = "".join(
x for x in file_name if x.isalnum() or x in "- ")
with open(f"{output_folder}/{safe_file_name}.html", "w", encoding="utf-8") as f:
f.write(template.render(name=name, msgs=data[i]["messages"].values(), my_avatar=None, their_avatar=f"WhatsApp/Avatars/{i}.j"))
f.write(template.render(name=name, msgs=data[i]["messages"].values(
), my_avatar=None, their_avatar=f"WhatsApp/Avatars/{i}.j"))
if current % 10 == 0:
print(f"Creating HTML...({current}/{total_row_number})", end="\r")
print(f"Creating HTML...({total_row_number}/{total_row_number})", end="\r")
@@ -267,7 +318,7 @@ if __name__ == "__main__":
# "--template",
# dest="html",
# default="wa.db",
# help="Path to HTML template")
# help="Path to HTML template")
(options, args) = parser.parse_args()
msg_db = "msgstore.db"
output_folder = "temp"
@@ -279,7 +330,7 @@ if __name__ == "__main__":
elif len(args) == 2:
msg_db = args[0]
output_folder = args[1]
data = {}
if os.path.isfile(contact_db):

View File

@@ -1,17 +1,16 @@
#!/usr/bin/python3
import sqlite3
import sys
import json
import jinja2
import os
import base64
import requests
import shutil
from datetime import datetime
from mimetypes import MimeTypes
APPLE_TIME = datetime.timestamp(datetime(2001,1,1))
APPLE_TIME = datetime.timestamp(datetime(2001, 1, 1))
def determine_day(last, current):
last = datetime.fromtimestamp(last).date()
@@ -21,6 +20,7 @@ def determine_day(last, current):
else:
return current
def messages(db, data):
c = db.cursor()
# Get contacts
@@ -31,7 +31,7 @@ def messages(db, data):
c.execute("""SELECT ZCONTACTJID, ZPARTNERNAME FROM ZWACHATSESSION; """)
row = c.fetchone()
while row is not None:
data[row[0]] = {"name": row[1], "messages":{}}
data[row[0]] = {"name": row[1], "messages": {}}
row = c.fetchone()
# Get message history
@@ -39,7 +39,16 @@ def messages(db, data):
total_row_number = c.fetchone()[0]
print(f"Gathering messages...(0/{total_row_number})", end="\r")
c.execute("""SELECT COALESCE(ZFROMJID, ZTOJID), ZWAMESSAGE.Z_PK, ZISFROMME, ZMESSAGEDATE, ZTEXT, ZMESSAGETYPE, ZWAGROUPMEMBER.ZMEMBERJID FROM main.ZWAMESSAGE LEFT JOIN main.ZWAGROUPMEMBER ON main.ZWAMESSAGE.ZGROUPMEMBER = main.ZWAGROUPMEMBER.Z_PK;""")
c.execute("""SELECT COALESCE(ZFROMJID, ZTOJID),
ZWAMESSAGE.Z_PK,
ZISFROMME,
ZMESSAGEDATE,
ZTEXT,
ZMESSAGETYPE,
ZWAGROUPMEMBER.ZMEMBERJID
FROM main.ZWAMESSAGE
LEFT JOIN main.ZWAGROUPMEMBER
ON main.ZWAMESSAGE.ZGROUPMEMBER = main.ZWAGROUPMEMBER.Z_PK;""")
i = 0
content = c.fetchone()
while content is not None:
@@ -65,7 +74,8 @@ def messages(db, data):
fallback = None
else:
fallback = None
data[content[0]]["messages"][content[1]]["sender"] = name or fallback
data[content[0]]["messages"][content[1]
]["sender"] = name or fallback
else:
data[content[0]]["messages"][content[1]]["sender"] = None
if content[5] == 6:
@@ -76,8 +86,9 @@ def messages(db, data):
# Chnaged name
try:
int(content[4])
except:
data[content[0]]["messages"][content[1]]["data"] = "{The group name changed to "f"{content[4]}"" }"
except ValueError:
msg = "{The group name changed to "f"{content[4]}"" }"
data[content[0]]["messages"][content[1]]["data"] = msg
else:
del data[content[0]]["messages"][content[1]]
else:
@@ -88,21 +99,23 @@ def messages(db, data):
# real message
if content[2] == 1:
if content[5] == 14:
data[content[0]]["messages"][content[1]]["data"] = "{Message deleted}"
msg = "{Message deleted}"
else:
data[content[0]]["messages"][content[1]]["data"] = content[4]
msg = content[4]
else:
if content[5] == 14:
data[content[0]]["messages"][content[1]]["data"] = "{Message deleted}"
msg = "{Message deleted}"
else:
data[content[0]]["messages"][content[1]]["data"] = content[4]
msg = content[4]
data[content[0]]["messages"][content[1]]["data"] = msg
i += 1
if i % 1000 == 0:
print(f"Gathering messages...({i}/{total_row_number})", end="\r")
content = c.fetchone()
print(f"Gathering messages...({total_row_number}/{total_row_number})", end="\r")
print(
f"Gathering messages...({total_row_number}/{total_row_number})", end="\r")
def media(db, data, media_folder):
c = db.cursor()
# Get media
@@ -110,13 +123,24 @@ def media(db, data, media_folder):
total_row_number = c.fetchone()[0]
print(f"\nGathering media...(0/{total_row_number})", end="\r")
i = 0
c.execute("""SELECT COALESCE(ZWAMESSAGE.ZFROMJID, ZWAMESSAGE.ZTOJID) as _id, ZMESSAGE, ZMEDIALOCALPATH, ZMEDIAURL, ZVCARDSTRING, ZMEDIAKEY, ZTITLE FROM ZWAMEDIAITEM INNER JOIN ZWAMESSAGE ON ZWAMEDIAITEM.ZMESSAGE = ZWAMESSAGE.Z_PK WHERE ZMEDIALOCALPATH IS NOT NULL ORDER BY _id ASC""")
c.execute("""SELECT COALESCE(ZWAMESSAGE.ZFROMJID, ZWAMESSAGE.ZTOJID) as _id,
ZMESSAGE,
ZMEDIALOCALPATH,
ZMEDIAURL,
ZVCARDSTRING,
ZMEDIAKEY,
ZTITLE
FROM ZWAMEDIAITEM
INNER JOIN ZWAMESSAGE
ON ZWAMEDIAITEM.ZMESSAGE = ZWAMESSAGE.Z_PK
WHERE ZMEDIALOCALPATH IS NOT NULL
ORDER BY _id ASC""")
content = c.fetchone()
mime = MimeTypes()
while content is not None:
file_path = f"Message/{content[2]}"
data[content[0]]["messages"][content[1]]["media"] = True
if os.path.isfile(file_path):
data[content[0]]["messages"][content[1]]["data"] = file_path
if content[4] is None:
@@ -129,15 +153,16 @@ def media(db, data, media_folder):
data[content[0]]["messages"][content[1]]["mime"] = content[4]
else:
# if "https://mmg" in content[4]:
# try:
# r = requests.get(content[3])
# if r.status_code != 200:
# raise RuntimeError()
# except:
# data[content[0]]["messages"][content[1]]["data"] = "{The media is missing}"
# data[content[0]]["messages"][content[1]]["mime"] = "media"
# try:
# r = requests.get(content[3])
# if r.status_code != 200:
# raise RuntimeError()
# except:
# data[content[0]]["messages"][content[1]]["data"] = "{The media is missing}"
# data[content[0]]["messages"][content[1]]["mime"] = "media"
# else:
data[content[0]]["messages"][content[1]]["data"] = "{The media is missing}"
data[content[0]]["messages"][content[1]
]["data"] = "{The media is missing}"
data[content[0]]["messages"][content[1]]["mime"] = "media"
if content[6] is not None:
data[content[0]]["messages"][content[1]]["caption"] = content[6]
@@ -145,11 +170,23 @@ def media(db, data, media_folder):
if i % 100 == 0:
print(f"Gathering media...({i}/{total_row_number})", end="\r")
content = c.fetchone()
print(f"Gathering media...({total_row_number}/{total_row_number})", end="\r")
print(
f"Gathering media...({total_row_number}/{total_row_number})", end="\r")
def vcard(db, data):
c = db.cursor()
c.execute("""SELECT DISTINCT ZWAVCARDMENTION.ZMEDIAITEM, ZWAMEDIAITEM.ZMESSAGE, COALESCE(ZWAMESSAGE.ZFROMJID, ZWAMESSAGE.ZTOJID) as _id, ZVCARDNAME, ZVCARDSTRING FROM ZWAVCARDMENTION INNER JOIN ZWAMEDIAITEM ON ZWAVCARDMENTION.ZMEDIAITEM = ZWAMEDIAITEM.Z_PK INNER JOIN ZWAMESSAGE ON ZWAMEDIAITEM.ZMESSAGE = ZWAMESSAGE.Z_PK""")
c.execute("""SELECT DISTINCT ZWAVCARDMENTION.ZMEDIAITEM,
ZWAMEDIAITEM.ZMESSAGE,
COALESCE(ZWAMESSAGE.ZFROMJID,
ZWAMESSAGE.ZTOJID) as _id,
ZVCARDNAME,
ZVCARDSTRING
FROM ZWAVCARDMENTION
INNER JOIN ZWAMEDIAITEM
ON ZWAVCARDMENTION.ZMEDIAITEM = ZWAMEDIAITEM.Z_PK
INNER JOIN ZWAMESSAGE
ON ZWAMEDIAITEM.ZMESSAGE = ZWAMESSAGE.Z_PK""")
rows = c.fetchall()
total_row_number = len(rows)
print(f"\nGathering vCards...(0/{total_row_number})", end="\r")
@@ -162,11 +199,14 @@ def vcard(db, data):
if not os.path.isfile(file_path):
with open(file_path, "w", encoding="utf-8") as f:
f.write(row[4])
data[row[2]]["messages"][row[1]]["data"] = row[3] + "{ The vCard file cannot be displayed here, however it should be located at " + file_path + "}"
data[row[2]]["messages"][row[1]]["data"] = row[3] + \
"{ The vCard file cannot be displayed here, however it " \
"should be located at " + file_path + "}"
data[row[2]]["messages"][row[1]]["mime"] = "x-vcard"
data[row[2]]["messages"][row[1]]["media"] = True
print(f"Gathering vCards...({index + 1}/{total_row_number})", end="\r")
def create_html(data, output_folder):
templateLoader = jinja2.FileSystemLoader(searchpath="./")
templateEnv = jinja2.Environment(loader=templateLoader)
@@ -184,11 +224,11 @@ def create_html(data, output_folder):
if len(data[i]["messages"]) == 0:
continue
phone_number = i.split('@')[0]
if "-"in i:
if "-" in i:
file_name = ""
else:
file_name = phone_number
if data[i]["name"] is not None:
if file_name != "":
file_name += "-"
@@ -196,16 +236,18 @@ def create_html(data, output_folder):
name = data[i]["name"]
else:
name = phone_number
safe_file_name = ''
safe_file_name = "".join(x for x in file_name if x.isalnum() or x in "- ")
with open(f"{output_folder}/{safe_file_name}.html", "w", encoding="utf-8") as f:
f.write(template.render(name=name, msgs=data[i]["messages"].values(), my_avatar=None, their_avatar=f"WhatsApp/Avatars/{i}.j"))
f.write(template.render(name=name, msgs=data[i]["messages"].values(
), my_avatar=None, their_avatar=f"WhatsApp/Avatars/{i}.j"))
if current % 10 == 0:
print(f"Creating HTML...({current}/{total_row_number})", end="\r")
print(f"Creating HTML...({total_row_number}/{total_row_number})", end="\r")
if __name__ == "__main__":
from optparse import OptionParser
parser = OptionParser()
@@ -227,7 +269,7 @@ if __name__ == "__main__":
# "--template",
# dest="html",
# default="wa.db",
# help="Path to HTML template")
# help="Path to HTML template")
(options, args) = parser.parse_args()
msg_db = "7c7fba66680ef796b916b067077cc246adacf01d"
output_folder = "temp"
@@ -239,7 +281,7 @@ if __name__ == "__main__":
elif len(args) == 2:
msg_db = args[0]
output_folder = args[1]
data = {}
if os.path.isfile(msg_db):

View File

@@ -4,30 +4,46 @@ import shutil
import sqlite3
import os
manifest = sqlite3.connect(f"{sys.argv[2]}/Manifest.db")
c = manifest.cursor()
c.execute("""SELECT count() FROM Files WHERE relativePath LIKE 'Message/Media/%'""")
total_row_number = c.fetchone()[0]
print(f"Gathering media...(0/{total_row_number})", end="\r")
c.execute("""SELECT fileID, relativePath, flags FROM Files WHERE relativePath LIKE 'Message/Media/%'""")
row = c.fetchone()
if not os.path.isdir("Message"):
os.mkdir("Message")
if not os.path.isdir("Message/Media"):
os.mkdir("Message/Media")
i = 0
while row is not None:
destination = row[1]
hashes = row[0]
folder = hashes[:2]
flags = row[2]
if flags == 2:
os.mkdir(destination)
elif flags == 1:
shutil.copyfile(f"{sys.argv[2]}/{folder}/{hashes}", destination)
i += 1
if i % 100 == 0:
print(f"Gathering media...({i}/{total_row_number})", end="\r")
row = c.fetchone()
print(f"Gathering media...({total_row_number}/{total_row_number})", end="\r")
manifest.close()
def extract_media(base_dir):
with sqlite3.connect(f"{base_dir}/Manifest.db") as manifest:
c = manifest.cursor()
c.execute("""SELECT count()
FROM Files
WHERE relativePath
LIKE 'Message/Media/%'""")
total_row_number = c.fetchone()[0]
print(f"Gathering media...(0/{total_row_number})", end="\r")
c.execute("""SELECT fileID,
relativePath,
flags
FROM Files
WHERE relativePath
LIKE 'Message/Media/%'""")
row = c.fetchone()
if not os.path.isdir("Message"):
os.mkdir("Message")
if not os.path.isdir("Message/Media"):
os.mkdir("Message/Media")
i = 0
while row is not None:
destination = row[1]
hashes = row[0]
folder = hashes[:2]
flags = row[2]
if flags == 2:
os.mkdir(destination)
elif flags == 1:
shutil.copyfile(f"{base_dir}/{folder}/{hashes}", destination)
i += 1
if i % 100 == 0:
print(f"Gathering media...({i}/{total_row_number})", end="\r")
row = c.fetchone()
print(f"Gathering media...({total_row_number}/{total_row_number})", end="\r")
if __name__ == "__main__":
from optparse import OptionParser
parser = OptionParser()
(_, args) = parser.parse_args()
base_dir = args[0]