From a447a4192089d5a837275f3c741226dcc9932ea6 Mon Sep 17 00:00:00 2001 From: mtvpls Date: Mon, 2 Feb 2026 14:27:25 +0800 Subject: [PATCH] =?UTF-8?q?=E9=9F=B3=E4=B9=90=E6=95=B0=E6=8D=AE=E5=AF=BC?= =?UTF-8?q?=E5=85=A5=E5=AF=BC=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/admin/data_migration/export/route.ts | 15 ++++++++ .../api/admin/data_migration/import/route.ts | 38 +++++++++++++++++++ src/lib/redis-base.db.ts | 19 ++++++++++ 3 files changed, 72 insertions(+) diff --git a/src/app/api/admin/data_migration/export/route.ts b/src/app/api/admin/data_migration/export/route.ts index f01362f..c28fd56 100644 --- a/src/app/api/admin/data_migration/export/route.ts +++ b/src/app/api/admin/data_migration/export/route.ts @@ -94,6 +94,17 @@ export async function POST(req: NextRequest) { continue; } + // 获取用户的所有歌单 + const playlists = await db.getUserMusicPlaylists(username); + const playlistsWithSongs = []; + for (const playlist of playlists) { + const songs = await db.getPlaylistSongs(playlist.id); + playlistsWithSongs.push({ + ...playlist, + songs + }); + } + const userData = { // 播放记录 playRecords: await db.getAllPlayRecords(username), @@ -103,6 +114,10 @@ export async function POST(req: NextRequest) { searchHistory: await db.getSearchHistory(username), // 跳过片头片尾配置 skipConfigs: await db.getAllSkipConfigs(username), + // 音乐播放记录 + musicPlayRecords: await db.getAllMusicPlayRecords(username), + // 音乐歌单(包含歌曲) + musicPlaylists: playlistsWithSongs, // V2用户的加密密码 passwordV2: finalPasswordV2 }; diff --git a/src/app/api/admin/data_migration/import/route.ts b/src/app/api/admin/data_migration/import/route.ts index 939aedb..96b33d0 100644 --- a/src/app/api/admin/data_migration/import/route.ts +++ b/src/app/api/admin/data_migration/import/route.ts @@ -225,6 +225,44 @@ export async function POST(req: NextRequest) { } } } + + // 导入音乐播放记录 + if (user.musicPlayRecords) { + for (const [key, record] of Object.entries(user.musicPlayRecords)) { + const [platform, id] = key.split('+'); + if (platform && id) { + await db.saveMusicPlayRecord(username, platform, id, record as any); + } + } + } + + // 导入音乐歌单 + if (user.musicPlaylists && Array.isArray(user.musicPlaylists)) { + for (const playlist of user.musicPlaylists) { + // 创建歌单 + await db.createMusicPlaylist(username, { + id: playlist.id, + name: playlist.name, + description: playlist.description, + cover: playlist.cover, + }); + + // 导入歌单中的歌曲 + if (playlist.songs && Array.isArray(playlist.songs)) { + for (const song of playlist.songs) { + await db.addSongToPlaylist(playlist.id, { + platform: song.platform, + id: song.id, + name: song.name, + artist: song.artist, + album: song.album, + pic: song.pic, + duration: song.duration || 0, + }); + } + } + } + } } console.log(`成功导入 ${importedCount} 个用户的user:info`); diff --git a/src/lib/redis-base.db.ts b/src/lib/redis-base.db.ts index 3b089c0..94aa905 100644 --- a/src/lib/redis-base.db.ts +++ b/src/lib/redis-base.db.ts @@ -865,6 +865,25 @@ export abstract class BaseRedisStorage implements IStorage { if (skipConfigKeys.length > 0) { await this.withRetry(() => this.adapter.del(skipConfigKeys)); } + + // 删除音乐播放记录 + await this.withRetry(() => this.adapter.del(this.musicPlayRecordHashKey(userName))); + + // 删除用户的所有歌单 + const playlistIds = await this.withRetry(() => + this.adapter.zRange(this.musicPlaylistsKey(userName), 0, -1) + ); + if (playlistIds && playlistIds.length > 0) { + for (const playlistId of playlistIds) { + const id = ensureString(playlistId); + // 删除歌单信息 + await this.withRetry(() => this.adapter.del(this.musicPlaylistKey(id))); + // 删除歌单的歌曲列表 + await this.withRetry(() => this.adapter.del(this.musicPlaylistSongsKey(id))); + } + } + // 删除用户的歌单列表 + await this.withRetry(() => this.adapter.del(this.musicPlaylistsKey(userName))); } // ---------- 新版用户存储(使用Hash和Sorted Set) ----------