Skip to content

Commit 7b2b95b

Browse files
Merge pull request #83 from jerrymakesjelly/dev
Version 1.5.3
2 parents cf799d5 + 5f75d63 commit 7b2b95b

79 files changed

Lines changed: 1652 additions & 990 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README-cn.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,13 @@
107107

108108
更新日志
109109
----------
110+
**2020-08-27 周四**:1.5.3 版本。
111+
112+
* 修复 psutil 在群晖的兼容问题(用于检查磁盘剩余空间)。(#61)
113+
* 可以通过 ``--debug`` 或 ``-d`` 命令行启用调试模式。(#76)
114+
* 修复由主机 URL 末尾的 ``/`` 导致的 API 不兼容的问题。(#81)
115+
* 添加上传量与下载量两个条件。(#79)
116+
110117
**2020-03-27 周五**:1.5.2 版本。
111118

112119
* 支持 Deluge (#8);

README.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,13 @@ Screenshot
111111

112112
Changelog
113113
----------
114+
**Thu, 27 Aug 2020**: Version 1.5.3.
115+
116+
* Fix psutil's compatibility in Synology (use to check the free spaces). (#61)
117+
* Enable to output debug logs by specifying ``--debug`` or ``-d`` argument. (#76)
118+
* Fix API imcompatibility issue caused by the trailing ``/`` in host URL. (#81)
119+
* Add uploaded size and downloaded size conditions. (#79)
120+
114121
**Fri, 27 Mar 2020**: Version 1.5.2.
115122

116123
* Support Deluge. (#8)

autoremovetorrents/client/deluge.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
from deluge_client import DelugeRPCClient
33
from deluge_client.client import DelugeClientException
44
from ..torrent import Torrent
5+
from ..clientstatus import ClientStatus
6+
from ..portstatus import PortStatus
57
from ..torrentstatus import TorrentStatus
68
from ..exception.loginfailure import LoginFailure
79
from ..exception.remotefailure import RemoteFailure
@@ -45,6 +47,31 @@ def _call(self, method, *args, **kwargs):
4547
# Raise our own exception
4648
raise RemoteFailure(e.args[0].split('\n')[0] if len(e.args) > 0 else e.__class__.__name__)
4749

50+
# Get client status
51+
def client_status(self):
52+
cs = ClientStatus()
53+
54+
# Set remote free space checker
55+
cs.free_space = self.remote_free_space
56+
57+
# Get DL/UL information
58+
session_stats = self._call('core.get_session_status', [
59+
'payload_download_rate',
60+
'payload_upload_rate',
61+
'total_download',
62+
'total_upload',
63+
])
64+
cs.download_speed = session_stats['payload_download_rate']
65+
cs.total_downloaded = session_stats['total_download']
66+
cs.upload_speed = session_stats['payload_upload_rate']
67+
cs.total_uploaded = session_stats['total_upload']
68+
69+
# Get port status
70+
port_is_open = self._call('core.test_listen_port')
71+
cs.port_status = PortStatus.Open if port_is_open else PortStatus.Closed
72+
73+
return cs
74+
4875
# Get Deluge version
4976
def version(self):
5077
funcs = {
@@ -113,6 +140,7 @@ def torrent_properties(self, torrent_hash):
113140
torrent_obj.size = torrent['total_size']
114141
torrent_obj.ratio = torrent['ratio']
115142
torrent_obj.uploaded = torrent['total_uploaded']
143+
torrent_obj.downloaded = torrent['all_time_download']
116144
torrent_obj.create_time = int(torrent['time_added'])
117145
torrent_obj.seeding_time = torrent['seeding_time']
118146
torrent_obj.upload_speed = torrent['upload_payload_rate']
@@ -132,6 +160,10 @@ def torrent_properties(self, torrent_hash):
132160

133161
return torrent_obj
134162

163+
# Get free space
164+
def remote_free_space(self, path):
165+
return self._call('core.get_free_space', path)
166+
135167
# Judge Torrent Status
136168
@staticmethod
137169
def _judge_status(state):

autoremovetorrents/client/qbittorrent.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
#-*- coding:utf-8 -*-
22
import requests
33
import time
4+
from .. import logger
45
from ..torrent import Torrent
6+
from ..clientstatus import ClientStatus
57
from ..torrentstatus import TorrentStatus
8+
from ..portstatus import PortStatus
69
from ..exception.loginfailure import LoginFailure
710
from ..exception.connectionfailure import ConnectionFailure
811
from ..exception.incompatibleapi import IncompatibleAPIVersion
@@ -37,6 +40,10 @@ def client_version(self):
3740
def login(self, username, password):
3841
return self._session.post(self._host+'/login', data={'username':username, 'password':password})
3942

43+
# Get server state
44+
def server_state(self):
45+
return self._session.get(self._host+'/sync/maindata')
46+
4047
# Get torrent list
4148
def torrent_list(self):
4249
return self._session.get(self._host+'/query/torrents')
@@ -86,6 +93,10 @@ def client_version(self):
8693
def login(self, username, password):
8794
return self._session.post(self._host+'/api/v2/auth/login', data={'username':username, 'password':password})
8895

96+
# Get server state
97+
def server_state(self):
98+
return self._session.get(self._host+'/api/v2/sync/maindata')
99+
89100
# Get torrent list
90101
def torrent_list(self):
91102
return self._session.get(self._host+'/api/v2/torrents/info')
@@ -107,6 +118,9 @@ def delete_torrents_and_data(self, torrent_hash_list):
107118
return self._session.get(self._host+'/api/v2/torrents/delete', params={'hashes':'|'.join(torrent_hash_list), 'deleteFiles': True})
108119

109120
def __init__(self, host):
121+
# Logger
122+
self._logger = logger.Logger.register(__name__)
123+
110124
# Torrents list cache
111125
self._torrents_list_cache = []
112126
self._refresh_cycle = 30
@@ -135,6 +149,29 @@ def login(self, username, password):
135149
else:
136150
raise LoginFailure('The server returned HTTP %d.' % request.status_code)
137151

152+
# Get client status
153+
def client_status(self):
154+
status = self._request_handler.server_state().json()['server_state']
155+
156+
cs = ClientStatus()
157+
# Remote free space checker
158+
cs.free_space = self.remote_free_space
159+
# Downloading speed and downloaded size
160+
cs.download_speed = status['dl_info_speed']
161+
cs.total_downloaded = status['dl_info_data']
162+
# Uploading speed and uploaded size
163+
cs.upload_speed = status['up_info_speed']
164+
cs.total_uploaded = status['up_info_data']
165+
# Outgoing port status
166+
if status['connection_status'] == 'connected':
167+
cs.port_status = PortStatus.Open
168+
elif status['connection_status'] == 'firewalled':
169+
cs.port_status = PortStatus.Firewalled
170+
else:
171+
cs.port_status = PortStatus.Closed
172+
173+
return cs
174+
138175
# Get qBittorrent Version
139176
def version(self):
140177
request = self._request_handler.client_version()
@@ -182,6 +219,7 @@ def torrent_properties(self, torrent_hash):
182219
torrent_obj.size = torrent['size']
183220
torrent_obj.ratio = torrent['ratio']
184221
torrent_obj.uploaded = properties['total_uploaded']
222+
torrent_obj.downloaded = properties['total_downloaded']
185223
torrent_obj.create_time = properties['addition_date']
186224
torrent_obj.seeding_time = properties['seeding_time']
187225
torrent_obj.upload_speed = properties['up_speed']
@@ -200,6 +238,18 @@ def torrent_properties(self, torrent_hash):
200238

201239
return torrent_obj
202240

241+
# Get free space
242+
def remote_free_space(self, path):
243+
# Actually the path is ignored
244+
self._logger.info('Get Free Space: The path is ignored ' +
245+
'since qBitorrent does not support to specific a path to check the free space.')
246+
status = self._request_handler.server_state().json()['server_state']
247+
248+
# There is no free space data in qBittorrent 3.x
249+
if 'free_space_on_disk' in status:
250+
return status['free_space_on_disk']
251+
return None
252+
203253
# Judge Torrent Status (qBittorrent doesn't have stopped status)
204254
@staticmethod
205255
def _judge_status(state):

autoremovetorrents/client/transmission.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
#-*- coding:utf-8 -*-
22
import requests
33
from ..torrent import Torrent
4+
from ..clientstatus import ClientStatus
45
from ..torrentstatus import TorrentStatus
6+
from ..portstatus import PortStatus
57
from ..exception.connectionfailure import ConnectionFailure
68
from ..exception.loginfailure import LoginFailure
79
from ..exception.nosuchclient import NoSuchClient
@@ -53,6 +55,29 @@ def _make_transmission_request(self, method, arguments=None):
5355
% (request.status_code, method)
5456
)
5557

58+
# Get client status
59+
def client_status(self):
60+
status = self._make_transmission_request('session-stats')
61+
62+
cs = ClientStatus()
63+
# Remote free space checker
64+
cs.free_space = self.remote_free_space
65+
# Download speed and downloaded size
66+
cs.download_speed = status['downloadSpeed']
67+
cs.total_downloaded = status['current-stats']['downloadedBytes']
68+
# Uploading speed and uploaded size
69+
cs.upload_speed = status['uploadSpeed']
70+
cs.total_uploaded = status['current-stats']['uploadedBytes']
71+
72+
# Outgoing port status
73+
port_is_open = self._make_transmission_request('port-test')
74+
if port_is_open:
75+
cs.port_status = PortStatus.Open
76+
else:
77+
cs.port_status = PortStatus.Closed
78+
79+
return cs
80+
5681
# Get Transmission Version
5782
def version(self):
5883
ver = self._make_transmission_request('session-get')['version']
@@ -116,6 +141,7 @@ def torrent_properties(self, torrent_hash):
116141
torrent_obj.size = torrent['totalSize']
117142
torrent_obj.ratio = torrent['uploadRatio']
118143
torrent_obj.uploaded = torrent['uploadedEver']
144+
torrent_obj.downloaded = torrent['downloadedEver']
119145
torrent_obj.create_time = torrent['addedDate']
120146
torrent_obj.seeding_time = torrent['secondsSeeding']
121147
torrent_obj.upload_speed = torrent['rateUpload']
@@ -130,6 +156,12 @@ def torrent_properties(self, torrent_hash):
130156
torrent_obj.progress = torrent['percentDone']
131157

132158
return torrent_obj
159+
160+
# Get free space
161+
def remote_free_space(self, path):
162+
return self._make_transmission_request('free-space', {
163+
'path': path,
164+
})['size-bytes']
133165

134166
# Judge Torrent Status
135167
@staticmethod

autoremovetorrents/client/utorrent.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import time
44
import requests
55
from ..torrent import Torrent
6+
from ..clientstatus import ClientStatus
67
from autoremovetorrents.exception.connectionfailure import ConnectionFailure
78
from autoremovetorrents.exception.loginfailure import LoginFailure
89
from autoremovetorrents.exception.nosuchtorrent import NoSuchTorrent
@@ -44,6 +45,29 @@ def login(self, username, password):
4445
raise RemoteFailure('The server responsed %d.' \
4546
% request.status_code)
4647

48+
# Get client status
49+
def client_status(self):
50+
# In uTorrent we can only get the total download/upload speed,
51+
# and we should get it by summing the torrents list manually.
52+
53+
# Get torrent list
54+
if time.time() - self._refresh_time > self._refresh_cycle:
55+
self.torrents_list()
56+
57+
# Get sum
58+
download_speed = 0
59+
upload_speed = 0
60+
for torrent in self._torrents_list_cache['torrents']:
61+
upload_speed += torrent[8]
62+
download_speed += torrent[8]
63+
64+
# Generate client status
65+
cs = ClientStatus()
66+
cs.download_speed = download_speed
67+
cs.upload_speed = upload_speed
68+
69+
return cs
70+
4771
# Get uTorrent Version
4872
def version(self):
4973
if self._version == '': # Call torrents_list() to get the version
@@ -97,8 +121,8 @@ def torrent_properties(self, torrent_hash):
97121
torrent_obj.status = uTorrent._judge_status(torrent[1], torrent[4])
98122
torrent_obj.size = torrent[3]
99123
torrent_obj.ratio = torrent[7]/1000
124+
torrent_obj.downloaded = torrent[5]
100125
torrent_obj.uploaded = torrent[6]
101-
torrent_obj.seeding_time = torrent[6]
102126
torrent_obj.upload_speed = properties['ulrate']
103127
torrent_obj.download_speed = properties['dlrate']
104128
torrent_obj.seeder = torrent[15]

autoremovetorrents/clientstatus.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
from .util.convertbytes import convert_bytes
2+
from .util.convertspeed import convert_speed
3+
4+
class ClientStatus(object):
5+
def __init__(self):
6+
# Proper attributes:
7+
# free_space, total_download_speed, total_upload_speed, etc.
8+
#
9+
# Note:
10+
# The type of free_space is a function because we need to specific a
11+
# directory to check its free space.
12+
pass
13+
14+
# Format client status info
15+
def __str__(self):
16+
# Attribute Formater
17+
def disp(prop, converter = None):
18+
if hasattr(self, prop):
19+
attr = getattr(self, prop)
20+
if converter is not None:
21+
return converter(attr)
22+
else:
23+
return '(Not Provided)'
24+
25+
return ('Status reported by the client: \n' +
26+
'\tDownload Speed: %s\tTotal: %s\n' +
27+
'\tUpload Speed: %s\tTotal: %s\n' +
28+
'\tOutgoing Port Status: %s') % \
29+
(
30+
disp('download_speed', convert_speed),
31+
disp('total_downloaded', convert_bytes),
32+
disp('upload_speed', convert_speed),
33+
disp('total_uploaded', convert_bytes),
34+
disp('port_status', lambda s: s.name),
35+
)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import sys
2+
3+
# The shutil.disk_usage is available since Python 3.3,
4+
# but in other versions, we need to use psutil.disk_usage to replace it.
5+
# (For Synology's compatibility; there is no psutil in Python 3 in Synology)
6+
SUPPORT_SHUTIL = sys.version_info >= (3, 3, 0)
7+
8+
def disk_usage_(path):
9+
du = None
10+
11+
if SUPPORT_SHUTIL:
12+
import shutil
13+
du = shutil.disk_usage(path)
14+
else:
15+
import psutil
16+
du = psutil.disk_usage(path)
17+
18+
# Unified format
19+
return {
20+
'total': du.total,
21+
'used': du.used,
22+
'free': du.free,
23+
}

autoremovetorrents/condition/avgdownloadspeed.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ def __init__(self, avg_dl_speed, comp = Comparer.GT):
77
self._avg_dl_speed = avg_dl_speed # In KiB
88
self._comparer = comp
99

10-
def apply(self, torrents):
10+
def apply(self, client_status, torrents):
1111
for torrent in torrents:
1212
if self.compare(torrent.average_download_speed, self._avg_dl_speed * 1024, self._comparer):
1313
self.remove.add(torrent)

autoremovetorrents/condition/avguploadspeed.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ def __init__(self, avg_ul_speed, comp = Comparer.LT):
77
self._avg_ul_speed = avg_ul_speed # In KiB
88
self._comparer = comp
99

10-
def apply(self, torrents):
10+
def apply(self, client_status, torrents):
1111
for torrent in torrents:
1212
if self.compare(torrent.average_upload_speed, self._avg_ul_speed * 1024, self._comparer):
1313
self.remove.add(torrent)

0 commit comments

Comments
 (0)