fix dlsite-maniax
This commit is contained in:
parent
27c4784793
commit
3dfe483973
5 changed files with 92 additions and 23 deletions
|
@ -10,7 +10,7 @@ $ npx https://git.fogtype.com/nebel/gadl/archive/main.tar.gz --help
|
|||
|
||||
- Google Play ブックス (漫画)
|
||||
- DMM ブックス (漫画)
|
||||
- DLsite 同人
|
||||
- DLsite 同人/がるまに/成年コミック
|
||||
- FANZA 同人
|
||||
|
||||
## License
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import * as Playwright from "playwright";
|
||||
import type * as Playwright from "playwright";
|
||||
import { chromium, devices } from "playwright";
|
||||
import type { Database } from "./database";
|
||||
import type { TPlatform } from "./platform";
|
||||
|
||||
export type PageOrFrame = Playwright.Page | Playwright.Frame;
|
||||
|
||||
export type ImageFile = {
|
||||
url: string;
|
||||
blocks?: Array<Record<string, number>>;
|
||||
|
|
4
package-lock.json
generated
4
package-lock.json
generated
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "@fogtype/gadl",
|
||||
"version": "1.5.0",
|
||||
"version": "1.5.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@fogtype/gadl",
|
||||
"version": "1.5.0",
|
||||
"version": "1.5.1",
|
||||
"license": "AGPL-3.0",
|
||||
"dependencies": {
|
||||
"fflate": "^0.8.1",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@fogtype/gadl",
|
||||
"version": "1.5.0",
|
||||
"version": "1.5.1",
|
||||
"license": "AGPL-3.0",
|
||||
"type": "module",
|
||||
"bin": "bin/run.js",
|
||||
|
|
|
@ -1,5 +1,41 @@
|
|||
import type {
|
||||
Browser,
|
||||
BrowserContext,
|
||||
ImageFile,
|
||||
PageOrFrame,
|
||||
} from "../browser";
|
||||
import type { Book } from "../library";
|
||||
import type { Browser, BrowserContext, ImageFile } from "../browser";
|
||||
|
||||
// リーダーのページ要素
|
||||
const workTreeItemsSelector = `[class^=_worktree_] li[class^=_item_]`;
|
||||
|
||||
function Reader(page: PageOrFrame, readerUrl: string) {
|
||||
const workId = /^https:[/][/]play[.]dlsite[.]com[/]#[/]work[/]([^/]+)/.exec(
|
||||
readerUrl,
|
||||
)?.[1];
|
||||
|
||||
if (!workId) {
|
||||
throw new Error(`workId is not included: ${readerUrl}`);
|
||||
}
|
||||
|
||||
return {
|
||||
async load() {
|
||||
await page.goto(readerUrl);
|
||||
},
|
||||
async downloadUrl(): Promise<null | string> {
|
||||
const isBook = workId.startsWith("B");
|
||||
|
||||
if (isBook) {
|
||||
// PDFファイルでないことを確認
|
||||
const items = await page.waitForSelector(workTreeItemsSelector);
|
||||
const text = await items.textContent();
|
||||
if (!text?.match(/PDFファイル/u)) return null;
|
||||
}
|
||||
|
||||
return `https://www.dlsite.com/home/download/=/product_id/${workId}.html`;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function DlsiteManiax(browser: Browser) {
|
||||
async function* getAllBooks(ctx: BrowserContext): AsyncGenerator<Book> {
|
||||
|
@ -37,6 +73,7 @@ export function DlsiteManiax(browser: Browser) {
|
|||
ja_JP: string;
|
||||
};
|
||||
};
|
||||
author_name: string | null;
|
||||
}>;
|
||||
} = await res.json();
|
||||
|
||||
|
@ -46,7 +83,7 @@ export function DlsiteManiax(browser: Browser) {
|
|||
platform: "dlsite-maniax",
|
||||
readerUrl: `https://play.dlsite.com/#/work/${work.workno}`,
|
||||
title: work.name.ja_JP || "",
|
||||
authors: [work.maker.name.ja_JP || ""],
|
||||
authors: [work.author_name || work.maker.name.ja_JP || ""],
|
||||
};
|
||||
|
||||
process.stderr.write(".");
|
||||
|
@ -69,30 +106,60 @@ export function DlsiteManiax(browser: Browser) {
|
|||
async getFiles(book: Book): Promise<Array<() => Promise<Blob>>> {
|
||||
const ctx = await browser.loadBrowserContext("dlsite-maniax");
|
||||
const page = await ctx.newPage();
|
||||
const reader = Reader(page, book.readerUrl);
|
||||
|
||||
await page.goto(book.readerUrl);
|
||||
await reader.load();
|
||||
const downloadUrl = await reader.downloadUrl();
|
||||
|
||||
const [, workId] =
|
||||
/^https:[/][/]play[.]dlsite[.]com[/]#[/]work[/]([^/]+)/.exec(
|
||||
book.readerUrl,
|
||||
) ?? [];
|
||||
if (downloadUrl) {
|
||||
const imageFile: ImageFile = { url: downloadUrl };
|
||||
|
||||
if (!workId) {
|
||||
throw new Error(`workId is not included: ${book.readerUrl}`);
|
||||
return [
|
||||
async () => {
|
||||
const blob = await browser.drawImage(page, imageFile);
|
||||
|
||||
process.stderr.write(".");
|
||||
|
||||
return blob;
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
const url = `https://www.dlsite.com/home/download/=/product_id/${workId}.html`;
|
||||
const imageFile = { url };
|
||||
// ページ数 … 画面に表示されている要素を辿る
|
||||
await page.waitForSelector(workTreeItemsSelector);
|
||||
const workTreeItems = await page.locator(workTreeItemsSelector).count();
|
||||
await page.click(workTreeItemsSelector);
|
||||
|
||||
return [
|
||||
async () => {
|
||||
const blob = await browser.drawImage(page, imageFile);
|
||||
// 見開き表示の無効化 … 初回: 右下見開きボタンをクリックして無効化
|
||||
const spreadButton = page.getByRole("button", { name: "見開き" });
|
||||
await spreadButton.click();
|
||||
await Promise.all([
|
||||
spreadButton.waitFor({ state: "detached" }),
|
||||
page.mouse.click(0, 720 / 2),
|
||||
]);
|
||||
await page.keyboard.press("ArrowRight");
|
||||
|
||||
process.stderr.write(".");
|
||||
// ページ数だけ画面送りを繰り返し行い、canvasをそのままキャプチャしていく
|
||||
const files: Array<() => Promise<Blob>> = [];
|
||||
while (files.length < workTreeItems) {
|
||||
await page.waitForTimeout(1000);
|
||||
const n = Math.min(2, Math.max(0, workTreeItems - 1 - files.length));
|
||||
const canvas = page.locator("canvas").nth(n);
|
||||
await canvas.waitFor({ state: "visible" });
|
||||
const [width, height] = await Promise.all(
|
||||
["width", "height"].map((d) => canvas.getAttribute(d).then(Number)),
|
||||
);
|
||||
await page.setViewportSize({ width, height });
|
||||
await page.waitForTimeout(1000);
|
||||
const buff = await canvas.screenshot();
|
||||
files.push(async () => new Blob([buff], { type: "image/png" }));
|
||||
|
||||
return blob;
|
||||
},
|
||||
];
|
||||
process.stderr.write(".");
|
||||
|
||||
await page.keyboard.press("ArrowLeft");
|
||||
}
|
||||
|
||||
return files;
|
||||
},
|
||||
loginEndpoints: ["https://www.dlsite.com/home/login"],
|
||||
loginSuccessUrl: (url: URL) => url.origin === "https://www.dlsite.com",
|
||||
|
|
Loading…
Add table
Reference in a new issue