mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-04-28 02:47:22 +08:00
🐞 fix: 修复解析错误问题, 优化播放效果
This commit is contained in:
@@ -32,6 +32,49 @@ interface UnblockResult {
|
|||||||
// 所有可用平台
|
// 所有可用平台
|
||||||
export const ALL_PLATFORMS: Platform[] = ['migu', 'kugou', 'pyncmd', 'bilibili'];
|
export const ALL_PLATFORMS: Platform[] = ['migu', 'kugou', 'pyncmd', 'bilibili'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确保对象数据结构完整,处理null或undefined的情况
|
||||||
|
* @param data 需要处理的数据对象
|
||||||
|
*/
|
||||||
|
function ensureDataStructure(data: any): any {
|
||||||
|
// 如果数据本身为空,则返回一个基本结构
|
||||||
|
if (!data) {
|
||||||
|
return {
|
||||||
|
name: '',
|
||||||
|
artists: [],
|
||||||
|
album: { name: '' }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保name字段存在
|
||||||
|
if (data.name === undefined || data.name === null) {
|
||||||
|
data.name = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保artists字段存在且为数组
|
||||||
|
if (!data.artists || !Array.isArray(data.artists)) {
|
||||||
|
data.artists = data.ar && Array.isArray(data.ar) ? data.ar : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保artists中的每个元素都有name属性
|
||||||
|
if (data.artists.length > 0) {
|
||||||
|
data.artists = data.artists.map(artist => {
|
||||||
|
return artist ? { name: artist.name || '' } : { name: '' };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保album对象存在并有name属性
|
||||||
|
if (!data.album || typeof data.album !== 'object') {
|
||||||
|
data.album = data.al && typeof data.al === 'object' ? data.al : { name: '' };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data.album.name) {
|
||||||
|
data.album.name = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 音乐解析函数
|
* 音乐解析函数
|
||||||
* @param id 歌曲ID
|
* @param id 歌曲ID
|
||||||
@@ -46,16 +89,18 @@ const unblockMusic = async (
|
|||||||
retryCount = 1,
|
retryCount = 1,
|
||||||
enabledPlatforms?: Platform[]
|
enabledPlatforms?: Platform[]
|
||||||
): Promise<UnblockResult> => {
|
): Promise<UnblockResult> => {
|
||||||
|
|
||||||
// 过滤 enabledPlatforms,确保只包含 ALL_PLATFORMS 中存在的平台
|
// 过滤 enabledPlatforms,确保只包含 ALL_PLATFORMS 中存在的平台
|
||||||
const filteredPlatforms = enabledPlatforms
|
const filteredPlatforms = enabledPlatforms
|
||||||
? enabledPlatforms.filter(platform => ALL_PLATFORMS.includes(platform))
|
? enabledPlatforms.filter(platform => ALL_PLATFORMS.includes(platform))
|
||||||
: ALL_PLATFORMS;
|
: ALL_PLATFORMS;
|
||||||
|
|
||||||
songData.album = songData.album || songData.al;
|
// 处理歌曲数据,确保数据结构完整
|
||||||
songData.artists = songData.artists || songData.ar;
|
const processedSongData = ensureDataStructure(songData);
|
||||||
|
|
||||||
const retry = async (attempt: number): Promise<UnblockResult> => {
|
const retry = async (attempt: number): Promise<UnblockResult> => {
|
||||||
try {
|
try {
|
||||||
const data = await match(parseInt(String(id), 10), filteredPlatforms, songData);
|
const data = await match(parseInt(String(id), 10), filteredPlatforms, processedSongData);
|
||||||
const result: UnblockResult = {
|
const result: UnblockResult = {
|
||||||
data: {
|
data: {
|
||||||
data,
|
data,
|
||||||
|
|||||||
+94
-48
@@ -82,6 +82,66 @@ export const getMusicLrc = async (id: number) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从Bilibili获取音频URL
|
||||||
|
* @param data 歌曲数据
|
||||||
|
* @returns 解析结果
|
||||||
|
*/
|
||||||
|
const getBilibiliAudio = async (data: SongResult) => {
|
||||||
|
const songName = data?.name || '';
|
||||||
|
const artistName = Array.isArray(data?.ar) && data.ar.length > 0 && data.ar[0]?.name ? data.ar[0].name : '';
|
||||||
|
const albumName = data?.al && typeof data.al === 'object' && data.al?.name ? data.al.name : '';
|
||||||
|
|
||||||
|
const searchQuery = [songName, artistName, albumName].filter(Boolean).join(' ').trim();
|
||||||
|
console.log('开始搜索bilibili音频:', searchQuery);
|
||||||
|
|
||||||
|
const url = await searchAndGetBilibiliAudioUrl(searchQuery);
|
||||||
|
return {
|
||||||
|
data: {
|
||||||
|
code: 200,
|
||||||
|
message: 'success',
|
||||||
|
data: { url }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从GD音乐台获取音频URL
|
||||||
|
* @param id 歌曲ID
|
||||||
|
* @param data 歌曲数据
|
||||||
|
* @returns 解析结果,失败时返回null
|
||||||
|
*/
|
||||||
|
const getGDMusicAudio = async (id: number, data: SongResult) => {
|
||||||
|
try {
|
||||||
|
const gdResult = await parseFromGDMusic(id, data, '999');
|
||||||
|
if (gdResult) {
|
||||||
|
return gdResult;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('GD音乐台解析失败:', error);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用unblockMusic解析音频URL
|
||||||
|
* @param id 歌曲ID
|
||||||
|
* @param data 歌曲数据
|
||||||
|
* @param sources 音源列表
|
||||||
|
* @returns 解析结果
|
||||||
|
*/
|
||||||
|
const getUnblockMusicAudio = (id: number, data: SongResult, sources: any[]) => {
|
||||||
|
const filteredSources = sources.filter(source => source !== 'gdmusic');
|
||||||
|
console.log(`使用unblockMusic解析,音源:`, filteredSources);
|
||||||
|
return window.api.unblockMusic(id, cloneDeep(data), cloneDeep(filteredSources));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取解析后的音乐URL
|
||||||
|
* @param id 歌曲ID
|
||||||
|
* @param data 歌曲数据
|
||||||
|
* @returns 解析结果
|
||||||
|
*/
|
||||||
export const getParsingMusicUrl = async (id: number, data: SongResult) => {
|
export const getParsingMusicUrl = async (id: number, data: SongResult) => {
|
||||||
const settingStore = useSettingsStore();
|
const settingStore = useSettingsStore();
|
||||||
|
|
||||||
@@ -90,65 +150,51 @@ export const getParsingMusicUrl = async (id: number, data: SongResult) => {
|
|||||||
return Promise.resolve({ data: { code: 404, message: '音乐解析功能已禁用' } });
|
return Promise.resolve({ data: { code: 404, message: '音乐解析功能已禁用' } });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取音源设置,优先使用歌曲自定义音源
|
// 1. 确定使用的音源列表(自定义或全局)
|
||||||
const songId = String(id);
|
const songId = String(id);
|
||||||
const savedSource = localStorage.getItem(`song_source_${songId}`);
|
const savedSourceStr = localStorage.getItem(`song_source_${songId}`);
|
||||||
let enabledSources: any[] = [];
|
let musicSources: any[] = [];
|
||||||
|
|
||||||
// 如果有歌曲自定义音源,使用自定义音源
|
try {
|
||||||
if (savedSource) {
|
if (savedSourceStr) {
|
||||||
try {
|
// 使用自定义音源
|
||||||
enabledSources = JSON.parse(savedSource);
|
musicSources = JSON.parse(savedSourceStr);
|
||||||
console.log(`使用歌曲 ${id} 自定义音源:`, enabledSources);
|
console.log(`使用歌曲 ${id} 自定义音源:`, musicSources);
|
||||||
if(enabledSources.includes('bilibili')){
|
} else {
|
||||||
// 构建搜索关键词,依次判断歌曲名称、歌手名称和专辑名称是否存在
|
// 使用全局音源设置
|
||||||
const songName = data?.name || '';
|
musicSources = settingStore.setData.enabledMusicSources || [];
|
||||||
const artistName = Array.isArray(data?.ar) && data.ar.length > 0 && data.ar[0]?.name ? data.ar[0].name : '';
|
console.log(`使用全局音源设置:`, musicSources);
|
||||||
const albumName = data?.al && typeof data.al === 'object' && data.al?.name ? data.al.name : '';
|
if (isElectron && musicSources.length > 0) {
|
||||||
const name = [songName, artistName, albumName].filter(Boolean).join(' ').trim();
|
return getUnblockMusicAudio(id, data, musicSources);
|
||||||
console.log('开始搜索bilibili音频', name);
|
|
||||||
return {
|
|
||||||
data: {
|
|
||||||
code: 200,
|
|
||||||
message: 'success',
|
|
||||||
data: {
|
|
||||||
url: await searchAndGetBilibiliAudioUrl(name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
|
||||||
console.error('e',e)
|
|
||||||
console.error('解析自定义音源失败, 使用全局设置', e);
|
|
||||||
enabledSources = settingStore.setData.enabledMusicSources || [];
|
|
||||||
}
|
}
|
||||||
} else {
|
} catch (e) {
|
||||||
// 没有自定义音源,使用全局音源设置
|
console.error('解析音源设置失败,使用全局设置', e);
|
||||||
enabledSources = settingStore.setData.enabledMusicSources || [];
|
musicSources = settingStore.setData.enabledMusicSources || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否选择了GD音乐台解析
|
// 2. 按优先级解析
|
||||||
|
|
||||||
if (enabledSources.includes('gdmusic')) {
|
// 2.1 Bilibili解析(优先级最高)
|
||||||
// 获取音质设置并转换为GD音乐台格式
|
if (musicSources.includes('bilibili')) {
|
||||||
try {
|
return await getBilibiliAudio(data);
|
||||||
const gdResult = await parseFromGDMusic(id, data, '999');
|
|
||||||
if (gdResult) {
|
|
||||||
return gdResult;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('GD音乐台解析失败:', error);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('GD音乐台所有音源均解析失败,尝试使用unblockMusic');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果GD音乐台解析失败或者未启用,尝试使用unblockMusic
|
// 2.2 GD音乐台解析
|
||||||
if (isElectron) {
|
if (musicSources.includes('gdmusic')) {
|
||||||
const filteredSources = enabledSources.filter(source => source !== 'gdmusic');
|
const gdResult = await getGDMusicAudio(id, data);
|
||||||
return window.api.unblockMusic(id, cloneDeep(data), cloneDeep(filteredSources));
|
if (gdResult) return gdResult;
|
||||||
|
// GD解析失败,继续下一步
|
||||||
|
console.log('GD音乐台解析失败,尝试使用其他音源');
|
||||||
|
}
|
||||||
|
console.log('musicSources',musicSources)
|
||||||
|
// 2.3 使用unblockMusic解析其他音源
|
||||||
|
if (isElectron && musicSources.length > 0) {
|
||||||
|
return getUnblockMusicAudio(id, data, musicSources);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 3. 后备方案:使用API请求
|
||||||
|
console.log('无可用音源或不在Electron环境中,使用API请求');
|
||||||
return requestMusic.get<any>('/music', { params: { id } });
|
return requestMusic.get<any>('/music', { params: { id } });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -67,10 +67,10 @@ const visible = ref(props.show);
|
|||||||
const selectedSources = ref<Platform[]>(props.sources);
|
const selectedSources = ref<Platform[]>(props.sources);
|
||||||
|
|
||||||
const musicSourceOptions = ref([
|
const musicSourceOptions = ref([
|
||||||
{ label: 'MiGu音乐', value: 'migu' },
|
{ label: 'MG', value: 'migu' },
|
||||||
{ label: '酷狗音乐', value: 'kugou' },
|
{ label: 'KG', value: 'kugou' },
|
||||||
{ label: 'pyncmd', value: 'pyncmd' },
|
{ label: 'pyncmd', value: 'pyncmd' },
|
||||||
{ label: 'Bilibili音乐', value: 'bilibili' },
|
{ label: 'Bilibili', value: 'bilibili' },
|
||||||
{ label: 'GD音乐台', value: 'gdmusic' }
|
{ label: 'GD音乐台', value: 'gdmusic' }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -811,6 +811,40 @@ class AudioService {
|
|||||||
|
|
||||||
console.log('Volume applied (linear):', linearVolume);
|
console.log('Volume applied (linear):', linearVolume);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加方法检查当前音频是否在加载状态
|
||||||
|
isLoading(): boolean {
|
||||||
|
if (!this.currentSound) return false;
|
||||||
|
|
||||||
|
// 检查Howl对象的内部状态
|
||||||
|
// 如果状态为1表示已经加载但未完成,状态为2表示正在加载
|
||||||
|
const state = (this.currentSound as any)._state;
|
||||||
|
// 如果操作锁激活也认为是加载状态
|
||||||
|
return this.operationLock || (state === 'loading' || state === 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查音频是否真正在播放
|
||||||
|
isActuallyPlaying(): boolean {
|
||||||
|
if (!this.currentSound) return false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 综合判断:
|
||||||
|
// 1. Howler API是否报告正在播放
|
||||||
|
// 2. 是否不在加载状态
|
||||||
|
// 3. 确保音频上下文状态正常
|
||||||
|
const isPlaying = this.currentSound.playing();
|
||||||
|
const isLoading = this.isLoading();
|
||||||
|
const contextRunning = Howler.ctx && Howler.ctx.state === 'running';
|
||||||
|
|
||||||
|
console.log(`实际播放状态检查: playing=${isPlaying}, loading=${isLoading}, contextRunning=${contextRunning}`);
|
||||||
|
|
||||||
|
// 只有在三个条件都满足时才认为是真正在播放
|
||||||
|
return isPlaying && !isLoading && contextRunning;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('检查播放状态出错:', error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const audioService = new AudioService();
|
export const audioService = new AudioService();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { cloneDeep } from 'lodash';
|
import { cloneDeep } from 'lodash';
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
|
import { useThrottleFn } from '@vueuse/core';
|
||||||
|
|
||||||
import i18n from '@/../i18n/renderer';
|
import i18n from '@/../i18n/renderer';
|
||||||
import { getBilibiliAudioUrl } from '@/api/bilibili';
|
import { getBilibiliAudioUrl } from '@/api/bilibili';
|
||||||
@@ -556,16 +557,95 @@ export const usePlayerStore = defineStore('player', () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 添加用户意图跟踪变量
|
||||||
|
const userPlayIntent = ref(true);
|
||||||
|
|
||||||
|
let checkPlayTime: NodeJS.Timeout | null = null;
|
||||||
|
|
||||||
|
// 添加独立的播放状态检测函数
|
||||||
|
const checkPlaybackState = (song: SongResult, timeout: number = 4000) => {
|
||||||
|
if(checkPlayTime) {
|
||||||
|
clearTimeout(checkPlayTime);
|
||||||
|
}
|
||||||
|
const sound = audioService.getCurrentSound();
|
||||||
|
if (!sound) return;
|
||||||
|
|
||||||
|
// 使用audioService的事件系统监听播放状态
|
||||||
|
// 添加一次性播放事件监听器
|
||||||
|
const onPlayHandler = () => {
|
||||||
|
// 播放事件触发,表示成功播放
|
||||||
|
console.log('播放事件触发,歌曲成功开始播放');
|
||||||
|
audioService.off('play', onPlayHandler);
|
||||||
|
audioService.off('playerror', onPlayErrorHandler);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加一次性播放错误事件监听器
|
||||||
|
const onPlayErrorHandler = async () => {
|
||||||
|
console.log('播放错误事件触发,尝试重新获取URL');
|
||||||
|
audioService.off('play', onPlayHandler);
|
||||||
|
audioService.off('playerror', onPlayErrorHandler);
|
||||||
|
|
||||||
|
// 只有用户仍然希望播放时才重试
|
||||||
|
if (userPlayIntent.value && play.value) {
|
||||||
|
// 重置URL并重新播放
|
||||||
|
playMusic.value.playMusicUrl = undefined;
|
||||||
|
// 保持播放状态,但强制重新获取URL
|
||||||
|
const refreshedSong = { ...song, isFirstPlay: true };
|
||||||
|
await handlePlayMusic(refreshedSong, true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 注册事件监听器
|
||||||
|
audioService.on('play', onPlayHandler);
|
||||||
|
audioService.on('playerror', onPlayErrorHandler);
|
||||||
|
|
||||||
|
// 额外的安全检查:如果指定时间后仍未播放也未触发错误,且用户仍希望播放
|
||||||
|
checkPlayTime = setTimeout(() => {
|
||||||
|
// 使用更准确的方法检查是否真正在播放
|
||||||
|
if (!audioService.isActuallyPlaying() && userPlayIntent.value && play.value) {
|
||||||
|
console.log(`${timeout}ms后歌曲未真正播放且用户仍希望播放,尝试重新获取URL`);
|
||||||
|
// 移除事件监听器
|
||||||
|
audioService.off('play', onPlayHandler);
|
||||||
|
audioService.off('playerror', onPlayErrorHandler);
|
||||||
|
|
||||||
|
// 重置URL并重新播放
|
||||||
|
playMusic.value.playMusicUrl = undefined;
|
||||||
|
// 保持播放状态,强制重新获取URL
|
||||||
|
(async () => {
|
||||||
|
const refreshedSong = { ...song, isFirstPlay: true };
|
||||||
|
await handlePlayMusic(refreshedSong, true);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
}, timeout);
|
||||||
|
};
|
||||||
|
|
||||||
const setPlay = async (song: SongResult) => {
|
const setPlay = async (song: SongResult) => {
|
||||||
try {
|
try {
|
||||||
// 如果是当前正在播放的音乐,则切换播放/暂停状态
|
// 检查URL是否已过期
|
||||||
if (playMusic.value.id === song.id && playMusic.value.playMusicUrl === song.playMusicUrl && !song.isFirstPlay) {
|
if (song.expiredAt && song.expiredAt < Date.now()) {
|
||||||
if (play.value) {
|
console.info(`歌曲URL已过期,重新获取: ${song.name}`);
|
||||||
|
song.playMusicUrl = undefined;
|
||||||
|
// 重置过期时间,以便重新获取
|
||||||
|
song.expiredAt = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是当前正在播放的音乐,则切换播放/暂停状态
|
||||||
|
if (playMusic.value.id === song.id && playMusic.value.playMusicUrl === song.playMusicUrl && !song.isFirstPlay) {
|
||||||
|
if (play.value) {
|
||||||
setPlayMusic(false);
|
setPlayMusic(false);
|
||||||
audioService.getCurrentSound()?.pause();
|
audioService.getCurrentSound()?.pause();
|
||||||
|
// 设置用户意图为暂停
|
||||||
|
userPlayIntent.value = false;
|
||||||
} else {
|
} else {
|
||||||
setPlayMusic(true);
|
setPlayMusic(true);
|
||||||
audioService.getCurrentSound()?.play();
|
// 设置用户意图为播放
|
||||||
|
userPlayIntent.value = true;
|
||||||
|
const sound = audioService.getCurrentSound();
|
||||||
|
if (sound) {
|
||||||
|
sound.play();
|
||||||
|
// 使用独立的播放状态检测函数
|
||||||
|
checkPlaybackState(playMusic.value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -600,10 +680,14 @@ export const usePlayerStore = defineStore('player', () => {
|
|||||||
const setPlayMusic = async (value: boolean | SongResult) => {
|
const setPlayMusic = async (value: boolean | SongResult) => {
|
||||||
if (typeof value === 'boolean') {
|
if (typeof value === 'boolean') {
|
||||||
setIsPlay(value);
|
setIsPlay(value);
|
||||||
|
// 记录用户的播放意图
|
||||||
|
userPlayIntent.value = value;
|
||||||
} else {
|
} else {
|
||||||
await handlePlayMusic(value);
|
await handlePlayMusic(value);
|
||||||
play.value = true;
|
play.value = true;
|
||||||
isPlay.value = true;
|
isPlay.value = true;
|
||||||
|
// 设置为播放意图
|
||||||
|
userPlayIntent.value = true;
|
||||||
localStorage.setItem('currentPlayMusic', JSON.stringify(playMusic.value));
|
localStorage.setItem('currentPlayMusic', JSON.stringify(playMusic.value));
|
||||||
localStorage.setItem('currentPlayMusicUrl', playMusicUrl.value);
|
localStorage.setItem('currentPlayMusicUrl', playMusicUrl.value);
|
||||||
}
|
}
|
||||||
@@ -803,8 +887,7 @@ export const usePlayerStore = defineStore('player', () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 修改nextPlay方法,改进播放逻辑
|
const _nextPlay = async () => {
|
||||||
const nextPlay = async () => {
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
@@ -927,9 +1010,10 @@ export const usePlayerStore = defineStore('player', () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 修改 prevPlay 方法,使用与 nextPlay 相似的逻辑改进
|
// 节流
|
||||||
const prevPlay = async () => {
|
const nextPlay = useThrottleFn(_nextPlay, 500);
|
||||||
|
|
||||||
|
const _prevPlay = async () => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
@@ -1010,6 +1094,9 @@ export const usePlayerStore = defineStore('player', () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 节流
|
||||||
|
const prevPlay = useThrottleFn(_prevPlay, 500);
|
||||||
|
|
||||||
const togglePlayMode = () => {
|
const togglePlayMode = () => {
|
||||||
playMode.value = (playMode.value + 1) % 3;
|
playMode.value = (playMode.value + 1) % 3;
|
||||||
localStorage.setItem('playMode', JSON.stringify(playMode.value));
|
localStorage.setItem('playMode', JSON.stringify(playMode.value));
|
||||||
@@ -1185,6 +1272,12 @@ export const usePlayerStore = defineStore('player', () => {
|
|||||||
// 播放新音频,传递是否应该播放的状态
|
// 播放新音频,传递是否应该播放的状态
|
||||||
console.log('调用audioService.play,播放状态:', shouldPlay);
|
console.log('调用audioService.play,播放状态:', shouldPlay);
|
||||||
const newSound = await audioService.play(playMusicUrl.value, playMusic.value, shouldPlay, initialPosition || 0);
|
const newSound = await audioService.play(playMusicUrl.value, playMusic.value, shouldPlay, initialPosition || 0);
|
||||||
|
|
||||||
|
// 添加播放状态检测(仅当需要播放时)
|
||||||
|
if (shouldPlay) {
|
||||||
|
checkPlaybackState(playMusic.value);
|
||||||
|
}
|
||||||
|
|
||||||
// 发布音频就绪事件,让 MusicHook.ts 来处理设置监听器
|
// 发布音频就绪事件,让 MusicHook.ts 来处理设置监听器
|
||||||
window.dispatchEvent(new CustomEvent('audio-ready', { detail: { sound: newSound, shouldPlay } }));
|
window.dispatchEvent(new CustomEvent('audio-ready', { detail: { sound: newSound, shouldPlay } }));
|
||||||
|
|
||||||
@@ -1215,15 +1308,18 @@ export const usePlayerStore = defineStore('player', () => {
|
|||||||
|
|
||||||
// 延迟较长时间,确保锁已完全释放
|
// 延迟较长时间,确保锁已完全释放
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// 直接重试当前歌曲,而不是切换到下一首
|
// 如果用户仍希望播放
|
||||||
playAudio().catch(e => {
|
if (userPlayIntent.value && play.value) {
|
||||||
console.error('重试播放失败,切换到下一首:', e);
|
// 直接重试当前歌曲,而不是切换到下一首
|
||||||
|
playAudio().catch(e => {
|
||||||
// 只有再次失败才切换到下一首
|
console.error('重试播放失败,切换到下一首:', e);
|
||||||
if (playList.value.length > 1) {
|
|
||||||
nextPlay();
|
// 只有再次失败才切换到下一首
|
||||||
}
|
if (playList.value.length > 1) {
|
||||||
});
|
nextPlay();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
} else {
|
} else {
|
||||||
// 其他错误,切换到下一首
|
// 其他错误,切换到下一首
|
||||||
@@ -1253,7 +1349,7 @@ export const usePlayerStore = defineStore('player', () => {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存用户选择的音源
|
// 保存用户选择的音源(作为数组传递,确保unblockMusic可以使用)
|
||||||
const songId = String(currentSong.id);
|
const songId = String(currentSong.id);
|
||||||
localStorage.setItem(`song_source_${songId}`, JSON.stringify([sourcePlatform]));
|
localStorage.setItem(`song_source_${songId}`, JSON.stringify([sourcePlatform]));
|
||||||
|
|
||||||
@@ -1267,11 +1363,17 @@ export const usePlayerStore = defineStore('player', () => {
|
|||||||
const numericId = typeof currentSong.id === 'string'
|
const numericId = typeof currentSong.id === 'string'
|
||||||
? parseInt(currentSong.id, 10)
|
? parseInt(currentSong.id, 10)
|
||||||
: currentSong.id;
|
: currentSong.id;
|
||||||
|
|
||||||
|
console.log(`使用音源 ${sourcePlatform} 重新解析歌曲 ${numericId}`);
|
||||||
|
|
||||||
const res = await getParsingMusicUrl(numericId, cloneDeep(currentSong));
|
// 克隆一份歌曲数据,防止修改原始数据
|
||||||
|
const songData = cloneDeep(currentSong);
|
||||||
|
|
||||||
|
const res = await getParsingMusicUrl(numericId, songData);
|
||||||
if (res && res.data && res.data.data && res.data.data.url) {
|
if (res && res.data && res.data.data && res.data.data.url) {
|
||||||
// 更新URL
|
// 更新URL
|
||||||
const newUrl = res.data.data.url;
|
const newUrl = res.data.data.url;
|
||||||
|
console.log(`解析成功,获取新URL: ${newUrl.substring(0, 50)}...`);
|
||||||
|
|
||||||
// 使用新URL更新播放
|
// 使用新URL更新播放
|
||||||
const updatedMusic = {
|
const updatedMusic = {
|
||||||
@@ -1286,6 +1388,7 @@ export const usePlayerStore = defineStore('player', () => {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
console.warn(`使用音源 ${sourcePlatform} 解析失败`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -1307,6 +1410,8 @@ export const usePlayerStore = defineStore('player', () => {
|
|||||||
currentSound.pause();
|
currentSound.pause();
|
||||||
}
|
}
|
||||||
setPlayMusic(false);
|
setPlayMusic(false);
|
||||||
|
// 明确设置用户意图为暂停
|
||||||
|
userPlayIntent.value = false;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('暂停播放失败:', error);
|
console.error('暂停播放失败:', error);
|
||||||
}
|
}
|
||||||
@@ -1345,8 +1450,8 @@ export const usePlayerStore = defineStore('player', () => {
|
|||||||
clearPlayAll,
|
clearPlayAll,
|
||||||
setPlay,
|
setPlay,
|
||||||
setIsPlay,
|
setIsPlay,
|
||||||
nextPlay,
|
nextPlay: nextPlay as unknown as typeof _nextPlay,
|
||||||
prevPlay,
|
prevPlay: prevPlay as unknown as typeof _prevPlay,
|
||||||
setPlayMusic,
|
setPlayMusic,
|
||||||
setMusicFull,
|
setMusicFull,
|
||||||
setPlayList,
|
setPlayList,
|
||||||
|
|||||||
Reference in New Issue
Block a user