From cb86f79da1459e884b4accefa8ab099b919493b9 Mon Sep 17 00:00:00 2001 From: Codex Date: Sun, 9 Aug 2026 12:22:04 +0200 Subject: [PATCH] Move search controls and add result modal --- CHANGELOG.md | 7 ++ README.md | 2 + VERSION | 2 +- app.py | 7 +- config_page.py | 4 +- http_handler.py | 3 +- search_page.py | 172 +++++++++++++++++++++++++++++++----------------- 7 files changed, 132 insertions(+), 65 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e3e2a8..49a47eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 0.51.4 - 2026-08-09 + +- Moved Search controls from the sidebar to a top-of-page search panel. +- Removed the Search page quality selector; queued downloads now use the saved Config quality default. +- Added a Search page provider dropdown for choosing Anikoto, AniNeko, or AnimePahe per search. +- Moved result actions into a floating window that opens after selecting a search result. + ## 0.51.3 - 2026-08-09 - Removed the Episode mode selector from the Search page and now choose the selected result's episode language automatically from the saved Config default and available `SUB`/`DUB` flags. diff --git a/README.md b/README.md index bac99ca..dfcc8d7 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,10 @@ Kaizoku is a local web app for searching, tracking, and downloading anime from A ## Features - Search anime through the configured provider and tag results with available `SUB` and `DUB` episode languages. +- Choose the active search provider directly from the Search page. - Prefer provider-supplied search artwork, with a local title-based thumbnail fallback when provider artwork is missing or broken. - Queue single episodes or batches in subbed or dubbed mode. +- Open result actions in a floating window for watchlist, media type, library name, season, episode range, and download folder choices. - Fall back across the other configured providers when an episode or stream cannot be resolved on the primary provider. - Save files with Jellyfin-friendly layout: `TV/Series Name/Season 01/Series Name - S01E01.mp4`. - Save English external subtitles when the provider exposes usable subtitle tracks. diff --git a/VERSION b/VERSION index cf2529d..0c2d2af 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.51.3 +0.51.4 diff --git a/app.py b/app.py index 4e47fbf..631bae2 100644 --- a/app.py +++ b/app.py @@ -916,9 +916,12 @@ def episode_language_summary(show_id, provider): return summary -def search_anime(query, mode): +def search_anime(query, mode, provider=None): runtime = ensure_runtime() - provider = str((runtime.get("config") or {}).get("provider") or "anikoto").strip().lower() + configured_provider = str((runtime.get("config") or {}).get("provider") or "anikoto").strip().lower() + provider = str(provider or configured_provider).strip().lower() + if provider not in provider_bridge.PROVIDERS: + provider = configured_provider if configured_provider in provider_bridge.PROVIDERS else "anikoto" data = provider_bridge.search(query, provider=provider, page=1) shows = data.get("results") or [] results = [] diff --git a/config_page.py b/config_page.py index 8f4a06f..a4cf46b 100644 --- a/config_page.py +++ b/config_page.py @@ -454,7 +454,7 @@ CONFIG_HTML = r"""

Saved defaults

These values preload the Search page and act as the fallback folder for new queue jobs.

-

Mode and quality can still be changed on the Search page before queueing a download.

+

Search uses these saved mode and quality defaults when opening result actions and queueing downloads.

@@ -476,7 +476,7 @@ CONFIG_HTML = r"""

Defaults

-

Manage the folder, mode, and quality that the Search page starts with.

+

Manage the folder, mode, quality, and provider defaults used by Search and new queue jobs.

diff --git a/http_handler.py b/http_handler.py index b52255d..ea3569a 100644 --- a/http_handler.py +++ b/http_handler.py @@ -640,11 +640,12 @@ class Handler(BaseHTTPRequestHandler): params = parse_qs(parsed.query) query = (params.get("q") or [""])[0].strip() mode = (params.get("mode") or [config["mode"]])[0].lower() + provider = (params.get("provider") or [config.get("provider") or ""])[0].strip().lower() if not query: raise ValueError("Search query is required") if mode not in MODE_CHOICES: raise ValueError("Mode must be sub or dub") - self.json({"results": Handler._context(self).search_anime(query, mode)}) + self.json({"results": Handler._context(self).search_anime(query, mode, provider=provider)}) elif parsed.path == "/api/search/thumb": Handler._runtime(self) params = parse_qs(parsed.query) diff --git a/search_page.py b/search_page.py index a5aada5..ae43c34 100644 --- a/search_page.py +++ b/search_page.py @@ -120,7 +120,7 @@ INDEX_HTML = r""" } .app { display: grid; - grid-template-columns: minmax(320px, 380px) 1fr; + grid-template-columns: minmax(240px, 300px) 1fr; min-height: 100vh; } aside, main { @@ -173,16 +173,6 @@ INDEX_HTML = r""" .controls { align-items: end; } - .search-box { - display: grid; - gap: 12px; - padding: 16px; - border: 1px solid var(--line); - border-radius: 22px; - background: linear-gradient(180deg, rgba(31, 24, 50, 0.86), rgba(17, 13, 29, 0.92)); - box-shadow: var(--shadow); - backdrop-filter: blur(18px); - } .page-links { display: grid; gap: 8px; @@ -233,18 +223,26 @@ INDEX_HTML = r""" color: var(--text); font-weight: 700; } - .settings, .episodes-panel, .results-panel, .deps { + .settings, .search-panel, .episodes-panel, .results-panel, .deps { border: 1px solid var(--line); border-radius: 22px; background: linear-gradient(180deg, rgba(29, 22, 47, 0.88), rgba(17, 13, 29, 0.94)); box-shadow: var(--shadow); backdrop-filter: blur(18px); } - .settings, .episodes-panel, .results-panel, .deps { + .settings, .search-panel, .episodes-panel, .results-panel, .deps { padding: 18px; display: grid; gap: 14px; } + .search-panel { + align-items: end; + } + .search-panel .controls { + display: grid; + grid-template-columns: minmax(220px, 1fr) minmax(170px, 220px) auto; + align-items: end; + } .results-panel { min-width: 0; } @@ -385,6 +383,31 @@ INDEX_HTML = r""" color: #ddd0ff; font-size: 13px; } + .modal-overlay { + position: fixed; + inset: 0; + z-index: 20; + display: grid; + place-items: center; + padding: 22px; + background: rgba(4, 2, 10, 0.68); + backdrop-filter: blur(12px); + } + .modal-overlay[hidden] { + display: none; + } + .modal-window { + width: min(980px, 100%); + max-height: min(840px, calc(100vh - 44px)); + overflow: auto; + border: 1px solid var(--line-strong); + border-radius: 22px; + background: linear-gradient(180deg, rgba(29, 22, 47, 0.98), rgba(13, 9, 24, 0.98)); + box-shadow: 0 28px 80px rgba(0, 0, 0, 0.52); + padding: 18px; + display: grid; + gap: 14px; + } .results-panel .toolbar { align-items: end; } @@ -403,6 +426,7 @@ INDEX_HTML = r""" .app { grid-template-columns: 1fr; } aside { border-right: 0; border-bottom: 1px solid var(--line); } .controls, .row, .toolbar { align-items: stretch; flex-direction: column; } + .search-panel .controls { grid-template-columns: 1fr; } .results-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } } @media (max-width: 640px) { @@ -418,50 +442,71 @@ INDEX_HTML = r""" "Search", badge_id="serverBadge", ) + render_page_links("search") + r""" - - -
-
+
+
+
+

Search anime

+

Choose a provider and search across subbed and dubbed results.

+
+
+
+ + + +
+
+
+
+
+
+

Select results

+

Poster cards appear here after a search.

+
+
+
+
+
+ +
-
-
-
-

Select results

-

Poster cards appear here after a search.

-
-
-
-
- +