217 lines
5.9 KiB
TypeScript
217 lines
5.9 KiB
TypeScript
import type { Book } from "../library";
|
|
import type { Browser, BrowserContext, ImageFile } from "../browser";
|
|
|
|
var NFBR: any;
|
|
|
|
export async function getImageFiles(): Promise<Array<ImageFile>> {
|
|
const params = new URLSearchParams(location.search);
|
|
const model = new NFBR.a6G.Model({
|
|
settings: new NFBR.Settings("NFBR.SettingData"),
|
|
viewerFontSize: NFBR.a0X.a3K,
|
|
viewerFontFace: NFBR.a0X.a3k,
|
|
viewerSpreadDouble: true,
|
|
viewerSpread: {},
|
|
});
|
|
const a6l = new NFBR.a6G.a6L(model);
|
|
const a2f = new NFBR.a2F();
|
|
const a5w = await a2f.a5W({
|
|
contentId: params.get(NFBR.a5q.Key.CONTENT_ID),
|
|
a6m: params.get(NFBR.a5q.Key.a6M),
|
|
preview:
|
|
params.get(NFBR.a5q.Key.LOOK_INSIDE) !== NFBR.a5q.LookInsideType.DISABLED,
|
|
previewType:
|
|
params.get(NFBR.a5q.Key.LOOK_INSIDE) ?? NFBR.a5q.LookInsideType.DISABLED,
|
|
contentType: a6l.getContentType(),
|
|
title: true,
|
|
});
|
|
const content = new NFBR.a6i.Content(a5w.url);
|
|
const a5n = new NFBR.a5n();
|
|
await a5n.a5s(content, "configuration", a6l);
|
|
|
|
const imageFiles: Array<ImageFile> = [];
|
|
|
|
for (const index of Object.keys(content.files)) {
|
|
const file = content.files[index];
|
|
const conf = content.configuration.contents[index];
|
|
const {
|
|
No,
|
|
DummyWidth,
|
|
DummyHeight,
|
|
Size: { Width, Height },
|
|
} = file.FileLinkInfo.PageLinkInfoList[0].Page;
|
|
|
|
const page = new NFBR.a6i.Page(
|
|
`${conf.file}/${No}.jpeg`,
|
|
index,
|
|
`${conf["original-file-path"]}#-acs-position-${file.PageToBookmark[0][0]}-${file.PageToBookmark[0][1]}`,
|
|
);
|
|
|
|
const w = [...`${conf.file}/${No}`]
|
|
.map((c) => c.charCodeAt(0))
|
|
.reduce((a, cc) => a + cc, 0);
|
|
|
|
const pattern = (w % NFBR.a0X.a3h) + 1;
|
|
const blocks = NFBR.a3E.a3f(
|
|
Width + DummyWidth,
|
|
Height + DummyHeight,
|
|
NFBR.a0X.a3g,
|
|
NFBR.a0X.a3G,
|
|
pattern,
|
|
);
|
|
|
|
const url = `${a5w.url}${page.url}`;
|
|
|
|
imageFiles.push({
|
|
url,
|
|
blocks,
|
|
width: Width,
|
|
height: Height,
|
|
});
|
|
}
|
|
|
|
return imageFiles;
|
|
}
|
|
|
|
export function DmmBooks(browser: Browser) {
|
|
async function* getSeriesBooks(
|
|
ctx: BrowserContext,
|
|
series: {
|
|
seriesId: string;
|
|
shopName: string;
|
|
title: string;
|
|
authors: Array<string>;
|
|
},
|
|
): AsyncGenerator<Book> {
|
|
const endpoint = `https://book.dmm.com/ajax/bff/contents/?shop_name=${series.shopName}&series_id=${series.seriesId}`;
|
|
const pager = {
|
|
page: 1,
|
|
perPage: 0,
|
|
totalCount: Infinity,
|
|
};
|
|
|
|
while (pager.page * pager.perPage <= pager.totalCount) {
|
|
const res = await ctx.request.get(`${endpoint}&page=${pager.page}`);
|
|
|
|
if (!res.ok()) {
|
|
throw new Error(`${res.status()} ${res.statusText()}`);
|
|
}
|
|
|
|
const body: {
|
|
volume_books: Array<{
|
|
title: string;
|
|
purchased?: {
|
|
streaming_url: string;
|
|
};
|
|
}>;
|
|
pager: {
|
|
page: number;
|
|
per_page: number;
|
|
total_count: number;
|
|
};
|
|
} = await res.json();
|
|
|
|
for (const book of body.volume_books.filter((b) => b.purchased)) {
|
|
yield {
|
|
id: NaN,
|
|
platform: "dmm-books",
|
|
readerUrl: book.purchased?.streaming_url!,
|
|
title: book.title || series.title || "",
|
|
authors: series.authors,
|
|
};
|
|
|
|
process.stderr.write(".");
|
|
}
|
|
|
|
pager.page += 1;
|
|
pager.perPage = body.pager.per_page;
|
|
pager.totalCount = body.pager.total_count;
|
|
}
|
|
}
|
|
|
|
async function* getAllBooks(ctx: BrowserContext): AsyncGenerator<Book> {
|
|
const endpoint = "https://book.dmm.com/ajax/bff/library/?shop_name=all";
|
|
const pager = {
|
|
page: 1,
|
|
perPage: 0,
|
|
totalCount: Infinity,
|
|
};
|
|
|
|
while (pager.page * pager.perPage <= pager.totalCount) {
|
|
const res = await ctx.request.get(`${endpoint}&page=${pager.page}`);
|
|
|
|
if (!res.ok()) {
|
|
throw new Error(`${res.status()} ${res.statusText()}`);
|
|
}
|
|
|
|
const body: {
|
|
series_books: Array<{
|
|
shop_name: string;
|
|
series_id: string;
|
|
title: string;
|
|
author: Array<string>;
|
|
}>;
|
|
pager: {
|
|
page: number;
|
|
per_page: number;
|
|
total_count: number;
|
|
};
|
|
} = await res.json();
|
|
|
|
for (const series of body.series_books) {
|
|
yield* getSeriesBooks(ctx, {
|
|
seriesId: series.series_id,
|
|
shopName: series.shop_name,
|
|
title: series.title,
|
|
authors: series.author,
|
|
});
|
|
}
|
|
|
|
pager.page += 1;
|
|
pager.perPage = body.pager.per_page;
|
|
pager.totalCount = body.pager.total_count;
|
|
}
|
|
}
|
|
|
|
return {
|
|
async login() {
|
|
const ctx = await browser.newContext();
|
|
const page = await ctx.newPage();
|
|
await page.goto("https://accounts.dmm.com/service/login/password");
|
|
await page.waitForURL("https://www.dmm.com/", { timeout: 0 });
|
|
await page.goto("https://www.dmm.com/service/-/exchange");
|
|
await Promise.race([
|
|
page.waitForURL("https://www.dmm.com/", { timeout: 0 }),
|
|
page.waitForURL("https://www.dmm.co.jp/top/", { timeout: 0 }),
|
|
]);
|
|
await browser.saveBrowserContext("dmm-books", ctx);
|
|
},
|
|
|
|
async *pull(): AsyncGenerator<Book> {
|
|
const ctx = await browser.loadBrowserContext("dmm-books");
|
|
|
|
yield* getAllBooks(ctx);
|
|
|
|
process.stderr.write(`\n`);
|
|
},
|
|
|
|
async getFiles(book: Book): Promise<Array<() => Promise<string>>> {
|
|
const ctx = await browser.loadBrowserContext("dmm-books");
|
|
const page = await ctx.newPage();
|
|
|
|
await page.goto(book.readerUrl);
|
|
|
|
const imageFiles = await page.evaluate(getImageFiles);
|
|
|
|
return imageFiles.map((imageFile) => async () => {
|
|
const dataUrl = await browser.drawImage(page, imageFile);
|
|
|
|
process.stderr.write(".");
|
|
|
|
return dataUrl;
|
|
});
|
|
},
|
|
};
|
|
}
|
|
|
|
DmmBooks.siteUrl = (url: URL) =>
|
|
["https://book.dmm.com", "https://book.dmm.co.jp"].includes(url.origin);
|