feat (ui): series onthouden
This commit is contained in:
+112
-24
@@ -20,13 +20,17 @@
|
||||
settings: {
|
||||
set_file_date_to_first_aired_date: false,
|
||||
default_media_root_path: null,
|
||||
remember_max_series: 10,
|
||||
},
|
||||
rememberedSeries: [],
|
||||
liveSearchItems: [],
|
||||
};
|
||||
|
||||
const el = {
|
||||
sessionMeta: document.getElementById("sessionMeta"),
|
||||
outputBox: document.getElementById("outputBox"),
|
||||
searchInput: document.getElementById("searchInput"),
|
||||
searchDropdownBtn: document.getElementById("searchDropdownBtn"),
|
||||
searchBtn: document.getElementById("searchBtn"),
|
||||
searchResults: document.getElementById("searchResults"),
|
||||
seriesInfo: document.getElementById("seriesInfo"),
|
||||
@@ -43,6 +47,8 @@
|
||||
saveSettingsBtn: document.getElementById("saveSettingsBtn"),
|
||||
setFileDateToFirstAiredDateInput: document.getElementById("setFileDateToFirstAiredDateInput"),
|
||||
defaultMediaRootSelect: document.getElementById("defaultMediaRootSelect"),
|
||||
rememberMaxSeriesInput: document.getElementById("rememberMaxSeriesInput"),
|
||||
purgeRememberedSeriesBtn: document.getElementById("purgeRememberedSeriesBtn"),
|
||||
refreshEpisodesBtn: document.getElementById("refreshEpisodesBtn"),
|
||||
episodesList: document.getElementById("episodesList"),
|
||||
episodeMeta: document.getElementById("episodeMeta"),
|
||||
@@ -214,6 +220,9 @@
|
||||
|
||||
function applySettingsToForm() {
|
||||
el.setFileDateToFirstAiredDateInput.checked = !!state.settings.set_file_date_to_first_aired_date;
|
||||
if (el.rememberMaxSeriesInput) {
|
||||
el.rememberMaxSeriesInput.value = String(state.settings.remember_max_series || 10);
|
||||
}
|
||||
if (el.defaultMediaRootSelect) {
|
||||
const wanted = state.settings.default_media_root_path || "";
|
||||
el.defaultMediaRootSelect.value = wanted;
|
||||
@@ -262,14 +271,20 @@
|
||||
state.settings = data.settings || {
|
||||
set_file_date_to_first_aired_date: false,
|
||||
default_media_root_path: null,
|
||||
remember_max_series: 10,
|
||||
};
|
||||
applySettingsToForm();
|
||||
}
|
||||
|
||||
async function saveSettings() {
|
||||
const rememberMax = Number(el.rememberMaxSeriesInput.value || "10");
|
||||
if (!Number.isInteger(rememberMax) || rememberMax < 1 || rememberMax > 100) {
|
||||
throw new Error("Remember max series must be an integer between 1 and 100");
|
||||
}
|
||||
const payload = {
|
||||
set_file_date_to_first_aired_date: !!el.setFileDateToFirstAiredDateInput.checked,
|
||||
default_media_root_path: (el.defaultMediaRootSelect.value || "").trim() || null,
|
||||
remember_max_series: rememberMax,
|
||||
};
|
||||
const data = await api("/api/session/settings", {
|
||||
method: "PUT",
|
||||
@@ -283,6 +298,89 @@
|
||||
out("Settings saved", data);
|
||||
}
|
||||
|
||||
async function loadRememberedSeries() {
|
||||
const data = await api("/api/session/remembered-series");
|
||||
state.rememberedSeries = data.items || [];
|
||||
}
|
||||
|
||||
async function rememberSeries(item) {
|
||||
await api("/api/session/remembered-series", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ item }),
|
||||
});
|
||||
await loadRememberedSeries();
|
||||
}
|
||||
|
||||
async function purgeRememberedSeries() {
|
||||
const ok = window.confirm("Are you sure?");
|
||||
if (!ok) return;
|
||||
await api("/api/session/remembered-series", { method: "DELETE" });
|
||||
await loadRememberedSeries();
|
||||
renderRememberedDropdown();
|
||||
}
|
||||
|
||||
function rememberedForQuery(query) {
|
||||
const normalized = (query || "").trim().toLowerCase();
|
||||
const rememberedItems = (state.rememberedSeries || []).map((entry) => entry.series || {});
|
||||
return rememberedItems.filter((item) => {
|
||||
if (!normalized) return true;
|
||||
const text = `${item.display_name || ""} ${item.name || ""}`.toLowerCase();
|
||||
return text.includes(normalized);
|
||||
});
|
||||
}
|
||||
|
||||
function renderRememberedDropdown() {
|
||||
const query = (el.searchInput.value || "").trim();
|
||||
const items = rememberedForQuery(query);
|
||||
el.searchResults.innerHTML = "";
|
||||
|
||||
items.forEach((item) => {
|
||||
const li = document.createElement("li");
|
||||
const left = document.createElement("span");
|
||||
const label = item.display_name || item.name || "(series)";
|
||||
left.textContent = label;
|
||||
|
||||
const right = document.createElement("div");
|
||||
const tag = document.createElement("span");
|
||||
tag.className = "badge";
|
||||
tag.textContent = "Remembered";
|
||||
right.appendChild(tag);
|
||||
li.appendChild(left);
|
||||
li.appendChild(right);
|
||||
li.addEventListener("click", () => withHandler(() => selectSeries(item), li));
|
||||
el.searchResults.appendChild(li);
|
||||
});
|
||||
}
|
||||
|
||||
function renderSearchResults(items) {
|
||||
el.searchResults.innerHTML = "";
|
||||
(items || []).forEach((item) => {
|
||||
const li = document.createElement("li");
|
||||
const left = document.createElement("span");
|
||||
left.textContent = item.display_name || item.name || "(series)";
|
||||
li.appendChild(left);
|
||||
li.addEventListener("click", () => withHandler(() => selectSeries(item), li));
|
||||
el.searchResults.appendChild(li);
|
||||
});
|
||||
}
|
||||
|
||||
async function selectSeries(item) {
|
||||
state.selectedSeries = item;
|
||||
state.selectedSeriesSummary = null;
|
||||
el.seriesInfo.textContent = `Selected: ${item.display_name || item.name}`;
|
||||
renderSelectedSeriesDetails();
|
||||
await rememberSeries(item);
|
||||
renderRememberedDropdown();
|
||||
try {
|
||||
await loadSeriesSummary(item.id);
|
||||
renderSelectedSeriesDetails();
|
||||
} catch (_err) {
|
||||
// Keep UI responsive with fallback data.
|
||||
}
|
||||
await loadEpisodes();
|
||||
}
|
||||
|
||||
function preferredRootId() {
|
||||
if (!state.roots.length) return "";
|
||||
const wantedPath = (state.settings.default_media_root_path || "").trim();
|
||||
@@ -370,31 +468,14 @@
|
||||
|
||||
async function doSearch() {
|
||||
const query = (el.searchInput.value || "").trim();
|
||||
if (!query) return;
|
||||
if (!query || query.length < 2) {
|
||||
state.liveSearchItems = [];
|
||||
renderRememberedDropdown();
|
||||
return;
|
||||
}
|
||||
const data = await api(`/api/tvdb/search?q=${encodeURIComponent(query)}`);
|
||||
el.searchResults.innerHTML = "";
|
||||
(data.items || []).forEach((item) => {
|
||||
const li = document.createElement("li");
|
||||
const left = document.createElement("span");
|
||||
left.textContent = item.display_name || item.name || "(series)";
|
||||
const right = document.createElement("div");
|
||||
right.appendChild(makeBtn("Select", async () => {
|
||||
state.selectedSeries = item;
|
||||
state.selectedSeriesSummary = null;
|
||||
el.seriesInfo.textContent = `Selected: ${item.display_name || item.name}`;
|
||||
renderSelectedSeriesDetails();
|
||||
try {
|
||||
await loadSeriesSummary(item.id);
|
||||
renderSelectedSeriesDetails();
|
||||
} catch (_err) {
|
||||
// Keep UI responsive with search payload fallback if summary lookup fails.
|
||||
}
|
||||
await loadEpisodes();
|
||||
}));
|
||||
li.appendChild(left);
|
||||
li.appendChild(right);
|
||||
el.searchResults.appendChild(li);
|
||||
});
|
||||
state.liveSearchItems = data.items || [];
|
||||
renderSearchResults(state.liveSearchItems);
|
||||
out("Search result", data);
|
||||
}
|
||||
|
||||
@@ -704,9 +785,14 @@
|
||||
|
||||
function bindEvents() {
|
||||
el.searchBtn.addEventListener("click", () => withHandler(doSearch, el.searchBtn));
|
||||
el.searchInput.addEventListener("focus", renderRememberedDropdown);
|
||||
el.searchInput.addEventListener("click", renderRememberedDropdown);
|
||||
el.searchInput.addEventListener("input", renderRememberedDropdown);
|
||||
el.searchDropdownBtn.addEventListener("click", renderRememberedDropdown);
|
||||
el.settingsBtn.addEventListener("click", openSettingsModal);
|
||||
el.closeSettingsModalBtn.addEventListener("click", closeSettingsModal);
|
||||
el.saveSettingsBtn.addEventListener("click", () => withHandler(saveSettings, el.saveSettingsBtn));
|
||||
el.purgeRememberedSeriesBtn.addEventListener("click", () => withHandler(purgeRememberedSeries, el.purgeRememberedSeriesBtn));
|
||||
el.settingsModal.addEventListener("click", (e) => {
|
||||
if (e.target === el.settingsModal) closeSettingsModal();
|
||||
});
|
||||
@@ -765,6 +851,8 @@
|
||||
renderSelectedSeriesDetails();
|
||||
bindEvents();
|
||||
await loadSettings();
|
||||
await loadRememberedSeries();
|
||||
renderRememberedDropdown();
|
||||
await loadSelectedEpisodes();
|
||||
await loadSelectedFiles();
|
||||
await loadRoots();
|
||||
|
||||
Reference in New Issue
Block a user