Clarify no-download queue failures
This commit is contained in:
@@ -1,5 +1,9 @@
|
|||||||
# Changelog
|
# 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
|
## 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.
|
- 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,7 +2,7 @@
|
|||||||
|
|
||||||
Small local web UI for a system-wide `ani-cli` install.
|
Small local web UI for a system-wide `ani-cli` install.
|
||||||
|
|
||||||
Current version: `0.45.2`
|
Current version: `0.45.3`
|
||||||
|
|
||||||
## Project Layout
|
## Project Layout
|
||||||
|
|
||||||
@@ -222,6 +222,7 @@ Webhook details:
|
|||||||
- Download-completed notifications include the full saved file list, split across extra Discord embeds when needed.
|
- 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.
|
- 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.
|
- 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
|
### Watchlist
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -20,7 +20,7 @@ from uuid import uuid4
|
|||||||
PROJECT_ROOT = Path(__file__).resolve().parent
|
PROJECT_ROOT = Path(__file__).resolve().parent
|
||||||
ANI_CLI = os.environ.get("ANI_CLI_BIN") or shutil.which("ani-cli") or "ani-cli"
|
ANI_CLI = os.environ.get("ANI_CLI_BIN") or shutil.which("ani-cli") or "ani-cli"
|
||||||
APP_NAME = "ani-cli-web"
|
APP_NAME = "ani-cli-web"
|
||||||
VERSION = "0.45.2"
|
VERSION = "0.45.3"
|
||||||
ALLANIME_BASE = "allanime.day"
|
ALLANIME_BASE = "allanime.day"
|
||||||
ALLANIME_API = f"https://api.{ALLANIME_BASE}"
|
ALLANIME_API = f"https://api.{ALLANIME_BASE}"
|
||||||
ALLANIME_REFERER = "https://allmanga.to"
|
ALLANIME_REFERER = "https://allmanga.to"
|
||||||
|
|||||||
+8
-1
@@ -1124,7 +1124,14 @@ class DownloadQueue:
|
|||||||
job.setdefault("log", []).append("Canceled.")
|
job.setdefault("log", []).append("Canceled.")
|
||||||
elif finalize_error:
|
elif finalize_error:
|
||||||
job["status"] = "failed"
|
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:
|
elif exit_code == 0:
|
||||||
job["status"] = "done"
|
job["status"] = "done"
|
||||||
for path in moved_files:
|
for path in moved_files:
|
||||||
|
|||||||
+21
@@ -460,6 +460,27 @@ class DownloadQueueWorkerFailureTests(unittest.TestCase):
|
|||||||
self.assertEqual(stored["status"], "failed")
|
self.assertEqual(stored["status"], "failed")
|
||||||
self.assertFalse(staging_dir.exists())
|
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):
|
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)
|
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"})
|
job = queue.add({"query": "Queue Show", "title": "Queue Show", "season": "1", "episodes": "1"})
|
||||||
|
|||||||
Reference in New Issue
Block a user