automatyzacje-comit3

This commit is contained in:
Mateusz Gruszczyński
2026-05-07 08:48:59 +02:00
parent f9280daa21
commit e99d19ece0
2 changed files with 32 additions and 9 deletions

View File

@@ -172,7 +172,9 @@ def _without_smart_queue_label(value: str | None) -> str:
def _has_stalled_label(value: str | None) -> bool: def _has_stalled_label(value: str | None) -> bool:
return SMART_QUEUE_STALLED_LABEL in _label_names(value) # Note: Stalled is treated case-insensitively so manually edited labels still block Smart Queue.
target = SMART_QUEUE_STALLED_LABEL.casefold()
return any(label.casefold() == target for label in _label_names(value))
def _without_queue_technical_labels(value: str | None) -> str: def _without_queue_technical_labels(value: str | None) -> str:
@@ -182,7 +184,7 @@ def _without_queue_technical_labels(value: str | None) -> str:
def _ensure_stalled_label(client: Any, torrent_hash: str, current_label: str = '') -> bool: def _ensure_stalled_label(client: Any, torrent_hash: str, current_label: str = '') -> bool:
labels = [label for label in _label_names(current_label) if label != SMART_QUEUE_LABEL] labels = [label for label in _label_names(current_label) if label != SMART_QUEUE_LABEL]
changed = False changed = False
if SMART_QUEUE_STALLED_LABEL not in labels: if not any(label.casefold() == SMART_QUEUE_STALLED_LABEL.casefold() for label in labels):
labels.append(SMART_QUEUE_STALLED_LABEL) labels.append(SMART_QUEUE_STALLED_LABEL)
changed = True changed = True
if SMART_QUEUE_LABEL in _label_names(current_label): if SMART_QUEUE_LABEL in _label_names(current_label):
@@ -476,7 +478,9 @@ def check(profile: dict | None = None, user_id: int | None = None, force: bool =
return {'ok': True, 'enabled': False, 'paused': [], 'resumed': [], 'labels_restored': restored, 'message': 'Smart Queue disabled'} return {'ok': True, 'enabled': False, 'paused': [], 'resumed': [], 'labels_restored': restored, 'message': 'Smart Queue disabled'}
torrents = rtorrent.list_torrents(profile) torrents = rtorrent.list_torrents(profile)
excluded = _excluded_hashes(profile_id, user_id) # Note: Torrents marked as Stalled are treated as queue-blocked even when there are no other pending downloads.
stalled_label_hashes = {str(t.get('hash') or '') for t in torrents if _has_stalled_label(str(t.get('label') or '')) and t.get('hash')}
excluded = _excluded_hashes(profile_id, user_id) | stalled_label_hashes
manage_stopped = bool(settings.get('manage_stopped')) manage_stopped = bool(settings.get('manage_stopped'))
def is_managed_hold(t: dict[str, Any]) -> bool: def is_managed_hold(t: dict[str, Any]) -> bool:
return _has_smart_queue_label(str(t.get('label') or '')) return _has_smart_queue_label(str(t.get('label') or ''))
@@ -622,6 +626,6 @@ def check(profile: dict | None = None, user_id: int | None = None, force: bool =
| {str(t.get('hash') or '') for t in stopped if _has_smart_queue_label(str(t.get('label') or '')) and str(t.get('hash') or '') not in set(resumed)} | {str(t.get('hash') or '') for t in stopped if _has_smart_queue_label(str(t.get('label') or '')) and str(t.get('hash') or '') not in set(resumed)}
) )
restored = _cleanup_auto_labels(c, profile_id, torrents, keep_labels, manage_stopped) 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, 'stalled_label': SMART_QUEUE_STALLED_LABEL, 'stalled_labeled': stalled_labeled, 'labels_restored': restored, 'labels_failed': label_failed, 'start_failed': start_failed, 'start_no_effect': start_no_effect, 'start_results': start_results, 'resume_requested': resume_requested, 'active_verified': active_verified, 'waiting_labeled': len(to_label_waiting), 'manage_stopped': manage_stopped, 'max_active_downloads': max_active, 'active_before': len(downloading), 'active_after_expected': active_after_pause + len(resumed), 'paused_planned': len(to_pause), 'resumed_planned': len(to_resume), 'rtorrent_cap': rtorrent_cap} details = {'excluded': len(excluded), 'excluded_stalled': len(stalled_label_hashes), 'enabled': bool(settings.get('enabled')), 'auto_label': SMART_QUEUE_LABEL, 'stalled_label': SMART_QUEUE_STALLED_LABEL, 'stalled_labeled': stalled_labeled, 'labels_restored': restored, 'labels_failed': label_failed, 'start_failed': start_failed, 'start_no_effect': start_no_effect, 'start_results': start_results, 'resume_requested': resume_requested, 'active_verified': active_verified, 'waiting_labeled': len(to_label_waiting), 'manage_stopped': manage_stopped, 'max_active_downloads': max_active, 'active_before': len(downloading), 'active_after_expected': active_after_pause + len(resumed), 'paused_planned': len(to_pause), 'resumed_planned': len(to_resume), '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, 'waiting_labeled': len(to_label_waiting), 'stalled_labeled': stalled_labeled, 'labels_restored': restored, 'labels_failed': label_failed, 'start_failed': start_failed, 'start_no_effect': start_no_effect, 'active_verified': active_verified, '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, 'waiting_labeled': len(to_label_waiting), 'stalled_labeled': stalled_labeled, 'excluded_stalled': len(stalled_label_hashes), 'labels_restored': restored, 'labels_failed': label_failed, 'start_failed': start_failed, 'start_no_effect': start_no_effect, 'active_verified': active_verified, 'rtorrent_cap': rtorrent_cap, 'checked': len(torrents), 'excluded': len(excluded), 'settings': settings}

View File

@@ -1317,49 +1317,67 @@ body.mobile-mode .mobile-card {
border-radius: 999px; border-radius: 999px;
background: var(--bs-secondary-bg); background: var(--bs-secondary-bg);
font-size: 0.78rem; font-size: 0.78rem;
overflow-wrap: anywhere;
white-space: normal; white-space: normal;
word-break: break-word;
} }
.automation-history-toolbar { .automation-history-toolbar {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
} }
/* Note: Automation history has fixed compact metadata columns and a flexible Actions column, so long JSON cannot overlap Time/Rule. */
.automation-history-table { .automation-history-table {
width: 100%; width: 100%;
table-layout: fixed; table-layout: fixed;
white-space: normal;
} }
.automation-history-table th, .automation-history-table th,
.automation-history-table td { .automation-history-table td {
min-width: 0;
vertical-align: top; vertical-align: top;
} }
.automation-history-table th:nth-child(1), .automation-history-table th:nth-child(1),
.automation-history-table td:nth-child(1) { .automation-history-table td:nth-child(1) {
width: 10.5rem; width: 9rem;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
.automation-history-table th:nth-child(2), .automation-history-table th:nth-child(2),
.automation-history-table td:nth-child(2) { .automation-history-table td:nth-child(2) {
width: 13rem; width: 11rem;
overflow: hidden;
overflow-wrap: anywhere; overflow-wrap: anywhere;
word-break: break-word;
} }
.automation-history-table th:nth-child(3), .automation-history-table th:nth-child(3),
.automation-history-table td:nth-child(3) { .automation-history-table td:nth-child(3) {
width: 14rem; width: 12rem;
overflow: hidden;
overflow-wrap: anywhere; overflow-wrap: anywhere;
word-break: break-word;
} }
.automation-history-table th:nth-child(4), .automation-history-table th:nth-child(4),
.automation-history-table td:nth-child(4) { .automation-history-table td:nth-child(4) {
width: auto; width: auto;
min-width: 0; overflow: hidden;
overflow-wrap: anywhere; overflow-wrap: anywhere;
word-break: break-word; word-break: break-word;
} }
.automation-history-details { .automation-history-details {
display: block;
min-width: 0;
max-width: 100%; max-width: 100%;
} }
.automation-history-details summary { .automation-history-details summary {
display: block;
max-width: 100%;
cursor: pointer; cursor: pointer;
list-style-position: inside; list-style-position: inside;
overflow-wrap: anywhere;
white-space: normal;
word-break: break-word;
} }
.automation-history-details pre, .automation-history-details pre,
.automation-history-raw { .automation-history-raw {
@@ -1371,6 +1389,7 @@ body.mobile-mode .mobile-card {
border: 1px solid var(--bs-border-color); border: 1px solid var(--bs-border-color);
border-radius: 0.5rem; border-radius: 0.5rem;
background: var(--bs-tertiary-bg); background: var(--bs-tertiary-bg);
overflow-wrap: anywhere;
white-space: pre-wrap; white-space: pre-wrap;
word-break: break-word; word-break: break-word;
} }