mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-07-08 02:17:30 +08:00
fix(main): 修复下载过期无法恢复、配置写放大、主进程 i18n 崩溃
- downloadManager: axios 放行 403/410,让直链过期能触发重新解析(修复重启恢复队列时下载失效) - cache: getCacheConfig 纯读不再落盘 config.json,消除播放/下载热路径的写放大与文件争用 - i18n/main: 未知/非法 locale 回退默认语言并加空值防护,避免托盘/登录窗构建时崩溃 - lxMusicHttp: 超时定时器在 fetch 出错路径也清理 - loginWindow: 标题改为打开窗口时求值,跟随当前语言
This commit is contained in:
+6
-2
@@ -18,9 +18,13 @@ const mainI18n = {
|
|||||||
},
|
},
|
||||||
t(key: string) {
|
t(key: string) {
|
||||||
const keys = key.split('.');
|
const keys = key.split('.');
|
||||||
let current: any = messages[this.currentLocale];
|
// 未知/非法 locale 时回退默认语言,避免 messages[locale] 为 undefined 导致崩溃
|
||||||
|
let current: any = messages[this.currentLocale] ?? messages[DEFAULT_LANGUAGE as Language];
|
||||||
|
if (current == null) {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
for (const k of keys) {
|
for (const k of keys) {
|
||||||
if (current[k] === undefined) {
|
if (current == null || current[k] === undefined) {
|
||||||
// 如果找不到翻译,返回键名
|
// 如果找不到翻译,返回键名
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -413,7 +413,9 @@ class DiskCacheManager {
|
|||||||
cleanupPolicy
|
cleanupPolicy
|
||||||
};
|
};
|
||||||
|
|
||||||
this.saveConfig(normalizedConfig);
|
// 注意:getCacheConfig 是纯读取,处于播放/下载/歌词等多个热路径。
|
||||||
|
// 此处不再落盘(electron-store.set 每次整文件写 config.json,会造成写放大与文件争用),
|
||||||
|
// 持久化交由 updateCacheConfig / setCacheDirectory 等真正的写操作完成。
|
||||||
return normalizedConfig;
|
return normalizedConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -484,13 +484,17 @@ class DownloadManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start download
|
// Start download
|
||||||
|
// 注意:axios 默认只接受 2xx,403/410 会直接抛错进入 catch,导致下方"直链过期重新解析"
|
||||||
|
// 分支永远走不到。这里放行 403/410,让过期直链能触发重新解析(尤其是重启后恢复队列时)。
|
||||||
const response = await axios({
|
const response = await axios({
|
||||||
url: task.url,
|
url: task.url,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
responseType: 'stream',
|
responseType: 'stream',
|
||||||
timeout: 30000,
|
timeout: 30000,
|
||||||
signal: controller.signal,
|
signal: controller.signal,
|
||||||
headers
|
headers,
|
||||||
|
validateStatus: (status) =>
|
||||||
|
(status >= 200 && status < 300) || status === 403 || status === 410
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle response status
|
// Handle response status
|
||||||
@@ -498,6 +502,8 @@ class DownloadManager {
|
|||||||
|
|
||||||
if (status === 403 || status === 410) {
|
if (status === 403 || status === 410) {
|
||||||
// URL expired, request re-resolution from renderer
|
// URL expired, request re-resolution from renderer
|
||||||
|
// 排空未消费的错误响应流,避免连接悬挂
|
||||||
|
response.data?.destroy?.();
|
||||||
this.sendToRenderer('download:request-url', {
|
this.sendToRenderer('download:request-url', {
|
||||||
taskId: task.taskId,
|
taskId: task.taskId,
|
||||||
songInfo: task.songInfo
|
songInfo: task.songInfo
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import i18n from '../../i18n/main';
|
|||||||
let loginWindow: BrowserWindow | null = null;
|
let loginWindow: BrowserWindow | null = null;
|
||||||
|
|
||||||
const loginUrl = 'https://music.163.com/#/login/';
|
const loginUrl = 'https://music.163.com/#/login/';
|
||||||
const loginTitle = i18n.global.t('login.qrTitle');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 打开登录窗口获取Cookie
|
* 打开登录窗口获取Cookie
|
||||||
@@ -29,7 +28,8 @@ const openLoginWindow = async (mainWin: BrowserWindow) => {
|
|||||||
|
|
||||||
loginWindow = new BrowserWindow({
|
loginWindow = new BrowserWindow({
|
||||||
parent: mainWin,
|
parent: mainWin,
|
||||||
title: loginTitle,
|
// 在打开窗口时求值,确保跟随当前语言(模块加载时 i18n locale 可能尚未设置)
|
||||||
|
title: i18n.global.t('login.qrTitle'),
|
||||||
width: 1280,
|
width: 1280,
|
||||||
height: 800,
|
height: 800,
|
||||||
center: true,
|
center: true,
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ export const initLxMusicHttp = () => {
|
|||||||
// 保存取消控制器
|
// 保存取消控制器
|
||||||
abortControllers.set(requestId, controller);
|
abortControllers.set(requestId, controller);
|
||||||
|
|
||||||
|
let timeoutId: ReturnType<typeof setTimeout> | null = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log(`[LxMusicHttp] 请求: ${options.method || 'GET'} ${url}`);
|
console.log(`[LxMusicHttp] 请求: ${options.method || 'GET'} ${url}`);
|
||||||
|
|
||||||
@@ -77,13 +79,14 @@ export const initLxMusicHttp = () => {
|
|||||||
|
|
||||||
// 设置超时
|
// 设置超时
|
||||||
const timeout = options.timeout || 30000;
|
const timeout = options.timeout || 30000;
|
||||||
const timeoutId = setTimeout(() => {
|
timeoutId = setTimeout(() => {
|
||||||
console.warn(`[LxMusicHttp] 请求超时: ${url}`);
|
console.warn(`[LxMusicHttp] 请求超时: ${url}`);
|
||||||
controller.abort();
|
controller.abort();
|
||||||
}, timeout);
|
}, timeout);
|
||||||
|
|
||||||
const response = await fetch(url, fetchOptions);
|
const response = await fetch(url, fetchOptions);
|
||||||
clearTimeout(timeoutId);
|
clearTimeout(timeoutId);
|
||||||
|
timeoutId = null;
|
||||||
|
|
||||||
console.log(`[LxMusicHttp] 响应: ${response.status} ${url}`);
|
console.log(`[LxMusicHttp] 响应: ${response.status} ${url}`);
|
||||||
|
|
||||||
@@ -122,7 +125,10 @@ export const initLxMusicHttp = () => {
|
|||||||
console.error(`[LxMusicHttp] 请求失败: ${url}`, error.message);
|
console.error(`[LxMusicHttp] 请求失败: ${url}`, error.message);
|
||||||
throw error;
|
throw error;
|
||||||
} finally {
|
} finally {
|
||||||
// 清理取消控制器
|
// 清理超时定时器(fetch 出错时前面来不及 clear)与取消控制器
|
||||||
|
if (timeoutId) {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
}
|
||||||
abortControllers.delete(requestId);
|
abortControllers.delete(requestId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user