diff --git a/autoremovetorrents/client/qbittorrent.py b/autoremovetorrents/client/qbittorrent.py index 2ff6c17..46be0dc 100644 --- a/autoremovetorrents/client/qbittorrent.py +++ b/autoremovetorrents/client/qbittorrent.py @@ -69,6 +69,11 @@ def torrent_properties(self, torrent_hash): # Get other information properties = self._torrent_generic_properties(torrent_hash) trackers = self._torrent_trackers(torrent_hash) + # For qBittorrent 3.x, the last activity field doesn't exist. + # We use current timestamp to avoid erroneous deletion. + last_activity = int(time.time()) + if 'last_activity' in torrent: + last_activity = torrent['last_activity'] return Torrent( torrent['hash'], torrent['name'], torrent['category'] if 'category' in torrent else torrent['label'], @@ -77,7 +82,7 @@ def torrent_properties(self, torrent_hash): torrent['state'] == 'stalledUP' or torrent['state'] == 'stalledDL', torrent['size'], torrent['ratio'], properties['total_uploaded'], properties['addition_date'], - properties['seeding_time']) + properties['seeding_time'], last_activity) # Judge Torrent Status (qBittorrent doesn't have stopped status) @staticmethod diff --git a/autoremovetorrents/client/transmission.py b/autoremovetorrents/client/transmission.py index 898863e..6b300a5 100644 --- a/autoremovetorrents/client/transmission.py +++ b/autoremovetorrents/client/transmission.py @@ -71,7 +71,7 @@ def torrents_list(self): def torrent_properties(self, torrent_hash): result = self._make_transmission_request('torrent-get', {'ids': [torrent_hash], - 'fields': ['hashString', 'name', 'trackers', 'status', 'totalSize', 'uploadRatio', 'uploadedEver', 'addedDate', 'secondsSeeding', 'isStalled']} + 'fields': ['hashString', 'name', 'trackers', 'status', 'totalSize', 'uploadRatio', 'uploadedEver', 'addedDate', 'secondsSeeding', 'isStalled', 'activityDate']} ) if len(result['torrents']) == 0: # No such torrent raise NoSuchClient("No such torrent of hash '%s'." % torrent_hash) @@ -82,7 +82,7 @@ def torrent_properties(self, torrent_hash): Transmission._judge_status(torrent['status']), torrent['isStalled'], torrent['totalSize'], torrent['uploadRatio'], - torrent['uploadedEver'], torrent['addedDate'], torrent['secondsSeeding']) + torrent['uploadedEver'], torrent['addedDate'], torrent['secondsSeeding'], torrent['activityDate']) # Judge Torrent Status @staticmethod diff --git a/autoremovetorrents/client/utorrent.py b/autoremovetorrents/client/utorrent.py index dd100b3..004e854 100644 --- a/autoremovetorrents/client/utorrent.py +++ b/autoremovetorrents/client/utorrent.py @@ -90,7 +90,9 @@ def torrent_properties(self, torrent_hash): torrent[0], torrent[2], torrent[11], trackers, uTorrent._judge_status(torrent[1], torrent[4]), False, # uTorrent never has stall status torrent[3], torrent[7]/1000, - torrent[6], sys.maxsize, -1) + torrent[6], sys.maxsize, -1, + int(time.time()) # uTorrent doesn't have last activity time field + ) # Not Found raise NoSuchTorrent('No such torrent.') diff --git a/autoremovetorrents/condition/lastactivity.py b/autoremovetorrents/condition/lastactivity.py new file mode 100644 index 0000000..9be9da6 --- /dev/null +++ b/autoremovetorrents/condition/lastactivity.py @@ -0,0 +1,16 @@ +import time +from .base import Comparer +from .base import Condition + +class LastActivityCondition(Condition): + def __init__(self, la, comp = Comparer.GT): + Condition.__init__(self) + self._last_activity = la + self._comparer = comp + + def apply(self, torrents): + for torrent in torrents: + if self.compare(time.time() - torrent.last_activity, self._last_activity, self._comparer): + self.remove.add(torrent) + else: + self.remain.add(torrent) \ No newline at end of file diff --git a/autoremovetorrents/conditionparser.py b/autoremovetorrents/conditionparser.py index 33a689d..81c5096 100644 --- a/autoremovetorrents/conditionparser.py +++ b/autoremovetorrents/conditionparser.py @@ -5,6 +5,7 @@ from .condition.createtime import CreateTimeCondition from .condition.ratio import RatioCondition from .condition.seedingtime import SeedingTimeCondition +from .condition.lastactivity import LastActivityCondition from .exception.nosuchcondition import NoSuchCondition from .exception.syntaxerror import ConditionSyntaxError @@ -13,7 +14,8 @@ class ConditionParser(object): _condition_map = { 'create_time': CreateTimeCondition, 'ratio': RatioCondition, - 'seeding_time': SeedingTimeCondition + 'seeding_time': SeedingTimeCondition, + 'last_activity': LastActivityCondition } # Condition expression diff --git a/autoremovetorrents/strategy.py b/autoremovetorrents/strategy.py index 90fed08..ae28ada 100644 --- a/autoremovetorrents/strategy.py +++ b/autoremovetorrents/strategy.py @@ -9,6 +9,7 @@ from .condition.ratio import RatioCondition from .condition.torrentsize import TorrentSizeCondition from .condition.torrentnumber import TorrentNumberCondition +from .condition.lastactivity import LastActivityCondition from .condition.donothing import EmptyCondition from .conditionparser import ConditionParser @@ -66,6 +67,7 @@ def _apply_conditions(self): 'ratio': RatioCondition, 'seed_size': TorrentSizeCondition, 'maximum_number': TorrentNumberCondition, + 'last_activity': LastActivityCondition, 'nothing': EmptyCondition } for conf in self._conf: diff --git a/autoremovetorrents/torrent.py b/autoremovetorrents/torrent.py index 35b7aa8..dbeee89 100644 --- a/autoremovetorrents/torrent.py +++ b/autoremovetorrents/torrent.py @@ -7,7 +7,7 @@ class Torrent(object): def __init__(self, hash_value, name, category, tracker, status, stalled, size, ratio, - uploaded, create_time, seeding_time): + uploaded, create_time, seeding_time, last_activity): # Save Properties self.hash = hash_value self.name = name @@ -20,6 +20,7 @@ def __init__(self, hash_value, name, category, tracker, status, stalled, size, r self.uploaded = uploaded self.create_time = create_time self.seeding_time = seeding_time + self.last_activity = last_activity # Format torrent info def __str__(self): diff --git a/pytest/test_strategies/cases/last_activity/test_last_activity.yml b/pytest/test_strategies/cases/last_activity/test_last_activity.yml new file mode 100644 index 0000000..9a35176 --- /dev/null +++ b/pytest/test_strategies/cases/last_activity/test_last_activity.yml @@ -0,0 +1,5 @@ +test: + last_activity: 700000 +remove: + - Torrent - 4 + - Torrent - 9 \ No newline at end of file diff --git a/pytest/test_strategies/cases/remove_conditions/test_last_activity_gt.yml b/pytest/test_strategies/cases/remove_conditions/test_last_activity_gt.yml new file mode 100644 index 0000000..f945077 --- /dev/null +++ b/pytest/test_strategies/cases/remove_conditions/test_last_activity_gt.yml @@ -0,0 +1,4 @@ +test: + remove: last_activity > 800000 +remove: + - Torrent - 4 \ No newline at end of file diff --git a/pytest/test_strategies/cases/remove_conditions/test_last_activity_lt.yml b/pytest/test_strategies/cases/remove_conditions/test_last_activity_lt.yml new file mode 100644 index 0000000..70cc0d5 --- /dev/null +++ b/pytest/test_strategies/cases/remove_conditions/test_last_activity_lt.yml @@ -0,0 +1,7 @@ +test: + remove: last_activity < 100000 +remove: + - Torrent - 13 + - Torrent - 14 + - Torrent - 15 + - Torrent - 16 \ No newline at end of file diff --git a/pytest/test_strategies/conftest.py b/pytest/test_strategies/conftest.py index ded4ef3..4e77fe9 100644 --- a/pytest/test_strategies/conftest.py +++ b/pytest/test_strategies/conftest.py @@ -27,7 +27,8 @@ def test_data(): torrent['ratio'], torrent['uploaded'], torrent['added_on'], - torrent['seeding_time'] + torrent['seeding_time'], + torrent['last_activity'] )) return input_torrents