git
This commit is contained in:
@@ -1,12 +1,9 @@
|
|||||||
import pymysql
|
import pymysql
|
||||||
import re
|
|
||||||
import time
|
|
||||||
import qbittorrentapi
|
import qbittorrentapi
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# CONFIG
|
# CONFIG
|
||||||
# ============================================================
|
# ============================================================
|
||||||
MAX_SIZE_GB = 950
|
|
||||||
DRY_RUN = False
|
DRY_RUN = False
|
||||||
|
|
||||||
QBT_URL = "https://vladob.zen.usbx.me/qbittorrent"
|
QBT_URL = "https://vladob.zen.usbx.me/qbittorrent"
|
||||||
@@ -23,70 +20,24 @@ DB_CONFIG = {
|
|||||||
"autocommit": True,
|
"autocommit": True,
|
||||||
}
|
}
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# SIZE PARSER
|
|
||||||
# ============================================================
|
|
||||||
def parse_size_to_gb(size_str):
|
|
||||||
if not size_str:
|
|
||||||
return 0.0
|
|
||||||
|
|
||||||
s = str(size_str).upper().replace(",", ".").strip()
|
|
||||||
match = re.search(r"([\d\.]+)", s)
|
|
||||||
if not match:
|
|
||||||
return 0.0
|
|
||||||
|
|
||||||
val = float(match.group(1))
|
|
||||||
|
|
||||||
if "TB" in s:
|
|
||||||
return val * 1024
|
|
||||||
if "GB" in s:
|
|
||||||
return val
|
|
||||||
if "MB" in s:
|
|
||||||
return val / 1024
|
|
||||||
if "KB" in s:
|
|
||||||
return val / 1024 / 1024
|
|
||||||
|
|
||||||
return 0.0
|
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# MAIN
|
# MAIN
|
||||||
# ============================================================
|
# ============================================================
|
||||||
def main():
|
def main():
|
||||||
|
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
print("TORRENT DOWNLOAD SCHEDULER")
|
print("QB COMPLETED CLEANUP")
|
||||||
print(f"DRY_RUN = {DRY_RUN}")
|
print(f"DRY_RUN = {DRY_RUN}")
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
|
|
||||||
# --------------------------------------------------------
|
# --------------------------------------------------------
|
||||||
# DB LOAD
|
# DB CONNECT
|
||||||
# --------------------------------------------------------
|
# --------------------------------------------------------
|
||||||
db = pymysql.connect(**DB_CONFIG)
|
db = pymysql.connect(**DB_CONFIG)
|
||||||
cursor = db.cursor()
|
cursor = db.cursor()
|
||||||
|
|
||||||
print("📥 Loading DB candidates...")
|
|
||||||
|
|
||||||
cursor.execute("""
|
|
||||||
SELECT
|
|
||||||
torrent_hash,
|
|
||||||
title_visible,
|
|
||||||
size_pretty,
|
|
||||||
seeders,
|
|
||||||
torrent_content
|
|
||||||
FROM torrents
|
|
||||||
WHERE
|
|
||||||
qb_completed_datetime IS NULL
|
|
||||||
AND torrent_content IS NOT NULL
|
|
||||||
ORDER BY seeders DESC
|
|
||||||
""")
|
|
||||||
|
|
||||||
rows = cursor.fetchall()
|
|
||||||
|
|
||||||
print(f"Candidates from DB: {len(rows)}")
|
|
||||||
|
|
||||||
# --------------------------------------------------------
|
# --------------------------------------------------------
|
||||||
# CONNECT QBITTORRENT
|
# CONNECT QB
|
||||||
# --------------------------------------------------------
|
# --------------------------------------------------------
|
||||||
print("🔌 Connecting qBittorrent...")
|
print("🔌 Connecting qBittorrent...")
|
||||||
|
|
||||||
@@ -98,105 +49,67 @@ def main():
|
|||||||
)
|
)
|
||||||
qbt.auth_log_in()
|
qbt.auth_log_in()
|
||||||
|
|
||||||
qb_hashes = {t.hash.lower() for t in qbt.torrents_info()}
|
torrents = qbt.torrents_info()
|
||||||
|
|
||||||
print(f"qB active torrents: {len(qb_hashes)}")
|
print(f"Loaded torrents from qB: {len(torrents)}")
|
||||||
|
|
||||||
|
processed = 0
|
||||||
|
removed = 0
|
||||||
|
|
||||||
# --------------------------------------------------------
|
# --------------------------------------------------------
|
||||||
# SELECTION
|
# LOOP
|
||||||
# --------------------------------------------------------
|
# --------------------------------------------------------
|
||||||
selected = []
|
for t in torrents:
|
||||||
total_size = 0.0
|
|
||||||
|
|
||||||
for row in rows:
|
if getattr(t, "amount_left", 1) != 0:
|
||||||
|
|
||||||
t_hash, title, size_str, seeders, content = row
|
|
||||||
t_hash = t_hash.lower()
|
|
||||||
|
|
||||||
# Guard 3 – already in qB
|
|
||||||
if t_hash in qb_hashes:
|
|
||||||
print(f"⏭ Already in qB → {title}")
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
size_gb = parse_size_to_gb(size_str)
|
print(f"✅ COMPLETED → {t.name}")
|
||||||
|
|
||||||
if total_size + size_gb > MAX_SIZE_GB:
|
|
||||||
print(f"🛑 Capacity reached → {title}")
|
|
||||||
break
|
|
||||||
|
|
||||||
selected.append({
|
|
||||||
"hash": t_hash,
|
|
||||||
"title": title,
|
|
||||||
"size": size_gb,
|
|
||||||
"seeders": seeders,
|
|
||||||
"content": content
|
|
||||||
})
|
|
||||||
|
|
||||||
total_size += size_gb
|
|
||||||
|
|
||||||
print(f"✅ Selected → {title} | {size_gb:.2f} GB | seeders={seeders}")
|
|
||||||
|
|
||||||
# --------------------------------------------------------
|
|
||||||
# REPORT
|
|
||||||
# --------------------------------------------------------
|
|
||||||
print("-" * 50)
|
|
||||||
print(f"Selected torrents: {len(selected)}")
|
|
||||||
print(f"Total size: {total_size:.2f} GB / {MAX_SIZE_GB} GB")
|
|
||||||
print("-" * 50)
|
|
||||||
|
|
||||||
if not selected:
|
|
||||||
print("Nothing to schedule.")
|
|
||||||
return
|
|
||||||
|
|
||||||
|
# ----------------------------------------------------
|
||||||
|
# UPDATE DB
|
||||||
|
# ----------------------------------------------------
|
||||||
if not DRY_RUN:
|
if not DRY_RUN:
|
||||||
confirm = input("Upload to qBittorrent? (ano/ne): ")
|
|
||||||
if confirm.lower() not in ["ano", "yes", "y"]:
|
|
||||||
print("Cancelled.")
|
|
||||||
return
|
|
||||||
|
|
||||||
# --------------------------------------------------------
|
|
||||||
# UPLOAD LOOP
|
|
||||||
# --------------------------------------------------------
|
|
||||||
print("🚀 Uploading torrents...")
|
|
||||||
|
|
||||||
success = 0
|
|
||||||
|
|
||||||
for i, item in enumerate(selected):
|
|
||||||
|
|
||||||
try:
|
|
||||||
|
|
||||||
if DRY_RUN:
|
|
||||||
print(f"[DRY] Would upload: {item['title']}")
|
|
||||||
continue
|
|
||||||
|
|
||||||
file_dict = {
|
|
||||||
f"{item['hash']}.torrent": item["content"]
|
|
||||||
}
|
|
||||||
|
|
||||||
qbt.torrents_add(
|
|
||||||
torrent_files=file_dict,
|
|
||||||
is_paused=False
|
|
||||||
)
|
|
||||||
|
|
||||||
# Mark scheduled in DB
|
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
UPDATE torrents
|
UPDATE torrents
|
||||||
SET
|
SET
|
||||||
qb_state = 'scheduled',
|
qb_completed_datetime = COALESCE(qb_completed_datetime, NOW()),
|
||||||
|
qb_state = %s,
|
||||||
qb_last_update = NOW()
|
qb_last_update = NOW()
|
||||||
WHERE torrent_hash = %s
|
WHERE torrent_hash = %s
|
||||||
""", (item["hash"],))
|
""", (t.state, t.hash.lower()))
|
||||||
|
|
||||||
print(f"[{i+1}/{len(selected)}] Uploaded → {item['title']}")
|
else:
|
||||||
success += 1
|
print(f"[DRY] Would update DB → {t.name}")
|
||||||
|
|
||||||
time.sleep(0.2)
|
processed += 1
|
||||||
|
|
||||||
|
# ----------------------------------------------------
|
||||||
|
# REMOVE FROM QB (KEEP FILES)
|
||||||
|
# ----------------------------------------------------
|
||||||
|
try:
|
||||||
|
|
||||||
|
if DRY_RUN:
|
||||||
|
print(f"[DRY] Would remove torrent from qB → {t.name}")
|
||||||
|
else:
|
||||||
|
qbt.torrents_delete(
|
||||||
|
torrent_hashes=t.hash,
|
||||||
|
delete_files=False
|
||||||
|
)
|
||||||
|
|
||||||
|
removed += 1
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"❌ Error uploading {item['title']}: {e}")
|
print(f"❌ Remove failed: {t.name} → {e}")
|
||||||
|
|
||||||
print("\n✔ DONE")
|
# --------------------------------------------------------
|
||||||
print(f"Uploaded torrents: {success}")
|
# SUMMARY
|
||||||
|
# --------------------------------------------------------
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print(f"Completed processed: {processed}")
|
||||||
|
print(f"Removed from qB: {removed}")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
db.close()
|
db.close()
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ QBT_USER = "vladob"
|
|||||||
QBT_PASS = "jCni3U6d#y4bfcm"
|
QBT_PASS = "jCni3U6d#y4bfcm"
|
||||||
|
|
||||||
DB_CONFIG = {
|
DB_CONFIG = {
|
||||||
"host": "192.168.1.50",
|
"host": "192.168.1.76",
|
||||||
"port": 3306,
|
"port": 3306,
|
||||||
"user": "root",
|
"user": "root",
|
||||||
"password": "Vlado9674+",
|
"password": "Vlado9674+",
|
||||||
|
|||||||
Reference in New Issue
Block a user