-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathqbit_client.py
More file actions
94 lines (84 loc) · 3.28 KB
/
Copy pathqbit_client.py
File metadata and controls
94 lines (84 loc) · 3.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
"""
qBittorrent Web API wrapper for Mass Torrent Loader.
All public methods return (success: bool, message: str) tuples — never raise.
"""
import qbittorrentapi
class QBitClient:
def __init__(self, host="localhost", port=8080, username="admin", password="adminadmin"):
self.client = qbittorrentapi.Client(
host=host,
port=port,
username=username,
password=password,
)
def test_connection(self):
"""Test connection and auth. Returns (ok, message)."""
try:
self.client.auth_log_in()
version = self.client.app.version
return True, f"Connected — qBittorrent {version}"
except qbittorrentapi.LoginFailed:
return False, "Login failed — check username and password."
except qbittorrentapi.APIConnectionError:
return False, (
"Cannot connect. Make sure qBittorrent is running and "
"Web UI is enabled (Tools > Options > Web UI)."
)
except Exception as e:
return False, f"Unexpected error: {e}"
def get_categories(self):
"""Return list of category names. Empty list on failure."""
try:
cats = self.client.torrent_categories.categories
return sorted(cats.keys())
except Exception:
return []
def get_category_details(self):
"""Return {name: save_path} dict for all categories."""
try:
cats = self.client.torrent_categories.categories
return {name: cat.savePath for name, cat in cats.items()}
except Exception:
return {}
def add_torrent(self, file_path, category="", save_path="", paused=False):
"""
Add a single .torrent file.
Returns (status, message) where status is one of: "ok", "skip", "error".
"""
try:
with open(file_path, "rb") as f:
torrent_data = f.read()
except OSError as e:
return "error", f"Cannot read file: {e}"
try:
result = self.client.torrents_add(
torrent_files=torrent_data,
category=category or None,
save_path=save_path or None,
is_paused=paused,
)
if result == "Ok.":
return "ok", "Added successfully"
else:
return "skip", "Already exists or rejected by qBittorrent"
except qbittorrentapi.Conflict409Error:
return "skip", "Already exists in qBittorrent"
except Exception as e:
return "error", f"{e}"
def get_paused_torrents(self, category=""):
"""Get info hashes of paused torrents in a category."""
try:
torrents = self.client.torrents_info(
status_filter="paused",
category=category or None,
)
return [t.hash for t in torrents]
except Exception:
return []
def resume_torrents(self, hashes):
"""Resume a list of torrents by hash. Returns (ok, message)."""
try:
self.client.torrents_resume(torrent_hashes=hashes)
return True, f"Resumed {len(hashes)} torrent(s)"
except Exception as e:
return False, f"Resume failed: {e}"