This commit is contained in:
2026-02-09 18:08:19 +01:00
parent ec1735e629
commit f1a5967430

View File

@@ -4,9 +4,11 @@ import time
import qbittorrentapi
# ============================================================
# KONFIGURACE
# CONFIG
# ============================================================
MAX_SIZE_GB = 950
DRY_RUN = False
QBT_URL = "https://vladob.zen.usbx.me/qbittorrent"
QBT_USER = "vladob"
QBT_PASS = "jCni3U6d#y4bfcm"
@@ -21,130 +23,183 @@ DB_CONFIG = {
"autocommit": True,
}
# ============================================================
# POMOCNÉ FUNKCE
# SIZE PARSER
# ============================================================
def parse_size_to_gb(size_str):
"""Převede text '1.5 GB' nebo '500 MB' na float v GB"""
if not size_str: return 0.0
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
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
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
# ============================================================
# HLAVNÍ LOGIKA
# MAIN
# ============================================================
def main():
print(f"🚀 Plánuji přímý upload z DB (Limit: {MAX_SIZE_GB} GB, řazeno dle seederů)...")
# 1. Načtení dat z DB
# Stahujeme i BLOB (torrent_content), takže to může chvilku trvat
print("=" * 60)
print("TORRENT DOWNLOAD SCHEDULER")
print(f"DRY_RUN = {DRY_RUN}")
print("=" * 60)
# --------------------------------------------------------
# DB LOAD
# --------------------------------------------------------
db = pymysql.connect(**DB_CONFIG)
cursor = db.cursor()
print("⏳ Načítám data z MySQL...")
sql = """
SELECT torrent_hash, title_visible, size_pretty, seeders, torrent_content
FROM torrents
WHERE physical_exists = 0 AND torrent_content IS NOT NULL
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
"""
cursor.execute(sql)
""")
rows = cursor.fetchall()
db.close()
print(f"🔍 Nalezeno {len(rows)} kandidátů. Vybírám ty nejlepší...")
print(f"Candidates from DB: {len(rows)}")
# 2. Výběr do kapacity 950 GB
selected_torrents = []
total_size_gb = 0.0
# --------------------------------------------------------
# CONNECT QBITTORRENT
# --------------------------------------------------------
print("🔌 Connecting qBittorrent...")
qbt = qbittorrentapi.Client(
host=QBT_URL,
username=QBT_USER,
password=QBT_PASS,
VERIFY_WEBUI_CERTIFICATE=False
)
qbt.auth_log_in()
qb_hashes = {t.hash.lower() for t in qbt.torrents_info()}
print(f"qB active torrents: {len(qb_hashes)}")
# --------------------------------------------------------
# SELECTION
# --------------------------------------------------------
selected = []
total_size = 0.0
for row in rows:
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
size_gb = parse_size_to_gb(size_str)
# Pojistka proti nesmyslně velkým souborům nebo chybám v parsování
if size_gb == 0 and "MB" not in str(size_str).upper() and "KB" not in str(size_str).upper():
pass
# Kontrola limitu
if total_size_gb + size_gb > MAX_SIZE_GB:
# Jakmile narazíme na něco, co se nevejde, končíme výběr (protože jsou seřazeny dle priority)
print(f"🛑 Limit naplněn! '{title}' ({size_gb:.2f} GB) by přesáhl {MAX_SIZE_GB} GB.")
if total_size + size_gb > MAX_SIZE_GB:
print(f"🛑 Capacity reached → {title}")
break
selected_torrents.append({
"filename": f"{t_hash}.torrent", # Virtuální název souboru
"content": content, # Binární data
selected.append({
"hash": t_hash,
"title": title,
"size": size_gb,
"seeders": seeders
"seeders": seeders,
"content": content
})
total_size_gb += size_gb
# 3. Report
print("-" * 40)
print(f"📦 Vybráno: {len(selected_torrents)} torrentů")
print(f"💾 Celková velikost: {total_size_gb:.2f} GB / {MAX_SIZE_GB} GB")
if selected_torrents:
avg_seeders = sum(t['seeders'] for t in selected_torrents) / len(selected_torrents)
print(f"⚡ Průměrně seederů: {avg_seeders:.1f}")
print("-" * 40)
total_size += size_gb
if not selected_torrents:
print("Nic k nahrání.")
exit()
print(f"✅ Selected → {title} | {size_gb:.2f} GB | seeders={seeders}")
confirm = input("❓ Nahrát tento výběr na Seedbox? (ano/ne): ")
if confirm.lower() not in ['ano', 'y', 'yes']:
print("❌ Zrušeno.")
exit()
# --------------------------------------------------------
# REPORT
# --------------------------------------------------------
print("-" * 50)
print(f"Selected torrents: {len(selected)}")
print(f"Total size: {total_size:.2f} GB / {MAX_SIZE_GB} GB")
print("-" * 50)
# 4. Připojení k qBittorrent
try:
qbt = qbittorrentapi.Client(
host=QBT_URL,
username=QBT_USER,
password=QBT_PASS,
VERIFY_WEBUI_CERTIFICATE=False
)
qbt.auth_log_in()
print("✅ Připojeno k Seedboxu.")
except Exception as e:
print(f"❌ Chyba připojení: {e}")
exit()
if not selected:
print("Nothing to schedule.")
return
# 5. Odeslání dat
print("🚀 Odesílám...")
success_count = 0
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):
for i, item in enumerate(selected_torrents):
try:
# Posíláme binární data přímo (tváříme se, že posíláme soubor)
# formát: {'nazev_souboru.torrent': b'binarni_data...'}
file_dict = {item['filename']: item['content']}
qbt.torrents_add(torrent_files=file_dict, is_paused=False)
if DRY_RUN:
print(f"[DRY] Would upload: {item['title']}")
continue
print(f"[{i + 1}/{len(selected_torrents)}] 📤 {item['title']} ({item['size']:.1f} GB)")
success_count += 1
time.sleep(0.2) # Malá pauza pro stabilitu API
file_dict = {
f"{item['hash']}.torrent": item["content"]
}
qbt.torrents_add(
torrent_files=file_dict,
is_paused=False
)
# Mark scheduled in DB
cursor.execute("""
UPDATE torrents
SET
qb_state = 'scheduled',
qb_last_update = NOW()
WHERE torrent_hash = %s
""", (item["hash"],))
print(f"[{i+1}/{len(selected)}] Uploaded → {item['title']}")
success += 1
time.sleep(0.2)
except Exception as e:
print(f"Chyba u {item['title']}: {e}")
print(f"Error uploading {item['title']}: {e}")
print("\n✅ HOTOVO.")
print("Torrenty jsou na Seedboxu. Až se stáhnou, stáhni je domů a spusť skript 99_Scan...")
print("\n✔ DONE")
print(f"Uploaded torrents: {success}")
db.close()
if __name__ == "__main__":
main()
main()