Stop forcing watchlist ani-cli result indexes

This commit is contained in:
Dymas
2026-05-25 23:24:31 +02:00
parent 1f50c3c666
commit 5db94cffb1
6 changed files with 36 additions and 17 deletions
+4
View File
@@ -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.
+2 -1
View File
@@ -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 <index>` from API search ordering, which avoids bad result mismatches when `ani-cli`s own search order differs from the web apps result list.
### Watchlist
+1 -1
View File
@@ -1 +1 @@
0.45.3
0.45.4
-2
View File
@@ -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,
+13 -9
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.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"])
+16 -4
View File
@@ -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",