数据迁移支持电子书和漫画
This commit is contained in:
@@ -44,7 +44,7 @@ export async function POST(req: NextRequest) {
|
||||
}
|
||||
|
||||
// 解析请求体获取密码
|
||||
const { password } = await req.json();
|
||||
const { password, includeMangaData = true, includeBookData = true } = await req.json();
|
||||
if (!password || typeof password !== 'string') {
|
||||
return NextResponse.json({ error: '请提供加密密码' }, { status: 400 });
|
||||
}
|
||||
@@ -59,7 +59,7 @@ export async function POST(req: NextRequest) {
|
||||
// 所有用户数据
|
||||
userData: {} as { [username: string]: any },
|
||||
// V2用户信息
|
||||
usersV2: [] as any[]
|
||||
usersV2: [] as any[],
|
||||
}
|
||||
};
|
||||
|
||||
@@ -116,14 +116,22 @@ export async function POST(req: NextRequest) {
|
||||
searchHistory,
|
||||
skipConfigs,
|
||||
musicV2History,
|
||||
playlists
|
||||
playlists,
|
||||
mangaShelf,
|
||||
mangaReadRecords,
|
||||
bookShelf,
|
||||
bookReadRecords
|
||||
] = await Promise.all([
|
||||
db.getAllPlayRecords(username),
|
||||
db.getAllFavorites(username),
|
||||
db.getSearchHistory(username),
|
||||
db.getAllSkipConfigs(username),
|
||||
db.listMusicV2History(username),
|
||||
db.listMusicV2Playlists(username)
|
||||
db.listMusicV2Playlists(username),
|
||||
includeMangaData ? db.getAllMangaShelf(username) : Promise.resolve({}),
|
||||
includeMangaData ? db.getAllMangaReadRecords(username) : Promise.resolve({}),
|
||||
includeBookData ? db.getAllBookShelf(username) : Promise.resolve({}),
|
||||
includeBookData ? db.getAllBookReadRecords(username) : Promise.resolve({})
|
||||
]);
|
||||
|
||||
// 并行获取所有歌单的歌曲
|
||||
@@ -143,6 +151,8 @@ export async function POST(req: NextRequest) {
|
||||
skipConfigs,
|
||||
musicV2History,
|
||||
musicV2Playlists: playlistsWithSongs,
|
||||
...(includeMangaData ? { mangaData: { shelf: mangaShelf, readRecords: mangaReadRecords } } : {}),
|
||||
...(includeBookData ? { bookData: { shelf: bookShelf, readRecords: bookReadRecords } } : {}),
|
||||
passwordV2: finalPasswordV2
|
||||
}
|
||||
};
|
||||
|
||||
@@ -80,6 +80,32 @@ export async function POST(req: NextRequest) {
|
||||
return NextResponse.json({ error: '备份文件格式无效' }, { status: 400 });
|
||||
}
|
||||
|
||||
const importUsernames = Object.keys(importData.data.userData || {});
|
||||
const backupHasMangaData = importUsernames.some((name) => Object.prototype.hasOwnProperty.call(importData.data.userData?.[name] || {}, 'mangaData'));
|
||||
const backupHasBookData = importUsernames.some((name) => Object.prototype.hasOwnProperty.call(importData.data.userData?.[name] || {}, 'bookData'));
|
||||
const preserveMangaData = !backupHasMangaData;
|
||||
const preserveBookData = !backupHasBookData;
|
||||
|
||||
const preservedMangaData = preserveMangaData
|
||||
? Object.fromEntries(await Promise.all(importUsernames.map(async (name) => ([
|
||||
name,
|
||||
{
|
||||
mangaShelf: await db.getAllMangaShelf(name),
|
||||
mangaReadRecords: await db.getAllMangaReadRecords(name),
|
||||
},
|
||||
]))))
|
||||
: {};
|
||||
|
||||
const preservedBookData = preserveBookData
|
||||
? Object.fromEntries(await Promise.all(importUsernames.map(async (name) => ([
|
||||
name,
|
||||
{
|
||||
bookShelf: await db.getAllBookShelf(name),
|
||||
bookReadRecords: await db.getAllBookReadRecords(name),
|
||||
},
|
||||
]))))
|
||||
: {};
|
||||
|
||||
// 开始导入数据 - 先清空现有数据
|
||||
updateProgress(username, 'import', 'clearing', 0, 1, '正在清空现有数据...');
|
||||
await db.clearAllData();
|
||||
@@ -371,6 +397,46 @@ export async function POST(req: NextRequest) {
|
||||
}
|
||||
}
|
||||
}
|
||||
})(),
|
||||
|
||||
// 导入漫画书架 / 阅读记录
|
||||
(async () => {
|
||||
if (!backupHasMangaData) return;
|
||||
const mangaShelfEntries = Object.entries((user.mangaData?.shelf || preservedMangaData[username]?.mangaShelf || {}));
|
||||
for (let j = 0; j < mangaShelfEntries.length; j += DATA_BATCH_SIZE) {
|
||||
const batch = mangaShelfEntries.slice(j, j + DATA_BATCH_SIZE);
|
||||
await Promise.all(
|
||||
batch.map(([, item]: [string, any]) => db.saveMangaShelf(username, item.sourceId, item.mangaId, item))
|
||||
);
|
||||
}
|
||||
|
||||
const mangaReadEntries = Object.entries((user.mangaData?.readRecords || preservedMangaData[username]?.mangaReadRecords || {}));
|
||||
for (let j = 0; j < mangaReadEntries.length; j += DATA_BATCH_SIZE) {
|
||||
const batch = mangaReadEntries.slice(j, j + DATA_BATCH_SIZE);
|
||||
await Promise.all(
|
||||
batch.map(([, record]: [string, any]) => db.saveMangaReadRecord(username, record.sourceId, record.mangaId, record))
|
||||
);
|
||||
}
|
||||
})(),
|
||||
|
||||
// 导入电子书书架 / 阅读记录
|
||||
(async () => {
|
||||
if (!backupHasBookData) return;
|
||||
const bookShelfEntries = Object.entries((user.bookData?.shelf || preservedBookData[username]?.bookShelf || {}));
|
||||
for (let j = 0; j < bookShelfEntries.length; j += DATA_BATCH_SIZE) {
|
||||
const batch = bookShelfEntries.slice(j, j + DATA_BATCH_SIZE);
|
||||
await Promise.all(
|
||||
batch.map(([, item]: [string, any]) => db.saveBookShelf(username, item.sourceId, item.bookId, item))
|
||||
);
|
||||
}
|
||||
|
||||
const bookReadEntries = Object.entries((user.bookData?.readRecords || preservedBookData[username]?.bookReadRecords || {}));
|
||||
for (let j = 0; j < bookReadEntries.length; j += DATA_BATCH_SIZE) {
|
||||
const batch = bookReadEntries.slice(j, j + DATA_BATCH_SIZE);
|
||||
await Promise.all(
|
||||
batch.map(([, record]: [string, any]) => db.saveBookReadRecord(username, record.sourceId, record.bookId, record))
|
||||
);
|
||||
}
|
||||
})()
|
||||
]);
|
||||
|
||||
@@ -404,6 +470,8 @@ export async function POST(req: NextRequest) {
|
||||
message: '数据导入成功',
|
||||
importedUsers: Object.keys(userData).length,
|
||||
importedUsersV2: importData.data.usersV2?.length || 0,
|
||||
importedMangaData: backupHasMangaData,
|
||||
importedBookData: backupHasBookData,
|
||||
timestamp: importData.timestamp,
|
||||
serverVersion: typeof importData.serverVersion === 'string' ? importData.serverVersion : '未知版本'
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user