mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-05-17 02:07:29 +08:00
✨ feat: 更新网易云音乐 API 版本,添加 B站视频搜索功能和播放器组件
This commit is contained in:
@@ -24,13 +24,27 @@ function getLocalStorageItem<T>(key: string, defaultValue: T): T {
|
||||
}
|
||||
}
|
||||
|
||||
export const getSongUrl = async (id: number, songData: any, isDownloaded: boolean = false) => {
|
||||
const { data } = await getMusicUrl(id, isDownloaded);
|
||||
export const getSongUrl = async (
|
||||
id: string | number,
|
||||
songData: SongResult,
|
||||
isDownloaded: boolean = false
|
||||
) => {
|
||||
if (songData.playMusicUrl) {
|
||||
return songData.playMusicUrl;
|
||||
}
|
||||
|
||||
if (songData.source === 'bilibili' && songData.bilibiliData) {
|
||||
console.log('加载B站音频URL');
|
||||
return songData.playMusicUrl || '';
|
||||
}
|
||||
|
||||
const numericId = typeof id === 'string' ? parseInt(id, 10) : id;
|
||||
const { data } = await getMusicUrl(numericId, isDownloaded);
|
||||
let url = '';
|
||||
let songDetail = null;
|
||||
try {
|
||||
if (data.data[0].freeTrialInfo || !data.data[0].url) {
|
||||
const res = await getParsingMusicUrl(id, songData);
|
||||
const res = await getParsingMusicUrl(numericId, cloneDeep(songData));
|
||||
url = res.data.data.url;
|
||||
songDetail = res.data.data;
|
||||
} else {
|
||||
@@ -45,6 +59,7 @@ export const getSongUrl = async (id: number, songData: any, isDownloaded: boolea
|
||||
url = url || data.data[0].url;
|
||||
return url;
|
||||
};
|
||||
|
||||
const parseTime = (timeString: string): number => {
|
||||
const [minutes, seconds] = timeString.split(':');
|
||||
return Number(minutes) * 60 + Number(seconds);
|
||||
@@ -71,9 +86,18 @@ const parseLyrics = (lyricsString: string): { lyrics: ILyricText[]; times: numbe
|
||||
return { lyrics, times };
|
||||
};
|
||||
|
||||
export const loadLrc = async (playMusicId: number): Promise<ILyric> => {
|
||||
export const loadLrc = async (id: string | number): Promise<ILyric> => {
|
||||
if (typeof id === 'string' && id.includes('--')) {
|
||||
console.log('B站音频,无需加载歌词');
|
||||
return {
|
||||
lrcTimeArray: [],
|
||||
lrcArray: []
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const { data } = await getMusicLrc(playMusicId);
|
||||
const numericId = typeof id === 'string' ? parseInt(id, 10) : id;
|
||||
const { data } = await getMusicLrc(numericId);
|
||||
const { lyrics, times } = parseLyrics(data.lrc.lyric);
|
||||
const tlyric: Record<string, string> = {};
|
||||
|
||||
@@ -102,8 +126,19 @@ export const loadLrc = async (playMusicId: number): Promise<ILyric> => {
|
||||
|
||||
const getSongDetail = async (playMusic: SongResult) => {
|
||||
playMusic.playLoading = true;
|
||||
const playMusicUrl =
|
||||
playMusic.playMusicUrl || (await getSongUrl(playMusic.id, cloneDeep(playMusic)));
|
||||
|
||||
if (playMusic.source === 'bilibili') {
|
||||
console.log('处理B站音频详情');
|
||||
const { backgroundColor, primaryColor } =
|
||||
playMusic.backgroundColor && playMusic.primaryColor
|
||||
? playMusic
|
||||
: await getImageLinearBackground(getImgUrl(playMusic?.picUrl, '30y30'));
|
||||
|
||||
playMusic.playLoading = false;
|
||||
return { ...playMusic, backgroundColor, primaryColor } as SongResult;
|
||||
}
|
||||
|
||||
const playMusicUrl = playMusic.playMusicUrl || (await getSongUrl(playMusic.id, playMusic));
|
||||
const { backgroundColor, primaryColor } =
|
||||
playMusic.backgroundColor && playMusic.primaryColor
|
||||
? playMusic
|
||||
@@ -115,7 +150,6 @@ const getSongDetail = async (playMusic: SongResult) => {
|
||||
|
||||
const preloadNextSong = (nextSongUrl: string) => {
|
||||
try {
|
||||
// 限制同时预加载的数量
|
||||
if (preloadingSounds.value.length >= 2) {
|
||||
const oldestSound = preloadingSounds.value.shift();
|
||||
if (oldestSound) {
|
||||
@@ -132,7 +166,6 @@ const preloadNextSong = (nextSongUrl: string) => {
|
||||
|
||||
preloadingSounds.value.push(sound);
|
||||
|
||||
// 添加加载错误处理
|
||||
sound.on('loaderror', () => {
|
||||
console.error('预加载音频失败:', nextSongUrl);
|
||||
const index = preloadingSounds.value.indexOf(sound);
|
||||
@@ -156,8 +189,7 @@ const fetchSongs = async (playList: SongResult[], startIndex: number, endIndex:
|
||||
const detailedSongs = await Promise.all(
|
||||
songs.map(async (song: SongResult) => {
|
||||
try {
|
||||
// 如果歌曲详情已经存在,就不重复请求
|
||||
if (!song.playMusicUrl) {
|
||||
if (!song.playMusicUrl || (song.source === 'netease' && !song.backgroundColor)) {
|
||||
return await getSongDetail(song);
|
||||
}
|
||||
return song;
|
||||
@@ -168,7 +200,6 @@ const fetchSongs = async (playList: SongResult[], startIndex: number, endIndex:
|
||||
})
|
||||
);
|
||||
|
||||
// 加载下一首的歌词
|
||||
const nextSong = detailedSongs[0];
|
||||
if (nextSong && !(nextSong.lyric && nextSong.lyric.lrcTimeArray.length > 0)) {
|
||||
try {
|
||||
@@ -178,14 +209,12 @@ const fetchSongs = async (playList: SongResult[], startIndex: number, endIndex:
|
||||
}
|
||||
}
|
||||
|
||||
// 更新播放列表中的歌曲详情
|
||||
detailedSongs.forEach((song, index) => {
|
||||
if (song && startIndex + index < playList.length) {
|
||||
playList[startIndex + index] = song;
|
||||
}
|
||||
});
|
||||
|
||||
// 只预加载下一首歌曲
|
||||
if (nextSong && nextSong.playMusicUrl) {
|
||||
preloadNextSong(nextSong.playMusicUrl);
|
||||
}
|
||||
@@ -194,7 +223,6 @@ const fetchSongs = async (playList: SongResult[], startIndex: number, endIndex:
|
||||
}
|
||||
};
|
||||
|
||||
// 异步加载歌词的方法
|
||||
const loadLrcAsync = async (playMusic: SongResult) => {
|
||||
if (playMusic.lyric && playMusic.lyric.lrcTimeArray.length > 0) {
|
||||
return;
|
||||
@@ -204,7 +232,6 @@ const loadLrcAsync = async (playMusic: SongResult) => {
|
||||
};
|
||||
|
||||
export const usePlayerStore = defineStore('player', () => {
|
||||
// 状态
|
||||
const play = ref(false);
|
||||
const isPlay = ref(false);
|
||||
const playMusic = ref<SongResult>(getLocalStorageItem('currentPlayMusic', {} as SongResult));
|
||||
@@ -216,7 +243,6 @@ export const usePlayerStore = defineStore('player', () => {
|
||||
const favoriteList = ref<number[]>(getLocalStorageItem('favoriteList', []));
|
||||
const savedPlayProgress = ref<number | undefined>();
|
||||
|
||||
// 计算属性
|
||||
const currentSong = computed(() => playMusic.value);
|
||||
const isPlaying = computed(() => isPlay.value);
|
||||
const currentPlayList = computed(() => playList.value);
|
||||
@@ -227,24 +253,36 @@ export const usePlayerStore = defineStore('player', () => {
|
||||
playMusic.value = updatedPlayMusic;
|
||||
playMusicUrl.value = updatedPlayMusic.playMusicUrl as string;
|
||||
|
||||
// 记录当前设置的播放状态
|
||||
play.value = isPlay;
|
||||
|
||||
// 每次设置新歌曲时,立即更新 localStorage
|
||||
localStorage.setItem('currentPlayMusic', JSON.stringify(playMusic.value));
|
||||
localStorage.setItem('currentPlayMusicUrl', playMusicUrl.value);
|
||||
localStorage.setItem('isPlaying', play.value.toString());
|
||||
|
||||
// 设置网页标题
|
||||
document.title = `${updatedPlayMusic.name} - ${updatedPlayMusic?.song?.artists?.reduce((prev, curr) => `${prev}${curr.name}/`, '')}`;
|
||||
let title = updatedPlayMusic.name;
|
||||
|
||||
if (updatedPlayMusic.source === 'netease' && updatedPlayMusic?.song?.artists) {
|
||||
title += ` - ${updatedPlayMusic.song.artists.reduce(
|
||||
(prev: string, curr: any) => `${prev}${curr.name}/`,
|
||||
''
|
||||
)}`;
|
||||
} else if (updatedPlayMusic.source === 'bilibili' && updatedPlayMusic?.song?.ar?.[0]) {
|
||||
title += ` - ${updatedPlayMusic.song.ar[0].name}`;
|
||||
}
|
||||
|
||||
document.title = title;
|
||||
|
||||
loadLrcAsync(playMusic.value);
|
||||
|
||||
musicHistory.addMusic(playMusic.value);
|
||||
playListIndex.value = playList.value.findIndex((item: SongResult) => item.id === music.id);
|
||||
// 请求后续五首歌曲的详情
|
||||
|
||||
playListIndex.value = playList.value.findIndex(
|
||||
(item: SongResult) => item.id === music.id && item.source === music.source
|
||||
);
|
||||
|
||||
fetchSongs(playList.value, playListIndex.value + 1, playListIndex.value + 6);
|
||||
};
|
||||
|
||||
// 方法
|
||||
const setPlay = async (song: SongResult) => {
|
||||
await handlePlayMusic(song);
|
||||
localStorage.setItem('currentPlayMusic', JSON.stringify(playMusic.value));
|
||||
@@ -303,12 +341,10 @@ export const usePlayerStore = defineStore('player', () => {
|
||||
let nowPlayListIndex: number;
|
||||
|
||||
if (playMode.value === 2) {
|
||||
// 随机播放模式
|
||||
do {
|
||||
nowPlayListIndex = Math.floor(Math.random() * playList.value.length);
|
||||
} while (nowPlayListIndex === playListIndex.value && playList.value.length > 1);
|
||||
} else {
|
||||
// 列表循环模式
|
||||
nowPlayListIndex = (playListIndex.value + 1) % playList.value.length;
|
||||
}
|
||||
|
||||
@@ -344,7 +380,6 @@ export const usePlayerStore = defineStore('player', () => {
|
||||
localStorage.setItem('favoriteList', JSON.stringify(favoriteList.value));
|
||||
};
|
||||
|
||||
// 初始化播放状态
|
||||
const initializePlayState = async () => {
|
||||
const settingStore = useSettingsStore();
|
||||
const savedPlayList = getLocalStorageItem('playList', []);
|
||||
@@ -390,16 +425,13 @@ export const usePlayerStore = defineStore('player', () => {
|
||||
|
||||
const initializeFavoriteList = async () => {
|
||||
const userStore = useUserStore();
|
||||
// 先获取本地收藏列表
|
||||
const localFavoriteList = localStorage.getItem('favoriteList');
|
||||
const localList: number[] = localFavoriteList ? JSON.parse(localFavoriteList) : [];
|
||||
|
||||
// 如果用户已登录,尝试获取服务器收藏列表并合并
|
||||
if (userStore.user && userStore.user.userId) {
|
||||
try {
|
||||
const res = await getLikedList(userStore.user.userId);
|
||||
if (res.data?.ids) {
|
||||
// 合并本地和服务器的收藏列表,去重
|
||||
const serverList = res.data.ids.reverse();
|
||||
const mergedList = Array.from(new Set([...localList, ...serverList]));
|
||||
favoriteList.value = mergedList;
|
||||
@@ -414,12 +446,10 @@ export const usePlayerStore = defineStore('player', () => {
|
||||
favoriteList.value = localList;
|
||||
}
|
||||
|
||||
// 更新本地存储
|
||||
localStorage.setItem('favoriteList', JSON.stringify(favoriteList.value));
|
||||
};
|
||||
|
||||
return {
|
||||
// 状态
|
||||
play,
|
||||
isPlay,
|
||||
playMusic,
|
||||
@@ -431,13 +461,11 @@ export const usePlayerStore = defineStore('player', () => {
|
||||
savedPlayProgress,
|
||||
favoriteList,
|
||||
|
||||
// 计算属性
|
||||
currentSong,
|
||||
isPlaying,
|
||||
currentPlayList,
|
||||
currentPlayListIndex,
|
||||
|
||||
// 方法
|
||||
setPlay,
|
||||
setIsPlay,
|
||||
nextPlay,
|
||||
|
||||
Reference in New Issue
Block a user