Hide keyboard shortcuts

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> 

3 

4This file is part of torrent-download. 

5 

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. 

10 

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. 

15 

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""" 

19 

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 

28 

29 

30class QBittorrentDownloader: 

31 """ 

32 Class that uses the qBittorrent Server API to download torrents 

33 """ 

34 

35 def __init__( 

36 self, 

37 url: str, 

38 username: str, 

39 password: str, 

40 download_dir: str 

41 ): 

42 """ 

43 

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 

52 

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 ) 

66 

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 

75 

76 print(f"Downloading Torrent: {torrent_info.filename}") 

77 

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) 

90 

91 time.sleep(1) 

92 

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 ) 

102 

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) 

114 

115 self.client.delete(active["hash"]) 

116 

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") 

129 

130 time.sleep(1)