#!/usr/bin/env python3 from datetime import timedelta import argparse import requests QBT_URL = "http://192.168.0.2:8080" API_KEY = "qbt_Fw6R39WuJVY7rdhv2IXIc5n8Yfhc" HEADERS = { "Authorization": f"Bearer {API_KEY}", } def get_torrents(): r = requests.get( f"{QBT_URL}/api/v2/torrents/info", headers=HEADERS, timeout=30, ) r.raise_for_status() return r.json() def get_trackers(torrent_hash): r = requests.get( f"{QBT_URL}/api/v2/torrents/trackers", params={"hash": torrent_hash}, headers=HEADERS, timeout=30, ) r.raise_for_status() return r.json() def set_force_start(torrent_hash, enabled=True): requests.post( f"{QBT_URL}/api/v2/torrents/setForceStart", data={ "hashes": torrent_hash, "value": str(enabled).lower(), }, headers=HEADERS, timeout=30, ).raise_for_status() def force_start_by_tracker(trackers): """ trackers = { "myanonamouse": True, "leo-test": False, "nordicq": True, } """ for torrent in get_torrents(): torrent_hash = torrent["hash"] name = torrent["name"] tracker_urls = " ".join( t.get("url", "") for t in get_trackers(torrent_hash) ).lower() for tracker, force_start in trackers.items(): if tracker.lower() in tracker_urls: set_force_start(torrent_hash, force_start) print(f"{name} -> force_start={force_start} (matched {tracker})") break def format_duration(seconds): hours = seconds / 3600 days = seconds // 86400 return f"{days}d ({hours:.1f}h)" def show_torrents(sort_by="name", reverse=True): sort_keys = { "name": lambda t: t["name"].lower(), "ratio": lambda t: t.get("ratio", 0), "seed_time": lambda t: t.get("seeding_time", 0), } torrents = sorted( get_torrents(), key=sort_keys[sort_by], reverse=reverse, ) rows = [ ( t["name"], f"{t.get('ratio', 0):.2f}", format_duration(t.get("seeding_time", 0)), ) for t in torrents ] name_w = max((len(name) for name, _, _ in rows), default=0) ratio_w = max((len(ratio) for _, ratio, _ in rows), default=0) for name, ratio, seed_time in rows: print(f"{name:<{name_w}} Ratio: {ratio:>{ratio_w}} Seed Time: {seed_time}") if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument( "--sort", choices=["name", "ratio", "seed_time"], default="name", ) parser.add_argument( "--force", action="store_true", ) parser.add_argument( "--asc", action="store_true", ) args = parser.parse_args() show_torrents( sort_by=args.sort, reverse=not args.asc, ) if args.force: force_start_by_tracker( { "myanonamouse": True, "leo-test": True, "nordicq": True, } )