mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-04-15 07:20:49 +08:00
fix: 修复优化bili解析搜索和播放问题
This commit is contained in:
@@ -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站视频');
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user