From 280fec1990be01f337353da7708dfc73ff2e8064 Mon Sep 17 00:00:00 2001 From: alger Date: Sat, 29 Mar 2025 23:19:51 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E2=9C=A8=20feat:=20=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E7=BD=91=E6=98=93=E4=BA=91=E9=9F=B3=E4=B9=90=20API=20=E7=89=88?= =?UTF-8?q?=E6=9C=AC=EF=BC=8C=E6=B7=BB=E5=8A=A0=20B=E7=AB=99=E8=A7=86?= =?UTF-8?q?=E9=A2=91=E6=90=9C=E7=B4=A2=E5=8A=9F=E8=83=BD=E5=92=8C=E6=92=AD?= =?UTF-8?q?=E6=94=BE=E5=99=A8=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cursor/rules/music-vue-rule.mdc | 90 +++ package.json | 2 +- src/renderer/api/bilibili.ts | 128 +++++ src/renderer/components/BilibiliPlayer.vue | 519 ++++++++++++++++++ src/renderer/components/MusicBar.vue | 410 ++++++++++++++ .../components/common/BilibiliItem.vue | 117 ++++ src/renderer/const/bar-const.ts | 13 + src/renderer/layout/components/MusicFull.vue | 2 +- src/renderer/store/modules/player.ts | 96 ++-- src/renderer/type/music.ts | 40 +- src/renderer/types/bilibili.ts | 111 ++++ src/renderer/views/search/index.vue | 227 +++++--- 12 files changed, 1630 insertions(+), 125 deletions(-) create mode 100644 .cursor/rules/music-vue-rule.mdc create mode 100644 src/renderer/api/bilibili.ts create mode 100644 src/renderer/components/BilibiliPlayer.vue create mode 100644 src/renderer/components/MusicBar.vue create mode 100644 src/renderer/components/common/BilibiliItem.vue create mode 100644 src/renderer/types/bilibili.ts diff --git a/.cursor/rules/music-vue-rule.mdc b/.cursor/rules/music-vue-rule.mdc new file mode 100644 index 0000000..4dd9f3d --- /dev/null +++ b/.cursor/rules/music-vue-rule.mdc @@ -0,0 +1,90 @@ +--- +description: 这个规则是项目描述 +globs: +alwaysApply: false +--- +您是 TypeScript、Node.j、Vue3、Electron、naive-ui、VueUse 和 Tailwind 方面的专家。 + +项目结构 +- 这是 Electron 项目,使用 Vue3 和 Vuex 进行开发的第三方网易云音乐播放器。 +- 使用 Vue3 和 Vuex 进行开发。 +- 使用 Vuex 进行状态管理。 +- 使用 VueUse 进行状态管理。 +- 使用 naive-ui 进行 UI 设计。 +- 使用 Tailwind 进行样式设计。 +- 使用 remixicon 进行图标设计。 +- 使用 vite 进行项目构建。 +- 使用 electron-builder 进行项目打包。 +- 使用 electron-vite 进行项目开发。 +- 使用 netease-cloud-music-api 进行网易云音乐接口调用。 +- 使用 electron-store 进行本地数据存储。 +- 使用 axios 进行网络请求。 +- 使用 @unblockneteasemusic/server 进行网易云音乐解锁。 +- 使用 vue-i18n 进行国际化。目录为 src/i18n + +代码风格和结构 +- 编写简洁、技术性的 TypeScript 代码,并提供准确示例。 +- 使用组合 API 和声明性编程模式;避免使用选项 API。 +- 优先使用迭代和模块化,而不是代码重复。 +- 使用带有助动词的描述性变量名称(例如 isLoading、hasError)。 +- 结构文件:导出的组件、可组合项、帮助程序、静态内容、类型。 + +命名约定 +- 使用带破折号的小写字母表示目录(例如 components/auth-wizard)。 +- 使用 PascalCase 表示组件名称(例如 AuthWizard.vue)。 +- 使用 camelCase 表示可组合项(例如 useAuthState.ts)。 + +TypeScript 用法 +- 对所有代码使用 TypeScript;优先使用类型而不是接口。 +- 避免使用枚举;改用 const 对象。 +- 将 Vue 3 与 TypeScript 结合使用,利用 defineComponent 和 PropType。 + +语法和格式 +- 对方法和计算属性使用箭头函数。 +- 避免在条件中使用不必要的花括号;对简单语句使用简洁的语法。 +- 使用模板语法进行声明式渲染。 + +UI 和样式 +- 使用 naive-ui 和 Tailwind 进行组件和样式设计。 +- 使用 Tailwind CSS 实现响应式设计;采用移动优先方法。 + +图标 +- 使用 remixicon 作为图标库。 + +性能优化 +- 对异步组件使用 Suspense。 +- 为路由和组件实现延迟加载。 + +关键约定 +- 对常见可组合项和实用函数使用 VueUse。 +- 使用 Vuex 进行状态管理。 +- 优化 Web Vitals(LCP、CLS、FID)。 + + +Vue 3 和 Composition API 最佳实践 +- 使用 + + diff --git a/src/renderer/components/MusicBar.vue b/src/renderer/components/MusicBar.vue new file mode 100644 index 0000000..c904a2a --- /dev/null +++ b/src/renderer/components/MusicBar.vue @@ -0,0 +1,410 @@ + + + + + diff --git a/src/renderer/components/common/BilibiliItem.vue b/src/renderer/components/common/BilibiliItem.vue new file mode 100644 index 0000000..7ef5684 --- /dev/null +++ b/src/renderer/components/common/BilibiliItem.vue @@ -0,0 +1,117 @@ + + + + + diff --git a/src/renderer/const/bar-const.ts b/src/renderer/const/bar-const.ts index 3040ac5..49f174d 100644 --- a/src/renderer/const/bar-const.ts +++ b/src/renderer/const/bar-const.ts @@ -45,6 +45,10 @@ export const SEARCH_TYPES = [ { label: 'MV', key: 1004 + }, + { + label: 'B站', + key: 2000 } // { // label: '歌词', @@ -63,3 +67,12 @@ export const SEARCH_TYPES = [ // key: 1018, // }, ]; + +export const SEARCH_TYPE = { + MUSIC: 1, // 单曲 + ALBUM: 10, // 专辑 + ARTIST: 100, // 歌手 + PLAYLIST: 1000, // 歌单 + MV: 1004, // MV + BILIBILI: 2000 // B站视频 +} as const; diff --git a/src/renderer/layout/components/MusicFull.vue b/src/renderer/layout/components/MusicFull.vue index bafcb19..b4ff89a 100644 --- a/src/renderer/layout/components/MusicFull.vue +++ b/src/renderer/layout/components/MusicFull.vue @@ -112,7 +112,7 @@ -
+
{{ t('player.lrc.noLrc') }}
diff --git a/src/renderer/store/modules/player.ts b/src/renderer/store/modules/player.ts index 7c33d80..65a34ce 100644 --- a/src/renderer/store/modules/player.ts +++ b/src/renderer/store/modules/player.ts @@ -24,13 +24,27 @@ function getLocalStorageItem(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 => { +export const loadLrc = async (id: string | number): Promise => { + 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 = {}; @@ -102,8 +126,19 @@ export const loadLrc = async (playMusicId: number): Promise => { 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(getLocalStorageItem('currentPlayMusic', {} as SongResult)); @@ -216,7 +243,6 @@ export const usePlayerStore = defineStore('player', () => { const favoriteList = ref(getLocalStorageItem('favoriteList', [])); const savedPlayProgress = ref(); - // 计算属性 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, diff --git a/src/renderer/type/music.ts b/src/renderer/type/music.ts index 4388575..3962e15 100644 --- a/src/renderer/type/music.ts +++ b/src/renderer/type/music.ts @@ -13,23 +13,26 @@ export interface ILyric { } export interface SongResult { - id: number; - type: number; + id: string | number; name: string; - copywriter?: any; picUrl: string; - canDislike: boolean; - trackNumberUpdateTime?: any; - song: Song; - alg: string; - count?: number; + playCount?: number; + song?: any; + copywriter?: string; + type?: number; + canDislike?: boolean; + program?: any; + alg?: string; + playMusicUrl?: string; playLoading?: boolean; - ar?: Artist[]; - al?: Album; + lyric?: ILyric; backgroundColor?: string; primaryColor?: string; - playMusicUrl?: string; - lyric?: ILyric; + bilibiliData?: { + bvid: string; + cid: number; + }; + source?: 'netease' | 'bilibili'; } export interface Song { @@ -214,3 +217,16 @@ interface FreeTrialPrivilege { resConsumable: boolean; userConsumable: boolean; } + +export interface IArtists { + id: number; + name: string; + picUrl: string | null; + alias: string[]; + albumSize: number; + picId: number; + fansGroup: null; + img1v1Url: string; + img1v1: number; + trans: null; +} diff --git a/src/renderer/types/bilibili.ts b/src/renderer/types/bilibili.ts new file mode 100644 index 0000000..93ebbf8 --- /dev/null +++ b/src/renderer/types/bilibili.ts @@ -0,0 +1,111 @@ +export interface IBilibiliSearchResult { + id: number; + bvid: string; + title: string; + pic: string; + duration: number | string; + pubdate: number; + ctime: number; + owner: { + mid: number; + name: string; + face: string; + }; + stat: { + view: number; + danmaku: number; + reply: number; + favorite: number; + coin: number; + share: number; + like: number; + }; +} + +export interface IBilibiliVideoDetail { + aid: number; + bvid: string; + title: string; + pic: string; + desc: string; + duration: number; + pubdate: number; + ctime: number; + owner: { + mid: number; + name: string; + face: string; + }; + stat: { + view: number; + danmaku: number; + reply: number; + favorite: number; + coin: number; + share: number; + like: number; + }; + pages: IBilibiliPage[]; +} + +export interface IBilibiliPage { + cid: number; + page: number; + part: string; + duration: number; + dimension: { + width: number; + height: number; + rotate: number; + }; +} + +export interface IBilibiliPlayUrl { + durl?: { + order: number; + length: number; + size: number; + ahead: string; + vhead: string; + url: string; + backup_url: string[]; + }[]; + dash?: { + duration: number; + minBufferTime: number; + min_buffer_time: number; + video: IBilibiliDashItem[]; + audio: IBilibiliDashItem[]; + }; + support_formats: { + quality: number; + format: string; + new_description: string; + display_desc: string; + }[]; + accept_quality: number[]; + accept_description: string[]; + quality: number; + format: string; + timelength: number; + high_format: string; +} + +export interface IBilibiliDashItem { + id: number; + baseUrl: string; + base_url: string; + backupUrl: string[]; + backup_url: string[]; + bandwidth: number; + mimeType: string; + mime_type: string; + codecs: string; + width?: number; + height?: number; + frameRate?: string; + frame_rate?: string; + startWithSap?: number; + start_with_sap?: number; + codecid: number; +} diff --git a/src/renderer/views/search/index.vue b/src/renderer/views/search/index.vue index 9c8f0e8..0433c95 100644 --- a/src/renderer/views/search/index.vue +++ b/src/renderer/views/search/index.vue @@ -40,33 +40,52 @@
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 @@