Clarify no-download queue failures

This commit is contained in:
Dymas
2026-05-25 23:13:41 +02:00
parent 94ded2725e
commit 1f50c3c666
6 changed files with 37 additions and 4 deletions
+4
View File
@@ -1,5 +1,9 @@
# Changelog
## 0.45.3 - 2026-05-25
- Improved queue failure handling for no-op `ani-cli` runs: when the command exits successfully but downloads no files, the job now fails with a clear message explaining that nothing was downloaded and the empty staging folder is cleaned up.
## 0.45.2 - 2026-05-25
- Fixed watchlist completion so a successful partial dub or sub download no longer moves a TV series to `Finished`; the category now changes only when the downloaded mode has every expected episode both available and downloaded.
+2 -1
View File
@@ -2,7 +2,7 @@
Small local web UI for a system-wide `ani-cli` install.
Current version: `0.45.2`
Current version: `0.45.3`
## Project Layout
@@ -222,6 +222,7 @@ Webhook details:
- Download-completed notifications include the full saved file list, split across extra Discord embeds when needed.
- Jellyfin handoff notifications fire when a finished library is moved successfully and also on actionable move failures such as missing targets or move errors.
- Watchlist entries only move to `Finished` automatically when the downloaded mode itself is complete, and Jellyfin handoff for TV entries follows that same mode-aware completion rule.
- Queue jobs that exit successfully but produce no downloaded files are marked as failed with a clearer explanation instead of looking like a generic rename problem.
### Watchlist
+1 -1
View File
@@ -1 +1 @@
0.45.2
0.45.3
+1 -1
View File
@@ -20,7 +20,7 @@ from uuid import uuid4
PROJECT_ROOT = Path(__file__).resolve().parent
ANI_CLI = os.environ.get("ANI_CLI_BIN") or shutil.which("ani-cli") or "ani-cli"
APP_NAME = "ani-cli-web"
VERSION = "0.45.2"
VERSION = "0.45.3"
ALLANIME_BASE = "allanime.day"
ALLANIME_API = f"https://api.{ALLANIME_BASE}"
ALLANIME_REFERER = "https://allmanga.to"
+8 -1
View File
@@ -1124,7 +1124,14 @@ class DownloadQueue:
job.setdefault("log", []).append("Canceled.")
elif finalize_error:
job["status"] = "failed"
job.setdefault("log", []).append(f"Library rename failed: {finalize_error}")
message = str(finalize_error).strip()
if "No downloaded files were found in the staging folder" in message:
job.setdefault("log", []).append(
"ani-cli exited without downloading any files. The selected result or episodes may not be downloadable."
)
else:
job.setdefault("log", []).append(f"Library rename failed: {finalize_error}")
cleanup_staging = True
elif exit_code == 0:
job["status"] = "done"
for path in moved_files:
+21
View File
@@ -460,6 +460,27 @@ class DownloadQueueWorkerFailureTests(unittest.TestCase):
self.assertEqual(stored["status"], "failed")
self.assertFalse(staging_dir.exists())
def test_zero_exit_without_downloaded_files_marks_job_failed_with_clear_message(self):
queue = APP.DownloadQueue(lambda: {"mode": "sub", "quality": "best", "download_dir": "/tmp/example"}, start_worker=False)
job = queue.add({"query": "Queue Show", "title": "Queue Show", "season": "1", "episodes": "1-10"})
staging_dir = queue_jobs.job_staging_dir(job)
class FakeProc:
pid = 4321
stdout = ["Checking dependencies...\n"]
def wait(self):
return 0
with mock.patch.object(queue_jobs.subprocess, "Popen", return_value=FakeProc()):
queue._run_job(job)
stored = queue._find(job["id"])
self.assertEqual(stored["status"], "failed")
self.assertEqual(stored["exit_code"], 1)
self.assertIn("without downloading any files", "\n".join(stored["log"]))
self.assertFalse(staging_dir.exists())
def test_run_job_marks_post_start_exception_failed_without_killing_worker_state(self):
queue = APP.DownloadQueue(lambda: {"mode": "sub", "quality": "best", "download_dir": "/tmp/example"}, start_worker=False)
job = queue.add({"query": "Queue Show", "title": "Queue Show", "season": "1", "episodes": "1"})