feat:优化lx音源问题

This commit is contained in:
alger
2025-12-20 02:29:22 +08:00
parent a9fb487332
commit 5bcef29f10
10 changed files with 814 additions and 130 deletions
+4
View File
@@ -17,6 +17,7 @@ import { setupUpdateHandlers } from './modules/update';
import { createMainWindow, initializeWindowManager, setAppQuitting } from './modules/window';
import { initWindowSizeManager } from './modules/window-size';
import { startMusicApi } from './server';
import { initLxMusicHttp } from './modules/lxMusicHttp';
// 导入所有图标
const iconPath = join(__dirname, '../../resources');
@@ -57,6 +58,9 @@ function initialize(configStore: any) {
// 启动音乐API
startMusicApi();
// 初始化落雪音乐 HTTP 请求处理
initLxMusicHttp();
// 加载歌词窗口
loadLyricWindow(ipcMain, mainWindow);
+153
View File
@@ -0,0 +1,153 @@
/**
* 落雪音乐 HTTP 请求处理(主进程)
* 绕过渲染进程的 CORS 限制
*/
import { ipcMain } from 'electron';
import fetch, { type RequestInit } from 'node-fetch';
interface LxHttpRequest {
url: string;
options: {
method?: string;
headers?: Record<string, string>;
body?: string;
form?: Record<string, string>;
formData?: Record<string, string>;
timeout?: number;
};
requestId: string;
}
interface LxHttpResponse {
statusCode: number;
headers: Record<string, string | string[]>;
body: any;
}
// 取消控制器映射
const abortControllers = new Map<string, AbortController>();
/**
* 初始化 HTTP 请求处理
*/
export const initLxMusicHttp = () => {
// 处理 HTTP 请求
ipcMain.handle(
'lx-music-http-request',
async (_, request: LxHttpRequest): Promise<LxHttpResponse> => {
const { url, options, requestId } = request;
const controller = new AbortController();
// 保存取消控制器
abortControllers.set(requestId, controller);
try {
console.log(`[LxMusicHttp] 请求: ${options.method || 'GET'} ${url}`);
const fetchOptions: RequestInit = {
method: options.method || 'GET',
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
...(options.headers || {})
},
signal: controller.signal
};
// 处理请求体
if (options.body) {
fetchOptions.body = options.body;
} else if (options.form) {
const formData = new URLSearchParams(options.form);
fetchOptions.body = formData.toString();
fetchOptions.headers = {
...fetchOptions.headers,
'Content-Type': 'application/x-www-form-urlencoded'
};
} else if (options.formData) {
// node-fetch 的 FormData 需要特殊处理
const FormData = (await import('form-data')).default;
const formData = new FormData();
for (const [key, value] of Object.entries(options.formData)) {
formData.append(key, value);
}
fetchOptions.body = formData as any;
// FormData 会自动设置 Content-Type
}
// 设置超时
const timeout = options.timeout || 30000;
const timeoutId = setTimeout(() => {
console.warn(`[LxMusicHttp] 请求超时: ${url}`);
controller.abort();
}, timeout);
const response = await fetch(url, fetchOptions);
clearTimeout(timeoutId);
console.log(`[LxMusicHttp] 响应: ${response.status} ${url}`);
// 读取响应体
const rawBody = await response.text();
// 尝试解析 JSON
let parsedBody: any = rawBody;
const contentType = response.headers.get('content-type') || '';
if (
contentType.includes('application/json') ||
rawBody.startsWith('{') ||
rawBody.startsWith('[')
) {
try {
parsedBody = JSON.parse(rawBody);
} catch {
// 解析失败则使用原始字符串
}
}
// 转换 headers 为普通对象
const headers: Record<string, string | string[]> = {};
response.headers.forEach((value, key) => {
headers[key] = value;
});
const result: LxHttpResponse = {
statusCode: response.status,
headers,
body: parsedBody
};
return result;
} catch (error: any) {
console.error(`[LxMusicHttp] 请求失败: ${url}`, error.message);
throw error;
} finally {
// 清理取消控制器
abortControllers.delete(requestId);
}
}
);
// 处理请求取消
ipcMain.handle('lx-music-http-cancel', (_, requestId: string) => {
const controller = abortControllers.get(requestId);
if (controller) {
console.log(`[LxMusicHttp] 取消请求: ${requestId}`);
controller.abort();
abortControllers.delete(requestId);
}
});
console.log('[LxMusicHttp] HTTP 请求处理已初始化');
};
/**
* 清理所有正在进行的请求
*/
export const cleanupLxMusicHttp = () => {
for (const [requestId, controller] of abortControllers.entries()) {
console.log(`[LxMusicHttp] 清理请求: ${requestId}`);
controller.abort();
}
abortControllers.clear();
};