Compare commits

...
2 Commits
Author SHA1 Message Date
Dymas 5c4f251fa6 Fix ready border condition on watchlist cards 2026-05-17 21:49:27 +02:00
Dymas 91b1e36a94 Highlight fully ready finished watchlist cards 2026-05-17 21:43:11 +02:00
6 changed files with 31 additions and 3 deletions
+8
View File
@@ -1,5 +1,13 @@
# Changelog
## 0.32.5 - 2026-05-17
- Fixed the green ready-border highlight so it applies to any watchlist card with both subbed and dubbed episodes complete, instead of only cards filed under the `Finished` category.
## 0.32.4 - 2026-05-17
- Highlighted fully ready finished watchlist entries with a thin green card border when both subbed and dubbed episodes are complete, making download-complete anime easier to scan quickly.
## 0.32.3 - 2026-05-17
- Fixed watchlist download sync so a successful download now reuses the existing tracked entry when the resolved `show_id` changes, preserving its category and marking it downloaded instead of creating a duplicate finished-only row.
+1
View File
@@ -157,6 +157,7 @@ The app currently includes:
- Per-show watchlist refresh queueing now also deduplicates in-flight refreshes, so the same show is not fetched twice back-to-back while one refresh is already running.
- The watchlist page now silently refreshes itself while queued per-show refresh work is still being processed, so queued entries settle into their updated state without a manual reload.
- The watchlist page now also avoids re-triggering the same unresolved thumbnail warm-up request on every silent poll cycle while a show's thumbnail state is unchanged.
- Watchlist cards with both sub and dub fully ready now get a thin green border for quicker visual scanning, regardless of which category tab they are in.
- Background `Refresh All` execution with status polling, no inline thumbnail downloads during the bulk job, and a configurable delay between shows to reduce upstream request bursts.
- Optional scheduled background watchlist refreshes with Config page controls for enable/disable and refresh period.
- Scheduled background refresh runs now log queue, start, and completion status to stdout so container logs show whether they finished successfully, with errors, or failed.
+1 -1
View File
@@ -1 +1 @@
0.32.3
0.32.5
+1 -1
View File
@@ -16,7 +16,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.32.3"
VERSION = "0.32.5"
ALLANIME_BASE = "allanime.day"
ALLANIME_API = f"https://api.{ALLANIME_BASE}"
ALLANIME_REFERER = "https://allmanga.to"
+5
View File
@@ -1481,6 +1481,11 @@ class TemplateHelperTests(unittest.TestCase):
self.assertIn("else if (state.queuedCount > 0)", APP.WATCHLIST_HTML)
self.assertIn("fetchWatchlist(state.watchlistPage, { silent: true })", APP.WATCHLIST_HTML)
def test_watchlist_page_highlights_fully_ready_cards(self):
self.assertIn(".anime-card.fully-ready", APP.WATCHLIST_HTML)
self.assertIn("const isFullyReady = item.sub_complete && item.dub_complete;", APP.WATCHLIST_HTML)
self.assertIn("card.className = watchlistCardClassName(item);", APP.WATCHLIST_HTML)
def test_watchlist_thumbnail_warmup_skips_repeated_attempts(self):
self.assertIn("thumbnailWarmupPending: new Set()", APP.WATCHLIST_HTML)
self.assertIn("function thumbnailWarmupToken(item)", APP.WATCHLIST_HTML)
+15 -1
View File
@@ -303,10 +303,19 @@ WATCHLIST_HTML = r"""<!doctype html>
box-shadow: 0 18px 38px rgba(5, 2, 15, 0.32);
transition: transform 0.18s ease, border-color 0.18s ease;
}
.anime-card.fully-ready {
border-color: rgba(149, 228, 186, 0.72);
box-shadow:
inset 0 0 0 1px rgba(149, 228, 186, 0.18),
0 18px 38px rgba(5, 2, 15, 0.32);
}
.anime-card:hover {
border-color: var(--line-strong);
transform: translateY(-2px);
}
.anime-card.fully-ready:hover {
border-color: rgba(149, 228, 186, 0.88);
}
.anime-card.error {
border-color: rgba(255, 144, 164, 0.3);
}
@@ -699,6 +708,11 @@ WATCHLIST_HTML = r"""<!doctype html>
return parts.map((part) => part[0]).join("").slice(0, 2);
}
function watchlistCardClassName(item) {
const isFullyReady = item.sub_complete && item.dub_complete;
return `anime-card${item.status === "error" ? " error" : ""}${isFullyReady ? " fully-ready" : ""}`;
}
function formatModeProgress(currentCount, expectedCount) {
const current = Number(currentCount || 0);
const expected = Number(expectedCount || 0);
@@ -965,7 +979,7 @@ WATCHLIST_HTML = r"""<!doctype html>
for (const item of items) {
const card = document.createElement("article");
const checked = item.last_checked ? new Date(item.last_checked).toLocaleString() : "Never";
card.className = `anime-card${item.status === "error" ? " error" : ""}`;
card.className = watchlistCardClassName(item);
card.dataset.showId = item.show_id;
card.title = item.thumbnail_debug || "Thumbnail source: unresolved";
card.innerHTML = `