multilang_and_other #8

Merged
gru merged 11 commits from multilang_and_other into master 2026-05-28 22:08:32 +02:00
5 changed files with 90 additions and 10 deletions
Showing only changes of commit a611113d2a - Show all commits

View File

@@ -977,13 +977,37 @@ def _refill_underfilled_queue(profile: dict, settings: dict[str, Any], profile_i
| {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(started_by_queue)}
)
restored = _cleanup_auto_labels(c, profile_id, torrents, keep_labels, True)
# Note: Cooldown refill uses started incomplete torrents as queue slots. This diagnostic
# explains why a refill may legitimately start nothing even when only a few torrents transfer data.
active_transferring = sum(1 for t in downloading if int(t.get('down_rate') or 0) > 0 or int(t.get('up_rate') or 0) > 0)
active_rtorrent = sum(1 for t in downloading if int(t.get('active') or 0))
active_state = sum(1 for t in downloading if int(t.get('state') or 0))
active_after_expected = len(downloading) + len(start_requested)
if available_slots <= 0:
refill_decision = f'Cooldown refill skipped: active slots at limit ({len(downloading)}/{max_active})'
refill_blocked_reason = 'active_slots_at_limit'
elif not candidates:
refill_decision = 'Cooldown refill skipped: no stopped candidates available'
refill_blocked_reason = 'no_candidates'
elif start_requested:
refill_decision = f'Cooldown refill requested {len(start_requested)} start(s)'
refill_blocked_reason = ''
else:
refill_decision = 'Cooldown refill ran but rTorrent did not confirm new starts yet'
refill_blocked_reason = 'start_not_confirmed'
details = {
'decision': refill_decision,
'blocked_reason': refill_blocked_reason,
'enabled': bool(settings.get('enabled')),
'cooldown_refill': True,
'cooldown_respected': True,
'refill_mode': _refill_mode(settings),
'refill_interval_minutes': int(settings.get('refill_interval_minutes') or 0),
'active_before': len(downloading),
'active_after_expected': active_after_expected,
'active_transferring_count': active_transferring,
'active_rtorrent_count': active_rtorrent,
'active_state_count': active_state,
'available_slots': available_slots,
'candidates': len(candidates),
'start_source_skipped': len(source_skipped),
@@ -1014,6 +1038,10 @@ def _refill_underfilled_queue(profile: dict, settings: dict[str, Any], profile_i
'max_active_downloads': max_active,
'available_slots': available_slots,
'candidates': len(candidates),
'active_transferring': active_transferring,
'active_rtorrent': active_rtorrent,
'active_state': active_state,
'blocked_reason': refill_blocked_reason,
'start_source_skipped': len(source_skipped),
'requested': len(start_requested),
'verified': len(active_verified),
@@ -1069,7 +1097,11 @@ def _refill_underfilled_queue(profile: dict, settings: dict[str, Any], profile_i
'start_pending_confirmation': start_pending_confirmation,
'active_verified': active_verified,
'active_before': len(downloading),
'active_after_expected': len(downloading) + len(started_by_queue),
'active_after_expected': active_after_expected,
'active_transferring_count': active_transferring,
'active_rtorrent_count': active_rtorrent,
'active_state_count': active_state,
'blocked_reason': refill_blocked_reason,
'available_slots': available_slots,
'start_source_skipped': len(source_skipped),
'checked': len(torrents),

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -551,7 +551,7 @@ body.resizing-details {
min-width: 680px;
}
.smart-history-table {
min-width: 760px;
min-width: 920px;
table-layout: fixed;
}
.smart-history-table th,
@@ -4373,6 +4373,33 @@ body,
/* Smart Queue exception picker */
.smart-exclusion-toolbar {
align-items: center;
display: grid;
gap: 0.65rem;
grid-template-columns: minmax(16rem, 1fr) auto auto auto;
}
.smart-exclusion-toolbar-actions {
display: flex;
flex-wrap: wrap;
gap: 0.4rem;
}
.smart-exclusion-counter {
color: var(--bs-secondary-color);
font-size: 0.875rem;
white-space: nowrap;
}
.smart-exclusion-toggle {
align-items: center;
display: flex;
gap: 0.45rem;
margin: 0;
white-space: nowrap;
}
.smart-exclusion-choice-list {
display: grid;
gap: 0.45rem;
@@ -4382,14 +4409,14 @@ body,
}
.smart-exclusion-choice-row {
display: flex;
align-items: flex-start;
gap: 0.65rem;
padding: 0.65rem 0.75rem;
background: rgba(var(--bs-secondary-bg-rgb), 0.24);
border: 1px solid var(--bs-border-color);
border-radius: 0.65rem;
background: rgba(var(--bs-secondary-bg-rgb), 0.24);
cursor: pointer;
display: flex;
gap: 0.65rem;
padding: 0.65rem 0.75rem;
}
.smart-exclusion-choice-row:hover {
@@ -4413,6 +4440,16 @@ body,
overflow-wrap: anywhere;
}
@media (max-width: 768px) {
.smart-exclusion-toolbar {
grid-template-columns: 1fr;
}
.smart-exclusion-toolbar-actions {
justify-content: flex-start;
}
}
/* Backup preview data samples */
.backup-preview-empty {
color: var(--bs-secondary-color);

View File

@@ -353,7 +353,7 @@
<div class="modal fade" id="smartExclusionModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-scrollable modal-lg">
<div class="modal-dialog modal-dialog-scrollable modal-xl">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><i class="fa-solid fa-ban"></i> Smart Queue exceptions</h5>
@@ -361,7 +361,18 @@
</div>
<div class="modal-body">
<div class="tool-note mb-3">Select torrents that Smart Queue should ignore. Use search to filter by name, label, status or hash.</div>
<input id="smartExclusionSearch" class="form-control mb-3" type="search" placeholder="Search torrents to exclude...">
<div class="smart-exclusion-toolbar mb-3">
<input id="smartExclusionSearch" class="form-control" type="search" placeholder="Search torrents to exclude...">
<label class="form-check form-switch smart-exclusion-toggle">
<input id="smartExclusionOnlySelected" class="form-check-input" type="checkbox">
<span class="form-check-label">Only selected</span>
</label>
<div class="smart-exclusion-toolbar-actions">
<button id="smartExclusionSelectVisibleBtn" type="button" class="btn btn-sm btn-outline-primary">Select visible</button>
<button id="smartExclusionClearVisibleBtn" type="button" class="btn btn-sm btn-outline-secondary">Clear visible</button>
</div>
<span id="smartExclusionCounter" class="smart-exclusion-counter">0 selected</span>
</div>
<div id="smartExclusionChoiceList" class="smart-exclusion-choice-list"></div>
</div>
<div class="modal-footer">