This commit is contained in:
2026-01-13 16:42:40 +01:00
parent 2aee823e87
commit 01aa1249b9
2 changed files with 267 additions and 0 deletions

View File

@@ -0,0 +1,200 @@
import os
import sys
import pymysql
import pymysql.cursors
# ================= KONFIGURACE =================
# --- BEZPEČNOSTNÍ POJISTKA ---
# True = POUZE VÝPIS (nic se nesmaže, databáze se nezmění)
# False = OSTRÝ REŽIM (maže soubory i záznamy v DB!)
DRY_MODE = True
# 1. Přístup k MySQL
DB_CONFIG = {
'host': '192.168.1.76',
'port': 3307,
'user': 'root',
'password': 'Vlado9674+',
'db': 'torrents',
'charset': 'utf8mb4',
'autocommit': True
}
TABULKA = "file_md5_index"
# 2. Mapování cest
SERVER_PREFIX = "/mnt/user/Library"
# Používáme 'r' pro raw string, aby se zpětná lomítka chápala správně
LOCAL_PREFIX = r"\\tower1\#library"
# ===============================================
def get_connection():
return pymysql.connect(
cursorclass=pymysql.cursors.DictCursor,
**DB_CONFIG
)
def convert_path(db_path):
"""Převede cestu z Linux serveru na lokální cestu Windows."""
if db_path.startswith(SERVER_PREFIX):
relative_path = db_path[len(SERVER_PREFIX):]
# Ořízneme počáteční lomítka z relativní cesty, aby fungoval join
relative_path = relative_path.lstrip("/").lstrip("\\")
# Spojí cesty a opraví lomítka
local_path = os.path.join(LOCAL_PREFIX, relative_path)
return os.path.normpath(local_path)
return None
def step_1_mark_duplicates():
print(f"\n--- KROK 1: Hledání duplicit v DB (DRY_MODE={DRY_MODE}) ---")
try:
conn = get_connection()
with conn.cursor() as cursor:
if DRY_MODE:
# V DRY_MODE jen počítáme, co bychom označili (neprovádíme UPDATE)
sql = f"""
SELECT COUNT(*) as pocet
FROM {TABULKA} t1
JOIN {TABULKA} t2 ON t1.blake3 = t2.blake3
WHERE t1.host_name = 'TOWER1'
AND t2.host_name = 'SYNOLOGY'
AND (t1.to_delete IS NULL OR t1.to_delete = 0);
"""
cursor.execute(sql)
result = cursor.fetchone()
affected = result['pocet']
print(f"[DRY-RUN] Našel jsem {affected} shodných záznamů (DB nebude změněna).")
else:
# V OSTRÉM režimu provádíme UPDATE
sql = f"""
UPDATE {TABULKA} t1
JOIN {TABULKA} t2 ON t1.blake3 = t2.blake3
SET t1.to_delete = 1
WHERE t1.host_name = 'TOWER'
AND t2.host_name = 'SYNOLOGY'
AND (t1.to_delete IS NULL OR t1.to_delete = 0);
"""
print("Provádím UPDATE záznamů v databázi...")
cursor.execute(sql)
affected = cursor.rowcount
conn.commit()
print(f"Hotovo. Označeno {affected} záznamů ke smazání.")
conn.close()
return affected
except pymysql.MySQLError as e:
print(f"Chyba MySQL při označování: {e}")
sys.exit(1)
def step_2_delete_files():
print(f"\n--- KROK 2: Mazání souborů (DRY_MODE={DRY_MODE}) ---")
try:
conn = get_connection()
files_to_process = []
with conn.cursor() as cursor:
print("Stahuji seznam souborů...")
if DRY_MODE:
# V DRY_MODE nemůžeme hledat podle 'to_delete=1' (protože jsme nic neoznačili),
# takže musíme použít JOIN dotaz přímo pro simulaci výpisu.
sql = f"""
SELECT t1.id, t1.full_path
FROM {TABULKA} t1
JOIN {TABULKA} t2 ON t1.blake3 = t2.blake3
WHERE t1.host_name = 'TOWER'
AND t2.host_name = 'SYNOLOGY'
AND (t1.to_delete IS NULL OR t1.to_delete = 0)
"""
else:
# V OSTRÉM režimu bereme to, co jsme v kroku 1 označili
sql = f"SELECT id, full_path FROM {TABULKA} WHERE host_name = 'TOWER' AND to_delete = 1"
cursor.execute(sql)
files_to_process = cursor.fetchall()
count = len(files_to_process)
print(f"Nalezeno {count} souborů.")
if count == 0:
print("Žádné soubory k zpracování. Konec.")
return
# V ostrém režimu se zeptáme na potvrzení
if not DRY_MODE:
confirm = input(f"-> [POZOR] Opravdu chcete SMAZAT {count} souborů? (napište 'ano'): ")
if confirm.lower() != 'ano':
print("Operace zrušena.")
return
else:
print("-" * 40)
print("VÝPIS SOUBORŮ, KTERÉ BY BYLY SMAZÁNY:")
print("-" * 40)
deleted_counter = 0
errors = 0
for row in files_to_process:
db_id = row['id']
server_path = row['full_path']
local_path = convert_path(server_path)
if not local_path:
print(f"[SKIP PATH] Nesedí prefix: {server_path}")
continue
# --- LOGIKA DRY RUN vs REAL ---
if DRY_MODE:
# Pouze výpis
print(f"[DRY-RUN] Bylo by smazáno: {local_path}")
deleted_counter += 1
else:
# Ostré mazání
try:
if os.path.exists(local_path):
os.remove(local_path)
print(f"[OK SMAZÁNO] {local_path}")
# Smazání z DB
with conn.cursor() as del_cursor:
del_sql = f"DELETE FROM {TABULKA} WHERE id = %s"
del_cursor.execute(del_sql, (db_id,))
conn.commit()
deleted_counter += 1
else:
print(f"[NENÍ NA DISKU] Mažu jen z DB: {local_path}")
with conn.cursor() as del_cursor:
del_sql = f"DELETE FROM {TABULKA} WHERE id = %s"
del_cursor.execute(del_sql, (db_id,))
conn.commit()
deleted_counter += 1
except OSError as e:
print(f"[CHYBA OS] {local_path}: {e}")
errors += 1
except pymysql.MySQLError as e:
print(f"[CHYBA DB] ID {db_id}: {e}")
conn.close()
print("-" * 30)
if DRY_MODE:
print(f"DRY RUN DOKONČEN. Zobrazena simulace pro {deleted_counter} souborů.")
else:
print(f"HOTOVO. Úspěšně smazáno: {deleted_counter}, Chyby: {errors}")
except pymysql.MySQLError as e:
print(f"Kritická chyba DB: {e}")
if __name__ == "__main__":
step_1_mark_duplicates()
step_2_delete_files()