Skip to content

Commit

Permalink
Merge pull request #83 from jerrymakesjelly/dev
Browse files Browse the repository at this point in the history
Version 1.5.3
  • Loading branch information
jerrymakesjelly authored Jan 21, 2021
2 parents cf799d5 + 5f75d63 commit 7b2b95b
Show file tree
Hide file tree
Showing 79 changed files with 1,652 additions and 990 deletions.
7 changes: 7 additions & 0 deletions README-cn.rst
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@

更新日志
----------
**2020-08-27 周四**:1.5.3 版本。

* 修复 psutil 在群晖的兼容问题(用于检查磁盘剩余空间)。(#61)
* 可以通过 ``--debug`` 或 ``-d`` 命令行启用调试模式。(#76)
* 修复由主机 URL 末尾的 ``/`` 导致的 API 不兼容的问题。(#81)
* 添加上传量与下载量两个条件。(#79)

**2020-03-27 周五**:1.5.2 版本。

* 支持 Deluge (#8);
Expand Down
7 changes: 7 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ Screenshot

Changelog
----------
**Thu, 27 Aug 2020**: Version 1.5.3.

* Fix psutil's compatibility in Synology (use to check the free spaces). (#61)
* Enable to output debug logs by specifying ``--debug`` or ``-d`` argument. (#76)
* Fix API imcompatibility issue caused by the trailing ``/`` in host URL. (#81)
* Add uploaded size and downloaded size conditions. (#79)

**Fri, 27 Mar 2020**: Version 1.5.2.

* Support Deluge. (#8)
Expand Down
32 changes: 32 additions & 0 deletions autoremovetorrents/client/deluge.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
from deluge_client import DelugeRPCClient
from deluge_client.client import DelugeClientException
from ..torrent import Torrent
from ..clientstatus import ClientStatus
from ..portstatus import PortStatus
from ..torrentstatus import TorrentStatus
from ..exception.loginfailure import LoginFailure
from ..exception.remotefailure import RemoteFailure
Expand Down Expand Up @@ -45,6 +47,31 @@ def _call(self, method, *args, **kwargs):
# Raise our own exception
raise RemoteFailure(e.args[0].split('\n')[0] if len(e.args) > 0 else e.__class__.__name__)

# Get client status
def client_status(self):
cs = ClientStatus()

# Set remote free space checker
cs.free_space = self.remote_free_space

# Get DL/UL information
session_stats = self._call('core.get_session_status', [
'payload_download_rate',
'payload_upload_rate',
'total_download',
'total_upload',
])
cs.download_speed = session_stats['payload_download_rate']
cs.total_downloaded = session_stats['total_download']
cs.upload_speed = session_stats['payload_upload_rate']
cs.total_uploaded = session_stats['total_upload']

# Get port status
port_is_open = self._call('core.test_listen_port')
cs.port_status = PortStatus.Open if port_is_open else PortStatus.Closed

return cs

# Get Deluge version
def version(self):
funcs = {
Expand Down Expand Up @@ -113,6 +140,7 @@ def torrent_properties(self, torrent_hash):
torrent_obj.size = torrent['total_size']
torrent_obj.ratio = torrent['ratio']
torrent_obj.uploaded = torrent['total_uploaded']
torrent_obj.downloaded = torrent['all_time_download']
torrent_obj.create_time = int(torrent['time_added'])
torrent_obj.seeding_time = torrent['seeding_time']
torrent_obj.upload_speed = torrent['upload_payload_rate']
Expand All @@ -132,6 +160,10 @@ def torrent_properties(self, torrent_hash):

return torrent_obj

# Get free space
def remote_free_space(self, path):
return self._call('core.get_free_space', path)

# Judge Torrent Status
@staticmethod
def _judge_status(state):
Expand Down
50 changes: 50 additions & 0 deletions autoremovetorrents/client/qbittorrent.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
#-*- coding:utf-8 -*-
import requests
import time
from .. import logger
from ..torrent import Torrent
from ..clientstatus import ClientStatus
from ..torrentstatus import TorrentStatus
from ..portstatus import PortStatus
from ..exception.loginfailure import LoginFailure
from ..exception.connectionfailure import ConnectionFailure
from ..exception.incompatibleapi import IncompatibleAPIVersion
Expand Down Expand Up @@ -37,6 +40,10 @@ def client_version(self):
def login(self, username, password):
return self._session.post(self._host+'/login', data={'username':username, 'password':password})

# Get server state
def server_state(self):
return self._session.get(self._host+'/sync/maindata')

# Get torrent list
def torrent_list(self):
return self._session.get(self._host+'/query/torrents')
Expand Down Expand Up @@ -86,6 +93,10 @@ def client_version(self):
def login(self, username, password):
return self._session.post(self._host+'/api/v2/auth/login', data={'username':username, 'password':password})

# Get server state
def server_state(self):
return self._session.get(self._host+'/api/v2/sync/maindata')

# Get torrent list
def torrent_list(self):
return self._session.get(self._host+'/api/v2/torrents/info')
Expand All @@ -107,6 +118,9 @@ def delete_torrents_and_data(self, torrent_hash_list):
return self._session.get(self._host+'/api/v2/torrents/delete', params={'hashes':'|'.join(torrent_hash_list), 'deleteFiles': True})

def __init__(self, host):
# Logger
self._logger = logger.Logger.register(__name__)

# Torrents list cache
self._torrents_list_cache = []
self._refresh_cycle = 30
Expand Down Expand Up @@ -135,6 +149,29 @@ def login(self, username, password):
else:
raise LoginFailure('The server returned HTTP %d.' % request.status_code)

# Get client status
def client_status(self):
status = self._request_handler.server_state().json()['server_state']

cs = ClientStatus()
# Remote free space checker
cs.free_space = self.remote_free_space
# Downloading speed and downloaded size
cs.download_speed = status['dl_info_speed']
cs.total_downloaded = status['dl_info_data']
# Uploading speed and uploaded size
cs.upload_speed = status['up_info_speed']
cs.total_uploaded = status['up_info_data']
# Outgoing port status
if status['connection_status'] == 'connected':
cs.port_status = PortStatus.Open
elif status['connection_status'] == 'firewalled':
cs.port_status = PortStatus.Firewalled
else:
cs.port_status = PortStatus.Closed

return cs

# Get qBittorrent Version
def version(self):
request = self._request_handler.client_version()
Expand Down Expand Up @@ -182,6 +219,7 @@ def torrent_properties(self, torrent_hash):
torrent_obj.size = torrent['size']
torrent_obj.ratio = torrent['ratio']
torrent_obj.uploaded = properties['total_uploaded']
torrent_obj.downloaded = properties['total_downloaded']
torrent_obj.create_time = properties['addition_date']
torrent_obj.seeding_time = properties['seeding_time']
torrent_obj.upload_speed = properties['up_speed']
Expand All @@ -200,6 +238,18 @@ def torrent_properties(self, torrent_hash):

return torrent_obj

# Get free space
def remote_free_space(self, path):
# Actually the path is ignored
self._logger.info('Get Free Space: The path is ignored ' +
'since qBitorrent does not support to specific a path to check the free space.')
status = self._request_handler.server_state().json()['server_state']

# There is no free space data in qBittorrent 3.x
if 'free_space_on_disk' in status:
return status['free_space_on_disk']
return None

# Judge Torrent Status (qBittorrent doesn't have stopped status)
@staticmethod
def _judge_status(state):
Expand Down
32 changes: 32 additions & 0 deletions autoremovetorrents/client/transmission.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#-*- coding:utf-8 -*-
import requests
from ..torrent import Torrent
from ..clientstatus import ClientStatus
from ..torrentstatus import TorrentStatus
from ..portstatus import PortStatus
from ..exception.connectionfailure import ConnectionFailure
from ..exception.loginfailure import LoginFailure
from ..exception.nosuchclient import NoSuchClient
Expand Down Expand Up @@ -53,6 +55,29 @@ def _make_transmission_request(self, method, arguments=None):
% (request.status_code, method)
)

# Get client status
def client_status(self):
status = self._make_transmission_request('session-stats')

cs = ClientStatus()
# Remote free space checker
cs.free_space = self.remote_free_space
# Download speed and downloaded size
cs.download_speed = status['downloadSpeed']
cs.total_downloaded = status['current-stats']['downloadedBytes']
# Uploading speed and uploaded size
cs.upload_speed = status['uploadSpeed']
cs.total_uploaded = status['current-stats']['uploadedBytes']

# Outgoing port status
port_is_open = self._make_transmission_request('port-test')
if port_is_open:
cs.port_status = PortStatus.Open
else:
cs.port_status = PortStatus.Closed

return cs

# Get Transmission Version
def version(self):
ver = self._make_transmission_request('session-get')['version']
Expand Down Expand Up @@ -116,6 +141,7 @@ def torrent_properties(self, torrent_hash):
torrent_obj.size = torrent['totalSize']
torrent_obj.ratio = torrent['uploadRatio']
torrent_obj.uploaded = torrent['uploadedEver']
torrent_obj.downloaded = torrent['downloadedEver']
torrent_obj.create_time = torrent['addedDate']
torrent_obj.seeding_time = torrent['secondsSeeding']
torrent_obj.upload_speed = torrent['rateUpload']
Expand All @@ -130,6 +156,12 @@ def torrent_properties(self, torrent_hash):
torrent_obj.progress = torrent['percentDone']

return torrent_obj

# Get free space
def remote_free_space(self, path):
return self._make_transmission_request('free-space', {
'path': path,
})['size-bytes']

# Judge Torrent Status
@staticmethod
Expand Down
26 changes: 25 additions & 1 deletion autoremovetorrents/client/utorrent.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import time
import requests
from ..torrent import Torrent
from ..clientstatus import ClientStatus
from autoremovetorrents.exception.connectionfailure import ConnectionFailure
from autoremovetorrents.exception.loginfailure import LoginFailure
from autoremovetorrents.exception.nosuchtorrent import NoSuchTorrent
Expand Down Expand Up @@ -44,6 +45,29 @@ def login(self, username, password):
raise RemoteFailure('The server responsed %d.' \
% request.status_code)

# Get client status
def client_status(self):
# In uTorrent we can only get the total download/upload speed,
# and we should get it by summing the torrents list manually.

# Get torrent list
if time.time() - self._refresh_time > self._refresh_cycle:
self.torrents_list()

# Get sum
download_speed = 0
upload_speed = 0
for torrent in self._torrents_list_cache['torrents']:
upload_speed += torrent[8]
download_speed += torrent[8]

# Generate client status
cs = ClientStatus()
cs.download_speed = download_speed
cs.upload_speed = upload_speed

return cs

# Get uTorrent Version
def version(self):
if self._version == '': # Call torrents_list() to get the version
Expand Down Expand Up @@ -97,8 +121,8 @@ def torrent_properties(self, torrent_hash):
torrent_obj.status = uTorrent._judge_status(torrent[1], torrent[4])
torrent_obj.size = torrent[3]
torrent_obj.ratio = torrent[7]/1000
torrent_obj.downloaded = torrent[5]
torrent_obj.uploaded = torrent[6]
torrent_obj.seeding_time = torrent[6]
torrent_obj.upload_speed = properties['ulrate']
torrent_obj.download_speed = properties['dlrate']
torrent_obj.seeder = torrent[15]
Expand Down
35 changes: 35 additions & 0 deletions autoremovetorrents/clientstatus.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from .util.convertbytes import convert_bytes
from .util.convertspeed import convert_speed

class ClientStatus(object):
def __init__(self):
# Proper attributes:
# free_space, total_download_speed, total_upload_speed, etc.
#
# Note:
# The type of free_space is a function because we need to specific a
# directory to check its free space.
pass

# Format client status info
def __str__(self):
# Attribute Formater
def disp(prop, converter = None):
if hasattr(self, prop):
attr = getattr(self, prop)
if converter is not None:
return converter(attr)
else:
return '(Not Provided)'

return ('Status reported by the client: \n' +
'\tDownload Speed: %s\tTotal: %s\n' +
'\tUpload Speed: %s\tTotal: %s\n' +
'\tOutgoing Port Status: %s') % \
(
disp('download_speed', convert_speed),
disp('total_downloaded', convert_bytes),
disp('upload_speed', convert_speed),
disp('total_uploaded', convert_bytes),
disp('port_status', lambda s: s.name),
)
23 changes: 23 additions & 0 deletions autoremovetorrents/compatibility/disk_usage_.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import sys

# The shutil.disk_usage is available since Python 3.3,
# but in other versions, we need to use psutil.disk_usage to replace it.
# (For Synology's compatibility; there is no psutil in Python 3 in Synology)
SUPPORT_SHUTIL = sys.version_info >= (3, 3, 0)

def disk_usage_(path):
du = None

if SUPPORT_SHUTIL:
import shutil
du = shutil.disk_usage(path)
else:
import psutil
du = psutil.disk_usage(path)

# Unified format
return {
'total': du.total,
'used': du.used,
'free': du.free,
}
2 changes: 1 addition & 1 deletion autoremovetorrents/condition/avgdownloadspeed.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ def __init__(self, avg_dl_speed, comp = Comparer.GT):
self._avg_dl_speed = avg_dl_speed # In KiB
self._comparer = comp

def apply(self, torrents):
def apply(self, client_status, torrents):
for torrent in torrents:
if self.compare(torrent.average_download_speed, self._avg_dl_speed * 1024, self._comparer):
self.remove.add(torrent)
Expand Down
2 changes: 1 addition & 1 deletion autoremovetorrents/condition/avguploadspeed.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ def __init__(self, avg_ul_speed, comp = Comparer.LT):
self._avg_ul_speed = avg_ul_speed # In KiB
self._comparer = comp

def apply(self, torrents):
def apply(self, client_status, torrents):
for torrent in torrents:
if self.compare(torrent.average_upload_speed, self._avg_ul_speed * 1024, self._comparer):
self.remove.add(torrent)
Expand Down
2 changes: 1 addition & 1 deletion autoremovetorrents/condition/connectedleecher.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def __init__(self, cl, comp = Comparer.LT):
self._connected_leecher = cl
self._comparer = comp

def apply(self, torrents):
def apply(self, client_status, torrents):
for torrent in torrents:
# Note: This condition is only available for the uploading and the downloading torrents
if (torrent.status == TorrentStatus.Downloading or torrent.status == TorrentStatus.Uploading) \
Expand Down
2 changes: 1 addition & 1 deletion autoremovetorrents/condition/connectedseeder.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def __init__(self, cs, comp = Comparer.GT):
self._connected_seeder = cs
self._comparer = comp

def apply(self, torrents):
def apply(self, client_status, torrents):
for torrent in torrents:
# Note: This condition is only available for the uploading and downloading torrents
if (torrent.status == TorrentStatus.Uploading or torrent.status == TorrentStatus.Downloading) and \
Expand Down
Loading

0 comments on commit 7b2b95b

Please sign in to comment.