import os import blake3 import sys import json from tqdm import tqdm # ============================== # ⚙️ NASTAVENÍ # ============================== LOCAL_ROOT = r"U:\#Syncthing" CACHE_FILE = "local_hashes.jsonl" ERROR_LOG = "errors_scan.txt" def calculate_blake3_hex(file_path): h = blake3.blake3() # Zde ošetříme chyby při otevírání/čtení souboru try: with open(file_path, "rb") as f: while True: chunk = f.read(4 * 1024 * 1024) if not chunk: break h.update(chunk) return h.hexdigest() except Exception as e: # Vyhodíme výjimku nahoru, abychom ji zachytili v hlavní smyčce i s názvem souboru raise e def count_files(path): print("⏳ Sčítám soubory...", end="\r") total = 0 for root, dirs, files in os.walk(path): if ".stfolder" in dirs: dirs.remove(".stfolder") if ".stversions" in dirs: dirs.remove(".stversions") total += len(files) print(f"✅ Celkem souborů: {total:,}") return total def load_processed_files(cache_file): """Načte cesty souborů, které už máme hotové""" processed = set() if os.path.exists(cache_file): print("📥 Načítám již hotové záznamy pro navázání...") try: with open(cache_file, "r", encoding="utf-8") as f: for line in f: line = line.strip() if not line: continue try: data = json.loads(line) processed.add(data["p"]) # "p" je cesta except: continue except Exception as e: print(f"⚠️ Chyba při čtení cache (nevadí, jedeme dál): {e}") print(f"⏭ Přeskočím {len(processed):,} již hotových souborů.") return processed def main(): print("🚀 KROK 1: Generování cache (RESUMABLE + SAFE MODE)") print(f"📂 Zdroj: {LOCAL_ROOT}") print(f"💾 Výstup: {CACHE_FILE}") print("===================================") # 1. Zjistit celkový počet total_files = count_files(LOCAL_ROOT) # 2. Zjistit, co už máme hotové processed_paths = load_processed_files(CACHE_FILE) errors = 0 newly_processed = 0 # Otevřeme v režimu 'a' (APPEND) - připisování na konec with open(CACHE_FILE, "a", encoding="utf-8") as f_out: with tqdm(total=total_files, unit="file", dynamic_ncols=True) as pbar: # Pokud už máme nějaká data, aktualizujeme progress bar if processed_paths: pbar.update(len(processed_paths)) for root, dirs, files in os.walk(LOCAL_ROOT): if ".stfolder" in dirs: dirs.remove(".stfolder") if ".stversions" in dirs: dirs.remove(".stversions") for filename in files: file_path = os.path.join(root, filename) # === SKIPPER: Pokud už to máme, jdeme dál === if file_path in processed_paths: continue # ============================================ # Pro dlouhé názvy ořízneme text v progress baru short_name = (filename[:30] + '...') if len(filename) > 30 else filename pbar.set_description(f"Hash: {short_name}") # === SAFE BLOCK: Try-Except uvnitř smyčky === try: hex_hash = calculate_blake3_hex(file_path) if hex_hash: record = {"h": hex_hash, "p": file_path} f_out.write(json.dumps(record, ensure_ascii=False) + "\n") # Flush, aby se to zapsalo na disk hned (pro jistotu) if newly_processed % 100 == 0: f_out.flush() newly_processed += 1 except Exception as e: errors += 1 error_msg = f"❌ CHYBA: {filename} -> {e}\n" # Zapíšeme chybu do logu, aby to nerušilo output with open(ERROR_LOG, "a", encoding="utf-8") as ferr: ferr.write(error_msg) # Posuneme progress bar pbar.update(1) print("\n\n✅ HOTOVO.") print(f"📄 Nově přidáno: {newly_processed}") print(f"⏭ Přeskočeno: {len(processed_paths)}") if errors > 0: print(f"⚠️ Počet chyb: {errors} (Detaily viz soubor '{ERROR_LOG}')") if __name__ == "__main__": main()