diff --git a/pytorrent/services/smart_queue.py b/pytorrent/services/smart_queue.py index d0cd51a..4c96337 100644 --- a/pytorrent/services/smart_queue.py +++ b/pytorrent/services/smart_queue.py @@ -165,7 +165,7 @@ def _restore_auto_label(client: Any, profile_id: int, torrent_hash: str, current previous = row.get('previous_label') or '' live_label = _read_label(client, torrent_hash, current_label or '') try: - # Note: Before Smart Queue resumes a paused torrent, restore the user label only when the auto label is still present. + # Note: Przy wznowieniu Smart Queue oddaje poprzedni label tylko wtedy, gdy nadal widzi swój label techniczny. 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)) @@ -195,27 +195,47 @@ def _mark_auto_paused(client: Any, profile_id: int, torrent: dict[str, Any]) -> return _set_smart_queue_label(client, torrent_hash) +def _is_smart_queue_hold(torrent: dict[str, Any] | None) -> bool: + if not torrent or int(torrent.get('complete') or 0): + return False + return bool(torrent.get('paused')) or not int(torrent.get('active') or 0) or not int(torrent.get('state') or 0) + + +def _clear_untracked_smart_queue_label(client: Any, torrent_hash: str, current_label: str) -> bool: + if current_label != SMART_QUEUE_LABEL: + return False + try: + # Note: Czyści osierocony label Smart Queue, gdy brak wpisu z poprzednim labelem w bazie. + client.call('d.custom1.set', torrent_hash, '') + return True + except Exception: + return False + + def _cleanup_auto_labels(client: Any, profile_id: int, torrents: list[dict[str, Any]], keep_hashes: set[str]) -> list[str]: by_hash = {str(t.get('hash') or ''): t for t in torrents} restored: list[str] = [] with connect() as conn: rows = conn.execute('SELECT torrent_hash FROM smart_queue_auto_labels WHERE profile_id=?', (profile_id,)).fetchall() + tracked_hashes = {str(row.get('torrent_hash') or '') for row in rows if row.get('torrent_hash')} + for row in rows: h = str(row.get('torrent_hash') or '') t = by_hash.get(h) if not h or h in keep_hashes: continue - if t is None or int(t.get('complete') or 0): - if _restore_auto_label(client, profile_id, h, None if t is None else str(t.get('label') or '')): + current_label = '' if t is None else str(t.get('label') or '') + if not _is_smart_queue_hold(t): + if _restore_auto_label(client, profile_id, h, None if t is None else current_label): restored.append(h) continue - is_paused_or_stopped = bool(t.get('paused')) or not int(t.get('active') or 0) or not int(t.get('state') or 0) - current_label = str(t.get('label') or '') - if is_paused_or_stopped: - if current_label != SMART_QUEUE_LABEL: - _set_smart_queue_label(client, h) + if current_label != SMART_QUEUE_LABEL: + _set_smart_queue_label(client, h) + + for h, t in by_hash.items(): + if not h or h in keep_hashes or h in tracked_hashes or _is_smart_queue_hold(t): continue - if _restore_auto_label(client, profile_id, h, current_label): + if _clear_untracked_smart_queue_label(client, h, str(t.get('label') or '')): restored.append(h) return restored @@ -228,8 +248,15 @@ def check(profile: dict | None = None, user_id: int | None = None, force: bool = profile_id = int(profile['id']) settings = get_settings(profile_id, user_id) if not force and not int(settings.get('enabled') or 0): - add_history(profile_id, 'skipped_disabled', [], [], 0, {'enabled': False}, user_id) - return {'ok': True, 'enabled': False, 'paused': [], 'resumed': [], 'message': 'Smart Queue disabled'} + restored: list[str] = [] + try: + # Note: Przy wyłączonym Smart Queue sprzątamy wyłącznie techniczne labele, bez startowania lub pauzowania torrentów. + torrents = rtorrent.list_torrents(profile) + restored = _cleanup_auto_labels(rtorrent.client_for(profile), profile_id, torrents, set()) + except Exception: + restored = [] + add_history(profile_id, 'skipped_disabled', [], [], 0, {'enabled': False, 'labels_restored': restored}, user_id) + return {'ok': True, 'enabled': False, 'paused': [], 'resumed': [], 'labels_restored': restored, 'message': 'Smart Queue disabled'} torrents = rtorrent.list_torrents(profile) excluded = _excluded_hashes(profile_id, user_id) @@ -310,7 +337,7 @@ def check(profile: dict | None = None, user_id: int | None = None, force: bool = pass for t in to_resume: try: - # Note: Resume path explicitly removes Smart Queue auto label before and after start to cover stale cache labels. + # Note: Wznowienie usuwa techniczny label przed startem i ponawia sprzątanie po starcie, gdy cache rTorrent jest opóźniony. _restore_auto_label(c, profile_id, t['hash'], str(t.get('label') or '')) c.call('d.resume', t['hash']) c.call('d.start', t['hash'])