Compare commits
6 Commits
197cb3f8db
...
claude/bea
| Author | SHA1 | Date | |
|---|---|---|---|
| 3ce8fa0080 | |||
| c4f2d8b13d | |||
| a74ad8ff00 | |||
| afbca5b348 | |||
| 20c4a7d8b4 | |||
| 489b236b9b |
@@ -14,12 +14,16 @@ Oba klienti sdílí stejnou DB frontu. Torrent "nárokovaný" jedním klientem
|
||||
import pymysql
|
||||
import qbittorrentapi
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
# ============================================================
|
||||
# CONFIG
|
||||
# ============================================================
|
||||
|
||||
DEAD_AFTER_HOURS = 72 # progress < 95% po 72h → dead
|
||||
DEAD_PROGRESS_THRESHOLD = 95.0
|
||||
STUCK_AFTER_HOURS = 168 # progress >= 95% ale < 100% po 7 dnech → dead
|
||||
|
||||
CLIENTS = [
|
||||
{
|
||||
"name": "UltraCC Seedbox",
|
||||
@@ -142,6 +146,68 @@ def handle_completed(qbt, cursor):
|
||||
return removed
|
||||
|
||||
|
||||
# ============================================================
|
||||
# STEP 1b: Handle dead torrents (z 50 MrtveTorrenty.py)
|
||||
# ============================================================
|
||||
|
||||
def handle_dead_torrents(qbt, cursor):
|
||||
"""
|
||||
Mrtvé torrenty: nízký progress po 72h NEBO zaseknutý >= 95% po 7 dnech.
|
||||
Smaže z qBittorrentu včetně souborů a označí v DB jako incomplete.
|
||||
"""
|
||||
now = datetime.now()
|
||||
deadline_a = now - timedelta(hours=DEAD_AFTER_HOURS)
|
||||
deadline_b = now - timedelta(hours=STUCK_AFTER_HOURS)
|
||||
|
||||
dead_count = 0
|
||||
|
||||
for t in qbt.torrents_info():
|
||||
# Přeskočit dokončené
|
||||
if t.completion_on and t.completion_on > 0:
|
||||
continue
|
||||
|
||||
added_on = t.added_on
|
||||
if not added_on:
|
||||
continue
|
||||
|
||||
added_dt = datetime.fromtimestamp(added_on)
|
||||
progress_pct = float(t.progress) * 100.0
|
||||
|
||||
# Kritérium A: nízký progress po 72h
|
||||
is_dead_a = (added_dt <= deadline_a) and (progress_pct < DEAD_PROGRESS_THRESHOLD)
|
||||
|
||||
# Kritérium B: zaseknutý blízko 100% po 7 dnech
|
||||
is_dead_b = (added_dt <= deadline_b) and (progress_pct >= DEAD_PROGRESS_THRESHOLD) and (progress_pct < 100.0)
|
||||
|
||||
if not is_dead_a and not is_dead_b:
|
||||
continue
|
||||
|
||||
thash = t.hash.lower()
|
||||
reason = "nízký progress po 72h" if is_dead_a else "zaseknutý blízko 100% po 7 dnech"
|
||||
|
||||
print(f" 💀 MRTVÝ ({reason}): {t.name[:50]}")
|
||||
print(f" Progress: {progress_pct:.1f}% | Stav: {t.state} | Seeds: {t.num_seeds}")
|
||||
|
||||
try:
|
||||
qbt.torrents_delete(torrent_hashes=thash, delete_files=True)
|
||||
except Exception as e:
|
||||
print(f" ❌ Smazání selhalo: {e}")
|
||||
continue
|
||||
|
||||
cursor.execute("""
|
||||
UPDATE torrents
|
||||
SET
|
||||
qb_state = 'incomplete',
|
||||
qb_progress = %s,
|
||||
qb_last_update = NOW()
|
||||
WHERE torrent_hash = %s OR qb_hash = %s
|
||||
""", (progress_pct, thash, thash))
|
||||
|
||||
dead_count += 1
|
||||
|
||||
return dead_count
|
||||
|
||||
|
||||
# ============================================================
|
||||
# STEP 2: Count active (non-completed) torrents in qBittorrent
|
||||
# ============================================================
|
||||
@@ -230,6 +296,14 @@ def process_client(client_cfg: dict, cursor):
|
||||
if removed == 0:
|
||||
print(f" │ Žádné dokončené.")
|
||||
|
||||
# Krok 1b: Mrtvé torrenty
|
||||
print(f" │ [1b] Kontrola mrtvých torrentů...")
|
||||
dead = handle_dead_torrents(qbt, cursor)
|
||||
if dead == 0:
|
||||
print(f" │ Žádné mrtvé.")
|
||||
else:
|
||||
print(f" │ Odstraněno mrtvých: {dead}")
|
||||
|
||||
# Krok 2: Stav slotů
|
||||
active_hashes = get_active_hashes(qbt)
|
||||
active = len(active_hashes)
|
||||
|
||||
182
Seedbox/80 DeleteWhatWeHaveUltraCC2.py
Normal file
182
Seedbox/80 DeleteWhatWeHaveUltraCC2.py
Normal file
@@ -0,0 +1,182 @@
|
||||
#!/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/ultracc2"
|
||||
|
||||
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()
|
||||
182
Seedbox/81 DeleteWhatWeHaveUltraCC.py
Normal file
182
Seedbox/81 DeleteWhatWeHaveUltraCC.py
Normal file
@@ -0,0 +1,182 @@
|
||||
#!/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 = True # 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()
|
||||
182
Seedbox/82 DeleteWhatWeHaveUltraCC1.py
Normal file
182
Seedbox/82 DeleteWhatWeHaveUltraCC1.py
Normal file
@@ -0,0 +1,182 @@
|
||||
#!/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/ultracc1"
|
||||
|
||||
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()
|
||||
Reference in New Issue
Block a user