fix: 修复音源解析致命性错误

This commit is contained in:
alger
2025-12-13 14:46:15 +08:00
parent 1a0e449e13
commit b9287e1c36
8 changed files with 331 additions and 437 deletions
+6 -153
View File
@@ -1,7 +1,5 @@
import { Howl } from 'howler';
import { cloneDeep } from 'lodash';
import { getParsingMusicUrl } from '@/api/music';
import type { SongResult } from '@/types/music';
class PreloadService {
@@ -60,167 +58,22 @@ class PreloadService {
}
// 创建初始音频实例
let sound = await this._createSound(song.playMusicUrl);
const sound = await this._createSound(song.playMusicUrl);
// 检查时长
const duration = sound.duration();
const expectedDuration = (song.dt || 0) / 1000;
// 如果时长差异超过5秒,且不是B站视频,且预期时长大于0
// 时长差异只记录警告,不自动触发重新解析
// 用户可以通过 ReparsePopover 手动选择正确的音源
if (
expectedDuration > 0 &&
Math.abs(duration - expectedDuration) > 5 &&
song.source !== 'bilibili'
) {
const songId = String(song.id);
const sourceType = localStorage.getItem(`song_source_type_${songId}`);
// 如果不是用户手动锁定的音源,尝试自动重新解析
if (sourceType !== 'manual') {
console.warn(
`[PreloadService] 时长不匹配 (实际: ${duration}s, 预期: ${expectedDuration}s),尝试智能解析`
);
// 动态导入 store
const { useSettingsStore } = await import('@/store/modules/settings');
const { usePlaylistStore } = await import('@/store/modules/playlist');
const settingsStore = useSettingsStore();
const playlistStore = usePlaylistStore();
const enabledSources = settingsStore.setData.enabledMusicSources || [
'migu',
'kugou',
'pyncmd',
'gdmusic'
];
const availableSources = enabledSources.filter((s: string) => s !== 'bilibili');
const triedSources = new Set<string>();
const triedSourceDiffs = new Map<string, number>();
// 记录当前音源
let currentSource = 'unknown';
const currentSavedSource = localStorage.getItem(`song_source_${songId}`);
if (currentSavedSource) {
try {
const sources = JSON.parse(currentSavedSource);
if (Array.isArray(sources) && sources.length > 0) {
currentSource = sources[0];
}
} catch (e) {
console.log(
`[PreloadService] 时长不匹配 (实际: ${duration}s, 预期: ${expectedDuration}s),尝试智能解析`,
e
);
}
}
triedSources.add(currentSource);
triedSourceDiffs.set(currentSource, Math.abs(duration - expectedDuration));
// 卸载当前不匹配的音频
sound.unload();
// 尝试其他音源
for (const source of availableSources) {
if (triedSources.has(source)) continue;
console.log(`[PreloadService] 尝试音源: ${source}`);
triedSources.add(source);
try {
const songData = cloneDeep(song);
// 临时保存设置以便 getParsingMusicUrl 使用
localStorage.setItem(`song_source_${songId}`, JSON.stringify([source]));
const res = await getParsingMusicUrl(
typeof song.id === 'string' ? parseInt(song.id) : song.id,
songData
);
if (res && res.data && res.data.data && res.data.data.url) {
const newUrl = res.data.data.url;
const tempSound = await this._createSound(newUrl);
const newDuration = tempSound.duration();
const diff = Math.abs(newDuration - expectedDuration);
triedSourceDiffs.set(source, diff);
if (diff <= 5) {
console.log(`[PreloadService] 找到匹配音源: ${source}, 更新歌曲信息`);
// 更新歌曲信息
const updatedSong = {
...song,
playMusicUrl: newUrl,
expiredAt: Date.now() + 1800000
};
// 更新 store
playlistStore.updateSong(updatedSong);
// 记录新的音源设置
localStorage.setItem(`song_source_${songId}`, JSON.stringify([source]));
localStorage.setItem(`song_source_type_${songId}`, 'auto');
return tempSound;
} else {
tempSound.unload();
}
}
} catch (e) {
console.error(`[PreloadService] 尝试音源 ${source} 失败:`, e);
}
}
// 如果没有找到完美匹配,使用最佳匹配
console.warn('[PreloadService] 未找到完美匹配,寻找最佳匹配');
let bestSource = '';
let minDiff = Infinity;
for (const [source, diff] of triedSourceDiffs.entries()) {
if (diff < minDiff) {
minDiff = diff;
bestSource = source;
}
}
if (bestSource && bestSource !== currentSource) {
console.log(`[PreloadService] 使用最佳匹配音源: ${bestSource} (差异: ${minDiff}s)`);
try {
const songData = cloneDeep(song);
localStorage.setItem(`song_source_${songId}`, JSON.stringify([bestSource]));
const res = await getParsingMusicUrl(
typeof song.id === 'string' ? parseInt(song.id) : song.id,
songData
);
if (res && res.data && res.data.data && res.data.data.url) {
const newUrl = res.data.data.url;
const bestSound = await this._createSound(newUrl);
const updatedSong = {
...song,
playMusicUrl: newUrl,
expiredAt: Date.now() + 1800000
};
playlistStore.updateSong(updatedSong);
localStorage.setItem(`song_source_type_${songId}`, 'auto');
return bestSound;
}
} catch (e) {
console.error(`[PreloadService] 获取最佳匹配音源失败:`, e);
}
}
}
}
// 如果不需要修复或修复失败,重新加载原始音频(因为上面可能unload了)
if (sound.state() === 'unloaded') {
sound = await this._createSound(song.playMusicUrl);
console.warn(
`[PreloadService] 时长差异警告:实际 ${duration.toFixed(1)}s, 预期 ${expectedDuration.toFixed(1)}s (${song.name})`
);
}
return sound;