diff --git a/CHANGELOG.md b/CHANGELOG.md index 01b5958..27559ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 0.45.4 - 2026-05-25 + +- Fixed watchlist-triggered downloads to stop forcing `ani-cli` search result indexes from the web API result order; explicit search-page selections still keep their chosen result, but watchlist and auto-download jobs now avoid bad `-S` mismatches when `ani-cli` resolves the title differently. + ## 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. diff --git a/README.md b/README.md index 15ee965..79135ea 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Small local web UI for a system-wide `ani-cli` install. -Current version: `0.45.3` +Current version: `0.45.4` ## Project Layout @@ -223,6 +223,7 @@ Webhook details: - 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-driven downloads no longer force `ani-cli -S ` from API search ordering, which avoids bad result mismatches when `ani-cli`’s own search order differs from the web app’s result list. ### Watchlist diff --git a/VERSION b/VERSION index 460e2af..ac8f038 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.45.3 +0.45.4 diff --git a/app.py b/app.py index a053d5f..ae957c1 100644 --- a/app.py +++ b/app.py @@ -2326,7 +2326,6 @@ def download_watchlist_item(show_id, mode): "media_type": item.get("media_type") or "tv", "season": item.get("auto_download_series") or "1", "episode_offset": item.get("auto_download_offset"), - "index": match.get("index", 1), "mode": normalized_mode, "quality": runtime["config"]["quality"], "episodes": episode_spec, @@ -2395,7 +2394,6 @@ def queue_watchlist_auto_download(item, refresh_source="manual"): "media_type": item.get("media_type") or "tv", "season": series, "episode_offset": episode_offset, - "index": match.get("index", 1), "mode": mode, "quality": quality, "episodes": episode_spec, diff --git a/app_support.py b/app_support.py index 25e59d7..9ad66aa 100644 --- a/app_support.py +++ b/app_support.py @@ -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.3" +VERSION = "0.45.4" ALLANIME_BASE = "allanime.day" ALLANIME_API = f"https://api.{ALLANIME_BASE}" ALLANIME_REFERER = "https://allmanga.to" @@ -941,12 +941,16 @@ def build_job(payload, config): anime_name = sanitize_path_component(payload.get("anime_name") or title) if not query: raise ValueError("Missing search query") - try: - index = int(payload.get("index", 1)) - except (TypeError, ValueError) as exc: - raise ValueError("Invalid result index") from exc - if index < 1: - raise ValueError("Result index must be positive") + raw_index = payload.get("index") + if raw_index in (None, ""): + index = None + else: + try: + index = int(raw_index) + except (TypeError, ValueError) as exc: + raise ValueError("Invalid result index") from exc + if index < 1: + raise ValueError("Result index must be positive") mode = str(payload.get("mode") or config["mode"]).lower() quality = str(payload.get("quality") or config["quality"]).lower() @@ -990,9 +994,9 @@ def command_for_job(job): job["quality"], "-e", job["episodes"], - "-S", - str(job["result_index"]), ] + if job.get("result_index"): + command.extend(["-S", str(job["result_index"])]) if job["mode"] == "dub": command.append("--dub") command.append(job["query"]) diff --git a/test_app.py b/test_app.py index ad60629..ecbacbc 100644 --- a/test_app.py +++ b/test_app.py @@ -1279,6 +1279,22 @@ class WatchlistCompletionTests(unittest.TestCase): self.assertEqual(prepared["show_id"], "show-42") self.assertEqual(prepared["title"], "Queue Show Season 2") + def test_command_for_job_omits_result_switch_when_result_index_missing(self): + job = APP.app_support.build_job( + { + "query": "Queue Show", + "title": "Queue Show", + "mode": "dub", + "quality": "best", + "episodes": "1-10", + "download_dir": "/tmp/example", + "season": "1", + }, + {"mode": "sub", "quality": "best", "download_dir": "/tmp/example"}, + ) + + self.assertNotIn("-S", APP.app_support.command_for_job(job)) + def test_download_watchlist_item_queues_full_episode_range_for_selected_mode(self): item = { "show_id": "show-42", @@ -1306,7 +1322,6 @@ class WatchlistCompletionTests(unittest.TestCase): "media_type": "movie", "season": "4", "episode_offset": None, - "index": 3, "mode": "dub", "quality": "best", "episodes": "1-12", @@ -1990,7 +2005,6 @@ class AutoDownloadQueueTests(unittest.TestCase): "media_type": "tv", "season": "3", "episode_offset": "13", - "index": 2, "mode": "dub", "quality": "best", "episodes": "12", @@ -2045,7 +2059,6 @@ class AutoDownloadQueueTests(unittest.TestCase): "media_type": "tv", "season": "1", "episode_offset": None, - "index": 1, "mode": "dub", "quality": "best", "episodes": "1-3", @@ -2099,7 +2112,6 @@ class AutoDownloadQueueTests(unittest.TestCase): "media_type": "tv", "season": "2", "episode_offset": "13", - "index": 1, "mode": "dub", "quality": "best", "episodes": "1-2",