#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Projde /mnt/user/torrents/ultracc, pro každý soubor spočítá blake3 a porovná s tabulkou file_md5_index. Pokud je hash nalezen → soubor smaže. Po smazání souborů odstraní prázdné adresáře. """ import os import sys import blake3 import pymysql import paramiko from pathlib import Path # ============================================================ # CONFIG # ============================================================ SCAN_DIR = "//tower/torrents/ultracc" SSH_CONFIG = { "hostname": "192.168.1.76", "port": 22, "username": "root", "password": "7309208104", } ULTRACC_DIRS = [ "/mnt/user/Torrents/UltraCC", "/mnt/user/Torrents/UltraCC1", "/mnt/user/Torrents/UltraCC2", ] DB_CONFIG = { "host": "192.168.1.76", "port": 3306, "user": "root", "password": "Vlado9674+", "database": "torrents", "charset": "utf8mb4", } CHUNK_SIZE = 8 * 1024 * 1024 # 8 MB DRY_RUN = False # True = pouze vypíše, nesmaže # ============================================================ # HELPERS # ============================================================ def compute_blake3(path: Path) -> bytes: """Vrátí blake3 digest jako 32 raw bytes.""" h = blake3.blake3() with open(path, "rb") as f: while True: chunk = f.read(CHUNK_SIZE) if not chunk: break h.update(chunk) return h.digest() def hash_in_db(cursor, digest: bytes): """Vrátí (host_name, full_path) prvního záznamu s daným hashem, nebo None.""" cursor.execute( "SELECT host_name, full_path FROM file_md5_index WHERE blake3 = %s AND host_name = 'tower1' AND full_path LIKE '/mnt/user/#ColdData/Porno/%' LIMIT 1", (digest,) ) return cursor.fetchone() # None nebo (host_name, full_path) def remove_empty_dirs(root: str) -> int: """Rekurzivně smaže prázdné adresáře pod root. Vrátí počet smazaných.""" removed = 0 for dirpath, dirnames, filenames in os.walk(root, topdown=False): if dirpath == root: continue try: os.rmdir(dirpath) print(f" [rmdir] {dirpath}") removed += 1 except OSError: pass return removed # ============================================================ # MAIN # ============================================================ def set_ultracc_permissions(): """Přes SSH nastaví na Tower chown nobody:users + chmod 777 pro všechny UltraCC adresáře.""" print("Nastavuji práva na Tower (UltraCC*)...") ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect(**SSH_CONFIG) for d in ULTRACC_DIRS: _, out, err = ssh.exec_command( 'chown -R nobody:users "%s" && chmod -R 777 "%s" && echo OK' % (d, d) ) result = out.read().decode().strip() error = err.read().decode().strip() if result == "OK": print(f" [OK] {d}") else: print(f" [CHYBA] {d}: {error}") ssh.close() print() def main(): dry_run = DRY_RUN set_ultracc_permissions() if dry_run: print("=== DRY RUN — nic se nesmaže ===\n") conn = pymysql.connect(**DB_CONFIG) cursor = conn.cursor() scan_root = Path(SCAN_DIR) if not scan_root.exists(): print(f"CHYBA: Adresář neexistuje: {SCAN_DIR}") sys.exit(1) files_checked = 0 files_deleted = 0 files_kept = 0 bytes_deleted = 0 for file_path in scan_root.rglob("*"): if not file_path.is_file(): continue files_checked += 1 size = file_path.stat().st_size try: digest = compute_blake3(file_path) except OSError as e: print(f" [CHYBA čtení] {file_path}: {e}") continue db_match = hash_in_db(cursor, digest) if db_match: db_host, db_path = db_match print(f" [SMAZAT] {file_path} ({size:,} B)") print(f" ↳ originál v DB: [{db_host}] {db_path}") if not dry_run: try: file_path.unlink() files_deleted += 1 bytes_deleted += size except OSError as e: print(f" [CHYBA smazání] {file_path}: {e}") else: files_deleted += 1 bytes_deleted += size else: print(f" [zachovat] {file_path} ({size:,} B)") files_kept += 1 cursor.close() conn.close() print() print(f"Zkontrolováno: {files_checked} souborů") print(f"Ke smazání: {files_deleted} souborů ({bytes_deleted / 1024**3:.2f} GB)") print(f"Zachováno: {files_kept} souborů") if not dry_run and files_deleted > 0: print("\nOdstraňuji prázdné adresáře...") removed = remove_empty_dirs(SCAN_DIR) print(f"Odstraněno prázdných adresářů: {removed}") if dry_run: print("\n(Dry run — žádné změny nebyly provedeny)") if __name__ == "__main__": main()