feat: add QQ Music API integration, Pinia home cache, and unified search

- Start @sansenjian/qq-music-api server via dynamic import in api-server.ts
- Rewrite QQ Music provider to use real API endpoints (getSearchByKey,
  getMusicPlay, getSongListDetail, getAlbumInfo, getLyric, etc.)
- Cache home page data (recommend playlists, daily songs, user playlists)
  in Pinia store with 5-minute TTL to avoid refetching on every mount
- Add unified /api/music/search/all endpoint that queries both Netease
  and QQ providers in parallel and returns merged results
- Remove platform toggle from Search.vue; search both platforms at once
- Add platform badge (网易云 / QQ) to SongCard component

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
saopig1andClaude Opus 4.6 committed 2026-03-30 02:31:15 +08:00
1 parent ce6fc92780
commit 94a0df8391
8 files changed
+195 -155

No files matched your search

+40
View File
@@ -23,6 +23,16 @@ export interface BotStatus {
playMode: string;
}
export interface PlaylistItem {
id: string;
name: string;
coverUrl: string;
songCount: number;
platform: string;
}
const HOME_CACHE_TTL = 5 * 60 * 1000; // 5 minutes
export const usePlayerStore = defineStore('player', {
state: () => ({
bots: [] as BotStatus[],
@@ -31,6 +41,11 @@ export const usePlayerStore = defineStore('player', {
theme: 'dark' as 'dark' | 'light',
playStartedAt: 0, // timestamp when current song started
pausedElapsed: 0, // elapsed time when paused
// Home page cached data
recommendPlaylists: [] as PlaylistItem[],
dailySongs: [] as Song[],
userPlaylists: [] as PlaylistItem[],
lastFetchTime: 0,
}),
getters: {
@@ -188,5 +203,30 @@ export const usePlayerStore = defineStore('player', {
if (!this.activeBotId) return;
await axios.post(`/api/player/${this.activeBotId}/mode`, { mode });
},
async fetchHomeData() {
// Skip if data was fetched within the last 5 minutes
if (this.lastFetchTime > 0 && Date.now() - this.lastFetchTime < HOME_CACHE_TTL) {
return;
}
const [playlistRes, dailyRes, userRes] = await Promise.allSettled([
axios.get('/api/music/recommend/playlists'),
axios.get('/api/music/recommend/songs'),
axios.get('/api/music/user/playlists'),
]);
if (playlistRes.status === 'fulfilled') {
this.recommendPlaylists = playlistRes.value.data.playlists;
}
if (dailyRes.status === 'fulfilled') {
this.dailySongs = dailyRes.value.data.songs;
}
if (userRes.status === 'fulfilled') {
this.userPlaylists = userRes.value.data.playlists;
}
this.lastFetchTime = Date.now();
},
},
});