样式修改

This commit is contained in:
谢宇宁
2026-10-16 14:10:10 +07:00
parent d2ddb1c321
commit 4afd5f9143
42 changed files with 89 additions and 1765 deletions
+4 -126
View File
@@ -10,35 +10,14 @@ export class ApiError extends Error {
this.name = "ApiError";
}
}
export interface DramaContext {
media_id?: string | number;
drama_id?: string | number;
episode?: number;
video_id?: string | number;
recommend_trace_id?: string;
}
export interface RequestOptions {
method?: string;
params?: Record<string, unknown>;
headers?: Record<string, string>;
timeout?: number;
trackerContext?: DramaContext;
trackerEvent?: string | false;
signal?: AbortSignal;
skipRecovery?: boolean;
}
type Tracker = {
getSDKCommonHeader?: () => string | Promise<string>;
getCommonFields?: () =>
| Record<string, unknown>
| Promise<Record<string, unknown>>;
getDramaContext?: () => DramaContext;
setUid?: (uid: string) => void;
};
const tracker = () =>
typeof window === "undefined"
? undefined
: (window as unknown as { tracker?: Tracker }).tracker;
export function getCookie(name: string): string {
if (typeof document === "undefined") return "";
const value =
@@ -103,7 +82,6 @@ export function setAuthSession(user: Record<string, unknown>) {
} catch {
/* storage disabled */
}
if (user.userId != null) tracker()?.setUid?.(String(user.userId));
document.dispatchEvent(new CustomEvent("auth:login", { detail: { user } }));
}
export function getDeviceID(): string {
@@ -149,111 +127,11 @@ export function getChannel(): string {
setCookie("channel", value, 365);
return value;
}
const events: Record<string, string> = {
"/api/playlet/chapter/like/set": "drama_like",
"/api/playlet/like/set": "drama_like",
"/api/playlet/chapter/collect/set": "drama_collect",
"/api/playlet/collect/set": "drama_collect",
"/api/comment/send": "drama_comment",
"/api/playlet/chapter/unlock": "drama_purchase",
};
const base64 = (value: unknown) =>
btoa(
Array.from(new TextEncoder().encode(JSON.stringify(value)), (n) =>
String.fromCharCode(n),
).join(""),
)
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, "");
const clean = (value: unknown) =>
String(value ?? "")
.replace(/[^\x20-\x7e]|[;=]/g, " ")
.trim();
async function deadline<T>(
promise: Promise<T>,
fallback: T,
ms = 1500,
): Promise<T> {
let timer: ReturnType<typeof setTimeout> | undefined;
try {
return await Promise.race([
promise.catch(() => fallback),
new Promise<T>((resolve) => {
timer = setTimeout(() => resolve(fallback), ms);
}),
]);
} finally {
clearTimeout(timer);
}
}
async function requestHeaders(
path: string,
method: string,
options: RequestOptions,
): Promise<Headers> {
const headers = new Headers({
function requestHeaders(options: RequestOptions): Headers {
return new Headers({
Accept: "application/json",
...options.headers,
});
if (new URL(path, location.href).origin !== location.origin) return headers;
const sdk = tracker();
const commonHeader = deadline(
Promise.resolve().then(() => sdk?.getSDKCommonHeader?.() || ""),
"",
);
const event =
options.trackerEvent === false
? ""
: options.trackerEvent || events[new URL(path, location.href).pathname];
const context = options.trackerContext || sdk?.getDramaContext?.();
const common =
event && !["GET", "HEAD"].includes(method) && context?.drama_id
? await deadline(
Promise.resolve().then(() => sdk?.getCommonFields?.() || {}),
{},
)
: null;
if (common && context) {
const requestID = Array.from(
crypto.getRandomValues(new Uint8Array(16)),
(n) => n.toString(16).padStart(2, "0"),
).join("");
const drama = {
media_id: String(context.media_id ?? "").trim(),
drama_id: String(context.drama_id ?? "").trim(),
episode: Math.max(1, context.episode || 1),
video_id: String(context.video_id ?? "").trim(),
recommend_trace_id: String(context.recommend_trace_id ?? "").trim(),
};
headers.set("X-Tracker-Request-Id", requestID);
headers.set("X-Tracker-Event-Name", event);
headers.set(
"X-DC-Request-Context",
base64({ v: 1, request_id: requestID, event_name: event, common, drama }),
);
headers.set(
"X-User-Agent",
[
"DevID=" + clean(common.device_id),
"DevType=" + clean(common.device || "OTHER"),
"SysType=" +
(common.device === "Android"
? "h5_android"
: common.device === "iOS"
? "h5_ios"
: "h5_pc"),
"Ver=" + clean(common.app_version || "1.0.0"),
"BuildID=web",
"device_brand=" + clean(common.device_brand),
"device_model=" + clean(common.device_model),
"sid=" + clean(common.sid),
].join(";"),
);
}
const value = await commonHeader;
if (value && !headers.has("X-SDK-Common")) headers.set("X-SDK-Common", value);
return headers;
}
let guestPromise: Promise<boolean> | null = null;
export async function ensureGuestSession(): Promise<boolean> {
@@ -294,7 +172,7 @@ async function recoverSession(): Promise<boolean> {
});
return recovery;
}
/** Same-origin BFF request; prepared tracking headers and request_id survive one guest retry. */
/** Same-origin BFF request; retries once after guest session recovery. */
export async function apiRequest<T = Record<string, unknown>>(
path: string,
body?: unknown,
@@ -304,7 +182,7 @@ export async function apiRequest<T = Record<string, unknown>>(
const url = new URL(path, location.href);
for (const [key, value] of Object.entries(options.params || {}))
if (value != null) url.searchParams.set(key, String(value));
const headers = await requestHeaders(url.href, method, options);
const headers = requestHeaders(options);
const payload =
body == null
? undefined
+1 -1
View File
@@ -79,7 +79,7 @@ const navigationFields = new Set([
// Raw API/SDK/payment/media objects must retain their request and signed source addresses.
const opaqueFields = new Set([
"appConfig", "config", "advitise", "advertise", "chapter", "rawMedia", "videoInfo", "video", "media", "images",
"reportSdkConfig", "ReportSDKConfig", "installGuide", "deposit", "payment", "payMethods",
"installGuide", "deposit", "payment", "payMethods",
"jsonLD", "seoInfo", "canonicalURL", "paginationPrevURL", "paginationNextURL",
]);
-10
View File
@@ -1,10 +0,0 @@
"use client";
export {
track,
tracker,
dramaEvent,
dramaStatusChange,
setDramaContext,
externalAd,
} from "@/components/analytics/tracker";
export type { Fields, TrackerBoot } from "@/components/analytics/tracker";