Open auto-download settings in modal overlay
This commit is contained in:
+184
-100
@@ -551,35 +551,63 @@ WATCHLIST_HTML = r"""<!doctype html>
|
||||
display: grid;
|
||||
gap: 6px;
|
||||
}
|
||||
.auto-download-panel {
|
||||
.overlay[hidden] {
|
||||
display: none;
|
||||
grid-column: 1 / -1;
|
||||
gap: 10px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 16px;
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
padding: 12px;
|
||||
}
|
||||
.auto-download-panel.visible {
|
||||
.overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
padding: 24px;
|
||||
background: rgba(7, 10, 16, 0.74);
|
||||
backdrop-filter: blur(10px);
|
||||
z-index: 1200;
|
||||
}
|
||||
.auto-download-modal {
|
||||
width: min(640px, 100%);
|
||||
display: grid;
|
||||
gap: 14px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 22px;
|
||||
background: linear-gradient(180deg, rgba(20, 27, 40, 0.98), rgba(12, 17, 28, 0.98));
|
||||
box-shadow: 0 24px 70px rgba(0, 0, 0, 0.45);
|
||||
padding: 18px;
|
||||
}
|
||||
.auto-download-modal-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
}
|
||||
.auto-download-modal-header p {
|
||||
margin: 4px 0 0;
|
||||
}
|
||||
.auto-download-modal-close {
|
||||
min-width: 36px;
|
||||
min-height: 36px;
|
||||
border-radius: 999px;
|
||||
font-size: 18px;
|
||||
line-height: 1;
|
||||
}
|
||||
.auto-download-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 8px;
|
||||
}
|
||||
.auto-download-panel label {
|
||||
.auto-download-modal label {
|
||||
font-size: 10px;
|
||||
}
|
||||
.auto-download-panel input,
|
||||
.auto-download-panel select {
|
||||
.auto-download-modal input,
|
||||
.auto-download-modal select {
|
||||
min-height: 36px;
|
||||
padding: 0 10px;
|
||||
font-size: 13px;
|
||||
}
|
||||
.auto-download-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
@@ -736,6 +764,47 @@ WATCHLIST_HTML = r"""<!doctype html>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div class="overlay" id="autoDownloadOverlay" hidden>
|
||||
<div class="auto-download-modal" role="dialog" aria-modal="true" aria-labelledby="autoDownloadTitle">
|
||||
<div class="auto-download-modal-header">
|
||||
<div>
|
||||
<h2 id="autoDownloadTitle">Auto-download</h2>
|
||||
<p class="muted" id="autoDownloadSubtitle">Used only while this anime is in the Watching tab. Manual add does not trigger it; later refreshes do.</p>
|
||||
</div>
|
||||
<button class="ghost auto-download-modal-close" id="autoDownloadCloseBtn" type="button" aria-label="Close auto-download settings">×</button>
|
||||
</div>
|
||||
<div class="auto-download-grid">
|
||||
<label>Language
|
||||
<select class="auto-download-mode" id="autoDownloadMode">
|
||||
<option value="dub">Dub</option>
|
||||
<option value="sub">Sub</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>Quality
|
||||
<select class="auto-download-quality" id="autoDownloadQuality">
|
||||
<option value="best">Best</option>
|
||||
<option value="1080">1080p</option>
|
||||
<option value="720">720p</option>
|
||||
<option value="480">480p</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>Series
|
||||
<input class="auto-download-series" id="autoDownloadSeries" type="number" min="1" step="1" value="1">
|
||||
</label>
|
||||
<label>Name source
|
||||
<select class="auto-download-name-select" id="autoDownloadNameSelect"></select>
|
||||
</label>
|
||||
<label>Name
|
||||
<input class="auto-download-name" id="autoDownloadName" type="text">
|
||||
</label>
|
||||
</div>
|
||||
<div class="auto-download-actions">
|
||||
<div class="muted" id="autoDownloadStatus">Manual add does not trigger it; later refreshes do.</div>
|
||||
<button class="ghost auto-download-save" id="autoDownloadSaveBtn" type="button">Save auto-download</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const state = {
|
||||
watchlistPage: 1,
|
||||
@@ -749,7 +818,8 @@ WATCHLIST_HTML = r"""<!doctype html>
|
||||
thumbnailWarmupPending: new Set(),
|
||||
refreshRunning: false,
|
||||
refreshJobId: null,
|
||||
watchlistRequestId: 0
|
||||
watchlistRequestId: 0,
|
||||
autoDownloadDraft: null
|
||||
};
|
||||
const categoryLabels = {
|
||||
watching: "Watching",
|
||||
@@ -757,6 +827,16 @@ WATCHLIST_HTML = r"""<!doctype html>
|
||||
finished: "Finished",
|
||||
dropped: "Dropped"
|
||||
};
|
||||
const autoDownloadOverlay = document.getElementById("autoDownloadOverlay");
|
||||
const autoDownloadCloseBtn = document.getElementById("autoDownloadCloseBtn");
|
||||
const autoDownloadSubtitle = document.getElementById("autoDownloadSubtitle");
|
||||
const autoDownloadStatus = document.getElementById("autoDownloadStatus");
|
||||
const autoDownloadMode = document.getElementById("autoDownloadMode");
|
||||
const autoDownloadQuality = document.getElementById("autoDownloadQuality");
|
||||
const autoDownloadSeries = document.getElementById("autoDownloadSeries");
|
||||
const autoDownloadNameSelect = document.getElementById("autoDownloadNameSelect");
|
||||
const autoDownloadName = document.getElementById("autoDownloadName");
|
||||
const autoDownloadSaveBtn = document.getElementById("autoDownloadSaveBtn");
|
||||
|
||||
const $ = (id) => document.getElementById(id);
|
||||
""" + BROWSER_API_HELPER + BROWSER_POLL_HELPER + r"""
|
||||
@@ -876,6 +956,96 @@ WATCHLIST_HTML = r"""<!doctype html>
|
||||
controls.append(prev, next);
|
||||
}
|
||||
|
||||
function closeAutoDownloadOverlay() {
|
||||
state.autoDownloadDraft = null;
|
||||
autoDownloadOverlay.hidden = true;
|
||||
}
|
||||
|
||||
function populateAutoDownloadNameChoices(item) {
|
||||
const selectedName = item.auto_download_name || "";
|
||||
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);
|
||||
}
|
||||
autoDownloadNameSelect.innerHTML = "";
|
||||
for (const name of nameSuggestions) {
|
||||
const option = document.createElement("option");
|
||||
option.value = name;
|
||||
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 === selectedName);
|
||||
autoDownloadNameSelect.value = matchedSuggestion || "__custom__";
|
||||
autoDownloadName.value = selectedName;
|
||||
}
|
||||
|
||||
function openAutoDownloadOverlay(item) {
|
||||
state.autoDownloadDraft = { ...item };
|
||||
autoDownloadSubtitle.textContent = `${item.title} · Used only while this anime is in the Watching tab. Manual add does not trigger it; later refreshes do.`;
|
||||
autoDownloadStatus.textContent = "Manual add does not trigger it; later refreshes do.";
|
||||
autoDownloadMode.value = item.auto_download_mode || "dub";
|
||||
autoDownloadQuality.value = item.auto_download_quality || "best";
|
||||
autoDownloadSeries.value = item.auto_download_series || "1";
|
||||
populateAutoDownloadNameChoices(item);
|
||||
autoDownloadOverlay.hidden = false;
|
||||
}
|
||||
|
||||
autoDownloadNameSelect.addEventListener("change", () => {
|
||||
if (autoDownloadNameSelect.value !== "__custom__") {
|
||||
autoDownloadName.value = autoDownloadNameSelect.value;
|
||||
}
|
||||
});
|
||||
autoDownloadCloseBtn.addEventListener("click", closeAutoDownloadOverlay);
|
||||
autoDownloadOverlay.addEventListener("click", (event) => {
|
||||
if (event.target === autoDownloadOverlay) {
|
||||
closeAutoDownloadOverlay();
|
||||
}
|
||||
});
|
||||
window.addEventListener("keydown", (event) => {
|
||||
if (event.key === "Escape" && !autoDownloadOverlay.hidden) {
|
||||
closeAutoDownloadOverlay();
|
||||
}
|
||||
});
|
||||
autoDownloadSaveBtn.addEventListener("click", async () => {
|
||||
if (!state.autoDownloadDraft) return;
|
||||
autoDownloadSaveBtn.disabled = true;
|
||||
try {
|
||||
const data = await api("/api/watchlist/update-auto-download", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
show_id: state.autoDownloadDraft.show_id,
|
||||
mode: autoDownloadMode.value,
|
||||
quality: autoDownloadQuality.value,
|
||||
name: autoDownloadName.value,
|
||||
series: autoDownloadSeries.value
|
||||
})
|
||||
});
|
||||
const savedItem = data.item || {};
|
||||
state.autoDownloadDraft = {
|
||||
...state.autoDownloadDraft,
|
||||
auto_download_mode: savedItem.auto_download_mode || autoDownloadMode.value,
|
||||
auto_download_quality: savedItem.auto_download_quality || autoDownloadQuality.value,
|
||||
auto_download_name: savedItem.auto_download_name || autoDownloadName.value,
|
||||
auto_download_series: savedItem.auto_download_series || autoDownloadSeries.value
|
||||
};
|
||||
populateAutoDownloadNameChoices(state.autoDownloadDraft);
|
||||
autoDownloadSeries.value = state.autoDownloadDraft.auto_download_series || autoDownloadSeries.value;
|
||||
autoDownloadStatus.textContent = data.message || "Auto-download settings saved.";
|
||||
setNotice(data.message || "Auto-download settings saved.");
|
||||
closeAutoDownloadOverlay();
|
||||
await fetchWatchlist(state.watchlistPage, { silent: true });
|
||||
} catch (error) {
|
||||
autoDownloadStatus.textContent = error.message;
|
||||
setNotice(error.message);
|
||||
} finally {
|
||||
autoDownloadSaveBtn.disabled = false;
|
||||
}
|
||||
});
|
||||
|
||||
function applyThumbnail(card, item, force = false) {
|
||||
const tile = card.querySelector(".cover-tile");
|
||||
const img = card.querySelector("img");
|
||||
@@ -1064,12 +1234,6 @@ WATCHLIST_HTML = r"""<!doctype html>
|
||||
renderPager();
|
||||
return;
|
||||
}
|
||||
const qualityOptions = `
|
||||
<option value="best">Best</option>
|
||||
<option value="1080">1080p</option>
|
||||
<option value="720">720p</option>
|
||||
<option value="480">480p</option>
|
||||
`;
|
||||
for (const item of items) {
|
||||
const card = document.createElement("article");
|
||||
const checked = item.last_checked ? new Date(item.last_checked).toLocaleString() : "Never";
|
||||
@@ -1115,32 +1279,6 @@ WATCHLIST_HTML = r"""<!doctype html>
|
||||
<button class="ghost" type="button">Sub</button>
|
||||
<button class="ghost" type="button">Dub</button>
|
||||
</div>
|
||||
<div class="auto-download-panel">
|
||||
<div class="muted">Used only while this anime is in the Watching tab. Manual add does not trigger it; later refreshes do.</div>
|
||||
<div class="auto-download-grid">
|
||||
<label>Language
|
||||
<select class="auto-download-mode">
|
||||
<option value="dub"${item.auto_download_mode === "dub" ? " selected" : ""}>Dub</option>
|
||||
<option value="sub"${item.auto_download_mode === "sub" ? " selected" : ""}>Sub</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>Quality
|
||||
<select class="auto-download-quality">${qualityOptions.replace(`value="${item.auto_download_quality}"`, `value="${item.auto_download_quality}" selected`)}</select>
|
||||
</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
|
||||
<input class="auto-download-name" type="text">
|
||||
</label>
|
||||
</div>
|
||||
<div class="auto-download-actions">
|
||||
<button class="ghost auto-download-save" type="button">Save auto-download</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
card.querySelector(".cover-fallback").textContent = coverInitials(item.title);
|
||||
@@ -1213,35 +1351,6 @@ WATCHLIST_HTML = r"""<!doctype html>
|
||||
const subBtn = actionButtons[4];
|
||||
const dubBtn = actionButtons[5];
|
||||
const downloadPicker = card.querySelector(".download-picker");
|
||||
const autoDownloadPanel = card.querySelector(".auto-download-panel");
|
||||
const autoDownloadMode = card.querySelector(".auto-download-mode");
|
||||
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 autoDownloadSave = card.querySelector(".auto-download-save");
|
||||
autoDownloadName.value = item.auto_download_name || "";
|
||||
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) {
|
||||
const option = document.createElement("option");
|
||||
option.value = name;
|
||||
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");
|
||||
categorySelect.addEventListener("change", async () => {
|
||||
categorySelect.disabled = true;
|
||||
@@ -1265,32 +1374,7 @@ WATCHLIST_HTML = r"""<!doctype html>
|
||||
downloadBtn.textContent = visible ? "Cancel download" : "Download all";
|
||||
});
|
||||
autoDownloadBtn.addEventListener("click", () => {
|
||||
const visible = autoDownloadPanel.classList.toggle("visible");
|
||||
autoDownloadBtn.textContent = visible ? "Hide auto-download" : "Auto-download";
|
||||
});
|
||||
autoDownloadSave.addEventListener("click", async () => {
|
||||
autoDownloadSave.disabled = true;
|
||||
try {
|
||||
const data = await api("/api/watchlist/update-auto-download", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
show_id: item.show_id,
|
||||
mode: autoDownloadMode.value,
|
||||
quality: autoDownloadQuality.value,
|
||||
name: autoDownloadName.value,
|
||||
series: autoDownloadSeries.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.");
|
||||
} catch (error) {
|
||||
setNotice(error.message);
|
||||
} finally {
|
||||
autoDownloadSave.disabled = false;
|
||||
}
|
||||
openAutoDownloadOverlay(item);
|
||||
});
|
||||
subBtn.addEventListener("click", () => downloadWatchlistItem(item, "sub", downloadPicker, downloadBtn));
|
||||
dubBtn.addEventListener("click", () => downloadWatchlistItem(item, "dub", downloadPicker, downloadBtn));
|
||||
|
||||
Reference in New Issue
Block a user