def run_merge(filenames): """Merges all Skype databases to a new database.""" dbs = [skypedata.SkypeDatabase(f) for f in filenames] db_base = dbs.pop() counts = collections.defaultdict(lambda: collections.defaultdict(int)) postbacks = Queue.Queue() postfunc = lambda r: postbacks.put(r) worker = workers.MergeThread(postfunc) name, ext = os.path.splitext(os.path.split(db_base.filename)[-1]) now = datetime.datetime.now().strftime("%Y%m%d") filename_final = util.unique_path("%s.merged.%s%s" % (name, now, ext)) print("Creating %s, using %s as base." % (filename_final, db_base)) shutil.copyfile(db_base.filename, filename_final) db2 = skypedata.SkypeDatabase(filename_final) chats2 = db2.get_conversations() db2.get_conversations_stats(chats2) for db1 in dbs: chats = db1.get_conversations() db1.get_conversations_stats(chats) bar_total = sum(c["message_count"] for c in chats) bar_text = " Processing %.*s.." % (30, db1) bar = ProgressBar(max=bar_total, afterword=bar_text) bar.start() args = {"db1": db1, "db2": db2, "chats": chats, "type": "diff_merge_left"} worker.work(args) while True: result = postbacks.get() if "error" in result: print("Error merging %s:\n\n%s" % (db1, result["error"])) worker = None # Signal for global break break # break while True if "done" in result: break # break while True if "diff" in result: counts[db1]["chats"] += 1 counts[db1]["msgs"] += len(result["diff"]["messages"]) msgcounts = sum(c["message_count"] for c in result["chats"]) bar.update(bar.value + msgcounts) if result["output"]: log(result["output"]) if not worker: break # break for db1 in dbs bar.stop() bar.afterword = " Processed %s." % db1 bar.update(bar_total) print if not counts: print("Nothing new to merge.") db2.close() os.unlink(filename_final) else: for db1 in dbs: print("Merged %s in %s from %s." % (util.plural("message", counts[db1]["msgs"]), util.plural("chat", counts[db1]["chats"]), db1)) print("Merge into %s complete." % db2)
def run_search(filenames, query): """Searches the specified databases for specified query.""" dbs = [skypedata.SkypeDatabase(f) for f in filenames] postbacks = Queue.Queue() postfunc = lambda r: postbacks.put(r) worker = workers.SearchThread(postfunc) for db in dbs: log("Searching \"%s\" in %s." % (query, db)) args = {"db": db, "text": query, "table": "messages", "output": "text"} worker.work(args) while True: result = postbacks.get() if "error" in result: print("Error searching %s:\n\n%s" % (db, result.get("error_short", result["error"]))) break # break while True if "done" in result: log("Finished searching for \"%s\" in %s.", query, db) break # break while True if result.get("count", 0) or is_verbose: if len(dbs) > 1: print "%s:" % db, print(result["output"])
def run_search(filenames, query): """Searches the specified databases for specified query.""" dbs = [skypedata.SkypeDatabase(f) for f in filenames] postbacks = Queue.Queue() args = {"text": query, "table": "messages", "output": "text"} worker = workers.SearchThread(postbacks.put) try: for db in dbs: log("Searching \"%s\" in %s." % (query, db)) worker.work(dict(args, db=db)) while True: result = postbacks.get() if "error" in result: output("Error searching %s:\n\n%s" % (db, result.get("error_short", result["error"]))) break # break while True if "done" in result: log("Finished searching for \"%s\" in %s.", query, db) break # break while True if result.get("count", 0) or is_verbose: if len(dbs) > 1: output("%s:" % db, end=" ") output(result["output"]) finally: worker and (worker.stop(), worker.join())
def run_export(filenames, format): """Exports the specified databases in specified format.""" dbs = [skypedata.SkypeDatabase(f) for f in filenames] is_xlsx_single = ("xlsx_single" == format) for db in dbs: formatargs = collections.defaultdict(str) formatargs["skypename"] = os.path.basename(db.filename) formatargs.update(db.account or {}) basename = util.safe_filename(conf.ExportDbTemplate % formatargs) dbstr = "from %s " % db if len(dbs) != 1 else "" if is_xlsx_single: export_dir = os.getcwd() filename = util.unique_path("%s.xlsx" % basename) else: export_dir = util.unique_path(os.path.join(os.getcwd(), basename)) filename = format target = filename if is_xlsx_single else export_dir try: print("Exporting as %s %sto %s." % (format[:4].upper(), dbstr, target)) chats = sorted(db.get_conversations(), key=lambda x: x["title"].lower()) db.get_conversations_stats(chats) bar_total = sum(c["message_count"] for c in chats) bartext = " Exporting %.*s.." % (30, db.filename) # Enforce width bar = ProgressBar(max=bar_total, afterword=bartext) bar.start() result = export.export_chats(chats, export_dir, filename, db, progress=bar.update) files, count = result bar.stop() if count: bar.afterword = " Exported %s to %s. " % (db, target) bar.update(bar_total) print() log("Exported %s %sto %s as %s.", util.plural("chat", count), dbstr, target, format) else: print("\nNo messages to export%s." % ("" if len(dbs) == 1 else " from %s" % db)) os.unlink(filename) if is_xlsx_single else os.rmdir(export_dir) except Exception as e: print("Error exporting chats: %s\n\n%s" % (e, traceback.format_exc()))
def run_export(filenames, format, chatnames, authornames, ask_password): """Exports the specified databases in specified format.""" dbs = [skypedata.SkypeDatabase(f) for f in filenames] is_xlsx_single = ("xlsx_single" == format) for db in dbs: if (ask_password and db.id and conf.SharedImageAutoDownload and format.lower().endswith("html")): prompt = "Enter Skype password for '%s': " % db.id while not skypedata.SharedImageDownload.has_login(db.id): with warnings.catch_warnings(): warnings.simplefilter("ignore") # possible GetPassWarning output(prompt, end="") # getpass output can raise errors pw = getpass.getpass("", io.BytesIO()) if not pw: continue # while try: skypedata.SharedImageDownload.login(db.id, pw) except Exception as e: log("Error signing in %s on Skype web.\n\n%s", db.id, util.format_exc(e)) prompt = "%s\nEnter Skype password for '%s': " % (e, db.id) formatargs = collections.defaultdict(str) formatargs["skypename"] = os.path.basename(db.filename) formatargs.update(db.account or {}) basename = util.safe_filename(conf.ExportDbTemplate % formatargs) dbstr = "from %s " % db if len(dbs) != 1 else "" if is_xlsx_single: export_dir = os.getcwd() filename = util.unique_path("%s.xlsx" % basename) else: export_dir = util.unique_path(os.path.join(os.getcwd(), basename)) filename = format target = filename if is_xlsx_single else export_dir try: extras = [("", chatnames)] if chatnames else [] extras += [(" with authors", authornames)] if authornames else [] output("Exporting%s%s as %s %sto %s." % (" chats" if extras else "", ",".join( "%s like %s" % (x, y) for x, y in extras), format[:4].upper(), dbstr, target)) chats = sorted(db.get_conversations(chatnames, authornames), key=lambda x: x["title"].lower()) db.get_conversations_stats(chats) bar_total = sum(c["message_count"] for c in chats) bartext = " Exporting %.*s.." % (30, db.filename) # Enforce width bar = ProgressBar(max=bar_total, afterword=bartext) bar.start() result = export.export_chats(chats, export_dir, filename, db, progress=bar.update) files, count = result bar.stop() if count: bar.afterword = " Exported %s to %s. " % (db, target) bar.update(bar_total) output() log("Exported %s %sto %s as %s.", util.plural("chat", count), dbstr, target, format) else: output("\nNo messages to export%s." % ("" if len(dbs) == 1 else " from %s" % db)) os.unlink(filename) if is_xlsx_single else os.rmdir(export_dir) except Exception as e: output("Error exporting chats: %s\n\n%s" % (e, traceback.format_exc()))
def run_merge(filenames, output_filename=None): """Merges all Skype databases to a new database.""" dbs = [skypedata.SkypeDatabase(f) for f in filenames] db_base = dbs.pop() counts = collections.defaultdict(lambda: collections.defaultdict(int)) postbacks = Queue.Queue() name, ext = os.path.splitext(os.path.split(db_base.filename)[-1]) now = datetime.datetime.now().strftime("%Y%m%d") if not output_filename: output_filename = util.unique_path("%s.merged.%s%s" % (name, now, ext)) output("Creating %s, using %s as base." % (output_filename, db_base)) bar = ProgressBar() bar.start() shutil.copyfile(db_base.filename, output_filename) db2 = skypedata.SkypeDatabase(output_filename) chats2 = db2.get_conversations() db2.get_conversations_stats(chats2) args = {"db2": db2, "type": "diff_merge_left"} worker = workers.MergeThread(postbacks.put) try: for db1 in dbs: chats = db1.get_conversations() db1.get_conversations_stats(chats) bar.afterword = " Processing %.*s.." % (30, db1) worker.work(dict(args, db1=db1, chats=chats)) while True: result = postbacks.get() if "error" in result: output("Error merging %s:\n\n%s" % (db1, result["error"])) db1 = None # Signal for global break break # break while True if "done" in result: break # break while True if "diff" in result: counts[db1]["chats"] += 1 counts[db1]["msgs"] += len(result["diff"]["messages"]) if "index" in result: bar.max = result["count"] bar.update(result["index"]) if result.get("output"): log(result["output"]) if not db1: break # break for db1 in dbs bar.stop() bar.afterword = " Processed %s." % db1 bar.update(bar.max) output() finally: worker and (worker.stop(), worker.join()) if not counts: output("Nothing new to merge.") db2.close() os.unlink(output_filename) else: for db1 in dbs: output("Merged %s in %s from %s." % (util.plural("message", counts[db1]["msgs"]), util.plural("chat", counts[db1]["chats"]), db1)) output("Merge into %s complete." % db2)