Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""LICENSE
2Copyright 2021 Hermann Krumrey <hermann@krumreyh.com>
4This file is part of torrent-download.
6torrent-download is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
11torrent-download is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
16You should have received a copy of the GNU General Public License
17along with torrent-download. If not, see <http://www.gnu.org/licenses/>.
18LICENSE"""
20import os
21import time
22import shutil
23import requests
24from typing import List
25from qbittorrent import Client
26from torrent_download.Config import Config
27from torrent_download.entities.TorrentDownload import TorrentDownload
30class QBittorrentDownloader:
31 """
32 Class that uses the qBittorrent Server API to download torrents
33 """
35 def __init__(
36 self,
37 url: str,
38 username: str,
39 password: str,
40 download_dir: str
41 ):
42 """
44 :param url:
45 :param username:
46 :param password:
47 :param download_dir:
48 """
49 self.client = Client(url)
50 self.client.login(username, password)
51 self.download_dir = download_dir
53 @classmethod
54 def from_config(cls) -> "QBittorrentDownloader":
55 """
56 :return: A QBittorrentDownloader object based on the stored
57 configuration files
58 """
59 config = Config.load()
60 return cls(
61 config.qbittorrent_address,
62 config.qbittorrent_username,
63 config.qbittorrent_password,
64 config.qbittorrent_download_dir
65 )
67 def download(self, torrents: List[TorrentDownload]):
68 """
69 Downloads a list of torrent files
70 :param torrents: The torrents to download
71 :return: None
72 """
73 for torrent in torrents:
74 torrent_info = torrent.torrent_info
76 print(f"Downloading Torrent: {torrent_info.filename}")
78 if torrent_info.magnet_link is not None:
79 self.client.download_from_link(torrent_info.magnet_link)
80 else:
81 assert torrent_info.torrent_file is not None
82 torrent_file = torrent_info.torrent_file
83 if not os.path.isfile(torrent_file):
84 torrent_file = "/tmp/torrentdltemp.torrent"
85 content = requests.get(torrent_info.torrent_file).content
86 with open(torrent_file, "wb") as f:
87 f.write(content)
88 with open(torrent_file, "rb") as f:
89 self.client.download_from_file(f)
91 time.sleep(1)
93 while len(self.client.torrents()) > 0:
94 for active in self.client.torrents():
95 if active["state"] not in [
96 "downloading", "metaDL", "stalledDL"
97 ]:
98 print("Done. ")
99 torrent_path = os.path.join(
100 self.download_dir, active["name"]
101 )
103 if os.path.isdir(torrent_path):
104 children = [
105 os.path.join(torrent_path, x)
106 for x in os.listdir(torrent_path)
107 ]
108 children.sort(
109 key=lambda x: os.path.getsize(x), reverse=True
110 )
111 torrent_path = children[0]
112 ext = torrent_path.rsplit(".", 1)[1]
113 torrent.add_extension(ext)
115 self.client.delete(active["hash"])
117 if os.path.isdir(torrent.destination):
118 shutil.move(
119 torrent_path,
120 os.path.join(
121 torrent.destination,
122 os.path.basename(torrent_path)
123 )
124 )
125 else:
126 shutil.move(torrent_path, torrent.destination)
127 else:
128 print(f"{(100 * active['progress']):.2f}%", end="\r")
130 time.sleep(1)