From e91ae58813533b67d423f3814c7b5ac954ba12f8 Mon Sep 17 00:00:00 2001 From: lifegpc Date: Sun, 15 Feb 2026 16:54:31 +0800 Subject: [PATCH] Add support to save chapter to db automaicly --- build.js | 7 +++++-- manifest.json | 6 +++++- src/background.ts | 43 +++++++++++++++++++++++++++++++++++++++++++ src/db/indexedDb.ts | 4 ++-- src/qdchapter.ts | 42 +++++++++++++++++++++++++++++++++++++++--- src/types.ts | 3 +++ src/utils.ts | 5 ++++- src/utils/qd.ts | 4 ++-- 8 files changed, 103 insertions(+), 11 deletions(-) create mode 100644 src/background.ts diff --git a/build.js b/build.js index c3fe140..fd47972 100644 --- a/build.js +++ b/build.js @@ -57,11 +57,14 @@ async function build(name, is_content_script = true) { return result; } -async function buildTsx(names) { +async function buildTsx(names, tsnames) { const entryPoints = []; for (const name of names) { entryPoints.push(`src/${name}.tsx`); } + for (const name of tsnames) { + entryPoints.push(`src/${name}.ts`); + } const result = await esbuild.build({ entryPoints: entryPoints, bundle: true, @@ -88,4 +91,4 @@ async function buildTsx(names) { fs.rmSync('dist', { recursive: true, force: true }); fs.mkdirSync('dist', { recursive: true }); await build('qdchapter'); -await buildTsx(['popup', 'settings']); +await buildTsx(['popup', 'settings'], ['background']); diff --git a/manifest.json b/manifest.json index 2428717..8b648b7 100644 --- a/manifest.json +++ b/manifest.json @@ -49,5 +49,9 @@ }, "permissions": [ "storage" - ] + ], + "background": { + "service_worker": "dist/background.js", + "type": "module" + } } \ No newline at end of file diff --git a/src/background.ts b/src/background.ts new file mode 100644 index 0000000..07303f3 --- /dev/null +++ b/src/background.ts @@ -0,0 +1,43 @@ +import type { SendMessage, Message } from "./types"; +import { createDb } from "./db/interfaces"; +import type { Db } from "./db/interfaces"; +import type { QdChapterInfo } from "./types"; + +let db: Db | null = null; + +async function get_db() { + if (!db) { + const d = await createDb(); + await d.init(); + db = d; + } + return db; +} + +async function save_qd_chapter_info(info: QdChapterInfo) { + const d = await get_db(); + await d.saveQdChapter(info); +} + +chrome.runtime.onMessage.addListener((message: SendMessage, sender, sendResponse) => { + if (message.type === 'SaveQdChapterInfo') { + save_qd_chapter_info(message.info).then(() => { + const msg: Message = { + ok: true, + code: 0, + for: 'SaveQdChapterInfo', + }; + sendResponse(msg); + }).catch(e => { + const msg: Message = { + ok: false, + code: 1, + msg: e instanceof Error ? e.message : 'Unknown error', + for: 'SaveQdChapterInfo', + }; + console.log('Failed to save chapter info:', e); + sendResponse(msg); + }); + return true; // Indicates that the response will be sent asynchronously + } +}); diff --git a/src/db/indexedDb.ts b/src/db/indexedDb.ts index c483a96..fa4ac4d 100644 --- a/src/db/indexedDb.ts +++ b/src/db/indexedDb.ts @@ -1,6 +1,6 @@ import { IndexedDbConfig } from "../config"; import type { QdChapterInfo } from "../types"; -import { compress } from "../utils"; +import { compress, isServiceWorker } from "../utils"; import { hash_qdchapter_info } from "../utils/qd"; import type { Db } from "./interfaces"; @@ -119,7 +119,7 @@ export class IndexedDb implements Db { }); } async init() { - make_storage_persist(); + if (!isServiceWorker) make_storage_persist(); await this.init_qddb(); } async saveQdChapter(info: QdChapterInfo) { diff --git a/src/qdchapter.ts b/src/qdchapter.ts index 98eb854..ce2653d 100644 --- a/src/qdchapter.ts +++ b/src/qdchapter.ts @@ -1,5 +1,7 @@ import type { PageContext } from './qdtypes'; import type { Message, SendMessage } from './types'; +import { QdConfig } from './config'; +import { get_chapter_content } from './utils'; function getPageData(): PageContext | undefined { let data = document.getElementById('vite-plugin-ssr_pageContext')?.innerHTML; @@ -11,12 +13,44 @@ function getPageData(): PageContext | undefined { let loaded = false; -function load() { +async function load() { const pageData = getPageData(); if (!pageData) { console.log(`No page data found on ${window.location.href}`); return; } + const cfg = new QdConfig(); + await cfg.init(); + if (!cfg.AutoSaveChapter) { + return; + } + const chapterInfo = pageData.pageContext.pageProps.pageData.chapterInfo; + const bookInfo = pageData.pageContext.pageProps.pageData.bookInfo; + let contents: string[] | undefined = undefined; + if (chapterInfo.vipStatus !== 0) { + if (!chapterInfo.isBuy) return; + if (chapterInfo.cES !== 0) return; + contents = getContents(); + } else { + contents = get_chapter_content(chapterInfo.content); + } + // Clear encrypted content to reduce size. + chapterInfo.content = ''; + const msg: SendMessage = { + type: 'SaveQdChapterInfo', + info: { + chapterInfo, + bookInfo, + bookId: bookInfo.bookId, + id: chapterInfo.chapterId, + contents, + time: Date.now(), + }, + } + const re: Message = await chrome.runtime.sendMessage(msg); + if (!re.ok) { + console.error(`Failed to save chapter info: ${re.msg}`); + } } function getContents() { @@ -48,9 +82,11 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => { let contents: string[] | undefined = undefined; if (chapterInfo.vipStatus !== 0) { contents = getContents(); - // Clear encrypted content to reduce size. - chapterInfo.content = ''; + } else { + contents = get_chapter_content(chapterInfo.content); } + // Clear encrypted content to reduce size. + chapterInfo.content = ''; const msg: Message = { ok: true, code: 0, diff --git a/src/types.ts b/src/types.ts index 6bab927..69bc4a8 100644 --- a/src/types.ts +++ b/src/types.ts @@ -24,6 +24,9 @@ export type QdChapterInfo = { export type SendMessageMap = { GetQdChapterInfo: {}; + SaveQdChapterInfo: { + info: QdChapterInfo; + }; } export type SendMessage = DiscriminatedUnion<"type", SendMessageMap>; diff --git a/src/utils.ts b/src/utils.ts index 93645cd..f750a43 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -132,6 +132,9 @@ export async function decompress(data: BufferSource, method: CompressionFormat = return result; } -export function ToHex(bytes: Uint8Array): string { +export function toHex(bytes: Uint8Array): string { return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join(''); } + +/**@ts-ignore */ +export const isServiceWorker = typeof ServiceWorkerGlobalScope !== 'undefined' && self instanceof ServiceWorkerGlobalScope; diff --git a/src/utils/qd.ts b/src/utils/qd.ts index 1f0f5cc..318706e 100644 --- a/src/utils/qd.ts +++ b/src/utils/qd.ts @@ -1,6 +1,6 @@ import { SHA256 } from "@stablelib/sha256"; import type { QdChapterInfo } from "../types"; -import { get_chapter_content, ToHex } from "../utils"; +import { get_chapter_content, toHex } from "../utils"; export function hash_qdchapter_info(info: QdChapterInfo): string { const encoder = new TextEncoder(); @@ -25,5 +25,5 @@ export function hash_qdchapter_info(info: QdChapterInfo): string { } } const hash = h.digest(); - return ToHex(hash); + return toHex(hash); }