import pymysql import qbittorrentapi from datetime import datetime, timedelta # ============================================================ # CONFIG # ============================================================ DRY_RUN = True # ← změň na False až si ověříš výstup DEAD_AFTER_HOURS = 72 # torrent musí být v qB alespoň tolik hodin DEAD_PROGRESS_THRESHOLD = 95.0 # pokud je progress < tato % po uplynutí doby → dead QBT_URL = "https://vladob.zen.usbx.me/qbittorrent" QBT_USER = "vladob" QBT_PASS = "jCni3U6d#y4bfcm" DB_CONFIG = { "host": "192.168.1.50", "port": 3306, "user": "root", "password": "Vlado9674+", "database": "torrents", "charset": "utf8mb4", "autocommit": True, } # ============================================================ # CONNECT # ============================================================ def connect_qbt(): qbt = qbittorrentapi.Client( host=QBT_URL, username=QBT_USER, password=QBT_PASS, VERIFY_WEBUI_CERTIFICATE=False ) qbt.auth_log_in() return qbt def connect_db(): return pymysql.connect(**DB_CONFIG) # ============================================================ # MAIN # ============================================================ def main(): print("=" * 60) print("MRTVÉ TORRENTY — UltraCC Seedbox cleanup") print(f"DRY_RUN = {DRY_RUN}") print(f"Kritéria : v qB déle než {DEAD_AFTER_HOURS}h A progress < {DEAD_PROGRESS_THRESHOLD}%") print("=" * 60) qbt = connect_qbt() db = connect_db() cursor = db.cursor() torrents = qbt.torrents_info() now = datetime.now() deadline = now - timedelta(hours=DEAD_AFTER_HOURS) dead_count = 0 skip_count = 0 error_count = 0 for t in torrents: # Přeskočit dokončené (ty řeší skript 40) if t.completion_on: skip_count += 1 continue added_on = t.added_on # unix timestamp if not added_on: skip_count += 1 continue added_dt = datetime.fromtimestamp(added_on) progress_pct = float(t.progress) * 100.0 # Torrent ještě není dost starý if added_dt > deadline: skip_count += 1 continue # Progress je OK (téměř hotov) → přeskočit if progress_pct >= DEAD_PROGRESS_THRESHOLD: skip_count += 1 continue # ── Torrent splňuje kritéria "mrtvý" ────────────────── thash = t.hash.lower() age_hours = (now - added_dt).total_seconds() / 3600 print(f"\n💀 MRTVÝ: {t.name}") print(f" Přidán : {added_dt} ({age_hours:.1f}h zpět)") print(f" Progress : {progress_pct:.1f}%") print(f" Stav : {t.state}") print(f" Seeds : {t.num_seeds} Peers: {t.num_leechs}") if DRY_RUN: print(f" [DRY] Smazal bych z qBittorrentu a označil v DB jako incomplete") dead_count += 1 continue # Smazat z qBittorrentu (i soubory — nekompletní data jsou k ničemu) try: qbt.torrents_delete(torrent_hashes=thash, delete_files=True) print(f" ✔ Smazán z qBittorrentu") except Exception as e: print(f" ❌ Smazání selhalo: {e}") error_count += 1 continue # Označit v DB jako incomplete cursor.execute(""" UPDATE torrents SET qb_state = 'incomplete', qb_progress = %s, qb_last_update = NOW() WHERE torrent_hash = %s """, (progress_pct, thash)) if cursor.rowcount > 0: print(f" ✔ DB → incomplete (progress={progress_pct:.1f}%)") else: print(f" ⚠ DB: žádný řádek pro hash {thash}") dead_count += 1 # ============================================================ # SUMMARY # ============================================================ print("\n" + "=" * 60) print(f"Mrtvé torrenty zpracováno : {dead_count}") print(f"Přeskočeno : {skip_count}") print(f"Chyby : {error_count}") print(f"DRY_RUN : {DRY_RUN}") print("=" * 60) db.close() if __name__ == "__main__": main()