fix ququq

This commit is contained in:
Mateusz Gruszczyński
2026-05-31 10:37:37 +02:00
parent f04eb7016f
commit 4fd18e3216
7 changed files with 40 additions and 14 deletions
+10 -1
View File
@@ -1,5 +1,7 @@
from __future__ import annotations
import time
from .client import *
from .files import set_file_priorities
from .system import disk_usage_for_default_path
@@ -214,6 +216,7 @@ TORRENT_FIELDS = [
]
TORRENT_OPTIONAL_FIELDS = [
"d.timestamp.last_active=",
"d.timestamp.finished=",
]
@@ -252,7 +255,12 @@ def normalize_row(row: list) -> dict:
directory = str(row[14] or "")
base_path = str(row[15] or "")
is_multi_file = int(row[22] or 0) if len(row) > 22 else 0
completed_at = int(row[23] or 0) if len(row) > 23 else 0
# Note: Last activity is optional because older rTorrent builds may not expose this timestamp.
last_activity = int(row[23] or 0) if len(row) > 23 else 0
if not last_activity and (down_rate > 0 or up_rate > 0):
# Note: rTorrent builds without d.timestamp.last_active still expose live rates, so active rows get a safe current timestamp.
last_activity = int(time.time())
completed_at = int(row[24] or 0) if len(row) > 24 else 0
# Show the selected download location only. Hide the torrent root
# directory for multi-file torrents and the filename for single-file
@@ -310,6 +318,7 @@ def normalize_row(row: list) -> dict:
"priority": int(row[13] or 0),
"path": display_path,
"created": int(row[16] or 0),
"last_activity": last_activity,
"completed_at": completed_at,
"label": str(row[17] or ""),
"ratio_group": str(row[18] or ""),
+25 -8
View File
@@ -66,6 +66,8 @@ def _diagnostics_torrent(t: dict[str, Any] | None) -> dict[str, Any]:
'hashing': int(t.get('hashing') or 0),
'priority': int(t.get('priority') or 0),
'down_rate': int(t.get('down_rate') or 0),
'up_rate': int(t.get('up_rate') or 0),
'last_activity': int(t.get('last_activity') or 0),
'peers': int(t.get('peers') or 0),
'seeds': int(t.get('seeds') or 0),
'label': str(t.get('label') or ''),
@@ -800,9 +802,22 @@ def _is_running_download_slot(t: dict[str, Any]) -> bool:
return _is_started_download_slot(t)
def _is_stalled_download(t: dict[str, Any], min_speed: int, min_seeds: int, min_peers: int, ignore_seed_peer: bool, ignore_speed: bool) -> bool:
def _has_recent_transfer_activity(t: dict[str, Any], stalled_seconds: int) -> bool:
"""Return True when a torrent is currently transferring or was active within the stalled window."""
# Note: Live transfer rates always protect a torrent from being marked as stalled.
if int(t.get('down_rate') or 0) > 0 or int(t.get('up_rate') or 0) > 0:
return True
last_activity = int(t.get('last_activity') or 0)
if last_activity <= 0:
return False
return time.time() - last_activity < max(1, int(stalled_seconds or 0))
def _is_stalled_download(t: dict[str, Any], min_speed: int, min_seeds: int, min_peers: int, stalled_seconds: int, ignore_seed_peer: bool, ignore_speed: bool) -> bool:
"""Return True when a started torrent should begin or continue the stalled timer."""
# Note: Each ignore switch removes only its own criterion; the stalled timer still applies after criteria match.
# Note: Recent transfer activity wins over ignored source/speed criteria, preventing active torrents from being stopped as stalled.
if _has_recent_transfer_activity(t, stalled_seconds):
return False
speed_ok = True if ignore_speed else int(t.get('down_rate') or 0) <= max(0, int(min_speed or 0))
source_ok = True if ignore_seed_peer else int(t.get('seeds') or 0) <= max(0, int(min_seeds or 0)) and (min_peers <= 0 or int(t.get('peers') or 0) <= min_peers)
return speed_ok and source_ok
@@ -810,13 +825,15 @@ def _is_stalled_download(t: dict[str, Any], min_speed: int, min_seeds: int, min_
def _stalled_timer_key(min_speed: int, min_seeds: int, min_peers: int, stalled_seconds: int, ignore_seed_peer: bool, ignore_speed: bool) -> str:
"""Return a stable key for the stalled rules that started the current timer."""
# Note: Changing ignore switches or thresholds restarts existing stalled timers instead of reusing old rows.
return f"v4|speed={int(min_speed or 0)}|seeds={int(min_seeds or 0)}|peers={int(min_peers or 0)}|seconds={int(stalled_seconds or 0)}|ignore_sources={int(bool(ignore_seed_peer))}|ignore_speed={int(bool(ignore_speed))}"
# Note: Version bump clears old timers created by the previous ignore-speed/source behavior.
return f"v5|speed={int(min_speed or 0)}|seeds={int(min_seeds or 0)}|peers={int(min_peers or 0)}|seconds={int(stalled_seconds or 0)}|ignore_sources={int(bool(ignore_seed_peer))}|ignore_speed={int(bool(ignore_speed))}"
def _is_low_activity_download(t: dict[str, Any], min_speed: int, min_seeds: int, min_peers: int, ignore_seed_peer: bool = False, ignore_speed: bool = False) -> bool:
def _is_low_activity_download(t: dict[str, Any], min_speed: int, min_seeds: int, min_peers: int, stalled_seconds: int, ignore_seed_peer: bool = False, ignore_speed: bool = False) -> bool:
"""Return True when a started torrent is weak and should be stopped first."""
# Note: Stop priority uses only criteria that are not ignored, so disabled criteria cannot stop torrents earlier.
# Note: Active transfers are never preferred for cleanup while non-transferring rows are available.
if _has_recent_transfer_activity(t, stalled_seconds):
return False
low_speed = False if ignore_speed else int(t.get('down_rate') or 0) <= max(0, int(min_speed or 0))
low_seeds = False if ignore_seed_peer else int(t.get('seeds') or 0) <= max(0, int(min_seeds or 0))
low_peers = False if ignore_seed_peer or min_peers <= 0 else int(t.get('peers') or 0) <= max(0, int(min_peers or 0))
@@ -1232,9 +1249,9 @@ def check(profile: dict | None = None, user_id: int | None = None, force: bool =
ignored_seed_peer_count += 1
if ignore_speed and int(t.get('down_rate') or 0) <= max(0, int(min_speed or 0)):
ignored_speed_count += 1
is_stalled = _is_stalled_download(t, min_speed, min_seeds, min_peers, ignore_seed_peer, ignore_speed)
is_stalled = _is_stalled_download(t, min_speed, min_seeds, min_peers, stalled_seconds, ignore_seed_peer, ignore_speed)
# Note: Hard-limit enforcement uses only non-ignored weak criteria before choosing weak items.
if _is_low_activity_download(t, min_speed, min_seeds, min_peers, ignore_seed_peer, ignore_speed):
if _is_low_activity_download(t, min_speed, min_seeds, min_peers, stalled_seconds, ignore_seed_peer, ignore_speed):
stop_eligible.append(t)
h = str(t.get('hash') or '')
if not h: