frontend: prefix-agnostic fetch paths (reverse-proxy subpath safe)

login.html/app.js now resolve fetch targets relative to the page's
directory (BASE), so the app works served at / or under a path prefix
(https://host/ani/) as long as the proxy strips the prefix.
This commit is contained in:
jozamudi committed 2026-08-19 16:24:22 +00:00
1 parent c697500c7d
commit 7e6db5a41c
2 files changed
+19 -7

No files matched your search

+11 -5
View File
@@ -1,11 +1,17 @@
// app.js — ani-web frontend: search -> detail -> play, vanilla JS + hls.js
// BASE = this page's directory, so the app works at / or behind a
// prefixing reverse proxy (e.g. https://host/ani/)
const BASE = (() => {
const p = location.pathname;
return p.endsWith("/") ? p : p.slice(0, p.lastIndexOf("/") + 1);
})();
const main = document.getElementById("main");
let hls = null, detail = null, lang = "eng", seasonId = null;
async function api(path) {
const r = await fetch(path);
const r = await fetch(BASE + path.replace(/^\//, ""));
if (r.status === 401) {
location.href = "/login?next=" + encodeURIComponent(location.pathname + location.search);
location.href = BASE + "login?next=" + encodeURIComponent(location.pathname + location.search);
throw new Error("not authenticated");
}
if (!r.ok) {
@@ -40,7 +46,7 @@ async function refreshHistory() {
try { history = await api("/api/history"); } catch { /* home just shows empty */ }
}
function postHistory(entry) {
fetch("/api/history", {method: "POST", headers: {"Content-Type": "application/json"},
fetch(BASE + "api/history", {method: "POST", headers: {"Content-Type": "application/json"},
body: JSON.stringify(entry)}).catch(() => {});
}
const fmtPos = s => { s = Math.floor(s || 0); return `${Math.floor(s / 60)}:${String(s % 60).padStart(2, "0")}`; };
@@ -222,12 +228,12 @@ function showPlayOverlay(v) {
document.getElementById("me").textContent = "hi, " + me.user;
const lo = document.getElementById("logout");
lo.style.display = ""; lo.onclick = async () => {
await fetch("/logout", {method: "POST"}); location.href = "/login";
await fetch(BASE + "logout", {method: "POST"}); location.href = BASE + "login";
};
const da = document.getElementById("delacct");
da.style.display = ""; da.onclick = async () => {
if (!confirm("Delete your account and watch history?")) return;
await fetch("/account/delete", {method: "POST"}); location.href = "/login";
await fetch(BASE + "account/delete", {method: "POST"}); location.href = BASE + "login";
};
} catch { /* not logged in: api() already redirected to /login */ }
await refreshHistory();