add auth support
This commit is contained in:
@@ -53,7 +53,7 @@ def save_settings(profile_id: int, data: dict[str, Any], user_id: int | None = N
|
||||
'stalled_seconds': max(30, int(data.get('stalled_seconds') or current.get('stalled_seconds') or 300)),
|
||||
'min_speed_bytes': max(0, int(data.get('min_speed_bytes') or current.get('min_speed_bytes') or 0)),
|
||||
'min_seeds': max(0, int(data.get('min_seeds') or current.get('min_seeds') or 0)),
|
||||
# Note: Switch chroni całkiem zatrzymane torrenty przed automatycznym startem; domyślnie Smart Queue zarządza tylko paused.
|
||||
# Note: This switch protects fully stopped torrents from automatic starts; by default Smart Queue manages only paused items.
|
||||
'manage_stopped': 1 if data.get('manage_stopped', current.get('manage_stopped')) else 0,
|
||||
}
|
||||
now = utcnow()
|
||||
@@ -169,14 +169,14 @@ def _restore_auto_label(client: Any, profile_id: int, torrent_hash: str, current
|
||||
if live_label != SMART_QUEUE_LABEL:
|
||||
return False
|
||||
try:
|
||||
# Note: Czyści label Smart Queue także wtedy, gdy torrent został oznaczony wcześniej, ale nie ma już wpisu z poprzednim labelem.
|
||||
# Note: Clear the Smart Queue label even when the torrent was marked earlier but no previous-label entry remains.
|
||||
client.call('d.custom1.set', torrent_hash, '')
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
previous = row.get('previous_label') or ''
|
||||
try:
|
||||
# Note: Przy wznowieniu Smart Queue oddaje poprzedni label tylko wtedy, gdy nadal widzi swój label techniczny.
|
||||
# Note: On resume, Smart Queue restores the previous label only while it still sees its own technical label.
|
||||
if live_label == SMART_QUEUE_LABEL or current_label is None:
|
||||
client.call('d.custom1.set', torrent_hash, previous)
|
||||
conn.execute('DELETE FROM smart_queue_auto_labels WHERE profile_id=? AND torrent_hash=?', (profile_id, torrent_hash))
|
||||
@@ -202,15 +202,15 @@ def _call_rtorrent_setter(client: Any, method: str, value: int) -> bool:
|
||||
def _ensure_rtorrent_download_cap(client: Any, max_active: int) -> dict[str, Any]:
|
||||
"""Raise rTorrent download caps that can silently limit Smart Queue to one item."""
|
||||
result: dict[str, Any] = {'checked': False, 'updated': False, 'items': []}
|
||||
# Note: rTorrent może mieć osobny limit globalny i per-throttle. Gdy div=1,
|
||||
# startowanie kończy się praktycznie jednym aktywnym torrentem mimo targetu 100.
|
||||
# Note: rTorrent may have separate global and per-throttle limits. When div=1,
|
||||
# starts can effectively stop at one active torrent even when the target is 100.
|
||||
for key in ('throttle.max_downloads.global', 'throttle.max_downloads.div'):
|
||||
item: dict[str, Any] = {'key': key, 'checked': False, 'updated': False}
|
||||
try:
|
||||
current = int(client.call(key) or 0)
|
||||
item.update({'checked': True, 'current': current, 'target': int(max_active)})
|
||||
result['checked'] = True
|
||||
# Note: 0 oznacza unlimited; podnosimy tylko dodatnie limity niższe od targetu.
|
||||
# Note: 0 means unlimited; raise only positive limits lower than the target.
|
||||
if 0 < current < max_active:
|
||||
ok = _call_rtorrent_setter(client, f'{key}.set', int(max_active))
|
||||
item['updated'] = ok
|
||||
@@ -231,9 +231,9 @@ def _start_download(client: Any, torrent: dict[str, Any]) -> dict[str, Any]:
|
||||
if not h:
|
||||
return {'hash': h, 'ok': False, 'error': 'missing hash'}
|
||||
if bool(torrent.get('paused')) or str(torrent.get('status') or '').lower() == 'paused' or int(torrent.get('state') or 0):
|
||||
# Note: Kandydaci Smart Queue po d.pause mają być wznawiani przez d.resume, bez d.start/d.stop.
|
||||
# Note: Smart Queue candidates paused with d.pause must be resumed with d.resume, without d.start/d.stop.
|
||||
return rtorrent.resume_paused_hash(client, h)
|
||||
# Note: Tylko opcjonalne manage_stopped korzysta ze ścieżki start dla całkowicie zatrzymanych torrentów.
|
||||
# Note: Only optional manage_stopped uses the start path for fully stopped torrents.
|
||||
return rtorrent.start_or_resume_hash(client, h)
|
||||
|
||||
|
||||
@@ -277,8 +277,8 @@ 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: Do not treat d.is_open or state=1 as resumed; Paused can also have those values.
|
||||
# Smart Queue counts a start only after d.is_active=1, meaning the pause was actually removed.
|
||||
result['started'] = bool(int(result.get('active') or 0))
|
||||
return result
|
||||
|
||||
@@ -308,11 +308,11 @@ def _is_smart_queue_hold(torrent: dict[str, Any] | None, manage_stopped: bool =
|
||||
return False
|
||||
if str(torrent.get('label') or '') == SMART_QUEUE_LABEL:
|
||||
return True
|
||||
# Note: Paused w rTorrent zwykle ma state=1 i active=0, więc nie wolno wymagać state=0.
|
||||
# Dzięki temu Smart Queue widzi pauzowane torrenty jako oczekujące i może później dobić target kolejki.
|
||||
# Note: Paused in rTorrent usually has state=1 and active=0, so state=0 must not be required.
|
||||
# This lets Smart Queue treat paused torrents as pending and fill the queue target later.
|
||||
if bool(torrent.get('paused')):
|
||||
return True
|
||||
# Note: Całkiem zatrzymane pozycje są zarządzane tylko po włączeniu opcji Use stopped torrents.
|
||||
# Note: Fully stopped items are managed only when Use stopped torrents is enabled.
|
||||
if not manage_stopped:
|
||||
return False
|
||||
return not int(torrent.get('state') or 0)
|
||||
@@ -322,7 +322,7 @@ def _clear_untracked_smart_queue_label(client: Any, torrent_hash: str, current_l
|
||||
if current_label != SMART_QUEUE_LABEL:
|
||||
return False
|
||||
try:
|
||||
# Note: Czyści osierocony label Smart Queue, gdy brak wpisu z poprzednim labelem w bazie.
|
||||
# Note: Clear an orphaned Smart Queue label when no previous-label entry exists in the database.
|
||||
client.call('d.custom1.set', torrent_hash, '')
|
||||
return True
|
||||
except Exception:
|
||||
@@ -359,8 +359,8 @@ def _cleanup_auto_labels(client: Any, profile_id: int, torrents: list[dict[str,
|
||||
|
||||
def _is_running_download_slot(t: dict[str, Any]) -> bool:
|
||||
"""Return True for incomplete torrents that already occupy a Smart Queue slot."""
|
||||
# Note: Limit Smart Queue oznacza docelową liczbę realnie aktywnych slotów.
|
||||
# Paused potrafi mieć state=1/open=1, dlatego slot liczymy dopiero po d.is_active=1.
|
||||
# Note: The Smart Queue limit means the target number of actually active slots.
|
||||
# Paused can have state=1/open=1, so a slot is counted only after d.is_active=1.
|
||||
if int(t.get('complete') or 0):
|
||||
return False
|
||||
if str(t.get('label') or '') == SMART_QUEUE_LABEL:
|
||||
@@ -377,10 +377,10 @@ def _is_waiting_download_candidate(t: dict[str, Any], manage_stopped: bool) -> b
|
||||
return False
|
||||
if str(t.get('label') or '') == SMART_QUEUE_LABEL:
|
||||
return True
|
||||
# Note: Paused jest podstawowym źródłem dobijania kolejki, niezależnie od opcji manage_stopped.
|
||||
# Note: Paused items are the primary source for filling the queue, regardless of manage_stopped.
|
||||
if bool(t.get('paused')) or str(t.get('status') or '').lower() == 'paused':
|
||||
return True
|
||||
# Note: Stopped dokładamy tylko wtedy, gdy użytkownik zaznaczył Use stopped torrents.
|
||||
# Note: Stopped items are added only when the user enabled Use stopped torrents.
|
||||
return bool(manage_stopped) and not int(t.get('state') or 0)
|
||||
|
||||
|
||||
@@ -394,7 +394,7 @@ def check(profile: dict | None = None, user_id: int | None = None, force: bool =
|
||||
if not force and not int(settings.get('enabled') or 0):
|
||||
restored: list[str] = []
|
||||
try:
|
||||
# Note: Przy wyłączonym Smart Queue sprzątamy wyłącznie techniczne labele, bez startowania lub pauzowania torrentów.
|
||||
# Note: When Smart Queue is disabled, only technical labels are cleaned up, without starting or pausing torrents.
|
||||
torrents = rtorrent.list_torrents(profile)
|
||||
restored = _cleanup_auto_labels(rtorrent.client_for(profile), profile_id, torrents, set(), bool(settings.get('manage_stopped')))
|
||||
except Exception:
|
||||
@@ -408,15 +408,15 @@ def check(profile: dict | None = None, user_id: int | None = None, force: bool =
|
||||
def is_managed_hold(t: dict[str, Any]) -> bool:
|
||||
return str(t.get('label') or '') == SMART_QUEUE_LABEL
|
||||
|
||||
# Note: Slot Smart Queue liczymy po d.is_active, bo Paused może mieć state=1/open=1 i nie może zajmować miejsca w limicie.
|
||||
# Note: Count Smart Queue slots by d.is_active because Paused can have state=1/open=1 and must not occupy the limit.
|
||||
downloading = [
|
||||
t for t in torrents
|
||||
if _is_running_download_slot(t)
|
||||
and not is_managed_hold(t)
|
||||
and t.get('hash') not in excluded
|
||||
]
|
||||
# Note: Kandydaci obejmują także zwykłe Paused bez labela. Inaczej kolejka widzi tylko 1-2 sztuki
|
||||
# i nie potrafi dobić do zadanego targetu 100.
|
||||
# Note: Candidates also include regular Paused items without a label. Otherwise the queue sees only one or two items
|
||||
# and cannot fill the configured target of 100.
|
||||
stopped = [
|
||||
t for t in torrents
|
||||
if t.get('hash') not in excluded
|
||||
@@ -472,8 +472,8 @@ def check(profile: dict | None = None, user_id: int | None = None, force: bool =
|
||||
to_pause: list[dict[str, Any]] = pause_rank[:max(0, len(downloading) - max_active)]
|
||||
pause_hashes = {str(t.get('hash') or '') for t in to_pause}
|
||||
|
||||
# Note: Rotacja stalled działa tylko przy pełnej kolejce. Gdy brakuje slotów, Smart Queue ma
|
||||
# najpierw dobrać brakujące pozycje, a nie pauzować już istniejące lub błędnie uznane za stalled.
|
||||
# Note: Stalled rotation runs only when the queue is full. When slots are missing, Smart Queue should
|
||||
# first add missing items instead of pausing existing or incorrectly detected stalled items.
|
||||
if candidates and len(downloading) >= max_active:
|
||||
replaceable_stalled = [t for t in stalled if str(t.get('hash') or '') not in pause_hashes]
|
||||
for t in replaceable_stalled[:max(0, len(candidates) - len(to_pause))]:
|
||||
@@ -483,7 +483,7 @@ def check(profile: dict | None = None, user_id: int | None = None, force: bool =
|
||||
active_after_pause = max(0, len(downloading) - len(to_pause))
|
||||
available_slots = max(0, max_active - active_after_pause)
|
||||
to_resume = candidates[:available_slots]
|
||||
# Note: Pozycje poza bieżącą pulą startu zostają jawnie oznaczone jako oczekujące Smart Queue.
|
||||
# Note: Items outside the current start batch are explicitly marked as pending Smart Queue items.
|
||||
to_label_waiting = candidates[available_slots:]
|
||||
|
||||
c = rtorrent.client_for(profile)
|
||||
@@ -517,8 +517,8 @@ def check(profile: dict | None = None, user_id: int | None = None, force: bool =
|
||||
except Exception:
|
||||
label_failed.append(h)
|
||||
|
||||
# Note: Startujemy całą pulę kandydatów w jednej rundzie. Label zdejmujemy po zaakceptowanym RPC,
|
||||
# bo rTorrent może trzymać część pozycji w swojej kolejce z active=0 mimo poprawnego d.start/d.resume.
|
||||
# Note: Start the whole candidate batch in one round. Remove the label after an accepted RPC,
|
||||
# because rTorrent may keep some items in its own queue with active=0 despite a valid d.start/d.resume.
|
||||
for t in to_resume:
|
||||
h = str(t.get('hash') or '')
|
||||
if not h:
|
||||
@@ -533,7 +533,7 @@ def check(profile: dict | None = None, user_id: int | None = None, force: bool =
|
||||
active_verified, start_no_effect = _verify_started_downloads(c, resume_requested)
|
||||
for h in active_verified:
|
||||
_restore_auto_label(c, profile_id, h, None)
|
||||
# Note: Historia pokazuje tylko torrenty faktycznie zdjęte z pauzy, a nie samą liczbę wysłanych komend.
|
||||
# Note: History shows only torrents actually unpaused, not just the number of sent commands.
|
||||
resumed = list(active_verified)
|
||||
keep_labels = (
|
||||
set(paused)
|
||||
|
||||
Reference in New Issue
Block a user