From 7547a34e032362519410328ffc9c154f7cafb388 Mon Sep 17 00:00:00 2001 From: Kohei Watanabe Date: Sun, 3 Dec 2023 12:44:31 +0900 Subject: [PATCH] support zip file --- library.ts | 23 ++++++++++++++++++-- package-lock.json | 4 ++-- package.json | 2 +- platform.ts | 2 ++ platforms/fanza-doujin.ts | 46 ++++++++++++++++++++++++++++++++++----- 5 files changed, 67 insertions(+), 10 deletions(-) diff --git a/library.ts b/library.ts index b4d2aab..49e66eb 100644 --- a/library.ts +++ b/library.ts @@ -107,6 +107,27 @@ on conflict(reader_url) book.title }`.replace(/[/]/g, "%2F"); + const files = await fs.readdir(path); + + if (files.every((f) => f.match(/[.](zip|cbz)$/))) { + const digits = String(files.length).length; + + function pad(n: string) { + return n.padStart(digits, "0"); + } + + for (const [n, f] of Object.entries(files)) { + await fs.rename( + `${path}/${f}`, + `${opts.outDir}/${title}${ + files.length > 1 ? ` - ${pad(n)}` : "" + }.${f.split(".").at(-1)}`, + ); + } + await fs.rmdir(path); + return; + } + const out = createWriteStream(`${opts.outDir}/${title}.cbz`); const zip = new Zip(function cb(err, data, final) { @@ -118,8 +139,6 @@ on conflict(reader_url) out[final ? "end" : "write"](data); }); - const files = await fs.readdir(path); - for (const file of files) { const data = new ZipPassThrough(file); zip.add(data); diff --git a/package-lock.json b/package-lock.json index 02082cc..7984233 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@fogtype/gadl", - "version": "1.0.0", + "version": "1.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@fogtype/gadl", - "version": "1.0.0", + "version": "1.2.0", "license": "AGPL-3.0", "dependencies": { "fflate": "^0.8.1", diff --git a/package.json b/package.json index 611fbb7..7ab4522 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@fogtype/gadl", - "version": "1.1.0", + "version": "1.2.0", "license": "AGPL-3.0", "type": "module", "bin": "bin/run.js", diff --git a/platform.ts b/platform.ts index 898335e..6e62715 100644 --- a/platform.ts +++ b/platform.ts @@ -55,6 +55,8 @@ export function createPlatform(opts: { const supportedTypes = { "image/png": "png", "image/jpeg": "jpg", + "application/zip": "zip", + "application/vnd.comicbook+zip": "cbz", }; for (const [n, dataUrl] of Object.entries(files)) { diff --git a/platforms/fanza-doujin.ts b/platforms/fanza-doujin.ts index cc37f48..7111296 100644 --- a/platforms/fanza-doujin.ts +++ b/platforms/fanza-doujin.ts @@ -72,13 +72,49 @@ export function FanzaDoujin(browser: Browser) { const page = await ctx.newPage(); await page.goto(book.readerUrl); - await page.waitForSelector(`li[class^="fileTreeItem"]`); - await page.click(`li[class^="fileTreeItem"]>a`); - await page.waitForURL((url) => - url.href.startsWith("https://www.dmm.co.jp/dc/-/viewer/=/product_id="), + + const [, productId] = /product_id=([^/]*)/.exec(book.readerUrl) ?? []; + + if (!productId) { + throw new Error(`product_id is not included: ${book.readerUrl}`); + } + + const res = await ctx.request.get( + `https://www.dmm.co.jp/dc/doujin/api/mylibraries/details/${productId}/`, ); - const imageFiles: Array = await page.evaluate(getImageFiles); + if (!res.ok()) { + throw new Error(`${res.status()} ${res.statusText()}`); + } + + const body: { + data: { + drm: { + dmmBooks: boolean; + softDenchi: boolean; + }; + downloadLinks: Record; + }; + } = await res.json(); + + const imageFiles: Array = []; + + if (body.data.drm.dmmBooks) { + await page.waitForSelector(`li[class^="fileTreeItem"]`); + await page.click(`li[class^="fileTreeItem"]>a`); + await page.waitForURL((url) => + url.href.startsWith( + "https://www.dmm.co.jp/dc/-/viewer/=/product_id=", + ), + ); + + imageFiles.push(...(await page.evaluate(getImageFiles))); + } else { + for (const link of Object.values(body.data.downloadLinks)) { + const url = new URL(link, "https://www.dmm.co.jp/").href; + imageFiles.push({ url }); + } + } return imageFiles.map((imageFile) => async () => { const dataUrl = await browser.drawImage(page, imageFile);