diff --git a/Seedbox/70 Manager.py b/Seedbox/70 Manager.py index 0496f20..260c5fe 100644 --- a/Seedbox/70 Manager.py +++ b/Seedbox/70 Manager.py @@ -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)