block file info for incomplete files

This commit is contained in:
Mateusz Gruszczyński
2026-05-22 23:03:30 +02:00
parent 7c0a4ff703
commit c69142e328
5 changed files with 23 additions and 2 deletions

View File

@@ -98,7 +98,10 @@ def record_job_event(profile_id: int, action: str, status: str, payload: dict |
severity = "danger" if status == "failed" else "info" severity = "danger" if status == "failed" else "info"
if action in {"add_magnet", "add_torrent_raw"}: if action in {"add_magnet", "add_torrent_raw"}:
name = str(payload.get("name") or payload.get("filename") or payload.get("uri") or "torrent")[:300] name = str(payload.get("name") or payload.get("filename") or payload.get("uri") or "torrent")[:300]
msg = f"{action} {status}: {name}" # Note: Keep the internal action name stable, but show a user-facing label instead of raw worker identifiers.
source_label = "Torrent file" if action == "add_torrent_raw" else "Magnet link"
status_label = {"started": "queued", "done": "added", "failed": "failed"}.get(str(status), str(status))
msg = f"{source_label} {status_label}: {name}"
record(profile_id, "torrent_added" if status == "done" else event_type, msg, severity=severity, source="job", action=action, details={"job_id": job_id, "status": status, "directory": payload.get("directory"), "label": payload.get("label"), "error": error, "result": result}, user_id=user_id) record(profile_id, "torrent_added" if status == "done" else event_type, msg, severity=severity, source="job", action=action, details={"job_id": job_id, "status": status, "directory": payload.get("directory"), "label": payload.get("label"), "error": error, "result": result}, user_id=user_id)
return return
if not hashes: if not hashes:

View File

@@ -429,12 +429,24 @@ def _media_info_hachoir_imports():
) from exc ) from exc
def _torrent_file_is_complete(selected: dict) -> bool:
# Note: File info reads real file bytes, so incomplete payload files are blocked before any parser touches them.
size = int(selected.get("size") or 0)
completed_chunks = int(selected.get("completed_chunks") or 0)
size_chunks = int(selected.get("size_chunks") or 0)
progress = float(selected.get("progress") or 0)
return size <= 0 or progress >= 100.0 or (size_chunks > 0 and completed_chunks >= size_chunks)
def torrent_file_media_info(profile: dict, torrent_hash: str, index: int, max_bytes: int = _MEDIA_INFO_SAMPLE_BYTES) -> dict: def torrent_file_media_info(profile: dict, torrent_hash: str, index: int, max_bytes: int = _MEDIA_INFO_SAMPLE_BYTES) -> dict:
# Note: This additive endpoint now acts as a smart file preview: media metadata, text/NFO reader, or image preview depending on file type. # Note: This additive endpoint now acts as a smart file preview: media metadata, text/NFO reader, or image preview depending on file type.
selected, remote_path = _torrent_file_remote_path(profile, torrent_hash, index) selected, remote_path = _torrent_file_remote_path(profile, torrent_hash, index)
name = str(selected.get("path") or remote_path) name = str(selected.get("path") or remote_path)
size = int(selected.get("size") or 0) size = int(selected.get("size") or 0)
if not _torrent_file_is_complete(selected):
raise RuntimeError("File info is available only after this file is fully downloaded.")
err = remote_file_readability_error(profile, remote_path) err = remote_file_readability_error(profile, remote_path)
if err: if err:
raise RuntimeError(err) raise RuntimeError(err)

View File

@@ -3,6 +3,8 @@ export const messagesSource = `
const APP_MESSAGES = { const APP_MESSAGES = {
actions: { actions: {
raw_torrent: 'Add torrent', raw_torrent: 'Add torrent',
add_torrent_raw: 'Add torrent file',
add_magnet: 'Add magnet link',
add: 'Add torrent', add: 'Add torrent',
start: 'Start torrent', start: 'Start torrent',
pause: 'Pause torrent', pause: 'Pause torrent',

File diff suppressed because one or more lines are too long

View File

@@ -1527,6 +1527,10 @@ body.mobile-mode .mobile-card {
padding-bottom: 0.1rem; padding-bottom: 0.1rem;
padding-top: 0.1rem; padding-top: 0.1rem;
} }
.file-priority-table .file-media-info-blocked {
cursor: not-allowed;
opacity: 0.55;
}
.file-priority-table .file-check, .file-priority-table .file-check,
.file-priority-table #fileSelectAll { .file-priority-table #fileSelectAll {
display: block; display: block;