From 1d614eafb77defc614699c1ce86afd4885624006 Mon Sep 17 00:00:00 2001 From: KnugiHK <24708955+KnugiHK@users.noreply.github.com> Date: Mon, 18 Jan 2021 15:55:21 +0800 Subject: [PATCH] Comply with PEP8 with some exception E501 and F401 are not fully enforced --- extract.py | 143 +++++++++++++++++++++++++++------------- extract_iphone.py | 112 +++++++++++++++++++++---------- extract_iphone_media.py | 70 ++++++++++++-------- 3 files changed, 217 insertions(+), 108 deletions(-) diff --git a/extract.py b/extract.py index 2228817..ceceffb 100644 --- a/extract.py +++ b/extract.py @@ -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): diff --git a/extract_iphone.py b/extract_iphone.py index 4db00ec..1e06584 100644 --- a/extract_iphone.py +++ b/extract_iphone.py @@ -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): diff --git a/extract_iphone_media.py b/extract_iphone_media.py index 0354b61..75d662c 100644 --- a/extract_iphone_media.py +++ b/extract_iphone_media.py @@ -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() \ No newline at end of file + +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]