Fix ranking auth during cloud login
This commit is contained in:
parent
8d075ac401
commit
b42059f4c8
@ -2163,6 +2163,7 @@ async function submitAccessPassword() {
|
||||
const payload = await response.json();
|
||||
if (!response.ok) throw new Error(payload.error || "访问密码不正确");
|
||||
if (payload.token) localStorage.setItem(HOTNESS_AUTH_TOKEN_KEY, payload.token);
|
||||
window.dispatchEvent(new CustomEvent("hotness:auth-updated"));
|
||||
if (authPassword) authPassword.value = "";
|
||||
setAuthMessage("登录成功,正在进入...");
|
||||
hideAuthGate();
|
||||
|
||||
@ -759,6 +759,7 @@ async function submitAccessPassword() {
|
||||
const payload = await response.json();
|
||||
if (!response.ok) throw new Error(payload.error || "访问密码不正确");
|
||||
if (payload.token) localStorage.setItem(HOTNESS_AUTH_TOKEN_KEY, payload.token);
|
||||
window.dispatchEvent(new CustomEvent("hotness:auth-updated"));
|
||||
if (authPassword) authPassword.value = "";
|
||||
setAuthMessage("登录成功,正在进入...");
|
||||
hideAuthGate();
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
const HOTNESS_AUTH_TOKEN_KEY = "video-hotness-auth-token-v1";
|
||||
const PLATFORM_LABELS = { tencent: "腾讯视频", youku: "优酷", iqiyi: "爱奇艺", mgtv: "芒果TV" };
|
||||
const TYPE_LABELS = { animation: "动画", education: "早教", song: "儿歌", toy: "玩具", movie: "电影", other: "其他" };
|
||||
const SOURCE_LABELS = { new: "新片", recommend: "推荐", rank: "榜单", hot: "热播", channel: "频道" };
|
||||
@ -21,19 +22,26 @@ const state = {
|
||||
};
|
||||
|
||||
const root = document.querySelector("#ranking-radar");
|
||||
if (root) init();
|
||||
if (root) {
|
||||
window.addEventListener("hotness:auth-updated", () => init());
|
||||
init();
|
||||
}
|
||||
|
||||
async function init() {
|
||||
render();
|
||||
const [defaults, latest] = await Promise.all([
|
||||
apiGet("/api/rankings/default-sources"),
|
||||
apiGet("/api/kids-trends/latest"),
|
||||
refreshPrograms(),
|
||||
]);
|
||||
state.defaults = defaults.sources || [];
|
||||
if (latest.trend?.results?.length) {
|
||||
state.trendResults = latest.trend.results || [];
|
||||
state.message = `已恢复上次上新趋势:${formatTime(latest.trend.captured_at)},采集 ${latest.trend.collected_count || state.trendResults.length} 个节目`;
|
||||
try {
|
||||
const [defaults, latest] = await Promise.all([
|
||||
apiGet("/api/rankings/default-sources"),
|
||||
apiGet("/api/kids-trends/latest"),
|
||||
refreshPrograms(),
|
||||
]);
|
||||
state.defaults = defaults.sources || [];
|
||||
if (latest.trend?.results?.length) {
|
||||
state.trendResults = latest.trend.results || [];
|
||||
state.message = `已恢复上次上新趋势:${formatTime(latest.trend.captured_at)},采集 ${latest.trend.collected_count || state.trendResults.length} 个节目`;
|
||||
}
|
||||
} catch (error) {
|
||||
state.message = error.requiresAuth ? "请先输入访问密码" : error.message;
|
||||
}
|
||||
render();
|
||||
}
|
||||
@ -386,25 +394,34 @@ function options(map, selected = "") {
|
||||
}
|
||||
|
||||
async function apiGet(path) {
|
||||
const response = await fetch(path);
|
||||
const response = await fetch(path, { headers: authHeaders() });
|
||||
return parseApiResponse(response);
|
||||
}
|
||||
|
||||
async function apiPost(path, payload) {
|
||||
const response = await fetch(path, {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
headers: { "content-type": "application/json", ...authHeaders() },
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
return parseApiResponse(response);
|
||||
}
|
||||
|
||||
async function parseApiResponse(response) {
|
||||
const data = await response.json();
|
||||
if (!response.ok) throw new Error(data.error || "request failed");
|
||||
const data = await response.json().catch(() => ({}));
|
||||
if (!response.ok) {
|
||||
const error = new Error(data.error || "request failed");
|
||||
error.requiresAuth = Boolean(data.requires_auth || response.status === 401);
|
||||
throw error;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
function authHeaders() {
|
||||
const token = localStorage.getItem(HOTNESS_AUTH_TOKEN_KEY) || "";
|
||||
return token ? { "x-hotness-auth-token": token } : {};
|
||||
}
|
||||
|
||||
function formatTime(value) {
|
||||
if (!value) return "";
|
||||
const date = new Date(value);
|
||||
|
||||
@ -9,6 +9,7 @@ const desktopCss = await readFile(new URL("../public/styles.css", import.meta.ur
|
||||
const mobileHtml = await readFile(new URL("../public/mobile.html", import.meta.url), "utf8");
|
||||
const mobileJs = await readFile(new URL("../public/mobile.js", import.meta.url), "utf8");
|
||||
const mobileCss = await readFile(new URL("../public/mobile.css", import.meta.url), "utf8");
|
||||
const rankingsJs = await readFile(new URL("../public/rankings.js", import.meta.url), "utf8");
|
||||
|
||||
test("server supports optional shared access password authentication", () => {
|
||||
assert.match(server, /HOTNESS_ACCESS_PASSWORD/);
|
||||
@ -60,3 +61,15 @@ test("mobile login submit is bound before normal capture events", () => {
|
||||
assert.ok(authBinding < collectBinding, "auth binding must run before normal app bindings");
|
||||
assert.ok(authClickBinding < collectBinding, "auth click binding must run before normal app bindings");
|
||||
});
|
||||
|
||||
test("ranking radar requests respect the shared cloud login token", () => {
|
||||
assert.match(rankingsJs, /HOTNESS_AUTH_TOKEN_KEY/);
|
||||
assert.match(rankingsJs, /authHeaders/);
|
||||
assert.match(rankingsJs, /x-hotness-auth-token/i);
|
||||
assert.match(rankingsJs, /requires_auth/);
|
||||
assert.match(rankingsJs, /hotness:auth-updated/);
|
||||
});
|
||||
|
||||
test("desktop login notifies secondary modules after auth succeeds", () => {
|
||||
assert.match(desktopJs, /hotness:auth-updated/);
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user