smart queue fix

This commit is contained in:
Mateusz Gruszczyński
2026-05-05 14:14:47 +02:00
parent 2d19481c4c
commit b74b32dd21

View File

@@ -243,7 +243,9 @@ def _read_live_start_state(client: Any, torrent_hash: str) -> dict[str, Any]:
result[key] = int(value or 0) if key in {'state', 'active'} else str(value or '') result[key] = int(value or 0) if key in {'state', 'active'} else str(value or '')
except Exception as exc: except Exception as exc:
result[f'{key}_error'] = str(exc) result[f'{key}_error'] = str(exc)
result['started'] = bool(int(result.get('state') or 0) and int(result.get('active') or 0)) # Note: rTorrent d.is_active oznacza realny transfer/aktywne peery, a nie slot kolejki.
# Torrenty uruchomione, ale czekajace na peery/throttle, maja state=1 i active=0.
result['started'] = bool(int(result.get('state') or 0))
return result return result
def _set_smart_queue_label(client: Any, torrent_hash: str, attempts: int = 3) -> bool: def _set_smart_queue_label(client: Any, torrent_hash: str, attempts: int = 3) -> bool:
@@ -270,12 +272,14 @@ def _mark_auto_paused(client: Any, profile_id: int, torrent: dict[str, Any]) ->
def _is_smart_queue_hold(torrent: dict[str, Any] | None, manage_stopped: bool = True) -> bool: def _is_smart_queue_hold(torrent: dict[str, Any] | None, manage_stopped: bool = True) -> bool:
if not torrent or int(torrent.get('complete') or 0): if not torrent or int(torrent.get('complete') or 0):
return False return False
if str(torrent.get('label') or '') == SMART_QUEUE_LABEL:
return True
# Note: Gdy manage_stopped=False, techniczne labele Smart Queue dotyczą tylko paused, a nie całkiem zatrzymanych torrentów. # Note: Gdy manage_stopped=False, techniczne labele Smart Queue dotyczą tylko paused, a nie całkiem zatrzymanych torrentów.
if bool(torrent.get('paused')): if bool(torrent.get('paused')) and not int(torrent.get('state') or 0):
return True return True
if not manage_stopped and not int(torrent.get('state') or 0): if not manage_stopped and not int(torrent.get('state') or 0):
return False return False
return not int(torrent.get('active') or 0) or not int(torrent.get('state') or 0) return not int(torrent.get('state') or 0)
def _clear_untracked_smart_queue_label(client: Any, torrent_hash: str, current_label: str) -> bool: def _clear_untracked_smart_queue_label(client: Any, torrent_hash: str, current_label: str) -> bool:
@@ -338,13 +342,25 @@ def check(profile: dict | None = None, user_id: int | None = None, force: bool =
torrents = rtorrent.list_torrents(profile) torrents = rtorrent.list_torrents(profile)
excluded = _excluded_hashes(profile_id, user_id) excluded = _excluded_hashes(profile_id, user_id)
manage_stopped = bool(settings.get('manage_stopped')) manage_stopped = bool(settings.get('manage_stopped'))
downloading = [t for t in torrents if not int(t.get('complete') or 0) and int(t.get('state') or 0) and not t.get('paused') and t.get('hash') not in excluded] def is_managed_hold(t: dict[str, Any]) -> bool:
# Note: Domyślnie kolejka wznawia wyłącznie paused; stopped są kandydatami tylko po włączeniu switcha w ustawieniach. return str(t.get('label') or '') == SMART_QUEUE_LABEL
# Note: Slot Smart Queue liczymy po d.state, nie po d.is_active. d.is_active bywa 0
# dla torrentu juz wystartowanego, ale chwilowo bez transferu, wiec powodowal startowanie po jednej sztuce.
downloading = [
t for t in torrents
if not int(t.get('complete') or 0)
and int(t.get('state') or 0)
and not is_managed_hold(t)
and t.get('hash') not in excluded
]
# Note: Kandydaci do uruchomienia to przede wszystkim torrenty odlozone przez Smart Queue.
# Nie traktujemy kazdego state=1/active=0 jako pauzy, bo rTorrent tak pokazuje tez oczekiwanie na peery/throttle.
stopped = [ stopped = [
t for t in torrents t for t in torrents
if not int(t.get('complete') or 0) if not int(t.get('complete') or 0)
and t.get('hash') not in excluded and t.get('hash') not in excluded
and (bool(t.get('paused')) or (manage_stopped and not int(t.get('state') or 0))) and (is_managed_hold(t) or (manage_stopped and not int(t.get('state') or 0)))
] ]
min_speed = int(settings.get('min_speed_bytes') or 0) min_speed = int(settings.get('min_speed_bytes') or 0)
min_seeds = int(settings.get('min_seeds') or 0) min_seeds = int(settings.get('min_seeds') or 0)
@@ -441,7 +457,8 @@ def check(profile: dict | None = None, user_id: int | None = None, force: bool =
for h in verified: for h in verified:
_restore_auto_label(c, profile_id, h, None) _restore_auto_label(c, profile_id, h, None)
resumed = verified resumed = verified
restored = _cleanup_auto_labels(c, profile_id, torrents, set(paused), manage_stopped) keep_labels = set(paused) | {str(t.get('hash') or '') for t in stopped if str(t.get('label') or '') == SMART_QUEUE_LABEL and str(t.get('hash') or '') not in set(resumed)}
restored = _cleanup_auto_labels(c, profile_id, torrents, keep_labels, manage_stopped)
details = {'excluded': len(excluded), 'enabled': bool(settings.get('enabled')), 'auto_label': SMART_QUEUE_LABEL, 'labels_restored': restored, 'labels_failed': label_failed, 'start_failed': start_failed, 'start_no_effect': start_no_effect, 'resume_requested': resume_requested, 'manage_stopped': manage_stopped, 'max_active_downloads': max_active, 'active_before': len(downloading), 'active_after': active_after_pause + len(resumed), 'rtorrent_cap': rtorrent_cap} details = {'excluded': len(excluded), 'enabled': bool(settings.get('enabled')), 'auto_label': SMART_QUEUE_LABEL, 'labels_restored': restored, 'labels_failed': label_failed, 'start_failed': start_failed, 'start_no_effect': start_no_effect, 'resume_requested': resume_requested, 'manage_stopped': manage_stopped, 'max_active_downloads': max_active, 'active_before': len(downloading), 'active_after': active_after_pause + len(resumed), 'rtorrent_cap': rtorrent_cap}
add_history(profile_id, 'force_check' if force else 'auto_check', paused, resumed, len(torrents), details, user_id) add_history(profile_id, 'force_check' if force else 'auto_check', paused, resumed, len(torrents), details, user_id)
return {'ok': True, 'enabled': bool(settings.get('enabled')), 'paused': paused, 'resumed': resumed, 'resume_requested': resume_requested, 'labels_restored': restored, 'labels_failed': label_failed, 'start_failed': start_failed, 'start_no_effect': start_no_effect, 'rtorrent_cap': rtorrent_cap, 'checked': len(torrents), 'excluded': len(excluded), 'settings': settings} return {'ok': True, 'enabled': bool(settings.get('enabled')), 'paused': paused, 'resumed': resumed, 'resume_requested': resume_requested, 'labels_restored': restored, 'labels_failed': label_failed, 'start_failed': start_failed, 'start_no_effect': start_no_effect, 'rtorrent_cap': rtorrent_cap, 'checked': len(torrents), 'excluded': len(excluded), 'settings': settings}