音乐数据v2导入导出适配
This commit is contained in:
@@ -115,21 +115,21 @@ export async function POST(req: NextRequest) {
|
|||||||
favorites,
|
favorites,
|
||||||
searchHistory,
|
searchHistory,
|
||||||
skipConfigs,
|
skipConfigs,
|
||||||
musicPlayRecords,
|
musicV2History,
|
||||||
playlists
|
playlists
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
db.getAllPlayRecords(username),
|
db.getAllPlayRecords(username),
|
||||||
db.getAllFavorites(username),
|
db.getAllFavorites(username),
|
||||||
db.getSearchHistory(username),
|
db.getSearchHistory(username),
|
||||||
db.getAllSkipConfigs(username),
|
db.getAllSkipConfigs(username),
|
||||||
db.getAllMusicPlayRecords(username),
|
db.listMusicV2History(username),
|
||||||
db.getUserMusicPlaylists(username)
|
db.listMusicV2Playlists(username)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 并行获取所有歌单的歌曲
|
// 并行获取所有歌单的歌曲
|
||||||
const playlistsWithSongs = await Promise.all(
|
const playlistsWithSongs = await Promise.all(
|
||||||
playlists.map(async (playlist) => {
|
playlists.map(async (playlist) => {
|
||||||
const songs = await db.getPlaylistSongs(playlist.id);
|
const songs = await db.listMusicV2PlaylistItems(playlist.id);
|
||||||
return { ...playlist, songs };
|
return { ...playlist, songs };
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@@ -141,8 +141,8 @@ export async function POST(req: NextRequest) {
|
|||||||
favorites,
|
favorites,
|
||||||
searchHistory,
|
searchHistory,
|
||||||
skipConfigs,
|
skipConfigs,
|
||||||
musicPlayRecords,
|
musicV2History,
|
||||||
musicPlaylists: playlistsWithSongs,
|
musicV2Playlists: playlistsWithSongs,
|
||||||
passwordV2: finalPasswordV2
|
passwordV2: finalPasswordV2
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -295,30 +295,43 @@ export async function POST(req: NextRequest) {
|
|||||||
}
|
}
|
||||||
})(),
|
})(),
|
||||||
|
|
||||||
// 导入音乐播放记录(批量)
|
// 导入音乐 V2 播放记录(批量)
|
||||||
(async () => {
|
(async () => {
|
||||||
if (user.musicPlayRecords) {
|
const historyRecords = Array.isArray(user.musicV2History)
|
||||||
const entries = Object.entries(user.musicPlayRecords);
|
? user.musicV2History
|
||||||
for (let j = 0; j < entries.length; j += DATA_BATCH_SIZE) {
|
: [];
|
||||||
const batch = entries.slice(j, j + DATA_BATCH_SIZE);
|
|
||||||
await Promise.all(
|
if (historyRecords.length > 0) {
|
||||||
batch.map(([key, record]) => {
|
for (let j = 0; j < historyRecords.length; j += DATA_BATCH_SIZE) {
|
||||||
const [platform, id] = key.split('+');
|
const batch = historyRecords.slice(j, j + DATA_BATCH_SIZE);
|
||||||
if (platform && id) {
|
await db.batchUpsertMusicV2History(
|
||||||
return db.saveMusicPlayRecord(username, platform, id, record as any);
|
username,
|
||||||
}
|
batch.map((record: any) => ({
|
||||||
return Promise.resolve();
|
...record,
|
||||||
})
|
source: record.source,
|
||||||
|
songId: record.songId,
|
||||||
|
name: record.name,
|
||||||
|
artist: record.artist,
|
||||||
|
playProgressSec: record.playProgressSec || 0,
|
||||||
|
lastPlayedAt: record.lastPlayedAt || Date.now(),
|
||||||
|
playCount: record.playCount || 1,
|
||||||
|
createdAt: record.createdAt || Date.now(),
|
||||||
|
updatedAt: record.updatedAt || Date.now(),
|
||||||
|
}))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})(),
|
})(),
|
||||||
|
|
||||||
// 导入音乐歌单
|
// 导入音乐 V2 歌单
|
||||||
(async () => {
|
(async () => {
|
||||||
if (user.musicPlaylists && Array.isArray(user.musicPlaylists)) {
|
const playlists = Array.isArray(user.musicV2Playlists)
|
||||||
for (const playlist of user.musicPlaylists) {
|
? user.musicV2Playlists
|
||||||
await db.createMusicPlaylist(username, {
|
: [];
|
||||||
|
|
||||||
|
if (playlists.length > 0) {
|
||||||
|
for (const playlist of playlists) {
|
||||||
|
await db.createMusicV2Playlist(username, {
|
||||||
id: playlist.id,
|
id: playlist.id,
|
||||||
name: playlist.name,
|
name: playlist.name,
|
||||||
description: playlist.description,
|
description: playlist.description,
|
||||||
@@ -330,15 +343,27 @@ export async function POST(req: NextRequest) {
|
|||||||
for (let j = 0; j < playlist.songs.length; j += DATA_BATCH_SIZE) {
|
for (let j = 0; j < playlist.songs.length; j += DATA_BATCH_SIZE) {
|
||||||
const batch = playlist.songs.slice(j, j + DATA_BATCH_SIZE);
|
const batch = playlist.songs.slice(j, j + DATA_BATCH_SIZE);
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
batch.map((song: any) =>
|
batch.map((song: any, index: number) =>
|
||||||
db.addSongToPlaylist(playlist.id, {
|
db.addMusicV2PlaylistItem(playlist.id, {
|
||||||
platform: song.platform,
|
playlistId: playlist.id,
|
||||||
id: song.id,
|
songId: song.songId || song.id,
|
||||||
|
source: song.source || song.platform,
|
||||||
|
songmid: song.songmid,
|
||||||
name: song.name,
|
name: song.name,
|
||||||
artist: song.artist,
|
artist: song.artist,
|
||||||
album: song.album,
|
album: song.album,
|
||||||
pic: song.pic,
|
cover: song.cover || song.pic,
|
||||||
duration: song.duration || 0,
|
durationSec: song.durationSec || song.duration || 0,
|
||||||
|
durationText: song.durationText,
|
||||||
|
hash: song.hash,
|
||||||
|
copyrightId: song.copyrightId,
|
||||||
|
albumId: song.albumId,
|
||||||
|
lrcUrl: song.lrcUrl,
|
||||||
|
mrcUrl: song.mrcUrl,
|
||||||
|
trcUrl: song.trcUrl,
|
||||||
|
sortOrder: song.sortOrder ?? (j + index),
|
||||||
|
addedAt: song.addedAt || Date.now(),
|
||||||
|
updatedAt: song.updatedAt || Date.now(),
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import { NextRequest, NextResponse } from 'next/server';
|
import { NextRequest, NextResponse } from 'next/server';
|
||||||
|
|
||||||
import { getAuthInfoFromCookie } from '@/lib/auth';
|
import { getAuthInfoFromCookie } from '@/lib/auth';
|
||||||
import { getConfig } from '@/lib/config';
|
import { getConfig, setCachedConfig } from '@/lib/config';
|
||||||
import { db } from '@/lib/db';
|
import { db } from '@/lib/db';
|
||||||
|
|
||||||
export const runtime = 'nodejs';
|
export const runtime = 'nodejs';
|
||||||
@@ -66,6 +66,7 @@ export async function POST(request: NextRequest) {
|
|||||||
|
|
||||||
// 写入数据库
|
// 写入数据库
|
||||||
await db.saveAdminConfig(adminConfig);
|
await db.saveAdminConfig(adminConfig);
|
||||||
|
await setCachedConfig(adminConfig);
|
||||||
|
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{ ok: true },
|
{ ok: true },
|
||||||
|
|||||||
@@ -2236,6 +2236,12 @@ export class D1Storage implements IStorage {
|
|||||||
'favorites',
|
'favorites',
|
||||||
'search_history',
|
'search_history',
|
||||||
'skip_configs',
|
'skip_configs',
|
||||||
|
'music_play_records',
|
||||||
|
'music_playlists',
|
||||||
|
'music_playlist_songs',
|
||||||
|
'music_v2_history',
|
||||||
|
'music_v2_playlists',
|
||||||
|
'music_v2_playlist_items',
|
||||||
'danmaku_filter_configs',
|
'danmaku_filter_configs',
|
||||||
'notifications',
|
'notifications',
|
||||||
'movie_requests',
|
'movie_requests',
|
||||||
|
|||||||
@@ -2206,6 +2206,12 @@ export class PostgresStorage implements IStorage {
|
|||||||
'favorites',
|
'favorites',
|
||||||
'search_history',
|
'search_history',
|
||||||
'skip_configs',
|
'skip_configs',
|
||||||
|
'music_play_records',
|
||||||
|
'music_playlists',
|
||||||
|
'music_playlist_songs',
|
||||||
|
'music_v2_history',
|
||||||
|
'music_v2_playlists',
|
||||||
|
'music_v2_playlist_items',
|
||||||
'danmaku_filter_configs',
|
'danmaku_filter_configs',
|
||||||
'notifications',
|
'notifications',
|
||||||
'movie_requests',
|
'movie_requests',
|
||||||
|
|||||||
@@ -1044,6 +1044,22 @@ export abstract class BaseRedisStorage implements IStorage {
|
|||||||
}
|
}
|
||||||
// 删除用户的歌单列表
|
// 删除用户的歌单列表
|
||||||
await this.withRetry(() => this.adapter.del(this.musicPlaylistsKey(userName)));
|
await this.withRetry(() => this.adapter.del(this.musicPlaylistsKey(userName)));
|
||||||
|
|
||||||
|
// 删除音乐 V2 播放记录
|
||||||
|
await this.withRetry(() => this.adapter.del(this.musicV2HistoryKey(userName)));
|
||||||
|
|
||||||
|
// 删除音乐 V2 歌单
|
||||||
|
const musicV2PlaylistIds = await this.withRetry(() =>
|
||||||
|
this.adapter.zRange(this.musicV2PlaylistsKey(userName), 0, -1)
|
||||||
|
);
|
||||||
|
if (musicV2PlaylistIds && musicV2PlaylistIds.length > 0) {
|
||||||
|
for (const playlistId of musicV2PlaylistIds) {
|
||||||
|
const id = ensureString(playlistId);
|
||||||
|
await this.withRetry(() => this.adapter.del(this.musicV2PlaylistKey(id)));
|
||||||
|
await this.withRetry(() => this.adapter.del(this.musicV2PlaylistItemsKey(id)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await this.withRetry(() => this.adapter.del(this.musicV2PlaylistsKey(userName)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------- 新版用户存储(使用Hash和Sorted Set) ----------
|
// ---------- 新版用户存储(使用Hash和Sorted Set) ----------
|
||||||
@@ -1683,7 +1699,7 @@ export abstract class BaseRedisStorage implements IStorage {
|
|||||||
|
|
||||||
// 删除所有用户及其数据
|
// 删除所有用户及其数据
|
||||||
for (const username of allUsers) {
|
for (const username of allUsers) {
|
||||||
await this.deleteUser(username);
|
await this.deleteUserV2(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除管理员配置
|
// 删除管理员配置
|
||||||
|
|||||||
Reference in New Issue
Block a user