110 lines
3.1 KiB
TypeScript
110 lines
3.1 KiB
TypeScript
import fs from "node:fs/promises";
|
|
import type { Book } from "./library";
|
|
import type { Browser } from "./browser";
|
|
import type { Database } from "./database";
|
|
import { GooglePlayBooks } from "./platforms/google-play-books";
|
|
import { DmmBooks } from "./platforms/dmm-books";
|
|
import { DlsiteManiax } from "./platforms/dlsite-maniax";
|
|
import { FanzaDoujin } from "./platforms/fanza-doujin";
|
|
|
|
export const platforms = {
|
|
"google-play-books": GooglePlayBooks,
|
|
"dmm-books": DmmBooks,
|
|
"dlsite-maniax": DlsiteManiax,
|
|
"fanza-doujin": FanzaDoujin,
|
|
};
|
|
|
|
export type TPlatform = keyof typeof platforms;
|
|
|
|
export function site(url: string): TPlatform {
|
|
for (const [platform, { siteUrl }] of Object.entries(platforms)) {
|
|
if (siteUrl(new URL(url))) return platform as TPlatform;
|
|
}
|
|
|
|
throw new Error(`Unsupported URL: ${url}`);
|
|
}
|
|
|
|
export function createPlatform(opts: {
|
|
platform: TPlatform;
|
|
db: Database;
|
|
browser: Browser;
|
|
}) {
|
|
if (!(opts.platform in platforms)) {
|
|
throw new Error(
|
|
`The value must be a platform type: ${[...Object.keys(platforms)].join(
|
|
", ",
|
|
)}.`,
|
|
);
|
|
}
|
|
|
|
const platform = platforms[opts.platform](opts.browser);
|
|
|
|
return {
|
|
...platform,
|
|
|
|
async download(dir: string, book: Book): Promise<void> {
|
|
await fs.mkdir(dir, { recursive: true });
|
|
|
|
const files: Array<() => Promise<Blob>> = await platform.getFiles(book);
|
|
const digits = String(files.length).length;
|
|
|
|
function pad(n: string) {
|
|
return n.padStart(digits, "0");
|
|
}
|
|
|
|
const supportedTypes = {
|
|
"image/png": "png",
|
|
"image/jpeg": "jpg",
|
|
"application/zip": "zip",
|
|
"application/vnd.comicbook+zip": "cbz",
|
|
};
|
|
|
|
for (const [n, getBlob] of Object.entries(files)) {
|
|
const blob = await getBlob();
|
|
const extension = supportedTypes[blob.type];
|
|
if (!extension) {
|
|
throw new Error(
|
|
`It was ${blob.type}. The image must be a file of type: ${[
|
|
...Object.keys(supportedTypes),
|
|
].join(", ")}.`,
|
|
);
|
|
}
|
|
|
|
const buffer = Buffer.from(await blob.arrayBuffer());
|
|
await fs.writeFile(`${dir}/${pad(n)}.${extension}`, buffer);
|
|
}
|
|
|
|
process.stderr.write(`\n`);
|
|
},
|
|
|
|
async login() {
|
|
const ctx = await opts.browser.newContext();
|
|
const page = await ctx.newPage();
|
|
|
|
for (const loginEndpoint of platform.loginEndpoints) {
|
|
await page.goto(loginEndpoint);
|
|
await page.waitForURL(platform.loginSuccessUrl, { timeout: 0 });
|
|
}
|
|
|
|
await opts.browser.saveBrowserContext(opts.platform, ctx);
|
|
},
|
|
|
|
async logout() {
|
|
try {
|
|
const ctx = await opts.browser.loadBrowserContext(opts.platform);
|
|
const page = await ctx.newPage();
|
|
|
|
for (const logoutEndpoint of platform.logoutEndpoints) {
|
|
await page.goto(logoutEndpoint);
|
|
}
|
|
} catch (error) {
|
|
process.stderr.write(`Warning: ${(error as Error).message}\n`);
|
|
}
|
|
|
|
await opts.db.run(
|
|
`update platforms set secrets = 'null' where name = ?`,
|
|
opts.platform,
|
|
);
|
|
},
|
|
};
|
|
}
|