mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-05-17 10:27:30 +08:00
refactor(player): 重构播放控制系统,移除 Howler.js 改用原生 HTMLAudioElement
- 新建 playbackController.ts,使用 generation-based 取消替代 playbackRequestManager 状态机 - audioService 重写:单一持久 HTMLAudioElement + Web Audio API,createMediaElementSource 只调一次 - playerCore 瘦身为纯状态管理,移除 handlePlayMusic/playAudio/checkPlaybackState - playlist next/prev 简化,区分用户手动切歌和歌曲自然播完 - MusicHook 适配 HTMLAudioElement API(.currentTime/.duration/.paused) - preloadService 从 Howl 实例缓存改为 URL 可用性验证 - 所有 view/component 调用者迁移到 playbackController.playTrack() 修复:快速切歌竞态、seek 到未缓冲位置失败、重启后自动播放循环提示、EQ 重建崩溃
This commit is contained in:
@@ -99,9 +99,9 @@ import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
import { getNewAlbums } from '@/api/album';
|
||||
import { getAlbum } from '@/api/list';
|
||||
import StickyTabPage from '@/components/common/StickyTabPage.vue';
|
||||
import { navigateToMusicList } from '@/components/common/MusicListNavigator';
|
||||
import { usePlayerCoreStore } from '@/store/modules/playerCore';
|
||||
import StickyTabPage from '@/components/common/StickyTabPage.vue';
|
||||
import { playTrack } from '@/services/playbackController';
|
||||
import { usePlaylistStore } from '@/store/modules/playlist';
|
||||
import { calculateAnimationDelay, getImgUrl } from '@/utils';
|
||||
|
||||
@@ -213,7 +213,6 @@ const playAlbum = async (album: any) => {
|
||||
try {
|
||||
const { data } = await getAlbum(album.id);
|
||||
if (data.code === 200 && data.songs?.length > 0) {
|
||||
const playerCore = usePlayerCoreStore();
|
||||
const playlistStore = usePlaylistStore();
|
||||
|
||||
const albumCover = data.album?.picUrl || album.picUrl;
|
||||
@@ -228,7 +227,7 @@ const playAlbum = async (album: any) => {
|
||||
}));
|
||||
|
||||
playlistStore.setPlayList(playlist, false, false);
|
||||
await playerCore.handlePlayMusic(playlist[0], true);
|
||||
await playTrack(playlist[0], true);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to play album:', error);
|
||||
|
||||
@@ -61,7 +61,7 @@ import { useRouter } from 'vue-router';
|
||||
import { getTopAlbum } from '@/api/home';
|
||||
import { getAlbum } from '@/api/list';
|
||||
import { navigateToMusicList } from '@/components/common/MusicListNavigator';
|
||||
import { usePlayerCoreStore } from '@/store/modules/playerCore';
|
||||
import { playTrack } from '@/services/playbackController';
|
||||
import { usePlaylistStore } from '@/store/modules/playlist';
|
||||
import { calculateAnimationDelay, isElectron, isMobile } from '@/utils';
|
||||
|
||||
@@ -178,7 +178,6 @@ const playAlbum = async (album: any) => {
|
||||
try {
|
||||
const { data } = await getAlbum(album.id);
|
||||
if (data.code === 200 && data.songs?.length > 0) {
|
||||
const playerCore = usePlayerCoreStore();
|
||||
const playlistStore = usePlaylistStore();
|
||||
|
||||
const albumCover = data.album?.picUrl || album.picUrl;
|
||||
@@ -193,7 +192,7 @@ const playAlbum = async (album: any) => {
|
||||
}));
|
||||
|
||||
playlistStore.setPlayList(playlist, false, false);
|
||||
await playerCore.handlePlayMusic(playlist[0], true);
|
||||
await playTrack(playlist[0], true);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to play album:', error);
|
||||
|
||||
@@ -146,10 +146,9 @@ const getArtistNames = (song: any) => {
|
||||
};
|
||||
|
||||
const handleSongClick = async (_song: any, index: number) => {
|
||||
const { usePlayerCoreStore } = await import('@/store/modules/playerCore');
|
||||
const { usePlaylistStore } = await import('@/store/modules/playlist');
|
||||
const { playTrack } = await import('@/services/playbackController');
|
||||
|
||||
const playerCore = usePlayerCoreStore();
|
||||
const playlistStore = usePlaylistStore();
|
||||
|
||||
const playlist = songs.value.map((s: any) => ({
|
||||
@@ -163,16 +162,15 @@ const handleSongClick = async (_song: any, index: number) => {
|
||||
}));
|
||||
|
||||
playlistStore.setPlayList(playlist, false, false);
|
||||
await playerCore.handlePlayMusic(playlist[index], true);
|
||||
await playTrack(playlist[index], true);
|
||||
};
|
||||
|
||||
const playAll = async () => {
|
||||
if (songs.value.length === 0) return;
|
||||
|
||||
const { usePlayerCoreStore } = await import('@/store/modules/playerCore');
|
||||
const { usePlaylistStore } = await import('@/store/modules/playlist');
|
||||
const { playTrack } = await import('@/services/playbackController');
|
||||
|
||||
const playerCore = usePlayerCoreStore();
|
||||
const playlistStore = usePlaylistStore();
|
||||
|
||||
const playlist = songs.value.map((s: any) => ({
|
||||
@@ -186,7 +184,7 @@ const playAll = async () => {
|
||||
}));
|
||||
|
||||
playlistStore.setPlayList(playlist, false, false);
|
||||
await playerCore.handlePlayMusic(playlist[0], true);
|
||||
await playTrack(playlist[0], true);
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
@@ -441,7 +441,8 @@ const handleFmPlay = async () => {
|
||||
];
|
||||
playlistStore.setPlayList(playlist, false, false);
|
||||
playerCore.isFmPlaying = true;
|
||||
await playerCore.handlePlayMusic(playlist[0], true);
|
||||
const { playTrack } = await import('@/services/playbackController');
|
||||
await playTrack(playlist[0], true);
|
||||
} catch (error) {
|
||||
console.error('Failed to play Personal FM:', error);
|
||||
}
|
||||
@@ -597,9 +598,7 @@ const showDayRecommend = () => {
|
||||
const playDayRecommend = async () => {
|
||||
if (dayRecommendSongs.value.length === 0) return;
|
||||
try {
|
||||
const { usePlayerCoreStore } = await import('@/store/modules/playerCore');
|
||||
const { usePlaylistStore } = await import('@/store/modules/playlist');
|
||||
const playerCore = usePlayerCoreStore();
|
||||
const playlistStore = usePlaylistStore();
|
||||
const songs = dayRecommendSongs.value.map((s: any) => ({
|
||||
id: s.id,
|
||||
@@ -611,7 +610,8 @@ const playDayRecommend = async () => {
|
||||
playLoading: false
|
||||
}));
|
||||
playlistStore.setPlayList(songs, false, false);
|
||||
await playerCore.handlePlayMusic(songs[0], true);
|
||||
const { playTrack } = await import('@/services/playbackController');
|
||||
await playTrack(songs[0], true);
|
||||
} catch (error) {
|
||||
console.error('Failed to play daily recommend:', error);
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ import { useRouter } from 'vue-router';
|
||||
import { getPersonalizedPlaylist } from '@/api/home';
|
||||
import { getListDetail } from '@/api/list';
|
||||
import { navigateToMusicList } from '@/components/common/MusicListNavigator';
|
||||
import { usePlayerCoreStore } from '@/store/modules/playerCore';
|
||||
import { playTrack } from '@/services/playbackController';
|
||||
import { usePlaylistStore } from '@/store/modules/playlist';
|
||||
import { calculateAnimationDelay, isElectron, isMobile } from '@/utils';
|
||||
|
||||
@@ -154,7 +154,6 @@ const playPlaylist = async (item: any) => {
|
||||
try {
|
||||
const { data } = await getListDetail(item.id);
|
||||
if (data.playlist?.tracks?.length > 0) {
|
||||
const playerCore = usePlayerCoreStore();
|
||||
const playlistStore = usePlaylistStore();
|
||||
|
||||
const playlist = data.playlist.tracks.map((s: any) => ({
|
||||
@@ -168,7 +167,7 @@ const playPlaylist = async (item: any) => {
|
||||
}));
|
||||
|
||||
playlistStore.setPlayList(playlist, false, false);
|
||||
await playerCore.handlePlayMusic(playlist[0], true);
|
||||
await playTrack(playlist[0], true);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to play playlist:', error);
|
||||
|
||||
Reference in New Issue
Block a user