Stop forcing watchlist ani-cli result indexes
This commit is contained in:
@@ -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,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 app’s result list.
|
||||
|
||||
### Watchlist
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
+8
-4
@@ -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,8 +941,12 @@ def build_job(payload, config):
|
||||
anime_name = sanitize_path_component(payload.get("anime_name") or title)
|
||||
if not query:
|
||||
raise ValueError("Missing search query")
|
||||
raw_index = payload.get("index")
|
||||
if raw_index in (None, ""):
|
||||
index = None
|
||||
else:
|
||||
try:
|
||||
index = int(payload.get("index", 1))
|
||||
index = int(raw_index)
|
||||
except (TypeError, ValueError) as exc:
|
||||
raise ValueError("Invalid result index") from exc
|
||||
if index < 1:
|
||||
@@ -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
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user