fix queue
This commit is contained in:
@@ -274,11 +274,25 @@ def _read_live_start_state(client: Any, torrent_hash: str) -> dict[str, Any]:
|
||||
result[key] = int(value or 0) if key in {'state', 'active', 'open', 'priority'} else str(value or '')
|
||||
except Exception as exc:
|
||||
result[f'{key}_error'] = str(exc)
|
||||
# Note: Nie uznajemy d.is_open ani state=1 za wznowienie; Paused też potrafi mieć te wartości.
|
||||
# Smart Queue zalicza start dopiero po d.is_active=1, czyli po realnym zdjęciu pauzy.
|
||||
# Note: Realny slot liczymy po d.is_active=1. Dodatkowo zwracamy state/open/priority,
|
||||
# bo przy masowym resume rTorrent czasem przyjmuje start, ale aktywuje transfer dopiero w kolejnym ticku.
|
||||
result['started'] = bool(int(result.get('active') or 0))
|
||||
result['start_accepted'] = bool(int(result.get('state') or 0) or int(result.get('open') or 0))
|
||||
return result
|
||||
|
||||
|
||||
def _refresh_active_slots(profile: dict, excluded: set[str], manage_stopped: bool) -> tuple[int, list[dict[str, Any]]]:
|
||||
"""Read a fresh torrent snapshot and count real active Smart Queue slots."""
|
||||
fresh = rtorrent.list_torrents(profile)
|
||||
active = [
|
||||
t for t in fresh
|
||||
if str(t.get('hash') or '') not in excluded
|
||||
and _is_running_download_slot(t)
|
||||
]
|
||||
# Note: Po batchowym resume nie ufamy staremu snapshotowi; odświeżenie z rTorrent
|
||||
# pozwala dobić kolejkę także wtedy, gdy aktywacja nastąpiła z opóźnieniem.
|
||||
return len(active), fresh
|
||||
|
||||
def _set_smart_queue_label(client: Any, torrent_hash: str, attempts: int = 3) -> bool:
|
||||
for attempt in range(max(1, attempts)):
|
||||
try:
|
||||
@@ -508,18 +522,23 @@ def check(profile: dict | None = None, user_id: int | None = None, force: bool =
|
||||
|
||||
candidate_queue = [t for t in candidates if str(t.get('hash') or '') and str(t.get('hash') or '') not in pause_hashes]
|
||||
active_slots = active_after_pause
|
||||
max_resume_attempts = max(len(candidate_queue), max_active * 3)
|
||||
|
||||
# Note: Resume dziala teraz w petli do pelnego limitu z ustawien. Gdy batch nie przejdzie
|
||||
# na d.is_active=1, Smart Queue nie zatrzymuje sie, tylko probuje nastepnych kandydatow.
|
||||
while candidate_queue and active_slots < max_active:
|
||||
# Note: Resume działa w rundach aż do pełnego limitu z ustawień. Po każdej rundzie
|
||||
# pobieramy świeży snapshot z rTorrent, bo masowe d.resume/d.start nie zawsze widać
|
||||
# natychmiast w d.is_active na pojedynczym RPC.
|
||||
while candidate_queue and active_slots < max_active and len(attempted_hashes) < max_resume_attempts:
|
||||
slots_left = max_active - active_slots
|
||||
batch = candidate_queue[:slots_left]
|
||||
candidate_queue = candidate_queue[slots_left:]
|
||||
# Note: Bierzemy mały nadmiar kandydatów tylko wtedy, gdy poprzednie resume nie zwiększyło
|
||||
# liczby aktywnych slotów; to naprawia przypadek, gdy część pauzowanych nie wstaje po komendzie.
|
||||
batch_size = min(len(candidate_queue), max(1, slots_left))
|
||||
batch = candidate_queue[:batch_size]
|
||||
candidate_queue = candidate_queue[batch_size:]
|
||||
batch_requested: list[str] = []
|
||||
|
||||
for t in batch:
|
||||
h = str(t.get('hash') or '')
|
||||
if not h:
|
||||
if not h or h in attempted_hashes:
|
||||
continue
|
||||
attempted_hashes.add(h)
|
||||
try:
|
||||
@@ -529,6 +548,10 @@ def check(profile: dict | None = None, user_id: int | None = None, force: bool =
|
||||
batch_requested.append(h)
|
||||
except Exception as exc:
|
||||
start_failed.append({'hash': h, 'error': str(exc)})
|
||||
time.sleep(0.03)
|
||||
|
||||
if not batch_requested:
|
||||
continue
|
||||
|
||||
active_verified, batch_no_effect = _verify_started_downloads(c, batch_requested)
|
||||
start_no_effect.extend(batch_no_effect)
|
||||
@@ -536,10 +559,24 @@ def check(profile: dict | None = None, user_id: int | None = None, force: bool =
|
||||
if h not in resumed:
|
||||
_restore_auto_label(c, profile_id, h, None)
|
||||
resumed.append(h)
|
||||
active_slots += len([h for h in active_verified if h])
|
||||
|
||||
if not batch_requested:
|
||||
break
|
||||
fresh_active_slots, fresh_torrents = _refresh_active_slots(profile, excluded, manage_stopped)
|
||||
active_slots = max(active_slots, fresh_active_slots)
|
||||
|
||||
# Note: Jeżeli rTorrent wznowił torrent dopiero po odświeżeniu listy, dopisujemy go
|
||||
# do resumed i zdejmujemy techniczny label Smart Queue.
|
||||
fresh_by_hash = {str(t.get('hash') or ''): t for t in fresh_torrents}
|
||||
for h in batch_requested:
|
||||
live_t = fresh_by_hash.get(h)
|
||||
if live_t and _is_running_download_slot(live_t) and h not in resumed:
|
||||
_restore_auto_label(c, profile_id, h, None)
|
||||
resumed.append(h)
|
||||
|
||||
if active_slots < max_active and not candidate_queue:
|
||||
# Note: Ostatnia próba dla pozycji, które przyjęły start, ale jeszcze nie pokazały active=1.
|
||||
time.sleep(0.75)
|
||||
fresh_active_slots, fresh_torrents = _refresh_active_slots(profile, excluded, manage_stopped)
|
||||
active_slots = max(active_slots, fresh_active_slots)
|
||||
|
||||
resumed_set = set(resumed)
|
||||
waiting_hashes = {
|
||||
|
||||
Reference in New Issue
Block a user