Show ani-cli version in config runtime info
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
# Changelog
|
||||
|
||||
## 0.40.6 - 2026-05-25
|
||||
|
||||
- Fixed the Config page `Dependencies` panel so it stretches across the full settings width, centered its dependency badges, and added the installed `ani-cli` version to the runtime info block.
|
||||
|
||||
## 0.40.5 - 2026-05-25
|
||||
|
||||
- Moved the Config page `Dependencies` panel to the top as a full-width card and changed the remaining settings panels to a two-column layout that collapses back to one column at `1080px` and below.
|
||||
|
||||
@@ -191,6 +191,7 @@ Layout:
|
||||
|
||||
- `Dependencies` stays at the top as a full-width runtime status card.
|
||||
- The remaining Config sections use two columns on larger screens and collapse to one column at `1080px` width and below.
|
||||
- Runtime info shows both the `ani-cli-web` version and the installed `ani-cli` version.
|
||||
|
||||
Saved settings are written to `.ani-cli-web/config.json`.
|
||||
|
||||
|
||||
+1
-1
@@ -19,7 +19,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.40.5"
|
||||
VERSION = "0.40.6"
|
||||
ALLANIME_BASE = "allanime.day"
|
||||
ALLANIME_API = f"https://api.{ALLANIME_BASE}"
|
||||
ALLANIME_REFERER = "https://allmanga.to"
|
||||
|
||||
+13
-6
@@ -134,7 +134,7 @@ CONFIG_HTML = r"""<!doctype html>
|
||||
gap: 20px;
|
||||
min-width: 0;
|
||||
align-content: start;
|
||||
justify-items: start;
|
||||
justify-items: stretch;
|
||||
}
|
||||
h1, h2, p { margin: 0; }
|
||||
h1 {
|
||||
@@ -280,17 +280,22 @@ CONFIG_HTML = r"""<!doctype html>
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
.deps {
|
||||
justify-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
.deps .chips {
|
||||
justify-content: center;
|
||||
}
|
||||
.settings-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 18px;
|
||||
align-items: start;
|
||||
width: 100%;
|
||||
}
|
||||
.settings-main, .deps {
|
||||
width: min(1180px, 100%);
|
||||
}
|
||||
.deps {
|
||||
width: min(1180px, 100%);
|
||||
width: 100%;
|
||||
}
|
||||
@media (max-width: 900px) {
|
||||
.app { grid-template-columns: 1fr; }
|
||||
@@ -325,9 +330,10 @@ CONFIG_HTML = r"""<!doctype html>
|
||||
</div>
|
||||
</section>
|
||||
<section class="settings">
|
||||
<h2>Runtime info</h2>
|
||||
<h2>Runtime info</h2>
|
||||
<div class="stack muted">
|
||||
<p id="versionLine">Loading version...</p>
|
||||
<p id="aniCliVersionLine">Detecting ani-cli version...</p>
|
||||
<p>Saved settings live in `.ani-cli-web/config.json` inside this project.</p>
|
||||
</div>
|
||||
</section>
|
||||
@@ -558,6 +564,7 @@ CONFIG_HTML = r"""<!doctype html>
|
||||
async function loadVersion() {
|
||||
const data = await api("/api/version");
|
||||
$("versionLine").textContent = `${data.name} ${data.version}`;
|
||||
$("aniCliVersionLine").textContent = `ani-cli ${data.ani_cli_version || "Unavailable"}`;
|
||||
}
|
||||
|
||||
$("saveConfigBtn").addEventListener("click", saveConfig);
|
||||
|
||||
+19
-1
@@ -6,7 +6,9 @@ import json
|
||||
import mimetypes
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import traceback
|
||||
from functools import lru_cache
|
||||
from dataclasses import dataclass
|
||||
from http.cookies import SimpleCookie
|
||||
from http import HTTPStatus
|
||||
@@ -72,6 +74,22 @@ def dependency_status():
|
||||
return result
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def installed_ani_cli_version():
|
||||
try:
|
||||
completed = subprocess.run(
|
||||
[ANI_CLI, "--version"],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=6,
|
||||
)
|
||||
except (OSError, subprocess.SubprocessError):
|
||||
return "Unavailable"
|
||||
version = str(completed.stdout or completed.stderr or "").strip()
|
||||
return version or "Unavailable"
|
||||
|
||||
|
||||
class Handler(BaseHTTPRequestHandler):
|
||||
server_version = "AniCliWeb/1.0"
|
||||
remote_token_cookie_name = "ani_cli_web_token"
|
||||
@@ -380,7 +398,7 @@ class Handler(BaseHTTPRequestHandler):
|
||||
elif parsed.path == "/api/config":
|
||||
self.json(Handler._context(self).get_config_snapshot())
|
||||
elif parsed.path == "/api/version":
|
||||
self.json({"name": APP_NAME, "version": VERSION})
|
||||
self.json({"name": APP_NAME, "version": VERSION, "ani_cli_version": installed_ani_cli_version()})
|
||||
elif parsed.path == "/api/dependencies":
|
||||
self.json(dependency_status())
|
||||
elif parsed.path == "/api/search":
|
||||
|
||||
+11
@@ -1748,6 +1748,14 @@ class HandlerRouteTests(unittest.TestCase):
|
||||
self.assertEqual(handler.json_payload["auto_download_mode"], "dub")
|
||||
self.assertEqual(handler.json_payload["auto_download_quality"], "720")
|
||||
|
||||
def test_version_route_includes_ani_cli_version(self):
|
||||
handler = DummyHandler("/api/version")
|
||||
APP.Handler.do_GET(handler)
|
||||
self.assertEqual(handler.json_status, HTTPStatus.OK)
|
||||
self.assertEqual(handler.json_payload["name"], APP.APP_NAME)
|
||||
self.assertEqual(handler.json_payload["version"], APP.VERSION)
|
||||
self.assertIn("ani_cli_version", handler.json_payload)
|
||||
|
||||
def test_config_post_accepts_discord_webhook_fields(self):
|
||||
body = b'{"download_dir":"/tmp/example","mode":"sub","quality":"best","discord_webhook_url":"https://discord.example/webhook","discord_webhook_events":["runtime_error","watchlist_refresh_failed","bad"]}'
|
||||
handler = DummyHandler("/api/config", body=body, content_length=len(body))
|
||||
@@ -1964,6 +1972,9 @@ class TemplateHelperTests(unittest.TestCase):
|
||||
self.assertIn('<div class="settings-grid">', APP.CONFIG_HTML)
|
||||
self.assertLess(APP.CONFIG_HTML.index('<section class="deps" id="deps"></section>'), APP.CONFIG_HTML.index('<div class="settings-grid">'))
|
||||
self.assertIn("@media (max-width: 1080px)", APP.CONFIG_HTML)
|
||||
self.assertIn("justify-items: stretch;", APP.CONFIG_HTML)
|
||||
self.assertIn('id="aniCliVersionLine"', APP.CONFIG_HTML)
|
||||
self.assertIn('ani-cli ${data.ani_cli_version || "Unavailable"}', APP.CONFIG_HTML)
|
||||
|
||||
def test_search_page_sends_watchlist_auto_download_series(self):
|
||||
self.assertIn('auto_download_series: $("seasonInput").value || "1"', APP.INDEX_HTML)
|
||||
|
||||
Reference in New Issue
Block a user