183 lines
5.1 KiB
Python
183 lines
5.1 KiB
Python
#!/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()
|