Add support to save chapter to db automaicly

This commit is contained in:
2026-02-15 16:54:31 +08:00
parent e355432436
commit e91ae58813
8 changed files with 103 additions and 11 deletions

View File

@@ -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']);

View File

@@ -49,5 +49,9 @@
},
"permissions": [
"storage"
]
],
"background": {
"service_worker": "dist/background.js",
"type": "module"
}
}

43
src/background.ts Normal file
View File

@@ -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
}
});

View File

@@ -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) {

View File

@@ -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,

View File

@@ -24,6 +24,9 @@ export type QdChapterInfo = {
export type SendMessageMap = {
GetQdChapterInfo: {};
SaveQdChapterInfo: {
info: QdChapterInfo;
};
}
export type SendMessage = DiscriminatedUnion<"type", SendMessageMap>;

View File

@@ -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;

View File

@@ -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);
}