Merge pull request 'fixes' (#3) from fixes into master
Reviewed-on: #3
This commit was merged in pull request #3.
This commit is contained in:
@@ -149,7 +149,8 @@ def _cleanup_post_check_label_if_ready(c: ScgiRtorrentClient, row: dict) -> bool
|
||||
if POST_CHECK_DOWNLOAD_LABEL not in labels:
|
||||
return False
|
||||
status = str(row.get("status") or "").lower()
|
||||
started_after_wait = bool(int(row.get("state") or 0)) and status != "checking"
|
||||
# Note: rTorrent may report state=1 after a recheck even when the download is not really active yet.
|
||||
started_after_wait = bool(int(row.get("state") or 0)) and bool(int(row.get("active") or 0)) and status != "checking"
|
||||
if not (_row_progress_complete(row) or status == "seeding" or started_after_wait):
|
||||
return False
|
||||
# Note: Keep the post-check label while the torrent is stopped; remove it once it is started for download/seeding.
|
||||
@@ -197,8 +198,8 @@ def apply_post_check_policy(profile: dict, rows: list[dict], previous_rows: dict
|
||||
except Exception:
|
||||
pass
|
||||
c.call("d.custom1.set", h, label_value)
|
||||
row.update({"state": 0, "active": 0, "paused": False, "status": "Stopped", "label": label_value})
|
||||
changes.append({"hash": h, "action": "stop_and_label_after_check", "complete": False, "label": POST_CHECK_DOWNLOAD_LABEL})
|
||||
row.update({"state": 0, "active": 0, "paused": False, "post_check": True, "status": "Post-check", "label": label_value})
|
||||
changes.append({"hash": h, "action": "mark_post_check_waiting", "complete": False, "label": POST_CHECK_DOWNLOAD_LABEL})
|
||||
_clear_post_check_watch(profile_id, h)
|
||||
except Exception as exc:
|
||||
changes.append({"hash": h, "action": "post_check_policy_failed", "error": str(exc)})
|
||||
@@ -267,8 +268,10 @@ def normalize_row(row: list) -> dict:
|
||||
complete = int(row[3] or 0)
|
||||
# Note: d.hashing is authoritative; stale "hash check complete" messages must not keep the UI in Checking forever.
|
||||
is_checking = bool(hashing) or _message_indicates_active_check(msg_l)
|
||||
is_paused = bool(state) and not bool(is_active) and not is_checking
|
||||
status = "Checking" if is_checking else "Paused" if is_paused else "Seeding" if complete and state else "Downloading" if state else "Stopped"
|
||||
post_check = POST_CHECK_DOWNLOAD_LABEL in _label_names(str(row[17] or "")) and not is_checking and not bool(is_active)
|
||||
is_paused = bool(state) and not bool(is_active) and not is_checking and not post_check
|
||||
# Note: Post-check is an application-level state that separates torrents waiting after a recheck from manually stopped torrents.
|
||||
status = "Checking" if is_checking else "Post-check" if post_check else "Paused" if is_paused else "Seeding" if complete and state else "Downloading" if state else "Stopped"
|
||||
to_download_bytes = remaining_bytes if not complete else 0
|
||||
# Note: The To download column is only meaningful for incomplete torrents; complete rows expose an empty display value.
|
||||
return {
|
||||
@@ -305,6 +308,7 @@ def normalize_row(row: list) -> dict:
|
||||
"ratio_group": str(row[18] or ""),
|
||||
"message": msg,
|
||||
"status": status,
|
||||
"post_check": post_check,
|
||||
"hashing": hashing,
|
||||
}
|
||||
|
||||
@@ -545,12 +549,16 @@ def _download_runtime_state(c: ScgiRtorrentClient, h: str) -> dict:
|
||||
active = _int_rpc(c, 'd.is_active', h)
|
||||
opened = _int_rpc(c, 'd.is_open', h)
|
||||
# Note: In rTorrent, pause does not change d.state. Paused means state=1, open=1, active=0.
|
||||
label = _str_rpc(c, 'd.custom1', h)
|
||||
post_check = POST_CHECK_DOWNLOAD_LABEL in _label_names(label) and not bool(active)
|
||||
return {
|
||||
'state': state,
|
||||
'open': opened,
|
||||
'active': active,
|
||||
'paused': bool(state and opened and not active),
|
||||
'paused': bool(state and opened and not active and not post_check),
|
||||
'stopped': not bool(state),
|
||||
'post_check': post_check,
|
||||
'label': label,
|
||||
'message': _str_rpc(c, 'd.message', h),
|
||||
}
|
||||
|
||||
@@ -590,10 +598,14 @@ def stop_hash(c: ScgiRtorrentClient, torrent_hash: str) -> dict:
|
||||
return {'hash': h, 'ok': False, 'error': 'missing hash'}
|
||||
before = _download_runtime_state(c, h)
|
||||
result = {'hash': h, 'before': before, 'commands': []}
|
||||
if before.get('stopped'):
|
||||
if before.get('stopped') and not before.get('post_check'):
|
||||
result.update({'ok': True, 'skipped': 'already_stopped', 'after': before})
|
||||
return result
|
||||
try:
|
||||
# Note: User Stop converts the app-level Post-check state into a regular stopped torrent.
|
||||
if before.get('post_check'):
|
||||
clear_post_check_download_label(c, h, before.get('label'))
|
||||
result['commands'].append('clear_post_check_label')
|
||||
# Note: Smart Queue now enforces the queue with d.stop only; user-paused torrents stay untouched.
|
||||
c.call('d.stop', h)
|
||||
result['commands'].append('d.stop')
|
||||
@@ -643,10 +655,13 @@ def start_or_resume_hash(c: ScgiRtorrentClient, torrent_hash: str, prefer_start:
|
||||
result: dict = {'hash': h, 'before': before, 'commands': []}
|
||||
|
||||
if before.get('active'):
|
||||
if before.get('post_check'):
|
||||
clear_post_check_download_label(c, h, before.get('label'))
|
||||
before = _download_runtime_state(c, h)
|
||||
result.update({'ok': True, 'skipped': 'already_active', 'after': before})
|
||||
return result
|
||||
|
||||
if before.get('paused') and not prefer_start:
|
||||
if before.get('paused') and not prefer_start and not before.get('post_check'):
|
||||
# Note: Manual Start keeps the clean pause-to-resume path. Do not classify every
|
||||
# state=1/active=0 item as paused; after auto-check this can be only a transient
|
||||
# open/inactive rTorrent state and needs d.open + d.start.
|
||||
@@ -654,6 +669,13 @@ def start_or_resume_hash(c: ScgiRtorrentClient, torrent_hash: str, prefer_start:
|
||||
resumed['mode'] = 'resume_paused'
|
||||
return resumed
|
||||
|
||||
if before.get('post_check'):
|
||||
try:
|
||||
# Note: Post-check start first forces a clean stopped state, matching the manual Stop -> Start recovery path.
|
||||
c.call('d.stop', h)
|
||||
result['commands'].append('d.stop')
|
||||
except Exception as exc:
|
||||
result.setdefault('ignored_errors', []).append(f'd.stop: {exc}')
|
||||
try:
|
||||
c.call('d.open', h)
|
||||
result['commands'].append('d.open')
|
||||
@@ -670,7 +692,13 @@ def start_or_resume_hash(c: ScgiRtorrentClient, torrent_hash: str, prefer_start:
|
||||
except Exception as exc2:
|
||||
result.setdefault('ignored_errors', []).append(f'd.try_start: {exc2}')
|
||||
result['ok'] = False
|
||||
result['after'] = _download_runtime_state(c, h)
|
||||
after = _download_runtime_state(c, h)
|
||||
if before.get('post_check') and after.get('active'):
|
||||
# Note: The marker stays in place when start fails so the row remains visible in the Post-check filter.
|
||||
clear_post_check_download_label(c, h, before.get('label'))
|
||||
result['commands'].append('clear_post_check_label')
|
||||
after = _download_runtime_state(c, h)
|
||||
result['after'] = after
|
||||
result['ok'] = result.get('ok', True)
|
||||
return result
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ _ERROR_PATTERNS = (
|
||||
"unreachable",
|
||||
"denied",
|
||||
)
|
||||
_SUMMARY_TYPES = ("all", "downloading", "seeding", "paused", "checking", "error", "stopped")
|
||||
_SUMMARY_TYPES = ("all", "downloading", "seeding", "paused", "checking", "error", "post_check", "stopped")
|
||||
_summary_cache: dict[int, dict] = {}
|
||||
_summary_lock = RLock()
|
||||
|
||||
@@ -55,9 +55,12 @@ def _matches(row: dict, summary_type: str) -> bool:
|
||||
return checking
|
||||
if summary_type == "error":
|
||||
return _has_error(row)
|
||||
if summary_type == "post_check":
|
||||
# Note: Post-check is counted separately from Stopped so automation can target it safely.
|
||||
return str(row.get("status") or "") == "Post-check" or bool(row.get("post_check"))
|
||||
if summary_type == "stopped":
|
||||
# Note: Stopped count follows the UI filter exactly, so torrents being hash-checked do not inflate an empty Stopped list.
|
||||
return not checking and not bool(row.get("state"))
|
||||
# Note: Stopped count follows the UI filter exactly and excludes app-level post-check waiting rows.
|
||||
return not checking and not bool(row.get("state")) and str(row.get("status") or "") != "Post-check" and not bool(row.get("post_check"))
|
||||
return False
|
||||
|
||||
|
||||
|
||||
2
pytorrent/static/js/bootstrap.js
vendored
2
pytorrent/static/js/bootstrap.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1422,7 +1422,7 @@ body.mobile-mode .mobile-card {
|
||||
display: none !important;
|
||||
}
|
||||
#bulkBar {
|
||||
grid-row: 1;
|
||||
display: none !important;
|
||||
}
|
||||
#mobileList {
|
||||
display: block !important;
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user