diff --git a/src/main/index.ts b/src/main/index.ts index 371b7aa..0a4d111 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -106,7 +106,6 @@ if (!isSingleInstance) { // 监听语言切换 ipcMain.on('change-language', (_, locale: Language) => { - console.log('locale',locale) // 更新主进程的语言设置 i18n.global.locale = locale; // 更新托盘菜单 diff --git a/src/main/modules/window.ts b/src/main/modules/window.ts index ce3f5b8..04b0c99 100644 --- a/src/main/modules/window.ts +++ b/src/main/modules/window.ts @@ -1,5 +1,5 @@ import { is } from '@electron-toolkit/utils'; -import { app, BrowserWindow, ipcMain, session, shell } from 'electron'; +import { app, BrowserWindow, globalShortcut, ipcMain, session, shell } from 'electron'; import Store from 'electron-store'; import { join } from 'path'; @@ -112,6 +112,11 @@ export function createMainWindow(icon: Electron.NativeImage): BrowserWindow { if (is.dev && process.env.ELECTRON_RENDERER_URL) { mainWindow.webContents.openDevTools({ mode: 'detach' }); mainWindow.loadURL(process.env.ELECTRON_RENDERER_URL); + + // 注册快捷键 打开开发者工具 + globalShortcut.register('CommandOrControl+Shift+I', () => { + mainWindow.webContents.openDevTools({ mode: 'detach' }); + }); } else { mainWindow.loadFile(join(__dirname, '../renderer/index.html')); } diff --git a/src/renderer/api/bilibili.ts b/src/renderer/api/bilibili.ts index 51efc00..b16a11d 100644 --- a/src/renderer/api/bilibili.ts +++ b/src/renderer/api/bilibili.ts @@ -126,3 +126,25 @@ export const getBilibiliProxyUrl = (url: string) => { const AUrl = url.startsWith('http') ? url : `https:${url}`; return `${import.meta.env.VITE_API}/bilibili/stream-proxy?url=${encodeURIComponent(AUrl)}`; }; + +export const getBilibiliAudioUrl = async (bvid: string, cid: number): Promise => { + console.log('获取B站音频URL', { bvid, cid }); + try { + const res = await getBilibiliPlayUrl(bvid, cid); + const playUrlData = res.data; + let url = ''; + + if (playUrlData.dash && playUrlData.dash.audio && playUrlData.dash.audio.length > 0) { + url = playUrlData.dash.audio[0].baseUrl; + } else if (playUrlData.durl && playUrlData.durl.length > 0) { + url = playUrlData.durl[0].url; + } else { + throw new Error('未找到可用的音频地址'); + } + + return getBilibiliProxyUrl(url); + } catch (error) { + console.error('获取B站音频URL失败:', error); + throw error; + } +}; diff --git a/src/renderer/components/MusicBar.vue b/src/renderer/components/MusicBar.vue deleted file mode 100644 index c904a2a..0000000 --- a/src/renderer/components/MusicBar.vue +++ /dev/null @@ -1,410 +0,0 @@ - - - - - diff --git a/src/renderer/components/common/SongItem.vue b/src/renderer/components/common/SongItem.vue index 11ef719..b6b94aa 100644 --- a/src/renderer/components/common/SongItem.vue +++ b/src/renderer/components/common/SongItem.vue @@ -140,7 +140,7 @@ const dropdownY = ref(0); const isDownloading = ref(false); -const openPlaylistDrawer = inject<(songId: number) => void>('openPlaylistDrawer'); +const openPlaylistDrawer = inject<(songId: number | string) => void>('openPlaylistDrawer'); const { navigateToArtist } = useArtist(); @@ -285,7 +285,7 @@ const downloadMusic = async () => { try { isDownloading.value = true; - const data = (await getSongUrl(props.item.id, cloneDeep(props.item), true)) as any; + const data = (await getSongUrl(props.item.id as number, cloneDeep(props.item), true)) as any; if (!data || !data.url) { throw new Error(t('songItem.message.getUrlFailed')); } @@ -358,6 +358,7 @@ const imageLoad = async () => { // 播放音乐 设置音乐详情 打开音乐底栏 const playMusicEvent = async (item: SongResult) => { + // 如果是当前正在播放的音乐,则切换播放/暂停状态 if (playMusic.value.id === item.id) { if (play.value) { playerStore.setPlayMusic(false); @@ -368,23 +369,37 @@ const playMusicEvent = async (item: SongResult) => { } return; } - await playerStore.setPlay(item); - playerStore.isPlay = true; - emits('play', item); + + try { + // 使用store的setPlay方法,该方法已经包含了B站视频URL处理逻辑 + const result = await playerStore.setPlay(item); + if (!result) { + throw new Error('播放失败'); + } + playerStore.isPlay = true; + emits('play', item); + } catch (error) { + console.error('播放出错:', error); + } }; // 判断是否已收藏 const isFavorite = computed(() => { - return playerStore.favoriteList.includes(props.item.id); + // 将id转换为number,兼容B站视频ID + const numericId = typeof props.item.id === 'string' ? parseInt(props.item.id, 10) : props.item.id; + return playerStore.favoriteList.includes(numericId); }); // 切换收藏状态 const toggleFavorite = async (e: Event) => { e.stopPropagation(); + // 将id转换为number,兼容B站视频ID + const numericId = typeof props.item.id === 'string' ? parseInt(props.item.id, 10) : props.item.id; + if (isFavorite.value) { - playerStore.removeFromFavorite(props.item.id); + playerStore.removeFromFavorite(numericId); } else { - playerStore.addToFavorite(props.item.id); + playerStore.addToFavorite(numericId); } }; diff --git a/src/renderer/hooks/MusicHook.ts b/src/renderer/hooks/MusicHook.ts index 6e8bae7..d76c2e2 100644 --- a/src/renderer/hooks/MusicHook.ts +++ b/src/renderer/hooks/MusicHook.ts @@ -2,6 +2,7 @@ import { createDiscreteApi } from 'naive-ui'; import { computed, nextTick, onUnmounted, ref, watch } from 'vue'; import i18n from '@/../i18n/renderer'; +import { getBilibiliAudioUrl } from '@/api/bilibili'; import useIndexedDB from '@/hooks/IndexDBHook'; import { audioService } from '@/services/audioService'; import pinia, { usePlayerStore } from '@/store'; @@ -235,6 +236,29 @@ watch( initialPosition = savedProgress.progress; } + // 对于B站视频,检查URL是否有效 + if (playMusic.value.source === 'bilibili' && (!newVal || newVal === 'undefined')) { + console.log('B站视频URL无效,尝试重新获取'); + + // 需要重新获取B站视频URL + if (playMusic.value.bilibiliData) { + try { + const proxyUrl = await getBilibiliAudioUrl( + playMusic.value.bilibiliData.bvid, + playMusic.value.bilibiliData.cid + ); + + // 设置URL到播放器状态 + (playMusic.value as any).playMusicUrl = proxyUrl; + playerStore.playMusicUrl = proxyUrl; + newVal = proxyUrl; + } catch (error) { + console.error('获取B站音频URL失败:', error); + return; + } + } + } + // 播放新音频,传递是否应该播放的状态 const newSound = await audioService.play(newVal, playMusic.value, shouldPlay); sound.value = newSound as Howl; diff --git a/src/renderer/hooks/MusicListHook.ts b/src/renderer/hooks/MusicListHook.ts index 79c42a3..574a4a8 100644 --- a/src/renderer/hooks/MusicListHook.ts +++ b/src/renderer/hooks/MusicListHook.ts @@ -12,7 +12,7 @@ import { getImageLinearBackground } from '@/utils/linearColor'; const musicHistory = useMusicHistory(); // 获取歌曲url -export const getSongUrl = async (id: number, songData: any, isDownloaded: boolean = false) => { +export const getSongUrl = async (id: any, songData: any, isDownloaded: boolean = false) => { const { data } = await getMusicUrl(id, isDownloaded); let url = ''; let songDetail = null; @@ -247,7 +247,7 @@ export const useMusicListHook = () => { }; // 异步加载歌词的方法 - const loadLrcAsync = async (state: any, playMusicId: number) => { + const loadLrcAsync = async (state: any, playMusicId: any) => { if (state.playMusic.lyric && state.playMusic.lyric.lrcTimeArray.length > 0) { return; } diff --git a/src/renderer/layout/components/MobilePlayBar.vue b/src/renderer/layout/components/MobilePlayBar.vue index 6162626..b0c703d 100644 --- a/src/renderer/layout/components/MobilePlayBar.vue +++ b/src/renderer/layout/components/MobilePlayBar.vue @@ -217,15 +217,15 @@ const scrollToPlayList = (val: boolean) => { // 收藏功能 const isFavorite = computed(() => { - return playerStore.favoriteList.includes(playMusic.value.id); + return playerStore.favoriteList.includes(playMusic.value.id as number); }); const toggleFavorite = () => { console.log('isFavorite.value', isFavorite.value); if (isFavorite.value) { - playerStore.removeFromFavorite(playMusic.value.id); + playerStore.removeFromFavorite(playMusic.value.id as number); } else { - playerStore.addToFavorite(playMusic.value.id); + playerStore.addToFavorite(playMusic.value.id as number); } }; diff --git a/src/renderer/layout/components/PlayBar.vue b/src/renderer/layout/components/PlayBar.vue index 35e4573..404cc2e 100644 --- a/src/renderer/layout/components/PlayBar.vue +++ b/src/renderer/layout/components/PlayBar.vue @@ -176,6 +176,7 @@