fix: 修改国际化问题 和 音源优先级以及音源解析错误处理

This commit is contained in:
alger
2025-09-13 22:52:37 +08:00
parent dc99331911
commit e91667a2e6
10 changed files with 494 additions and 424 deletions
+3 -1
View File
@@ -39,7 +39,9 @@ export default {
warning: 'Please select a music source', warning: 'Please select a music source',
bilibiliNotSupported: 'Bilibili videos do not support reparsing', bilibiliNotSupported: 'Bilibili videos do not support reparsing',
processing: 'Processing...', processing: 'Processing...',
clear: 'Clear Custom Source' clear: 'Clear Custom Source',
customApiFailed: 'Custom API parsing failed, trying built-in sources...',
customApiError: 'Custom API request error, trying built-in sources...'
}, },
playBar: { playBar: {
expand: 'Expand Lyrics', expand: 'Expand Lyrics',
+3 -1
View File
@@ -39,7 +39,9 @@ export default {
warning: '音源を選択してください', warning: '音源を選択してください',
bilibiliNotSupported: 'Bilibili動画は再解析をサポートしていません', bilibiliNotSupported: 'Bilibili動画は再解析をサポートしていません',
processing: '解析中...', processing: '解析中...',
clear: 'カスタム音源をクリア' clear: 'カスタム音源をクリア',
customApiFailed: 'カスタムAPIの解析に失敗しました。内蔵音源を試しています...',
customApiError: 'カスタムAPIのリクエストでエラーが発生しました。内蔵音源を試しています...'
}, },
playBar: { playBar: {
expand: '歌詞を展開', expand: '歌詞を展開',
+3 -1
View File
@@ -39,7 +39,9 @@ export default {
warning: '음원을 선택해주세요', warning: '음원을 선택해주세요',
bilibiliNotSupported: 'B站 비디오는 재분석을 지원하지 않습니다', bilibiliNotSupported: 'B站 비디오는 재분석을 지원하지 않습니다',
processing: '분석 중...', processing: '분석 중...',
clear: '사용자 정의 음원 지우기' clear: '사용자 정의 음원 지우기',
customApiFailed: '사용자 정의 API 분석 실패, 기본 음원을 시도합니다...',
customApiError: '사용자 정의 API 요청 오류, 기본 음원을 시도합니다...'
}, },
playBar: { playBar: {
expand: '가사 펼치기', expand: '가사 펼치기',
+3 -1
View File
@@ -39,7 +39,9 @@ export default {
warning: '请选择一个音源', warning: '请选择一个音源',
bilibiliNotSupported: 'B站视频不支持重新解析', bilibiliNotSupported: 'B站视频不支持重新解析',
processing: '解析中...', processing: '解析中...',
clear: '清除自定义音源' clear: '清除自定义音源',
customApiFailed: '自定义API解析失败,正在尝试使用内置音源...',
customApiError: '自定义API请求出错,正在尝试使用内置音源...'
}, },
playBar: { playBar: {
expand: '展开歌词', expand: '展开歌词',
+3 -1
View File
@@ -39,7 +39,9 @@ export default {
warning: '請選擇一個音源', warning: '請選擇一個音源',
bilibiliNotSupported: 'B站影片不支援重新解析', bilibiliNotSupported: 'B站影片不支援重新解析',
processing: '解析中...', processing: '解析中...',
clear: '清除自訂音源' clear: '清除自訂音源',
customApiFailed: '自定義API解析失敗,正在嘗試使用內置音源...',
customApiError: '自定義API請求出錯,正在嘗試使用內置音源...'
}, },
playBar: { playBar: {
expand: '展開歌詞', expand: '展開歌詞',
+1 -2
View File
@@ -27,8 +27,7 @@
"showTopAction": false, "showTopAction": false,
"contentZoomFactor": 1, "contentZoomFactor": 1,
"autoTheme": false, "autoTheme": false,
"manualTheme": "light"
"manualTheme": "light", "manualTheme": "light",
"customApiPlugin": "", "customApiPlugin": "",
"customApiPluginName": "", "customApiPluginName": ""
} }
+78 -22
View File
@@ -9,9 +9,9 @@ import request from '@/utils/request';
import requestMusic from '@/utils/request_music'; import requestMusic from '@/utils/request_music';
import { searchAndGetBilibiliAudioUrl } from './bilibili'; import { searchAndGetBilibiliAudioUrl } from './bilibili';
import type { ParsedMusicResult } from './gdmusic';
import { parseFromGDMusic } from './gdmusic'; import { parseFromGDMusic } from './gdmusic';
import { parseFromCustomApi } from './parseFromCustomApi'; import { parseFromCustomApi } from './parseFromCustomApi';
import type { ParsedMusicResult } from './gdmusic';
const { addData, getData, deleteData } = musicDB; const { addData, getData, deleteData } = musicDB;
@@ -32,6 +32,8 @@ export const getMusicUrl = async (id: number, isDownloaded: boolean = false) =>
params: { params: {
id, id,
level: settingStore.setData.musicQuality || 'higher', level: settingStore.setData.musicQuality || 'higher',
encodeType: settingStore.setData.musicQuality == 'lossless' ? 'aac' : 'flac',
// level为lossless时,encodeType=flac时网易云会返回hires音质,encodeType=aac时网易云会返回lossless音质
cookie: `${localStorage.getItem('token')} os=pc;` cookie: `${localStorage.getItem('token')} os=pc;`
} }
}); });
@@ -47,7 +49,8 @@ export const getMusicUrl = async (id: number, isDownloaded: boolean = false) =>
return await request.get('/song/url/v1', { return await request.get('/song/url/v1', {
params: { params: {
id, id,
level: settingStore.setData.musicQuality || 'higher' level: settingStore.setData.musicQuality || 'higher',
encodeType: settingStore.setData.musicQuality == 'lossless' ? 'aac' : 'flac'
} }
}); });
}; };
@@ -116,7 +119,8 @@ const getBilibiliAudio = async (data: SongResult) => {
* @param data 歌曲数据 * @param data 歌曲数据
* @returns 解析结果,失败时返回null * @returns 解析结果,失败时返回null
*/ */
const getGDMusicAudio = async (id: number, data: SongResult): Promise<ParsedMusicResult | null> => { // <-- 在这里明确声明返回类型 const getGDMusicAudio = async (id: number, data: SongResult): Promise<ParsedMusicResult | null> => {
// <-- 在这里明确声明返回类型
try { try {
const gdResult = await parseFromGDMusic(id, data, '999'); const gdResult = await parseFromGDMusic(id, data, '999');
if (gdResult) { if (gdResult) {
@@ -148,38 +152,63 @@ const getUnblockMusicAudio = (id: number, data: SongResult, sources: any[]) => {
* @returns 解析结果 * @returns 解析结果
*/ */
export const getParsingMusicUrl = async (id: number, data: SongResult) => { export const getParsingMusicUrl = async (id: number, data: SongResult) => {
try {
if (isElectron) { if (isElectron) {
let musicSources: any[] = [];
let quality: string = 'higher';
try {
const settingStore = useSettingsStore(); const settingStore = useSettingsStore();
const enableMusicUnblock = settingStore?.setData?.enableMusicUnblock;
// 如果禁用了音乐解析功能,则直接返回空结果 // 如果禁用了音乐解析功能,则直接返回空结果
if (!settingStore.setData.enableMusicUnblock) { if (!enableMusicUnblock) {
return Promise.resolve({ data: { code: 404, message: '音乐解析功能已禁用' } }); return Promise.resolve({ data: { code: 404, message: '音乐解析功能已禁用' } });
} }
// 1. 确定使用的音源列表(自定义或全局) // 1. 确定使用的音源列表(自定义或全局)
const songId = String(id); const songId = String(id);
const savedSourceStr = localStorage.getItem(`song_source_${songId}`); const savedSourceStr = (() => {
let musicSources: any[] = [];
try { try {
return localStorage.getItem(`song_source_${songId}`);
} catch (e) {
console.warn('读取本地存储失败,忽略自定义音源', e);
return null;
}
})();
if (savedSourceStr) { if (savedSourceStr) {
// 使用自定义音源 try {
musicSources = JSON.parse(savedSourceStr); musicSources = JSON.parse(savedSourceStr);
console.log(`使用歌曲 ${id} 自定义音源:`, musicSources); console.log(`使用歌曲 ${id} 自定义音源:`, musicSources);
} else {
// 使用全局音源设置
musicSources = settingStore.setData.enabledMusicSources || [];
console.log(`使用全局音源设置:`, musicSources);
}
} catch (e) { } catch (e) {
console.error('解析音源设置失败,回退到默认全局设置', e); console.error('解析音源设置失败,回退到默认全局设置', e);
musicSources = settingStore.setData.enabledMusicSources || []; musicSources = settingStore?.setData?.enabledMusicSources || [];
}
} else {
// 使用全局音源设置
musicSources = settingStore?.setData?.enabledMusicSources || [];
console.log(`使用全局音源设置:`, musicSources);
} }
const quality = settingStore.setData.musicQuality || 'higher'; quality = settingStore?.setData?.musicQuality || 'higher';
} catch (e) {
console.error('读取设置失败,使用默认配置', e);
musicSources = [];
quality = 'higher';
}
// 优先级 1: 自定义 API // 优先级 1: 自定义 API
if (musicSources.includes('custom') && settingStore.setData.customApiPlugin) { try {
const hasCustom = Array.isArray(musicSources) && musicSources.includes('custom');
const customEnabled = (() => {
try {
const st = useSettingsStore();
return Boolean(st?.setData?.customApiPlugin);
} catch {
return false;
}
})();
if (hasCustom && customEnabled) {
console.log('尝试使用 自定义API 解析...'); console.log('尝试使用 自定义API 解析...');
const customResult = await parseFromCustomApi(id, data, quality); const customResult = await parseFromCustomApi(id, data, quality);
if (customResult) { if (customResult) {
@@ -187,19 +216,27 @@ export const getParsingMusicUrl = async (id: number, data: SongResult) => {
} }
console.log('自定义API解析失败,继续尝试其他音源...'); console.log('自定义API解析失败,继续尝试其他音源...');
} }
} catch (e) {
console.error('自定义API解析发生异常,继续尝试其他音源', e);
}
// 优先级 2: Bilibili // 优先级 2: Bilibili
if (musicSources.includes('bilibili')) { try {
if (Array.isArray(musicSources) && musicSources.includes('bilibili')) {
console.log('尝试使用 Bilibili 解析...'); console.log('尝试使用 Bilibili 解析...');
const bilibiliResult = await getBilibiliAudio(data); const bilibiliResult = await getBilibiliAudio(data);
if (bilibiliResult?.data?.data?.url) { // 检查返回的 URL 是否有效 if (bilibiliResult?.data?.data?.url) {
return bilibiliResult; return bilibiliResult;
} }
console.log('Bilibili解析失败,继续尝试其他音源...'); console.log('Bilibili解析失败,继续尝试其他音源...');
} }
} catch (e) {
console.error('Bilibili解析发生异常,继续尝试其他音源', e);
}
// 优先级 3: GD 音乐台 // 优先级 3: GD 音乐台
if (musicSources.includes('gdmusic')) { try {
if (Array.isArray(musicSources) && musicSources.includes('gdmusic')) {
console.log('尝试使用 GD音乐台 解析...'); console.log('尝试使用 GD音乐台 解析...');
const gdResult = await getGDMusicAudio(id, data); const gdResult = await getGDMusicAudio(id, data);
if (gdResult) { if (gdResult) {
@@ -207,15 +244,28 @@ export const getParsingMusicUrl = async (id: number, data: SongResult) => {
} }
console.log('GD音乐台解析失败,继续尝试其他音源...'); console.log('GD音乐台解析失败,继续尝试其他音源...');
} }
} catch (e) {
console.error('GD音乐台解析发生异常,继续尝试其他音源', e);
}
// 优先级 4: UnblockMusic (migu, kugou, pyncmd) // 优先级 4: UnblockMusic (migu, kugou, pyncmd)
const unblockSources = musicSources.filter( try {
source => !['custom', 'bilibili', 'gdmusic'].includes(source) const unblockSources = (Array.isArray(musicSources) ? musicSources : []).filter(
(source) => !['custom', 'bilibili', 'gdmusic'].includes(source)
); );
if (unblockSources.length > 0) { if (unblockSources.length > 0) {
console.log('尝试使用 UnblockMusic 解析:', unblockSources); console.log('尝试使用 UnblockMusic 解析:', unblockSources);
return getUnblockMusicAudio(id, data, unblockSources); // 捕获内部可能的异常
return await getUnblockMusicAudio(id, data, unblockSources);
} else {
console.warn('UnblockMusic API 不可用,跳过此解析方式');
} }
} catch (e) {
console.error('UnblockMusic 解析发生异常,继续后备方案', e);
}
}
} catch (e) {
console.error('getParsingMusicUrl 执行异常,将使用后备方案:', e);
} }
// 后备方案:使用API请求 // 后备方案:使用API请求
@@ -228,6 +278,12 @@ export const likeSong = (id: number, like: boolean = true) => {
return request.get('/like', { params: { id, like } }); return request.get('/like', { params: { id, like } });
}; };
// 将每日推荐中的歌曲标记为不感兴趣,并获取一首新歌
export const dislikeRecommendedSong = (id: number | string) => {
return request.get('/recommend/songs/dislike', {
params: { id }
});
};
// 获取用户喜欢的音乐列表 // 获取用户喜欢的音乐列表
export const getLikedList = (uid: number) => { export const getLikedList = (uid: number) => {
return request.get('/likelist', { return request.get('/likelist', {
+6 -5
View File
@@ -1,9 +1,9 @@
import axios from 'axios'; import axios from 'axios';
import {get} from 'lodash'; import { get } from 'lodash';
import {useSettingsStore} from '@/store';
// 从同级目录的 gdmusic.ts 导入类型,确保兼容性 import { useSettingsStore } from '@/store';
import type {ParsedMusicResult} from './gdmusic';
import type { ParsedMusicResult } from './gdmusic';
/** /**
* 定义自定义API JSON插件的结构 * 定义自定义API JSON插件的结构
@@ -70,7 +70,8 @@ export const parseFromCustomApi = async (
if (method === 'POST') { if (method === 'POST') {
console.log('自定义API:发送 POST 请求到:', plugin.apiUrl, '参数:', finalParams); console.log('自定义API:发送 POST 请求到:', plugin.apiUrl, '参数:', finalParams);
response = await axios.post(plugin.apiUrl, finalParams, { timeout }); response = await axios.post(plugin.apiUrl, finalParams, { timeout });
} else { // 默认为 GET } else {
// 默认为 GET
const finalUrl = `${plugin.apiUrl}?${new URLSearchParams(finalParams).toString()}`; const finalUrl = `${plugin.apiUrl}?${new URLSearchParams(finalParams).toString()}`;
console.log('自定义API:发送 GET 请求到:', finalUrl); console.log('自定义API:发送 GET 请求到:', finalUrl);
response = await axios.get(finalUrl, { timeout }); response = await axios.get(finalUrl, { timeout });
@@ -59,7 +59,6 @@
<p v-else class="text-sm text-gray-500">尚未导入</p> <p v-else class="text-sm text-gray-500">尚未导入</p>
</div> </div>
</div> </div>
</n-space> </n-space>
</n-modal> </n-modal>
</template> </template>
@@ -68,8 +67,8 @@
import { useMessage } from 'naive-ui'; import { useMessage } from 'naive-ui';
import { ref, watch } from 'vue'; import { ref, watch } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useSettingsStore } from '@/store';
import { useSettingsStore } from '@/store';
import { type Platform } from '@/types/music'; import { type Platform } from '@/types/music';
// 扩展 Platform 类型以包含 'custom' // 扩展 Platform 类型以包含 'custom'
@@ -120,14 +119,17 @@ const importPlugin = async () => {
}; };
// 监听自定义插件内容的变化。如果用户清除了插件,要确保 'custom' 选项被取消勾选 // 监听自定义插件内容的变化。如果用户清除了插件,要确保 'custom' 选项被取消勾选
watch(() => settingsStore.setData.customApiPlugin, (newPluginContent) => { watch(
() => settingsStore.setData.customApiPlugin,
(newPluginContent) => {
if (!newPluginContent) { if (!newPluginContent) {
const index = selectedSources.value.indexOf('custom'); const index = selectedSources.value.indexOf('custom');
if (index > -1) { if (index > -1) {
selectedSources.value.splice(index, 1); selectedSources.value.splice(index, 1);
} }
} }
}); }
);
// 同步外部show属性变化 // 同步外部show属性变化
watch( watch(
+5 -3
View File
@@ -122,7 +122,9 @@ export const getSongUrl = async (
try { try {
const songSources = JSON.parse(savedSourceStr); const songSources = JSON.parse(savedSourceStr);
useCustomApiForSong = songSources.includes('custom'); useCustomApiForSong = songSources.includes('custom');
} catch (e) { /* ignore parsing error */ } } catch (e) {
console.error('解析歌曲音源设置失败:', e);
}
} }
// 如果全局或歌曲专属设置中启用了自定义API,则最优先尝试 // 如果全局或歌曲专属设置中启用了自定义API,则最优先尝试
@@ -140,11 +142,11 @@ export const getSongUrl = async (
} else { } else {
// 自定义API失败,给出提示,然后继续走默认流程 // 自定义API失败,给出提示,然后继续走默认流程
console.log('自定义API解析失败,将使用默认降级流程...'); console.log('自定义API解析失败,将使用默认降级流程...');
message.warning('自定义API解析失败,正在尝试使用内置音源...'); // 给用户一个提示 message.warning(i18n.global.t('player.reparse.customApiFailed')); // 给用户一个提示
} }
} catch (error) { } catch (error) {
console.error('调用自定义API时发生错误:', error); console.error('调用自定义API时发生错误:', error);
message.error('自定义API请求出错,正在尝试使用内置音源...'); message.error(i18n.global.t('player.reparse.customApiError'));
} }
} }
// 如果自定义API失败或未启用,则执行【原有】的解析流程 // 如果自定义API失败或未启用,则执行【原有】的解析流程