103 lines
3.9 KiB
TypeScript
103 lines
3.9 KiB
TypeScript
|
|
import { useState, useRef, useCallback } from "react";
|
||
|
|
import { decodeCustomBase64 } from "@/lib/luxsinApi";
|
||
|
|
|
||
|
|
/* ── Module-level cache: survives route switches ── */
|
||
|
|
const rawCurveCache = new Map<string, number[] | null>();
|
||
|
|
|
||
|
|
export function useRawCurve() {
|
||
|
|
const [currentRawCurve, setCurrentRawCurve] = useState<number[] | null>(null);
|
||
|
|
const [rawCurveLoading, setRawCurveLoading] = useState(false);
|
||
|
|
const rawCurveCacheRef = useRef(rawCurveCache);
|
||
|
|
|
||
|
|
const getModelCurve = async (brand: string, name: string) => {
|
||
|
|
try {
|
||
|
|
console.log("[modelCurve] request", { brand, name });
|
||
|
|
const resp = await fetch(
|
||
|
|
`//api.luxsin.com.cn/audio/modelCurve?brand=${encodeURIComponent(brand)}&name=${encodeURIComponent(name)}`
|
||
|
|
);
|
||
|
|
const data = await resp.text();
|
||
|
|
// 使用自定义 Base64 解码
|
||
|
|
const decoded = decodeCustomBase64(data);
|
||
|
|
const parsed = JSON.parse(decoded);
|
||
|
|
console.log("[modelCurve] decoded", {
|
||
|
|
hasFrRaw:
|
||
|
|
!!(parsed &&
|
||
|
|
typeof parsed === "object" &&
|
||
|
|
"fr" in (parsed as Record<string, unknown>) &&
|
||
|
|
(parsed as { fr?: unknown }).fr &&
|
||
|
|
typeof (parsed as { fr?: unknown }).fr === "object" &&
|
||
|
|
"raw" in ((parsed as { fr?: Record<string, unknown> }).fr ?? {})),
|
||
|
|
});
|
||
|
|
console.log("[modelCurve] fr.raw", (parsed as { fr?: { raw?: unknown } }).fr?.raw);
|
||
|
|
return parsed;
|
||
|
|
} catch (error) {
|
||
|
|
console.log("[modelCurve] request failed", error);
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
const loadRawCurveForPeq = useCallback(
|
||
|
|
async (peq: { brand?: string; model?: string; name?: string } | undefined): Promise<number[] | null> => {
|
||
|
|
const brand = peq?.brand?.trim() ?? "";
|
||
|
|
const model = peq?.model?.trim() ?? "";
|
||
|
|
if (!brand || !model) return null;
|
||
|
|
|
||
|
|
const cacheKey = `${brand}|${model}`;
|
||
|
|
if (rawCurveCacheRef.current.has(cacheKey)) {
|
||
|
|
const cached = rawCurveCacheRef.current.get(cacheKey);
|
||
|
|
if (cached) {
|
||
|
|
console.log("[modelCurve] cache hit", { brand, model, rawLength: cached.length });
|
||
|
|
} else {
|
||
|
|
console.log("[modelCurve] cache hit (no raw)", { brand, model });
|
||
|
|
}
|
||
|
|
return cached ?? null;
|
||
|
|
}
|
||
|
|
|
||
|
|
const modelCurve = await getModelCurve(brand, model);
|
||
|
|
if (modelCurve && typeof modelCurve === "object") {
|
||
|
|
const payload = modelCurve as {
|
||
|
|
fr?: { raw?: unknown } | unknown;
|
||
|
|
};
|
||
|
|
const rawCandidate =
|
||
|
|
payload.fr && typeof payload.fr === "object" && Array.isArray((payload.fr as { raw?: unknown }).raw)
|
||
|
|
? (payload.fr as { raw?: unknown }).raw
|
||
|
|
: null;
|
||
|
|
const raw = Array.isArray(rawCandidate)
|
||
|
|
? rawCandidate
|
||
|
|
.map((point) => {
|
||
|
|
if (typeof point === "number" && Number.isFinite(point)) return point;
|
||
|
|
if (Array.isArray(point) && point.length >= 2 && typeof point[1] === "number") return point[1];
|
||
|
|
if (point && typeof point === "object") {
|
||
|
|
const y = (point as Record<string, unknown>).y
|
||
|
|
?? (point as Record<string, unknown>).value
|
||
|
|
?? (point as Record<string, unknown>).db
|
||
|
|
?? (point as Record<string, unknown>).gain;
|
||
|
|
if (typeof y === "number" && Number.isFinite(y)) return y;
|
||
|
|
}
|
||
|
|
return NaN;
|
||
|
|
})
|
||
|
|
: null;
|
||
|
|
const cleanedRaw = raw && raw.every((v) => Number.isFinite(v)) ? (raw as number[]) : null;
|
||
|
|
rawCurveCacheRef.current.set(cacheKey, cleanedRaw);
|
||
|
|
console.log("[modelCurve] raw check", {
|
||
|
|
brand,
|
||
|
|
model,
|
||
|
|
hasRaw: !!cleanedRaw,
|
||
|
|
rawLength: cleanedRaw?.length ?? 0,
|
||
|
|
});
|
||
|
|
return cleanedRaw;
|
||
|
|
}
|
||
|
|
return null;
|
||
|
|
},
|
||
|
|
[],
|
||
|
|
);
|
||
|
|
|
||
|
|
return {
|
||
|
|
currentRawCurve,
|
||
|
|
setCurrentRawCurve,
|
||
|
|
rawCurveLoading,
|
||
|
|
setRawCurveLoading,
|
||
|
|
loadRawCurveForPeq,
|
||
|
|
};
|
||
|
|
}
|