mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-04-28 10:57:23 +08:00
fix: 修复优化bili解析搜索和播放问题
This commit is contained in:
@@ -10,14 +10,50 @@ interface ISearchParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 搜索B站视频
|
* 搜索B站视频(带自动重试)
|
||||||
|
* 最多重试10次,每次间隔100ms
|
||||||
* @param params 搜索参数
|
* @param params 搜索参数
|
||||||
*/
|
*/
|
||||||
export const searchBilibili = (params: ISearchParams) => {
|
export const searchBilibili = async (params: ISearchParams): Promise<any> => {
|
||||||
console.log('调用B站搜索API,参数:', params);
|
console.log('调用B站搜索API,参数:', params);
|
||||||
return request.get('/bilibili/search', {
|
const maxRetries = 10;
|
||||||
params
|
const delayMs = 100;
|
||||||
});
|
const delay = (ms: number) => new Promise((res) => setTimeout(res, ms));
|
||||||
|
|
||||||
|
let lastError: unknown = null;
|
||||||
|
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
||||||
|
try {
|
||||||
|
const response = await request.get('/bilibili/search', { params });
|
||||||
|
console.log('B站搜索API响应:', response);
|
||||||
|
const hasTitle = Boolean(response?.data?.data?.result?.length);
|
||||||
|
if (response?.status === 200 && hasTitle) {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastError = new Error(
|
||||||
|
`搜索结果不符合成功条件(缺少 data.title ) (attempt ${attempt}/${maxRetries})`
|
||||||
|
);
|
||||||
|
console.warn('B站搜索API响应不符合要求,将重试。调试信息:', {
|
||||||
|
status: response?.status,
|
||||||
|
hasData: Boolean(response?.data),
|
||||||
|
hasInnerData: Boolean(response?.data?.data),
|
||||||
|
title: response?.data?.data?.title
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
lastError = error;
|
||||||
|
console.warn(`B站搜索API错误[第${attempt}次],将重试:`, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attempt === maxRetries) {
|
||||||
|
console.error('B站搜索API重试达到上限,仍然失败');
|
||||||
|
if (lastError instanceof Error) throw lastError;
|
||||||
|
throw new Error('B站搜索失败且达到最大重试次数');
|
||||||
|
}
|
||||||
|
|
||||||
|
await delay(delayMs);
|
||||||
|
}
|
||||||
|
// 理论上不会到达这里,添加以满足TS控制流分析
|
||||||
|
throw new Error('B站搜索在重试后未返回有效结果');
|
||||||
};
|
};
|
||||||
|
|
||||||
interface IBilibiliResponse<T> {
|
interface IBilibiliResponse<T> {
|
||||||
@@ -139,7 +175,7 @@ export const getBilibiliAudioUrl = async (bvid: string, cid: number): Promise<st
|
|||||||
let url = '';
|
let url = '';
|
||||||
|
|
||||||
if (playUrlData.dash && playUrlData.dash.audio && playUrlData.dash.audio.length > 0) {
|
if (playUrlData.dash && playUrlData.dash.audio && playUrlData.dash.audio.length > 0) {
|
||||||
url = playUrlData.dash.audio[0].baseUrl;
|
url = playUrlData.dash.audio[playUrlData.dash.audio.length - 1].baseUrl;
|
||||||
} else if (playUrlData.durl && playUrlData.durl.length > 0) {
|
} else if (playUrlData.durl && playUrlData.durl.length > 0) {
|
||||||
url = playUrlData.durl[0].url;
|
url = playUrlData.durl[0].url;
|
||||||
} else {
|
} else {
|
||||||
@@ -158,6 +194,9 @@ export const searchAndGetBilibiliAudioUrl = async (keyword: string): Promise<str
|
|||||||
try {
|
try {
|
||||||
// 搜索B站视频,取第一页第一个结果
|
// 搜索B站视频,取第一页第一个结果
|
||||||
const res = await searchBilibili({ keyword, page: 1, pagesize: 1 });
|
const res = await searchBilibili({ keyword, page: 1, pagesize: 1 });
|
||||||
|
if (!res) {
|
||||||
|
throw new Error('B站搜索返回为空');
|
||||||
|
}
|
||||||
const result = res.data?.data?.result;
|
const result = res.data?.data?.result;
|
||||||
if (!result || result.length === 0) {
|
if (!result || result.length === 0) {
|
||||||
throw new Error('未找到相关B站视频');
|
throw new Error('未找到相关B站视频');
|
||||||
|
|||||||
@@ -42,7 +42,6 @@
|
|||||||
</template>
|
</template>
|
||||||
</n-input>
|
</n-input>
|
||||||
</template>
|
</template>
|
||||||
<!-- ==================== 搜索建议列表 ==================== -->
|
|
||||||
<div class="search-suggestions-panel">
|
<div class="search-suggestions-panel">
|
||||||
<n-scrollbar style="max-height: 300px">
|
<n-scrollbar style="max-height: 300px">
|
||||||
<div v-if="suggestionsLoading" class="suggestion-item loading">
|
<div v-if="suggestionsLoading" class="suggestion-item loading">
|
||||||
@@ -175,7 +174,7 @@ import { getSearchSuggestions } from '@/api/search';
|
|||||||
import alipay from '@/assets/alipay.png';
|
import alipay from '@/assets/alipay.png';
|
||||||
import wechat from '@/assets/wechat.png';
|
import wechat from '@/assets/wechat.png';
|
||||||
import Coffee from '@/components/Coffee.vue';
|
import Coffee from '@/components/Coffee.vue';
|
||||||
import { SEARCH_TYPES, USER_SET_OPTIONS } from '@/const/bar-const';
|
import { SEARCH_TYPE, SEARCH_TYPES, USER_SET_OPTIONS } from '@/const/bar-const';
|
||||||
import { useZoom } from '@/hooks/useZoom';
|
import { useZoom } from '@/hooks/useZoom';
|
||||||
import { useSearchStore } from '@/store/modules/search';
|
import { useSearchStore } from '@/store/modules/search';
|
||||||
import { useSettingsStore } from '@/store/modules/settings';
|
import { useSettingsStore } from '@/store/modules/settings';
|
||||||
@@ -312,12 +311,13 @@ const selectSearchType = (key: number) => {
|
|||||||
|
|
||||||
const rawSearchTypes = ref(SEARCH_TYPES);
|
const rawSearchTypes = ref(SEARCH_TYPES);
|
||||||
const searchTypeOptions = computed(() => {
|
const searchTypeOptions = computed(() => {
|
||||||
// 引用 locale 以创建响应式依赖
|
|
||||||
locale.value;
|
locale.value;
|
||||||
return rawSearchTypes.value.map((type) => ({
|
return rawSearchTypes.value
|
||||||
label: t(type.label),
|
.filter((type) => isElectron || type.key !== SEARCH_TYPE.BILIBILI)
|
||||||
key: type.key
|
.map((type) => ({
|
||||||
}));
|
label: t(type.label),
|
||||||
|
key: type.key
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
const selectItem = async (key: string) => {
|
const selectItem = async (key: string) => {
|
||||||
|
|||||||
@@ -113,23 +113,29 @@ class AudioService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private updateMediaSessionMetadata(track: SongResult) {
|
private updateMediaSessionMetadata(track: SongResult) {
|
||||||
if (!('mediaSession' in navigator)) return;
|
try {
|
||||||
|
if (!('mediaSession' in navigator)) return;
|
||||||
|
|
||||||
const artists = track.ar ? track.ar.map((a) => a.name) : track.song.artists?.map((a) => a.name);
|
const artists = track.ar
|
||||||
const album = track.al ? track.al.name : track.song.album.name;
|
? track.ar.map((a) => a.name)
|
||||||
const artwork = ['96', '128', '192', '256', '384', '512'].map((size) => ({
|
: track.song.artists?.map((a) => a.name);
|
||||||
src: `${track.picUrl}?param=${size}y${size}`,
|
const album = track.al ? track.al.name : track.song.album.name;
|
||||||
type: 'image/jpg',
|
const artwork = ['96', '128', '192', '256', '384', '512'].map((size) => ({
|
||||||
sizes: `${size}x${size}`
|
src: `${track.picUrl}?param=${size}y${size}`,
|
||||||
}));
|
type: 'image/jpg',
|
||||||
const metadata = {
|
sizes: `${size}x${size}`
|
||||||
title: track.name || '',
|
}));
|
||||||
artist: artists ? artists.join(',') : '',
|
const metadata = {
|
||||||
album: album || '',
|
title: track.name || '',
|
||||||
artwork
|
artist: artists ? artists.join(',') : '',
|
||||||
};
|
album: album || '',
|
||||||
|
artwork
|
||||||
|
};
|
||||||
|
|
||||||
navigator.mediaSession.metadata = new window.MediaMetadata(metadata);
|
navigator.mediaSession.metadata = new window.MediaMetadata(metadata);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('更新媒体会话元数据时出错:', error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateMediaSessionState(isPlaying: boolean) {
|
private updateMediaSessionState(isPlaying: boolean) {
|
||||||
@@ -140,14 +146,17 @@ class AudioService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private updateMediaSessionPositionState() {
|
private updateMediaSessionPositionState() {
|
||||||
if (!this.currentSound || !('mediaSession' in navigator)) return;
|
try {
|
||||||
|
if (!this.currentSound || !('mediaSession' in navigator)) return;
|
||||||
if ('setPositionState' in navigator.mediaSession) {
|
if ('setPositionState' in navigator.mediaSession) {
|
||||||
navigator.mediaSession.setPositionState({
|
navigator.mediaSession.setPositionState({
|
||||||
duration: this.currentSound.duration(),
|
duration: this.currentSound.duration(),
|
||||||
playbackRate: this.playbackRate,
|
playbackRate: this.playbackRate,
|
||||||
position: this.currentSound.seek() as number
|
position: this.currentSound.seek() as number
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('更新媒体会话位置状态时出错:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user