fix: 修复优化bili解析搜索和播放问题

This commit is contained in:
algerkong
2025-09-20 15:38:35 +08:00
parent 0df86b583b
commit 93022691e2
3 changed files with 84 additions and 36 deletions

View File

@@ -10,14 +10,50 @@ interface ISearchParams {
}
/**
* 搜索B站视频
* 搜索B站视频(带自动重试)
* 最多重试10次每次间隔100ms
* @param params 搜索参数
*/
export const searchBilibili = (params: ISearchParams) => {
export const searchBilibili = async (params: ISearchParams): Promise<any> => {
console.log('调用B站搜索API参数:', params);
return request.get('/bilibili/search', {
params
});
const maxRetries = 10;
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> {
@@ -139,7 +175,7 @@ export const getBilibiliAudioUrl = async (bvid: string, cid: number): Promise<st
let url = '';
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) {
url = playUrlData.durl[0].url;
} else {
@@ -158,6 +194,9 @@ export const searchAndGetBilibiliAudioUrl = async (keyword: string): Promise<str
try {
// 搜索B站视频取第一页第一个结果
const res = await searchBilibili({ keyword, page: 1, pagesize: 1 });
if (!res) {
throw new Error('B站搜索返回为空');
}
const result = res.data?.data?.result;
if (!result || result.length === 0) {
throw new Error('未找到相关B站视频');

View File

@@ -42,7 +42,6 @@
</template>
</n-input>
</template>
<!-- ==================== 搜索建议列表 ==================== -->
<div class="search-suggestions-panel">
<n-scrollbar style="max-height: 300px">
<div v-if="suggestionsLoading" class="suggestion-item loading">
@@ -175,7 +174,7 @@ import { getSearchSuggestions } from '@/api/search';
import alipay from '@/assets/alipay.png';
import wechat from '@/assets/wechat.png';
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 { useSearchStore } from '@/store/modules/search';
import { useSettingsStore } from '@/store/modules/settings';
@@ -312,12 +311,13 @@ const selectSearchType = (key: number) => {
const rawSearchTypes = ref(SEARCH_TYPES);
const searchTypeOptions = computed(() => {
// 引用 locale 以创建响应式依赖
locale.value;
return rawSearchTypes.value.map((type) => ({
label: t(type.label),
key: type.key
}));
return rawSearchTypes.value
.filter((type) => isElectron || type.key !== SEARCH_TYPE.BILIBILI)
.map((type) => ({
label: t(type.label),
key: type.key
}));
});
const selectItem = async (key: string) => {

View File

@@ -113,23 +113,29 @@ class AudioService {
}
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 album = track.al ? track.al.name : track.song.album.name;
const artwork = ['96', '128', '192', '256', '384', '512'].map((size) => ({
src: `${track.picUrl}?param=${size}y${size}`,
type: 'image/jpg',
sizes: `${size}x${size}`
}));
const metadata = {
title: track.name || '',
artist: artists ? artists.join(',') : '',
album: album || '',
artwork
};
const artists = track.ar
? track.ar.map((a) => a.name)
: track.song.artists?.map((a) => a.name);
const album = track.al ? track.al.name : track.song.album.name;
const artwork = ['96', '128', '192', '256', '384', '512'].map((size) => ({
src: `${track.picUrl}?param=${size}y${size}`,
type: 'image/jpg',
sizes: `${size}x${size}`
}));
const metadata = {
title: track.name || '',
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) {
@@ -140,14 +146,17 @@ class AudioService {
}
private updateMediaSessionPositionState() {
if (!this.currentSound || !('mediaSession' in navigator)) return;
if ('setPositionState' in navigator.mediaSession) {
navigator.mediaSession.setPositionState({
duration: this.currentSound.duration(),
playbackRate: this.playbackRate,
position: this.currentSound.seek() as number
});
try {
if (!this.currentSound || !('mediaSession' in navigator)) return;
if ('setPositionState' in navigator.mediaSession) {
navigator.mediaSession.setPositionState({
duration: this.currentSound.duration(),
playbackRate: this.playbackRate,
position: this.currentSound.seek() as number
});
}
} catch (error) {
console.error('更新媒体会话位置状态时出错:', error);
}
}