Files
torrents/Seedbox/50 MrtveTorrenty.py

158 lines
4.9 KiB
Python

import pymysql
import qbittorrentapi
from datetime import datetime, timedelta
# ============================================================
# CONFIG
# ============================================================
DRY_RUN = False # ← 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
STUCK_AFTER_HOURS = 168 # 7 dní — pro torrenty téměř hotové (>= 95%) ale zaseknuté
QBT_URL = "https://vladob.zen.usbx.me/qbittorrent"
QBT_USER = "vladob"
QBT_PASS = "jCni3U6d#y4bfcm"
DB_CONFIG = {
"host": "192.168.1.76",
"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érium A: progress < {DEAD_PROGRESS_THRESHOLD}% A v qB déle než {DEAD_AFTER_HOURS}h")
print(f"Kritérium B: progress >= {DEAD_PROGRESS_THRESHOLD}% ale < 100% A v qB déle než {STUCK_AFTER_HOURS}h (zaseknutý)")
print("=" * 60)
qbt = connect_qbt()
db = connect_db()
cursor = db.cursor()
torrents = qbt.torrents_info()
now = datetime.now()
deadline_a = now - timedelta(hours=DEAD_AFTER_HOURS)
deadline_b = now - timedelta(hours=STUCK_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
age_hours = (now - added_dt).total_seconds() / 3600
# ── 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:
skip_count += 1
continue
# ── Torrent splňuje kritéria "mrtvý" ──────────────────
thash = t.hash.lower()
reason = "nízký progress po 72h" if is_dead_a else "zaseknutý blízko 100% po 7 dnech"
print(f"\n💀 MRTVÝ ({reason}): {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()