mirror of
https://github.com/lifegpc/bookdownload.git
synced 2026-07-08 01:31:31 +08:00
Allow to insert original chapters by prev/next chapter id
This commit is contained in:
@@ -30,7 +30,9 @@
|
||||
"builddbg": "node build.js --dev --debug",
|
||||
"buildrel": "node build.js",
|
||||
"lint": "eslint src",
|
||||
"test": "node build_test.js && node --enable-source-maps test.cjs"
|
||||
"build_test": "node build_test.js",
|
||||
"test": "node build_test.js && node --enable-source-maps test.cjs",
|
||||
"run_test": "node --enable-source-maps test.cjs"
|
||||
},
|
||||
"type": "module",
|
||||
"types": "./data.d.ts",
|
||||
|
||||
@@ -345,6 +345,8 @@ export class IndexedDb implements Db {
|
||||
name: data.chapterInfo.chapterName,
|
||||
bookId: data.bookId,
|
||||
time: data.time,
|
||||
prev: data.chapterInfo.prev,
|
||||
next: data.chapterInfo.next,
|
||||
};
|
||||
} else if (!oldValue) {
|
||||
currents.set(data.id, value);
|
||||
@@ -354,6 +356,8 @@ export class IndexedDb implements Db {
|
||||
name: data.chapterInfo.chapterName,
|
||||
bookId: data.bookId,
|
||||
time: data.time,
|
||||
prev: data.chapterInfo.prev,
|
||||
next: data.chapterInfo.next,
|
||||
});
|
||||
}
|
||||
}, bookId, 'bookId');
|
||||
|
||||
@@ -244,7 +244,7 @@ export class PocketBaseDb implements Db {
|
||||
const currents: Map<number, [number, number]> = new Map();
|
||||
const list = await this.client.collection(`${this.cfg.prefix}qd_chapters`).getFullList({
|
||||
filter: `bookId = ${bookId}`,
|
||||
fields: 'id,chapterId,bookId,time,data.chapterInfo.chapterName',
|
||||
fields: 'id,chapterId,bookId,time,data.chapterInfo.chapterName,data.chapterInfo.prev,data.chapterInfo.next',
|
||||
});
|
||||
const re: QdChapterSimpleInfo[] = [];
|
||||
for (const item of list) {
|
||||
@@ -261,6 +261,8 @@ export class PocketBaseDb implements Db {
|
||||
name: data.chapterInfo.chapterName,
|
||||
bookId: item.bookId,
|
||||
time: item.time,
|
||||
prev: data.chapterInfo.prev,
|
||||
next: data.chapterInfo.next,
|
||||
};
|
||||
} else if (!oldValue) {
|
||||
currents.set(key, value);
|
||||
@@ -270,6 +272,8 @@ export class PocketBaseDb implements Db {
|
||||
name: data.chapterInfo.chapterName,
|
||||
bookId: item.bookId,
|
||||
time: item.time,
|
||||
prev: data.chapterInfo.prev,
|
||||
next: data.chapterInfo.next,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,10 @@ export type QdChapterSimpleInfo = {
|
||||
name: string;
|
||||
bookId: number;
|
||||
time: number;
|
||||
/// Previous chapter ID
|
||||
prev?: number;
|
||||
/// Next chapter ID
|
||||
next?: number;
|
||||
}
|
||||
|
||||
export type QdChapterHistoryInfo = {
|
||||
|
||||
@@ -83,4 +83,90 @@ export default function t() {
|
||||
},
|
||||
]);
|
||||
});
|
||||
test(filename, 'merge_volumes_2', () => {
|
||||
const sourceList: Volume[] = [
|
||||
{
|
||||
id: 'test',
|
||||
name: 'Test Volume',
|
||||
isVip: false,
|
||||
chapters: [
|
||||
{ id: 3, name: 'Chapter 3' },
|
||||
]
|
||||
}
|
||||
];
|
||||
const targetList: QdChapterSimpleInfo[] = [
|
||||
{
|
||||
primaryKey: 0,
|
||||
id: 1,
|
||||
name: 'Chapter 1',
|
||||
bookId: 0,
|
||||
time: 10,
|
||||
next: 3,
|
||||
},
|
||||
{
|
||||
primaryKey: 0,
|
||||
id: 4,
|
||||
name: 'Chapter 4',
|
||||
bookId: 0,
|
||||
time: 11,
|
||||
prev: 3,
|
||||
},
|
||||
{
|
||||
primaryKey: 0,
|
||||
id: 33,
|
||||
name: 'Other',
|
||||
bookId: 0,
|
||||
time: 12,
|
||||
},
|
||||
];
|
||||
expect(get_new_volumes(targetList, sourceList, ChapterShowMode.All)).toEqual([
|
||||
{
|
||||
id: 'vol_new',
|
||||
name: '其他已保存章节',
|
||||
isVip: false,
|
||||
chapters: [
|
||||
{ id: 33, name: 'Other', isSaved: true },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'test',
|
||||
name: 'Test Volume',
|
||||
isVip: false,
|
||||
chapters: [
|
||||
{ id: 1, name: 'Chapter 1', isSaved: true },
|
||||
{ id: 3, name: 'Chapter 3' },
|
||||
{ id: 4, name: 'Chapter 4', isSaved: true },
|
||||
]
|
||||
}
|
||||
]);
|
||||
expect(get_new_volumes(targetList, sourceList, ChapterShowMode.SavedOnly)).toEqual([
|
||||
{
|
||||
id: 'vol_new',
|
||||
name: '其他已保存章节',
|
||||
isVip: false,
|
||||
chapters: [
|
||||
{ id: 33, name: 'Other' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'test',
|
||||
name: 'Test Volume',
|
||||
isVip: false,
|
||||
chapters: [
|
||||
{ id: 1, name: 'Chapter 1' },
|
||||
{ id: 4, name: 'Chapter 4' },
|
||||
],
|
||||
},
|
||||
]);
|
||||
expect(get_new_volumes(targetList, sourceList, ChapterShowMode.UnsavedOnly)).toEqual([
|
||||
{
|
||||
id: 'test',
|
||||
name: 'Test Volume',
|
||||
isVip: false,
|
||||
chapters: [
|
||||
{ id: 3, name: 'Chapter 3' },
|
||||
],
|
||||
},
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -38,28 +38,72 @@ export function hash_qdchapter_info(info: QdChapterInfo): string {
|
||||
|
||||
export function get_new_volumes(chapterLists: QdChapterSimpleInfo[], volumes: Volume[], keepMode: ChapterShowMode): Volume[] {
|
||||
const vols: Volume[] = [];
|
||||
if (keepMode == ChapterShowMode.All) {
|
||||
const volMap: Map<number, Chapter> = new Map();
|
||||
if (keepMode == ChapterShowMode.All || keepMode == ChapterShowMode.SavedOnly) {
|
||||
const chMap: Map<number, Chapter> = new Map();
|
||||
const volMap: Map<number, Volume> = new Map();
|
||||
for (const vo of volumes) {
|
||||
const vol = structuredClone(vo);
|
||||
for (const ch of vol.chapters) {
|
||||
volMap.set(ch.id, ch);
|
||||
chMap.set(ch.id, ch);
|
||||
volMap.set(ch.id, vol);
|
||||
}
|
||||
vols.push(vol);
|
||||
}
|
||||
const volCh: Chapter[] = [];
|
||||
let needed: QdChapterSimpleInfo[] = [];
|
||||
for (const ch of chapterLists) {
|
||||
const chInfo = volMap.get(ch.id);
|
||||
const chInfo = chMap.get(ch.id);
|
||||
if (!chInfo) {
|
||||
volCh.push({
|
||||
id: ch.id,
|
||||
name: ch.name,
|
||||
isSaved: true,
|
||||
});
|
||||
needed.push(ch);
|
||||
} else {
|
||||
chInfo.isSaved = true;
|
||||
}
|
||||
}
|
||||
let changed = false;
|
||||
do {
|
||||
const current_len = needed.length;
|
||||
const not_found: QdChapterSimpleInfo[] = [];
|
||||
for (const ch of needed) {
|
||||
if (ch.prev) {
|
||||
const prevVol = volMap.get(ch.prev);
|
||||
if (prevVol) {
|
||||
const chIndex = prevVol.chapters.findIndex(c => c.id === ch.prev);
|
||||
if (chIndex !== -1) {
|
||||
prevVol.chapters.splice(chIndex + 1, 0, {
|
||||
id: ch.id,
|
||||
name: ch.name,
|
||||
isSaved: true,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ch.next) {
|
||||
const nextVol = volMap.get(ch.next);
|
||||
if (nextVol) {
|
||||
const chIndex = nextVol.chapters.findIndex(c => c.id === ch.next);
|
||||
if (chIndex !== -1) {
|
||||
nextVol.chapters.splice(chIndex, 0, {
|
||||
id: ch.id,
|
||||
name: ch.name,
|
||||
isSaved: true,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
not_found.push(ch);
|
||||
}
|
||||
needed = not_found;
|
||||
changed = current_len !== needed.length;
|
||||
} while (changed && needed.length > 0);
|
||||
for (const ch of needed) {
|
||||
volCh.push({
|
||||
id: ch.id,
|
||||
name: ch.name,
|
||||
isSaved: true,
|
||||
});
|
||||
}
|
||||
if (volCh.length > 0) {
|
||||
vols.unshift({
|
||||
id: 'vol_new',
|
||||
@@ -68,39 +112,12 @@ export function get_new_volumes(chapterLists: QdChapterSimpleInfo[], volumes: Vo
|
||||
isVip: false,
|
||||
});
|
||||
}
|
||||
} else if (keepMode == ChapterShowMode.SavedOnly) {
|
||||
const chIds = new Set(chapterLists.map(ch => ch.id));
|
||||
for (const vol of volumes) {
|
||||
const newChs = vol.chapters.filter(ch => chIds.has(ch.id));
|
||||
if (newChs.length > 0) {
|
||||
vols.push({
|
||||
...vol,
|
||||
chapters: newChs,
|
||||
});
|
||||
if (keepMode == ChapterShowMode.SavedOnly) {
|
||||
for (const vol of vols) {
|
||||
vol.chapters = vol.chapters.filter(ch => ch.isSaved);
|
||||
vol.chapters.forEach(ch => delete ch.isSaved);
|
||||
}
|
||||
}
|
||||
for (const vol of vols) {
|
||||
for (const ch of vol.chapters) {
|
||||
chIds.delete(ch.id);
|
||||
}
|
||||
}
|
||||
if (chIds.size > 0) {
|
||||
const volCh: Chapter[] = [];
|
||||
for (const ch of chapterLists) {
|
||||
if (chIds.has(ch.id)) {
|
||||
volCh.push({
|
||||
id: ch.id,
|
||||
name: ch.name,
|
||||
});
|
||||
}
|
||||
}
|
||||
vols.unshift({
|
||||
id: 'vol_new',
|
||||
name: '其他已保存章节',
|
||||
chapters: volCh,
|
||||
isVip: false,
|
||||
});
|
||||
}
|
||||
} else if (keepMode == ChapterShowMode.UnsavedOnly) {
|
||||
const chIds = new Set(chapterLists.map(ch => ch.id));
|
||||
for (const vol of volumes) {
|
||||
|
||||
Reference in New Issue
Block a user