Improve auto-download title and series controls
This commit is contained in:
@@ -1,5 +1,10 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.39.1 - 2026-05-25
|
||||||
|
|
||||||
|
- Replaced the auto-download name datalist with an explicit dropdown that lists the current title, AniDB alternative titles, and a `Custom` option.
|
||||||
|
- Added a per-anime `Series` field to auto-download settings so queued episodes can target a chosen series/season number instead of always using `1`.
|
||||||
|
|
||||||
## 0.39.0 - 2026-05-25
|
## 0.39.0 - 2026-05-25
|
||||||
|
|
||||||
- Added watchlist auto-download support with global Config controls plus per-anime mode, quality, and library-name settings hidden behind a card-level editor.
|
- Added watchlist auto-download support with global Config controls plus per-anime mode, quality, and library-name settings hidden behind a card-level editor.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Small local web UI for a system-wide `ani-cli` install.
|
Small local web UI for a system-wide `ani-cli` install.
|
||||||
|
|
||||||
Current version: `0.39.0`
|
Current version: `0.39.1`
|
||||||
|
|
||||||
## Project Layout
|
## Project Layout
|
||||||
|
|
||||||
@@ -224,7 +224,7 @@ Main behavior:
|
|||||||
7. Summary cards show total tracked shows plus `sub` and `dub` counts.
|
7. Summary cards show total tracked shows plus `sub` and `dub` counts.
|
||||||
8. Pagination shows 30 cards per page.
|
8. Pagination shows 30 cards per page.
|
||||||
9. `Alternative titles` expands English alternate titles from AniDB when the watchlist refresh can match the show to an AniDB entry.
|
9. `Alternative titles` expands English alternate titles from AniDB when the watchlist refresh can match the show to an AniDB entry.
|
||||||
10. `Auto-download` opens per-series settings for language, quality, and the sanitized library name used for automatically queued episodes.
|
10. `Auto-download` opens per-series settings for language, quality, series number, and the sanitized library name used for automatically queued episodes.
|
||||||
|
|
||||||
Status behavior:
|
Status behavior:
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ from app_support import (
|
|||||||
debug_log,
|
debug_log,
|
||||||
load_json,
|
load_json,
|
||||||
migrate_legacy_state_storage,
|
migrate_legacy_state_storage,
|
||||||
|
normalize_season,
|
||||||
normalize_config,
|
normalize_config,
|
||||||
now_iso,
|
now_iso,
|
||||||
sanitize_path_component,
|
sanitize_path_component,
|
||||||
@@ -1060,6 +1061,7 @@ class WatchlistStore:
|
|||||||
"auto_download_mode": str(config.get("auto_download_mode") or "dub").strip().lower() or "dub",
|
"auto_download_mode": str(config.get("auto_download_mode") or "dub").strip().lower() or "dub",
|
||||||
"auto_download_quality": str(config.get("auto_download_quality") or "best").strip().lower() or "best",
|
"auto_download_quality": str(config.get("auto_download_quality") or "best").strip().lower() or "best",
|
||||||
"auto_download_name": sanitize_path_component(title, "Anime"),
|
"auto_download_name": sanitize_path_component(title, "Anime"),
|
||||||
|
"auto_download_series": "1",
|
||||||
}
|
}
|
||||||
|
|
||||||
def _connect(self):
|
def _connect(self):
|
||||||
@@ -1136,6 +1138,7 @@ class WatchlistStore:
|
|||||||
auto_download_mode TEXT,
|
auto_download_mode TEXT,
|
||||||
auto_download_quality TEXT,
|
auto_download_quality TEXT,
|
||||||
auto_download_name TEXT,
|
auto_download_name TEXT,
|
||||||
|
auto_download_series TEXT,
|
||||||
thumbnail_path TEXT,
|
thumbnail_path TEXT,
|
||||||
thumbnail_checked_at TEXT
|
thumbnail_checked_at TEXT
|
||||||
)
|
)
|
||||||
@@ -1176,6 +1179,8 @@ class WatchlistStore:
|
|||||||
conn.execute("ALTER TABLE watchlist ADD COLUMN auto_download_quality TEXT")
|
conn.execute("ALTER TABLE watchlist ADD COLUMN auto_download_quality TEXT")
|
||||||
if "auto_download_name" not in columns:
|
if "auto_download_name" not in columns:
|
||||||
conn.execute("ALTER TABLE watchlist ADD COLUMN auto_download_name TEXT")
|
conn.execute("ALTER TABLE watchlist ADD COLUMN auto_download_name TEXT")
|
||||||
|
if "auto_download_series" not in columns:
|
||||||
|
conn.execute("ALTER TABLE watchlist ADD COLUMN auto_download_series TEXT")
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"UPDATE watchlist SET category = 'watching' WHERE category IS NULL OR TRIM(category) = ''"
|
"UPDATE watchlist SET category = 'watching' WHERE category IS NULL OR TRIM(category) = ''"
|
||||||
)
|
)
|
||||||
@@ -1212,6 +1217,7 @@ class WatchlistStore:
|
|||||||
item["auto_download_mode"] = mode if mode in MODE_CHOICES else defaults["auto_download_mode"]
|
item["auto_download_mode"] = mode if mode in MODE_CHOICES else defaults["auto_download_mode"]
|
||||||
item["auto_download_quality"] = quality if quality in QUALITY_CHOICES else defaults["auto_download_quality"]
|
item["auto_download_quality"] = quality if quality in QUALITY_CHOICES else defaults["auto_download_quality"]
|
||||||
item["auto_download_name"] = sanitize_path_component(item.get("auto_download_name") or defaults["auto_download_name"], defaults["auto_download_name"])
|
item["auto_download_name"] = sanitize_path_component(item.get("auto_download_name") or defaults["auto_download_name"], defaults["auto_download_name"])
|
||||||
|
item["auto_download_series"] = normalize_season(item.get("auto_download_series") or defaults["auto_download_series"])
|
||||||
if item.get("animeschedule_route"):
|
if item.get("animeschedule_route"):
|
||||||
title = str(item.get("animeschedule_title") or item.get("title") or "").strip() or "unknown title"
|
title = str(item.get("animeschedule_title") or item.get("title") or "").strip() or "unknown title"
|
||||||
item["thumbnail_debug"] = f"AnimeSchedule: {item['animeschedule_route']} - {title}"
|
item["thumbnail_debug"] = f"AnimeSchedule: {item['animeschedule_route']} - {title}"
|
||||||
@@ -1234,9 +1240,9 @@ class WatchlistStore:
|
|||||||
animeschedule_route, animeschedule_title,
|
animeschedule_route, animeschedule_title,
|
||||||
anilist_id, anilist_title, anilist_site_url, alternative_titles_json,
|
anilist_id, anilist_title, anilist_site_url, alternative_titles_json,
|
||||||
anidb_aid, anidb_title,
|
anidb_aid, anidb_title,
|
||||||
auto_download_mode, auto_download_quality, auto_download_name,
|
auto_download_mode, auto_download_quality, auto_download_name, auto_download_series,
|
||||||
thumbnail_path, thumbnail_checked_at
|
thumbnail_path, thumbnail_checked_at
|
||||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
ON CONFLICT(show_id) DO UPDATE SET
|
ON CONFLICT(show_id) DO UPDATE SET
|
||||||
title = excluded.title,
|
title = excluded.title,
|
||||||
category = excluded.category,
|
category = excluded.category,
|
||||||
@@ -1262,6 +1268,7 @@ class WatchlistStore:
|
|||||||
auto_download_mode = excluded.auto_download_mode,
|
auto_download_mode = excluded.auto_download_mode,
|
||||||
auto_download_quality = excluded.auto_download_quality,
|
auto_download_quality = excluded.auto_download_quality,
|
||||||
auto_download_name = excluded.auto_download_name,
|
auto_download_name = excluded.auto_download_name,
|
||||||
|
auto_download_series = excluded.auto_download_series,
|
||||||
thumbnail_path = excluded.thumbnail_path,
|
thumbnail_path = excluded.thumbnail_path,
|
||||||
thumbnail_checked_at = excluded.thumbnail_checked_at
|
thumbnail_checked_at = excluded.thumbnail_checked_at
|
||||||
""",
|
""",
|
||||||
@@ -1292,6 +1299,7 @@ class WatchlistStore:
|
|||||||
item.get("auto_download_mode"),
|
item.get("auto_download_mode"),
|
||||||
item.get("auto_download_quality"),
|
item.get("auto_download_quality"),
|
||||||
item.get("auto_download_name"),
|
item.get("auto_download_name"),
|
||||||
|
item.get("auto_download_series"),
|
||||||
item.get("thumbnail_path"),
|
item.get("thumbnail_path"),
|
||||||
item.get("thumbnail_checked_at"),
|
item.get("thumbnail_checked_at"),
|
||||||
),
|
),
|
||||||
@@ -1344,6 +1352,7 @@ class WatchlistStore:
|
|||||||
"auto_download_mode": None,
|
"auto_download_mode": None,
|
||||||
"auto_download_quality": None,
|
"auto_download_quality": None,
|
||||||
"auto_download_name": None,
|
"auto_download_name": None,
|
||||||
|
"auto_download_series": None,
|
||||||
"thumbnail_path": None,
|
"thumbnail_path": None,
|
||||||
"thumbnail_checked_at": None,
|
"thumbnail_checked_at": None,
|
||||||
},
|
},
|
||||||
@@ -1741,6 +1750,7 @@ class WatchlistStore:
|
|||||||
"alternative_titles_json": None,
|
"alternative_titles_json": None,
|
||||||
"anidb_aid": None,
|
"anidb_aid": None,
|
||||||
"anidb_title": None,
|
"anidb_title": None,
|
||||||
|
"auto_download_series": None,
|
||||||
"thumbnail_path": None,
|
"thumbnail_path": None,
|
||||||
"thumbnail_checked_at": None,
|
"thumbnail_checked_at": None,
|
||||||
}
|
}
|
||||||
@@ -1748,7 +1758,7 @@ class WatchlistStore:
|
|||||||
self.schedule_refresh(normalized_show_id, source="sync")
|
self.schedule_refresh(normalized_show_id, source="sync")
|
||||||
return self.get(normalized_show_id)
|
return self.get(normalized_show_id)
|
||||||
|
|
||||||
def update_auto_download_settings(self, show_id, mode=None, quality=None, name=None):
|
def update_auto_download_settings(self, show_id, mode=None, quality=None, name=None, series=None):
|
||||||
existing = self.get(show_id)
|
existing = self.get(show_id)
|
||||||
defaults = self._auto_download_defaults(existing["title"])
|
defaults = self._auto_download_defaults(existing["title"])
|
||||||
normalized_mode = str(mode or defaults["auto_download_mode"]).strip().lower()
|
normalized_mode = str(mode or defaults["auto_download_mode"]).strip().lower()
|
||||||
@@ -1758,14 +1768,15 @@ class WatchlistStore:
|
|||||||
if normalized_quality not in QUALITY_CHOICES:
|
if normalized_quality not in QUALITY_CHOICES:
|
||||||
raise ValueError("Unknown auto-download quality.")
|
raise ValueError("Unknown auto-download quality.")
|
||||||
normalized_name = sanitize_path_component(name or defaults["auto_download_name"], defaults["auto_download_name"])
|
normalized_name = sanitize_path_component(name or defaults["auto_download_name"], defaults["auto_download_name"])
|
||||||
|
normalized_series = normalize_season(series or existing.get("auto_download_series") or defaults["auto_download_series"])
|
||||||
with self.lock, self._connect() as conn:
|
with self.lock, self._connect() as conn:
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"""
|
"""
|
||||||
UPDATE watchlist
|
UPDATE watchlist
|
||||||
SET auto_download_mode = ?, auto_download_quality = ?, auto_download_name = ?, updated_at = ?
|
SET auto_download_mode = ?, auto_download_quality = ?, auto_download_name = ?, auto_download_series = ?, updated_at = ?
|
||||||
WHERE show_id = ?
|
WHERE show_id = ?
|
||||||
""",
|
""",
|
||||||
(normalized_mode, normalized_quality, normalized_name, now_iso(), existing["show_id"]),
|
(normalized_mode, normalized_quality, normalized_name, normalized_series, now_iso(), existing["show_id"]),
|
||||||
)
|
)
|
||||||
return self.get(show_id)
|
return self.get(show_id)
|
||||||
|
|
||||||
@@ -2051,6 +2062,7 @@ def queue_watchlist_auto_download(item, refresh_source="manual"):
|
|||||||
item.get("auto_download_name") or item.get("title") or match.get("title") or "Anime",
|
item.get("auto_download_name") or item.get("title") or match.get("title") or "Anime",
|
||||||
sanitize_path_component(item.get("title") or match.get("title") or "Anime", "Anime"),
|
sanitize_path_component(item.get("title") or match.get("title") or "Anime", "Anime"),
|
||||||
)
|
)
|
||||||
|
series = normalize_season(item.get("auto_download_series") or "1")
|
||||||
jobs = []
|
jobs = []
|
||||||
for episode_spec in specs:
|
for episode_spec in specs:
|
||||||
job = runtime["download_queue"].add(
|
job = runtime["download_queue"].add(
|
||||||
@@ -2059,7 +2071,7 @@ def queue_watchlist_auto_download(item, refresh_source="manual"):
|
|||||||
"query": match.get("query") or query,
|
"query": match.get("query") or query,
|
||||||
"title": match.get("title") or item["title"],
|
"title": match.get("title") or item["title"],
|
||||||
"anime_name": anime_name,
|
"anime_name": anime_name,
|
||||||
"season": "1",
|
"season": series,
|
||||||
"index": match.get("index", 1),
|
"index": match.get("index", 1),
|
||||||
"mode": mode,
|
"mode": mode,
|
||||||
"quality": quality,
|
"quality": quality,
|
||||||
@@ -2077,9 +2089,9 @@ def update_watchlist_category(show_id, category):
|
|||||||
return {"message": f"Moved {item['title']} to {item['category_label']}.", "item": item}
|
return {"message": f"Moved {item['title']} to {item['category_label']}.", "item": item}
|
||||||
|
|
||||||
|
|
||||||
def update_watchlist_auto_download(show_id, mode=None, quality=None, name=None):
|
def update_watchlist_auto_download(show_id, mode=None, quality=None, name=None, series=None):
|
||||||
ensure_runtime()
|
ensure_runtime()
|
||||||
item = WATCHLIST.update_auto_download_settings(show_id, mode=mode, quality=quality, name=name)
|
item = WATCHLIST.update_auto_download_settings(show_id, mode=mode, quality=quality, name=name, series=series)
|
||||||
return {"message": f"Saved auto-download settings for {item['title']}.", "item": item}
|
return {"message": f"Saved auto-download settings for {item['title']}.", "item": item}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@ from uuid import uuid4
|
|||||||
PROJECT_ROOT = Path(__file__).resolve().parent
|
PROJECT_ROOT = Path(__file__).resolve().parent
|
||||||
ANI_CLI = os.environ.get("ANI_CLI_BIN") or shutil.which("ani-cli") or "ani-cli"
|
ANI_CLI = os.environ.get("ANI_CLI_BIN") or shutil.which("ani-cli") or "ani-cli"
|
||||||
APP_NAME = "ani-cli-web"
|
APP_NAME = "ani-cli-web"
|
||||||
VERSION = "0.39.0"
|
VERSION = "0.39.1"
|
||||||
ALLANIME_BASE = "allanime.day"
|
ALLANIME_BASE = "allanime.day"
|
||||||
ALLANIME_API = f"https://api.{ALLANIME_BASE}"
|
ALLANIME_API = f"https://api.{ALLANIME_BASE}"
|
||||||
ALLANIME_REFERER = "https://allmanga.to"
|
ALLANIME_REFERER = "https://allmanga.to"
|
||||||
|
|||||||
@@ -529,6 +529,7 @@ class Handler(BaseHTTPRequestHandler):
|
|||||||
payload.get("mode"),
|
payload.get("mode"),
|
||||||
payload.get("quality"),
|
payload.get("quality"),
|
||||||
payload.get("name"),
|
payload.get("name"),
|
||||||
|
payload.get("series"),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
elif parsed.path == "/api/watchlist/update-all":
|
elif parsed.path == "/api/watchlist/update-all":
|
||||||
|
|||||||
+6
-2
@@ -1519,6 +1519,7 @@ class AutoDownloadQueueTests(unittest.TestCase):
|
|||||||
"auto_download_mode": "dub",
|
"auto_download_mode": "dub",
|
||||||
"auto_download_quality": "best",
|
"auto_download_quality": "best",
|
||||||
"auto_download_name": 'Queue Show: Alt/Name',
|
"auto_download_name": 'Queue Show: Alt/Name',
|
||||||
|
"auto_download_series": "3",
|
||||||
}
|
}
|
||||||
download_queue = mock.Mock()
|
download_queue = mock.Mock()
|
||||||
download_queue.covered_episodes.return_value = {"11"}
|
download_queue.covered_episodes.return_value = {"11"}
|
||||||
@@ -1549,7 +1550,7 @@ class AutoDownloadQueueTests(unittest.TestCase):
|
|||||||
"query": "Queue Show",
|
"query": "Queue Show",
|
||||||
"title": "Queue Show",
|
"title": "Queue Show",
|
||||||
"anime_name": "Queue Show- Alt-Name",
|
"anime_name": "Queue Show- Alt-Name",
|
||||||
"season": "1",
|
"season": "3",
|
||||||
"index": 2,
|
"index": 2,
|
||||||
"mode": "dub",
|
"mode": "dub",
|
||||||
"quality": "best",
|
"quality": "best",
|
||||||
@@ -1841,7 +1842,7 @@ class HandlerRouteTests(unittest.TestCase):
|
|||||||
self.assertEqual(handler.json_status, HTTPStatus.CREATED)
|
self.assertEqual(handler.json_status, HTTPStatus.CREATED)
|
||||||
|
|
||||||
def test_watchlist_auto_download_settings_post_returns_updated_item(self):
|
def test_watchlist_auto_download_settings_post_returns_updated_item(self):
|
||||||
body = b'{"show_id":"show-1","mode":"dub","quality":"best","name":"Example Name"}'
|
body = b'{"show_id":"show-1","mode":"dub","quality":"best","name":"Example Name","series":"2"}'
|
||||||
handler = DummyHandler("/api/watchlist/update-auto-download", body=body, content_length=len(body))
|
handler = DummyHandler("/api/watchlist/update-auto-download", body=body, content_length=len(body))
|
||||||
payload = {"message": "Saved auto-download settings for Show 1.", "item": {"show_id": "show-1"}}
|
payload = {"message": "Saved auto-download settings for Show 1.", "item": {"show_id": "show-1"}}
|
||||||
handler.handler_context = mock.Mock(update_watchlist_auto_download=mock.Mock(return_value=payload))
|
handler.handler_context = mock.Mock(update_watchlist_auto_download=mock.Mock(return_value=payload))
|
||||||
@@ -1947,6 +1948,9 @@ class TemplateHelperTests(unittest.TestCase):
|
|||||||
self.assertIn('api("/api/watchlist/update-auto-download"', APP.WATCHLIST_HTML)
|
self.assertIn('api("/api/watchlist/update-auto-download"', APP.WATCHLIST_HTML)
|
||||||
self.assertIn("Save auto-download", APP.WATCHLIST_HTML)
|
self.assertIn("Save auto-download", APP.WATCHLIST_HTML)
|
||||||
self.assertIn("Manual add does not trigger it", APP.WATCHLIST_HTML)
|
self.assertIn("Manual add does not trigger it", APP.WATCHLIST_HTML)
|
||||||
|
self.assertIn("Name source", APP.WATCHLIST_HTML)
|
||||||
|
self.assertIn("Custom", APP.WATCHLIST_HTML)
|
||||||
|
self.assertIn("Series", APP.WATCHLIST_HTML)
|
||||||
|
|
||||||
def test_watchlist_thumbnail_warmup_skips_repeated_attempts(self):
|
def test_watchlist_thumbnail_warmup_skips_repeated_attempts(self):
|
||||||
self.assertIn("thumbnailWarmupPending: new Set()", APP.WATCHLIST_HTML)
|
self.assertIn("thumbnailWarmupPending: new Set()", APP.WATCHLIST_HTML)
|
||||||
|
|||||||
+31
-6
@@ -1127,9 +1127,14 @@ WATCHLIST_HTML = r"""<!doctype html>
|
|||||||
<label>Quality
|
<label>Quality
|
||||||
<select class="auto-download-quality">${qualityOptions.replace(`value="${item.auto_download_quality}"`, `value="${item.auto_download_quality}" selected`)}</select>
|
<select class="auto-download-quality">${qualityOptions.replace(`value="${item.auto_download_quality}"`, `value="${item.auto_download_quality}" selected`)}</select>
|
||||||
</label>
|
</label>
|
||||||
|
<label>Series
|
||||||
|
<input class="auto-download-series" type="number" min="1" step="1" value="${item.auto_download_series || "1"}">
|
||||||
|
</label>
|
||||||
|
<label>Name source
|
||||||
|
<select class="auto-download-name-select"></select>
|
||||||
|
</label>
|
||||||
<label>Name
|
<label>Name
|
||||||
<input class="auto-download-name" type="text" list="auto-download-name-options-${item.show_id}">
|
<input class="auto-download-name" type="text">
|
||||||
<datalist id="auto-download-name-options-${item.show_id}"></datalist>
|
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="auto-download-actions">
|
<div class="auto-download-actions">
|
||||||
@@ -1211,16 +1216,32 @@ WATCHLIST_HTML = r"""<!doctype html>
|
|||||||
const autoDownloadPanel = card.querySelector(".auto-download-panel");
|
const autoDownloadPanel = card.querySelector(".auto-download-panel");
|
||||||
const autoDownloadMode = card.querySelector(".auto-download-mode");
|
const autoDownloadMode = card.querySelector(".auto-download-mode");
|
||||||
const autoDownloadQuality = card.querySelector(".auto-download-quality");
|
const autoDownloadQuality = card.querySelector(".auto-download-quality");
|
||||||
|
const autoDownloadSeries = card.querySelector(".auto-download-series");
|
||||||
|
const autoDownloadNameSelect = card.querySelector(".auto-download-name-select");
|
||||||
const autoDownloadName = card.querySelector(".auto-download-name");
|
const autoDownloadName = card.querySelector(".auto-download-name");
|
||||||
const autoDownloadSave = card.querySelector(".auto-download-save");
|
const autoDownloadSave = card.querySelector(".auto-download-save");
|
||||||
const autoDownloadNameOptions = card.querySelector(`#auto-download-name-options-${CSS.escape(item.show_id)}`);
|
|
||||||
autoDownloadName.value = item.auto_download_name || "";
|
autoDownloadName.value = item.auto_download_name || "";
|
||||||
const nameSuggestions = [item.title, ...(Array.isArray(item.alternative_titles) ? item.alternative_titles.map((entry) => entry.value) : [])];
|
const nameSuggestions = [];
|
||||||
|
for (const name of [item.title, ...(Array.isArray(item.alternative_titles) ? item.alternative_titles.map((entry) => entry.value) : [])]) {
|
||||||
|
if (name && !nameSuggestions.includes(name)) nameSuggestions.push(name);
|
||||||
|
}
|
||||||
for (const name of nameSuggestions) {
|
for (const name of nameSuggestions) {
|
||||||
const option = document.createElement("option");
|
const option = document.createElement("option");
|
||||||
option.value = name;
|
option.value = name;
|
||||||
autoDownloadNameOptions.appendChild(option);
|
option.textContent = name;
|
||||||
|
autoDownloadNameSelect.appendChild(option);
|
||||||
}
|
}
|
||||||
|
const customOption = document.createElement("option");
|
||||||
|
customOption.value = "__custom__";
|
||||||
|
customOption.textContent = "Custom";
|
||||||
|
autoDownloadNameSelect.appendChild(customOption);
|
||||||
|
const matchedSuggestion = nameSuggestions.find((name) => name === (item.auto_download_name || ""));
|
||||||
|
autoDownloadNameSelect.value = matchedSuggestion || "__custom__";
|
||||||
|
autoDownloadNameSelect.addEventListener("change", () => {
|
||||||
|
if (autoDownloadNameSelect.value !== "__custom__") {
|
||||||
|
autoDownloadName.value = autoDownloadNameSelect.value;
|
||||||
|
}
|
||||||
|
});
|
||||||
const categorySelect = card.querySelector(".category-select");
|
const categorySelect = card.querySelector(".category-select");
|
||||||
categorySelect.addEventListener("change", async () => {
|
categorySelect.addEventListener("change", async () => {
|
||||||
categorySelect.disabled = true;
|
categorySelect.disabled = true;
|
||||||
@@ -1256,10 +1277,14 @@ WATCHLIST_HTML = r"""<!doctype html>
|
|||||||
show_id: item.show_id,
|
show_id: item.show_id,
|
||||||
mode: autoDownloadMode.value,
|
mode: autoDownloadMode.value,
|
||||||
quality: autoDownloadQuality.value,
|
quality: autoDownloadQuality.value,
|
||||||
name: autoDownloadName.value
|
name: autoDownloadName.value,
|
||||||
|
series: autoDownloadSeries.value
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
autoDownloadName.value = (data.item || {}).auto_download_name || autoDownloadName.value;
|
autoDownloadName.value = (data.item || {}).auto_download_name || autoDownloadName.value;
|
||||||
|
autoDownloadSeries.value = (data.item || {}).auto_download_series || autoDownloadSeries.value;
|
||||||
|
const savedName = (data.item || {}).auto_download_name || "";
|
||||||
|
autoDownloadNameSelect.value = nameSuggestions.includes(savedName) ? savedName : "__custom__";
|
||||||
setNotice(data.message || "Auto-download settings saved.");
|
setNotice(data.message || "Auto-download settings saved.");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setNotice(error.message);
|
setNotice(error.message);
|
||||||
|
|||||||
Reference in New Issue
Block a user