-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathqbittorrent_sync.py
127 lines (106 loc) · 3.81 KB
/
qbittorrent_sync.py
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
from typing import Any, Callable
import qbittorrentapi
from stdl import fs
from stdl.st import colored
def is_windows_path(path: str) -> bool:
return ":" in path and "\\" in path
def win_to_unix_path(path: str, drive_path: str = "/mnt") -> str:
"""
E:\\files\\ -> /mnt/e/files/
/mnt/e/files/ -> /mnt/e/files/
"""
if not is_windows_path(path):
return path
path = path.replace("\\", "/")
drive = path[0].lower()
path = path[2:]
path = f"{drive_path}/{drive}{path}"
return path
def unix_to_win_path(path: str, drive_path: str = "/mnt") -> str:
"""
/mnt/e/files/ -> E:\\files\\
"""
path = path.replace(drive_path, "").replace("/", "\\")
drive = path[1].capitalize()
path = path[2:]
path = f"{drive}:{path}"
return path
def same_path(path: str) -> str:
return path
class QbitTorrentSync:
def __init__(
self,
host: str = "localhost",
port: int = 8080,
username: str = "admin",
password: str = "adminadmin",
path_transform_func: Callable[[str, str], str] = win_to_unix_path,
) -> None:
self.client = qbittorrentapi.Client(
host=host,
port=port,
username=username,
password=password,
)
self.client.auth_log_in()
self.path_transoform_func = path_transform_func
def get_torrents(self) -> list[dict[Any, Any]]:
torrents = [dict(**i) for i in self.client.torrents_info()] # type: ignore
for i in torrents:
if i["tags"] == "":
i["tags"] = []
else:
i["tags"] = [i.strip() for i in i["tags"].split(",")]
return torrents
def export_torrents(self, path: str) -> None:
torrents = self.get_torrents()
data = []
for i in torrents:
data.append(
{
"name": i["name"],
"urls": i["magnet_uri"],
"save_path": i["save_path"],
"category": i["category"],
"tags": i["tags"],
}
)
fs.json_dump(data, path)
print(f"{len(data)} torrents saved to {path}.")
def import_torrents(self, path: str) -> None:
current = [i["magnet_uri"] for i in self.get_torrents()]
fs.ensure_paths_exist(path)
data = fs.json_load(path)
data = [i for i in data if i["urls"] not in current]
print(f"Adding {len(data)} torrents ...")
for i in data:
name = i["name"]
del i["name"]
print(f"Adding '{name}' ... ", end="\r")
i["save_path"] = self.path_transoform_func(i["save_path"])
r = self.client.torrents_add(**i) == "Ok."
print("") if r else print(colored("FAILED", "red"))
def main():
import argparse
ap = argparse.ArgumentParser(
description="Sync qBitTorrent information between various operating system installations."
)
ap.add_argument("action", type=str, help="import/export")
ap.add_argument("path", type=str, help="File path")
ap.add_argument("-host", type=str, default="localhost", help="Default: localhost")
ap.add_argument("-port", type=int, default=8080, help="Default: 8080")
ap.add_argument("-username", type=str, default="admin", help="Default: admin")
ap.add_argument(
"-password", type=str, default="adminadmin", help="Default: adminadmin"
)
args = ap.parse_args()
if args.action not in ["import", "export"]:
print(f"ERROR: Unsupported action '{args.action}'")
exit(1)
client = QbitTorrentSync(args.host, args.port, args.username, args.password)
if args.action == "import":
client.import_torrents(args.path)
else:
client.export_torrents(args.path)
if __name__ == "__main__":
main()