diff --git a/src/renderer/views/favorite/index.vue b/src/renderer/views/favorite/index.vue index 3fd4369..519ac16 100644 --- a/src/renderer/views/favorite/index.vue +++ b/src/renderer/views/favorite/index.vue @@ -1,79 +1,110 @@ @@ -102,7 +148,6 @@ import { computed, onMounted, ref, watch } from 'vue'; import { useI18n } from 'vue-i18n'; import { useRouter } from 'vue-router'; -import { processBilibiliVideos } from '@/api/bilibili'; import { getMusicDetail } from '@/api/music'; import PlayBottom from '@/components/common/PlayBottom.vue'; import SongItem from '@/components/common/SongItem.vue'; @@ -117,12 +162,11 @@ const favoriteList = computed(() => playerStore.favoriteList); const favoriteSongs = ref([]); const loading = ref(false); const noMore = ref(false); -const scrollbarRef = ref(); // 多选相关 const isSelecting = ref(false); const selectedSongs = ref([]); -const { isDownloading, batchDownloadMusic } = useDownload(); +const { batchDownloadMusic } = useDownload(); // 开始多选 const startSelect = () => { @@ -215,8 +259,6 @@ const getFavoriteSongs = async () => { // 分离网易云音乐ID和B站视频ID const musicIds = currentIds.filter((id) => typeof id === 'number') as number[]; - // B站ID可能是字符串格式(包含"--")或特定数字ID,如113911642789603 - const bilibiliIds = currentIds.filter((id) => typeof id === 'string'); // 处理网易云音乐数据 let neteaseSongs: SongResult[] = []; @@ -231,12 +273,8 @@ const getFavoriteSongs = async () => { } } - // 处理B站视频数据 - 使用公用方法 - const bilibiliSongs = await processBilibiliVideos(bilibiliIds); - console.log('获取数据统计:', { - neteaseSongs: neteaseSongs.length, - bilibiliSongs: bilibiliSongs.length + neteaseSongs: neteaseSongs.length }); // 合并数据,保持原有顺序 @@ -244,12 +282,6 @@ const getFavoriteSongs = async () => { .map((id) => { const strId = String(id); - // 查找B站视频 - if (typeof id === 'string') { - const found = bilibiliSongs.find((song) => String(song.id) === strId); - if (found) return found; - } - // 查找网易云音乐 const found = neteaseSongs.find((song) => String(song.id) === strId); return found; @@ -343,156 +375,5 @@ const handleSelectAll = (checked: boolean) => { diff --git a/src/renderer/views/history/index.vue b/src/renderer/views/history/index.vue index 2f14793..b504e4d 100644 --- a/src/renderer/views/history/index.vue +++ b/src/renderer/views/history/index.vue @@ -1,113 +1,256 @@ @@ -117,9 +260,6 @@ import { onMounted, ref, watch } from 'vue'; import { useI18n } from 'vue-i18n'; import { useRouter } from 'vue-router'; -import { processBilibiliVideos } from '@/api/bilibili'; -import { getListDetail } from '@/api/list'; -import { getAlbumDetail } from '@/api/music'; import { getMusicDetail } from '@/api/music'; import { getRecentAlbums, getRecentPlaylists, getRecentSongs } from '@/api/user'; import AlbumItem from '@/components/common/AlbumItem.vue'; @@ -129,24 +269,23 @@ import SongItem from '@/components/common/SongItem.vue'; import { useAlbumHistory } from '@/hooks/AlbumHistoryHook'; import { useMusicHistory } from '@/hooks/MusicHistoryHook'; import { usePlaylistHistory } from '@/hooks/PlaylistHistoryHook'; +import { usePodcastHistory } from '@/hooks/PodcastHistoryHook'; +import { usePodcastRadioHistory } from '@/hooks/PodcastRadioHistoryHook'; import { usePlayerStore } from '@/store/modules/player'; import { useUserStore } from '@/store/modules/user'; import type { SongResult } from '@/types/music'; import { isMobile, setAnimationClass, setAnimationDelay } from '@/utils'; +import { mapDjProgramToSongResult } from '@/utils/podcastUtils'; // 扩展历史记录类型以包含 playTime interface HistoryRecord extends Partial { id: string | number; playTime?: number; score?: number; - source?: 'netease' | 'bilibili'; + source?: 'netease'; count?: number; recordSource?: 'local' | 'cloud'; sources?: ('local' | 'cloud')[]; - bilibiliData?: { - bvid: string; - cid: number; - }; } const { t } = useI18n(); @@ -155,6 +294,8 @@ const router = useRouter(); const { delMusic, musicList } = useMusicHistory(); const { delPlaylist, playlistList } = usePlaylistHistory(); const { delAlbum, albumList } = useAlbumHistory(); +const { delPodcast, podcastList } = usePodcastHistory(); +const { delPodcastRadio, podcastRadioList } = usePodcastRadioHistory(); const userStore = useUserStore(); const scrollbarRef = ref(); const loading = ref(false); @@ -162,11 +303,12 @@ const noMore = ref(false); const displayList = ref([]); const playerStore = usePlayerStore(); const hasLoaded = ref(false); -const currentCategory = ref<'songs' | 'playlists' | 'albums'>('songs'); +const currentCategory = ref<'songs' | 'playlists' | 'albums' | 'podcasts'>('songs'); const currentTab = ref<'local' | 'cloud'>('local'); const cloudRecords = ref([]); const cloudPlaylists = ref([]); const cloudAlbums = ref([]); +const currentPodcastSubTab = ref<'episodes' | 'radios'>('episodes'); // 无限滚动相关配置 const pageSize = 100; @@ -283,17 +425,27 @@ const getCurrentList = (): any[] => { case 'cloud': return cloudAlbums.value; } + } else if (currentCategory.value === 'podcasts') { + if (currentPodcastSubTab.value === 'episodes') { + return podcastList.value; + } else { + return podcastRadioList.value; + } } return []; }; // 处理分类切换 -const handleCategoryChange = async (value: 'songs' | 'playlists' | 'albums') => { +const handleCategoryChange = async (value: 'songs' | 'playlists' | 'albums' | 'podcasts') => { currentCategory.value = value; currentPage.value = 1; noMore.value = false; displayList.value = []; + if (value === 'podcasts') { + currentTab.value = 'local'; + } + // 如果切换到云端,且还没有加载对应的云端数据,则加载 if (currentTab.value === 'cloud') { loading.value = true; @@ -313,17 +465,13 @@ const handleCategoryChange = async (value: 'songs' | 'playlists' | 'albums') => // 处理歌单点击 const handlePlaylistClick = async (item: any) => { try { - const res = await getListDetail(item.id); - if (res.data?.playlist) { - navigateToMusicList(router, { - id: item.id, - type: 'playlist', - name: item.name, - songList: res.data.playlist.tracks || [], - listInfo: res.data.playlist, - canRemove: false - }); - } + navigateToMusicList(router, { + id: item.id, + type: 'playlist', + name: item.name, + listInfo: item, + canRemove: false + }); } catch (error) { console.error('打开歌单失败:', error); message.error('打开歌单失败'); @@ -333,23 +481,16 @@ const handlePlaylistClick = async (item: any) => { // 处理专辑点击 const handleAlbumClick = async (item: any) => { try { - const res = await getAlbumDetail(item.id.toString()); - if (res.data?.album && res.data?.songs) { - const albumData = res.data.album; - const songs = res.data.songs.map((song: any) => ({ - ...song, - picUrl: albumData.picUrl - })); - - navigateToMusicList(router, { - id: item.id, - type: 'album', - name: albumData.name, - songList: songs, - listInfo: albumData, - canRemove: false - }); - } + navigateToMusicList(router, { + id: item.id, + type: 'album', + name: item.name, + listInfo: { + ...item, + coverImgUrl: item.picUrl || item.coverImgUrl + }, + canRemove: false + }); } catch (error) { console.error('打开专辑失败:', error); message.error('打开专辑失败'); @@ -368,6 +509,44 @@ const handleDelAlbum = (item: any) => { displayList.value = displayList.value.filter((album) => album.id !== item.id); }; +// 播客相关处理 +const mapDjProgramToSong = (program: any): SongResult => { + return mapDjProgramToSongResult(program); +}; + +const mapPodcastRadioToPlaylistItem = (radio: any) => { + return { + id: radio.id, + name: radio.name, + picUrl: radio.picUrl, + coverImgUrl: radio.picUrl, + desc: radio.dj?.nickname || radio.desc, + type: 'podcast' + }; +}; + +const handlePlayPodcast = (item: any) => { + const song = mapDjProgramToSong(item); + playerStore.setPlay(song); +}; + +const handlePodcastRadioClick = (item: any) => { + router.push({ + name: 'podcastRadio', + params: { id: item.id } + }); +}; + +const handleDelPodcast = (item: any) => { + delPodcast(item); + displayList.value = displayList.value.filter((p) => p.id !== item.id); +}; + +const handleDelPodcastRadio = (item: any) => { + delPodcastRadio(item); + displayList.value = displayList.value.filter((r) => r.id !== item.id); +}; + // 加载历史数据(根据当前分类) const loadHistoryData = async () => { const currentList = getCurrentList(); @@ -386,7 +565,6 @@ const loadHistoryData = async () => { if (currentCategory.value === 'songs') { // 处理歌曲数据 const neteaseItems = currentPageItems.filter((item) => item.source !== 'bilibili'); - const bilibiliItems = currentPageItems.filter((item) => item.source === 'bilibili'); let neteaseSongs: SongResult[] = []; if (neteaseItems.length > 0) { @@ -405,32 +583,8 @@ const loadHistoryData = async () => { } } - const bilibiliIds = bilibiliItems - .map((item) => `${item.bilibiliData?.bvid}--1--${item.bilibiliData?.cid}`) - .filter((id) => id && !id.includes('undefined')); - - const bilibiliSongs = await processBilibiliVideos(bilibiliIds); - - bilibiliSongs.forEach((song) => { - const historyItem = bilibiliItems.find( - (item) => - item.bilibiliData?.bvid === song.bilibiliData?.bvid && - item.bilibiliData?.cid === song.bilibiliData?.cid - ); - if (historyItem) { - song.count = historyItem.count || 0; - } - }); - const newSongs = currentPageItems .map((item) => { - if (item.source === 'bilibili') { - return bilibiliSongs.find( - (song) => - song.bilibiliData?.bvid === item.bilibiliData?.bvid && - song.bilibiliData?.cid === item.bilibiliData?.cid - ); - } return neteaseSongs.find((song) => song.id === item.id); }) .filter((song): song is SongResult => !!song); @@ -441,7 +595,7 @@ const loadHistoryData = async () => { displayList.value = [...displayList.value, ...newSongs]; } } else { - // 处理歌单和专辑数据(直接显示,不需要额外请求) + // 处理歌单、专辑、播客数据(直接显示,不需要额外请求) if (currentPage.value === 1) { displayList.value = currentPageItems; } else { @@ -506,7 +660,7 @@ onMounted(async () => { // 监听历史列表变化,变化时重置并重新加载 watch( - [musicList, playlistList, albumList], + [musicList, playlistList, albumList, podcastList, podcastRadioList], async () => { if (hasLoaded.value) { currentPage.value = 1; @@ -531,87 +685,5 @@ const handleNavigateToHeatmap = () => { diff --git a/src/renderer/views/historyAndFavorite/index.vue b/src/renderer/views/historyAndFavorite/index.vue index 5970404..3232753 100644 --- a/src/renderer/views/historyAndFavorite/index.vue +++ b/src/renderer/views/historyAndFavorite/index.vue @@ -1,5 +1,5 @@