Archived
Compare commits
2
Commits
141dcd9c70
...
edb565d855
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
edb565d855 | ||
|
|
32fc0f2829 |
@@ -3,5 +3,5 @@
|
|||||||
- when needed you may install any tools using pip if the project reqires it
|
- when needed you may install any tools using pip if the project reqires it
|
||||||
- you can freely acces any LAN URL and github.com URL.
|
- you can freely acces any LAN URL and github.com URL.
|
||||||
- always update README.md to reflect current project.
|
- always update README.md to reflect current project.
|
||||||
- always commit changes with commentary
|
- always commit changes with commentary and push
|
||||||
- always make sure that update wont wipe ani data in a previosly running instance like configuration or watchlist content
|
- always make sure that update wont wipe ani data in a previosly running instance like configuration or watchlist content
|
||||||
@@ -1,5 +1,10 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.50.1 - 2026-08-01
|
||||||
|
|
||||||
|
- Passed the selected Search result number through queued `ani-cli` jobs as `-S`, so downloads avoid the interactive series picker when multiple similar titles are returned.
|
||||||
|
- Preserved the selected result index in queued jobs for more reliable watchlist identity sync after ambiguous downloads.
|
||||||
|
|
||||||
## 0.50.0 - 2026-08-01
|
## 0.50.0 - 2026-08-01
|
||||||
|
|
||||||
- Added `curl-impersonate` to Docker images using the maintained `lexiforest/curl-impersonate` image so `ani-cli` v5 can use browser-like curl wrappers before falling back to plain `curl`.
|
- Added `curl-impersonate` to Docker images using the maintained `lexiforest/curl-impersonate` image so `ani-cli` v5 can use browser-like curl wrappers before falling back to plain `curl`.
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
Local web UI for a system-wide `ani-cli` install.
|
Local web UI for a system-wide `ani-cli` install.
|
||||||
|
|
||||||
Current version: `0.50.0`
|
Current version: `0.50.1`
|
||||||
|
|
||||||
## What it does
|
## What it does
|
||||||
|
|
||||||
- Search anime in `sub` or `dub`, with poster-style results shown below the selection panel and the first English alternate title when available
|
- Search anime in `sub` or `dub`, with poster-style results shown below the selection panel and the first English alternate title when available
|
||||||
- Queue downloads with folder, quality, media type, season, and episode controls
|
- Queue downloads with folder, quality, media type, season, episode controls, and the selected upstream search result when a Search card is used
|
||||||
- Choose which download backends queue jobs may use: `ani-cli`, `anipy-cli`, and `animdl`
|
- Choose which download backends queue jobs may use: `ani-cli`, `anipy-cli`, and `animdl`
|
||||||
- Track shows in a watchlist with `Watching`, `Planned`, `Finished`, and `Dropped` categories
|
- Track shows in a watchlist with `Watching`, `Planned`, `Finished`, and `Dropped` categories
|
||||||
- Expose a small JSON summary endpoint for Homepage dashboard widgets
|
- Expose a small JSON summary endpoint for Homepage dashboard widgets
|
||||||
@@ -120,6 +120,7 @@ Docker notes:
|
|||||||
- Selecting one method disables fallback retry; selecting multiple methods makes later methods automatic fallbacks
|
- Selecting one method disables fallback retry; selecting multiple methods makes later methods automatic fallbacks
|
||||||
- Queue `ani-cli` downloads explicitly run with `ANI_CLI_PLAYER=download` so headless Docker installs do not need `mpv` or `vlc` just to save files
|
- Queue `ani-cli` downloads explicitly run with `ANI_CLI_PLAYER=download` so headless Docker installs do not need `mpv` or `vlc` just to save files
|
||||||
- Docker images include `curl-impersonate` wrappers before plain `curl` on `PATH`, matching the preference order used by `ani-cli` v5
|
- Docker images include `curl-impersonate` wrappers before plain `curl` on `PATH`, matching the preference order used by `ani-cli` v5
|
||||||
|
- Queue jobs created from Search pass the selected result number to `ani-cli -S`, avoiding the interactive series picker when the provider returns multiple similar titles
|
||||||
- Fallback retries keep the queued episode numbers when fallback downloader filenames are renumbered from `1`
|
- Fallback retries keep the queued episode numbers when fallback downloader filenames are renumbered from `1`
|
||||||
- Docker images install `anipy-cli` and `animdl` automatically; non-Docker installs should provide the selected tools in `PATH` themselves
|
- Docker images install `anipy-cli` and `animdl` automatically; non-Docker installs should provide the selected tools in `PATH` themselves
|
||||||
|
|
||||||
|
|||||||
+16
-1
@@ -1216,7 +1216,7 @@ def build_job(payload, config):
|
|||||||
"season": normalize_season(payload.get("season")),
|
"season": normalize_season(payload.get("season")),
|
||||||
"episode_offset": normalize_episode_offset(payload.get("episode_offset")),
|
"episode_offset": normalize_episode_offset(payload.get("episode_offset")),
|
||||||
"query": query,
|
"query": query,
|
||||||
"result_index": None,
|
"result_index": normalize_result_index(payload.get("result_index")),
|
||||||
"mode": mode,
|
"mode": mode,
|
||||||
"quality": quality,
|
"quality": quality,
|
||||||
"episodes": validate_episode_spec(payload.get("episodes")),
|
"episodes": validate_episode_spec(payload.get("episodes")),
|
||||||
@@ -1232,6 +1232,18 @@ def build_job(payload, config):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_result_index(value):
|
||||||
|
if value in (None, ""):
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
index = int(str(value).strip())
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
return None
|
||||||
|
if index < 1:
|
||||||
|
return None
|
||||||
|
return index
|
||||||
|
|
||||||
|
|
||||||
def anipy_search_spec(job):
|
def anipy_search_spec(job):
|
||||||
query = re.sub(r"\s+", " ", str(job.get("query") or "").replace(":", " ")).strip()
|
query = re.sub(r"\s+", " ", str(job.get("query") or "").replace(":", " ")).strip()
|
||||||
mode = "dub" if str(job.get("mode") or "").strip().lower() == "dub" else "sub"
|
mode = "dub" if str(job.get("mode") or "").strip().lower() == "dub" else "sub"
|
||||||
@@ -1276,6 +1288,9 @@ def command_for_job(job, backend="ani-cli", download_path=None):
|
|||||||
"-e",
|
"-e",
|
||||||
job["episodes"],
|
job["episodes"],
|
||||||
]
|
]
|
||||||
|
result_index = normalize_result_index(job.get("result_index"))
|
||||||
|
if result_index is not None:
|
||||||
|
command.extend(["-S", str(result_index)])
|
||||||
if job["mode"] == "dub":
|
if job["mode"] == "dub":
|
||||||
command.append("--dub")
|
command.append("--dub")
|
||||||
command.append(job["query"])
|
command.append(job["query"])
|
||||||
|
|||||||
@@ -688,6 +688,7 @@ INDEX_HTML = r"""<!doctype html>
|
|||||||
const payload = {
|
const payload = {
|
||||||
show_id: state.selected.id,
|
show_id: state.selected.id,
|
||||||
query: state.selected.title,
|
query: state.selected.title,
|
||||||
|
result_index: state.selected.index,
|
||||||
title: state.selected.title,
|
title: state.selected.title,
|
||||||
anime_name: $("animeNameInput").value || state.selected.title,
|
anime_name: $("animeNameInput").value || state.selected.title,
|
||||||
media_type: $("trackMediaType").value,
|
media_type: $("trackMediaType").value,
|
||||||
|
|||||||
+17
-3
@@ -1943,7 +1943,7 @@ class WatchlistCompletionTests(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertNotIn("-S", APP.app_support.command_for_job(job))
|
self.assertNotIn("-S", APP.app_support.command_for_job(job))
|
||||||
|
|
||||||
def test_command_for_job_ignores_legacy_result_index(self):
|
def test_command_for_job_includes_result_switch_for_selected_search_result(self):
|
||||||
command = APP.app_support.command_for_job(
|
command = APP.app_support.command_for_job(
|
||||||
{
|
{
|
||||||
"query": "Queue Show",
|
"query": "Queue Show",
|
||||||
@@ -1954,6 +1954,20 @@ class WatchlistCompletionTests(unittest.TestCase):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.assertIn("-S", command)
|
||||||
|
self.assertEqual(command[command.index("-S") + 1], "2")
|
||||||
|
|
||||||
|
def test_command_for_job_ignores_invalid_result_index(self):
|
||||||
|
command = APP.app_support.command_for_job(
|
||||||
|
{
|
||||||
|
"query": "Queue Show",
|
||||||
|
"quality": "best",
|
||||||
|
"episodes": "1-10",
|
||||||
|
"mode": "dub",
|
||||||
|
"result_index": "nope",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
self.assertNotIn("-S", command)
|
self.assertNotIn("-S", command)
|
||||||
|
|
||||||
def test_command_for_job_builds_anipy_fallback_search_spec(self):
|
def test_command_for_job_builds_anipy_fallback_search_spec(self):
|
||||||
@@ -4018,9 +4032,9 @@ class TemplateHelperTests(unittest.TestCase):
|
|||||||
self.assertIn('const progress = `${job.completed || 0}/${job.total || 0} entries`;', APP.QUEUE_HTML)
|
self.assertIn('const progress = `${job.completed || 0}/${job.total || 0} entries`;', APP.QUEUE_HTML)
|
||||||
self.assertIn('const moved = `${job.moved || 0} moved`;', APP.QUEUE_HTML)
|
self.assertIn('const moved = `${job.moved || 0} moved`;', APP.QUEUE_HTML)
|
||||||
|
|
||||||
def test_search_page_queues_selected_title_without_result_index(self):
|
def test_search_page_queues_selected_title_with_result_index(self):
|
||||||
self.assertIn('query: state.selected.title,', APP.INDEX_HTML)
|
self.assertIn('query: state.selected.title,', APP.INDEX_HTML)
|
||||||
self.assertNotIn('index: state.selected.index,', APP.INDEX_HTML)
|
self.assertIn('result_index: state.selected.index,', APP.INDEX_HTML)
|
||||||
|
|
||||||
def test_search_page_renders_poster_results_under_selection_panel(self):
|
def test_search_page_renders_poster_results_under_selection_panel(self):
|
||||||
self.assertIn('class="results-grid" id="results"', APP.INDEX_HTML)
|
self.assertIn('class="results-grid" id="results"', APP.INDEX_HTML)
|
||||||
|
|||||||
Reference in New Issue
Block a user