Add support to get book info from book info page

This commit is contained in:
2026-02-16 11:44:32 +08:00
parent ab46dcc2c1
commit 0cf5eccaf1
8 changed files with 204 additions and 1 deletions

View File

@@ -91,4 +91,5 @@ async function buildTsx(names, tsnames) {
fs.rmSync('dist', { recursive: true, force: true });
fs.mkdirSync('dist', { recursive: true });
await build('qdchapter');
await build('qdbook');
await buildTsx(['popup', 'settings'], ['background']);

3
inject/qdbook.js Normal file
View File

@@ -0,0 +1,3 @@
window.addEventListener('load', function() {
window.postMessage({'@type': 'g_data', g_data}, '*');
})

View File

@@ -41,6 +41,27 @@
],
"run_at": "document_start",
"world": "MAIN"
},
{
"matches": [
"http://*.qidian.com/book/*",
"https://*.qidian.com/book/*"
],
"js": [
"dist/qdbook.js"
],
"run_at": "document_start"
},
{
"matches": [
"http://*.qidian.com/book/*",
"https://*.qidian.com/book/*"
],
"js": [
"inject/qdbook.js"
],
"run_at": "document_start",
"world": "MAIN"
}
],
"options_ui": {

View File

@@ -42,6 +42,12 @@ function PopupBody() {
});
setResult(msg);
}
if (params.page === 'qdbook') {
const msg = await sendMessageToTab(tab.id, {
type: 'GetQdBookInfo',
});
setResult(msg);
}
} catch (e) {
setError(e instanceof Error ? e.message : 'Unknown error');
return;
@@ -63,6 +69,9 @@ function PopupBody() {
delete body.type;
return <QdChapterInfoModel info={body} />;
}
if (result.ok && result.body?.type === 'QdBookInfo') {
return <Result status="success" title={result.body.bookName} subTitle={`Book ID: ${result.body.id}`} />;
}
return <Result status="error" title="错误" subTitle={result.msg || '未知错误'} />;
}
if (error) {

103
src/qdbook.ts Normal file
View File

@@ -0,0 +1,103 @@
import type { BookGData, QdBookTag } from "./qdtypes";
import type { SendMessage, Message } from "./types";
import { QdBookTagType } from "./qdtypes";
let g_data: BookGData | undefined;
function get_book_name() {
const bookName = document.getElementById('bookName') as HTMLHeadingElement | null;
if (!bookName) {
throw new Error('Failed to find book name element');
}
return bookName.innerText.trim();
}
function get_book_tags() {
const tags: QdBookTag[] = [];
const attribute = document.querySelector('p.book-attribute');
if (attribute) {
for (const children of attribute.children) {
if (children instanceof HTMLSpanElement) {
if (children.classList.contains("dot")) {
continue;
}
tags.push({
type: QdBookTagType.System,
name: children.innerText.trim(),
});
} else if (children instanceof HTMLAnchorElement) {
tags.push({
type: QdBookTagType.Category,
name: children.innerText.trim(),
url: children.href,
});
} else {
throw new Error(`Unknown tag element: ${children.outerHTML}`);
}
}
}
const allLabel = document.querySelector('p.all-label');
if (allLabel) {
for (const label of allLabel.children) {
if (label instanceof HTMLAnchorElement) {
tags.push({
type: QdBookTagType.User,
name: label.innerText.trim(),
url: label.href,
});
} else {
throw new Error(`Unknown user tag element: ${label.outerHTML}`);
}
}
}
return tags;
}
window.addEventListener('message', (event) => {
const data = event.data;
if (data && data['@type'] === 'g_data') {
g_data = data.g_data;
console.log('Received g_data:', g_data);
}
});
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
const m = message as SendMessage;
try {
if (m.type === 'GetQdBookInfo') {
if (!g_data) {
const msg: Message = {
ok: false,
code: 404,
msg: '没有找到g_data,可能是页面数据还没有加载完成,请稍后再试或者尝试刷新页面',
for: m.type,
};
sendResponse(msg);
return;
}
const bookName = get_book_name();
const msg: Message = {
ok: true,
code: 0,
body: {
type: 'QdBookInfo',
bookInfo: g_data,
bookName,
id: g_data.pageJson.bookId,
tags: get_book_tags(),
},
for: m.type,
};
sendResponse(msg);
}
} catch (e) {
console.error(e);
const msg: Message = {
ok: false,
code: 500,
msg: e instanceof Error ? e.message : 'Unknown error',
for: m.type,
};
sendResponse(msg);
}
});

View File

@@ -166,3 +166,45 @@ export type PageContext = {
};
};
};
export type BookGData = {
chanId: number;
checkLevel8: boolean;
firstChapterId: number;
imgUrl: string;
isBookAlbum: boolean;
isCatelog: boolean;
isPublication: number;
pageJson: {
authorInfo: {
authorId: string;
authorName: string;
avatar: string;
},
bookId: number;
bookType: number;
isLogin: boolean;
isPublication: boolean;
isSign: number;
isVip: number;
salesMode: number;
signStatus: string;
}
}
export type Volume = {
name: string;
id: number;
}
export enum QdBookTagType {
System,
Category,
User,
}
export type QdBookTag = {
name: string;
type: QdBookTagType;
url?: string;
}

View File

@@ -1,4 +1,4 @@
import * as QdTypes from "./qdtypes";
import type * as QdTypes from "./qdtypes";
export type DiscriminatedUnion<
K extends PropertyKey,
@@ -22,8 +22,17 @@ export type QdChapterInfo = {
hash?: string;
}
export type QDBookInfo = {
bookInfo: QdTypes.BookGData;
bookName: string;
/**Book ID */
id: number;
tags: QdTypes.QdBookTag[];
}
export type SendMessageMap = {
GetQdChapterInfo: {};
GetQdBookInfo: {};
SaveQdChapterInfo: {
info: QdChapterInfo;
};
@@ -33,6 +42,7 @@ export type SendMessage = DiscriminatedUnion<"type", SendMessageMap>;
export type MessageMap = {
QdChapterInfo: QdChapterInfo,
QdBookInfo: QDBookInfo,
};
export type MessageBody = DiscriminatedUnion<"type", MessageMap>;
@@ -51,8 +61,13 @@ export type QdChapterUrlParams = {
chapterId: string;
}
export type QdBookUrlParams = {
bookId: string;
}
export type UrlParamsMap = {
qdchapter: QdChapterUrlParams;
qdbook: QdBookUrlParams;
}
export type UrlParams = DiscriminatedUnion<"page", UrlParamsMap>;

View File

@@ -1,6 +1,7 @@
import type { UrlParams, SendMessage, Message } from "./types";
export const QD_CHAPTER_URLPATH_REGEX = /^\/chapter\/(\d+)\/(\d+)\/?$/;
export const QD_BOOK_URLPATH_REGEX = /^\/book\/(\d+)\/?$/;
export function parseUrlParams(url: string | URL): UrlParams | undefined {
const u = url instanceof URL ? url : new URL(url);
@@ -14,6 +15,14 @@ export function parseUrlParams(url: string | URL): UrlParams | undefined {
chapterId,
} as UrlParams;
}
const bookMatch = u.pathname.match(QD_BOOK_URLPATH_REGEX);
if (bookMatch) {
const [, bookId] = bookMatch;
return {
page: 'qdbook',
bookId,
} as UrlParams;
}
}
}