优化 peq 流程
This commit is contained in:
+78
-55
@@ -295,6 +295,14 @@ function normalizeDeviceHost(input: string): string {
|
||||
// ============================================================
|
||||
export class LuxsinAPI {
|
||||
private baseUrl: string;
|
||||
private peqRequestQueue: Promise<void> = Promise.resolve();
|
||||
|
||||
/** EQ 写入、试听、选择和目录读取按调用顺序执行;单次失败不阻塞后续重试。 */
|
||||
private enqueuePeqRequest<T>(request: () => Promise<T>): Promise<T> {
|
||||
const result = this.peqRequestQueue.then(request);
|
||||
this.peqRequestQueue = result.then(() => undefined, () => undefined);
|
||||
return result;
|
||||
}
|
||||
|
||||
constructor(ip: string) {
|
||||
const host = normalizeDeviceHost(ip);
|
||||
@@ -339,17 +347,25 @@ export class LuxsinAPI {
|
||||
}
|
||||
|
||||
async setSetting(params: Record<string, string | number>): Promise<void> {
|
||||
const query = Object.entries(params)
|
||||
.map(([k, v]) => `${k}=${v}`)
|
||||
.join("&");
|
||||
await fetch(`${this.baseUrl}/dev/info.cgi?action=setting&${query}`);
|
||||
const request = async () => {
|
||||
const query = Object.entries(params)
|
||||
.map(([k, v]) => `${k}=${v}`)
|
||||
.join("&");
|
||||
const response = await fetch(`${this.baseUrl}/dev/info.cgi?action=setting&${query}`);
|
||||
if (!response.ok) throw new Error(`PEQ request failed: ${response.status}`);
|
||||
};
|
||||
if (params.peqSelect !== undefined) return this.enqueuePeqRequest(request);
|
||||
return request();
|
||||
}
|
||||
|
||||
async getPeqState(): Promise<PeqState> {
|
||||
const response = await fetch(`${this.baseUrl}/dev/info.cgi?action=syncPeq`);
|
||||
const text = await response.text();
|
||||
const decoded = decodeCustomBase64(text.trim());
|
||||
return JSON.parse(decoded) as PeqState;
|
||||
return this.enqueuePeqRequest(async () => {
|
||||
const response = await fetch(`${this.baseUrl}/dev/info.cgi?action=syncPeq`);
|
||||
if (!response.ok) throw new Error(`PEQ read failed: ${response.status}`);
|
||||
const text = await response.text();
|
||||
const decoded = decodeCustomBase64(text.trim());
|
||||
return JSON.parse(decoded) as PeqState;
|
||||
});
|
||||
}
|
||||
|
||||
async setPeqFilters(filters: PeqFilter[]): Promise<void> {
|
||||
@@ -368,69 +384,76 @@ export class LuxsinAPI {
|
||||
|
||||
/** POST `json=<custom-base64>` — matches legacy axios `upgradePeq`. */
|
||||
private async postPeqJson(body: PeqChangePayload | PeqApplyPayload): Promise<void> {
|
||||
if (import.meta.env.DEV) {
|
||||
const action =
|
||||
"peqChange" in body ? "peqChange" : "peqApply" in body ? "peqApply" : "peq";
|
||||
console.log(`[dev/info.cgi] POST ${action}`, body);
|
||||
}
|
||||
const encoded = encodeCustomBase64(JSON.stringify(body));
|
||||
const form = new URLSearchParams();
|
||||
form.set("json", encoded);
|
||||
const response = await fetch(`${this.baseUrl}/dev/info.cgi`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" },
|
||||
body: form.toString(),
|
||||
return this.enqueuePeqRequest(async () => {
|
||||
if (import.meta.env.DEV) {
|
||||
const action = "peqChange" in body ? "peqChange" : "peqApply" in body ? "peqApply" : "peq";
|
||||
console.log(`[dev/info.cgi] POST ${action}`, body);
|
||||
}
|
||||
const encoded = encodeCustomBase64(JSON.stringify(body));
|
||||
const form = new URLSearchParams();
|
||||
form.set("json", encoded);
|
||||
const response = await fetch(`${this.baseUrl}/dev/info.cgi`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" },
|
||||
body: form.toString(),
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`PEQ request failed: ${response.status}`);
|
||||
}
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`PEQ request failed: ${response.status}`);
|
||||
}
|
||||
}
|
||||
|
||||
/** Remove one or more headphone PEQ profiles. */
|
||||
async removePeq(names: string[]): Promise<void> {
|
||||
const encoded = encodeCustomBase64(JSON.stringify({ peqRemove: names }));
|
||||
const form = new URLSearchParams();
|
||||
form.set("json", encoded);
|
||||
const response = await fetch(`${this.baseUrl}/dev/info.cgi`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" },
|
||||
body: form.toString(),
|
||||
return this.enqueuePeqRequest(async () => {
|
||||
const encoded = encodeCustomBase64(JSON.stringify({ peqRemove: names }));
|
||||
const form = new URLSearchParams();
|
||||
form.set("json", encoded);
|
||||
const response = await fetch(`${this.baseUrl}/dev/info.cgi`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" },
|
||||
body: form.toString(),
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`PEQ remove failed: ${response.status}`);
|
||||
}
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`PEQ remove failed: ${response.status}`);
|
||||
}
|
||||
}
|
||||
|
||||
/** Rename a headphone PEQ profile. */
|
||||
async renamePeq(oldName: string, newName: string): Promise<void> {
|
||||
const payload: PeqRenamePayload = { peqRename: { oldName, newName } };
|
||||
const encoded = encodeCustomBase64(JSON.stringify(payload));
|
||||
const form = new URLSearchParams();
|
||||
form.set("json", encoded);
|
||||
const response = await fetch(`${this.baseUrl}/dev/info.cgi`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" },
|
||||
body: form.toString(),
|
||||
return this.enqueuePeqRequest(async () => {
|
||||
const payload: PeqRenamePayload = { peqRename: { oldName, newName } };
|
||||
const encoded = encodeCustomBase64(JSON.stringify(payload));
|
||||
const form = new URLSearchParams();
|
||||
form.set("json", encoded);
|
||||
const response = await fetch(`${this.baseUrl}/dev/info.cgi`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" },
|
||||
body: form.toString(),
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`PEQ rename failed: ${response.status}`);
|
||||
}
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`PEQ rename failed: ${response.status}`);
|
||||
}
|
||||
}
|
||||
|
||||
/** Reorder headphone PEQ profiles. */
|
||||
async sortPeq(names: string[], peqSelect: number): Promise<void> {
|
||||
const payload: PeqSoftPayload = { peqSoft: names, peqSelect };
|
||||
const encoded = encodeCustomBase64(JSON.stringify(payload));
|
||||
const form = new URLSearchParams();
|
||||
form.set("json", encoded);
|
||||
const response = await fetch(`${this.baseUrl}/dev/info.cgi`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" },
|
||||
body: form.toString(),
|
||||
return this.enqueuePeqRequest(async () => {
|
||||
const payload: PeqSoftPayload = { peqSoft: names, peqSelect };
|
||||
const encoded = encodeCustomBase64(JSON.stringify(payload));
|
||||
const form = new URLSearchParams();
|
||||
form.set("json", encoded);
|
||||
const response = await fetch(`${this.baseUrl}/dev/info.cgi`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" },
|
||||
body: form.toString(),
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`PEQ sort failed: ${response.status}`);
|
||||
}
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`PEQ sort failed: ${response.status}`);
|
||||
}
|
||||
}
|
||||
|
||||
setVolume(volume: number) { return this.setSetting({ volume }); }
|
||||
|
||||
Reference in New Issue
Block a user