refactor platform
This commit is contained in:
parent
4e6afe7bf0
commit
7f36682b04
3 changed files with 78 additions and 80 deletions
39
platform.ts
39
platform.ts
|
@ -36,11 +36,48 @@ export function createPlatform(opts: {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...platform,
|
...platform,
|
||||||
|
|
||||||
async download(dir: string, book: Book): Promise<void> {
|
async download(dir: string, book: Book): Promise<void> {
|
||||||
await fs.mkdir(path.dirname(dir), { recursive: true });
|
await fs.mkdir(path.dirname(dir), { recursive: true });
|
||||||
await fs.mkdir(dir);
|
await fs.mkdir(dir);
|
||||||
await platform.download(dir, book);
|
|
||||||
|
const files: Array<() => Promise<string>> = 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",
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const [n, dataUrl] of Object.entries(files)) {
|
||||||
|
const [prefix, base64] = (await dataUrl()).split(",", 2);
|
||||||
|
const [, type, encoding] =
|
||||||
|
/^data:([^;]*)(;base64)?$/.exec(prefix) ?? [];
|
||||||
|
|
||||||
|
const extension = supportedTypes[type];
|
||||||
|
if (!extension) {
|
||||||
|
throw new Error(
|
||||||
|
`It was ${type}. The image must be a file of type: ${[
|
||||||
|
...Object.keys(supportedTypes),
|
||||||
|
].join(", ")}.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (encoding !== ";base64") {
|
||||||
|
throw new Error("Only base64 is supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const buffer = Buffer.from(base64, "base64");
|
||||||
|
await fs.writeFile(`${dir}/${pad(n)}.${extension}`, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
process.stderr.write(`\n`);
|
||||||
},
|
},
|
||||||
|
|
||||||
async logout() {
|
async logout() {
|
||||||
await opts.db.run(
|
await opts.db.run(
|
||||||
`update platforms set secrets = 'null' where name = ?`,
|
`update platforms set secrets = 'null' where name = ?`,
|
||||||
|
|
|
@ -1,10 +1,16 @@
|
||||||
import fs from "node:fs/promises";
|
|
||||||
import type { Book } from "../library";
|
import type { Book } from "../library";
|
||||||
import type { Browser, BrowserContext } from "../browser";
|
import type { Browser, BrowserContext } from "../browser";
|
||||||
|
|
||||||
|
type ImageFile = {
|
||||||
|
url: string;
|
||||||
|
blocks: Array<Record<string, number>>;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
};
|
||||||
|
|
||||||
var NFBR: any;
|
var NFBR: any;
|
||||||
|
|
||||||
async function getFiles() {
|
async function getImageFiles(): Promise<Array<ImageFile>> {
|
||||||
const params = new URLSearchParams(location.search);
|
const params = new URLSearchParams(location.search);
|
||||||
const model = new NFBR.a6G.Model({
|
const model = new NFBR.a6G.Model({
|
||||||
settings: new NFBR.Settings("NFBR.SettingData"),
|
settings: new NFBR.Settings("NFBR.SettingData"),
|
||||||
|
@ -29,12 +35,7 @@ async function getFiles() {
|
||||||
const a5n = new NFBR.a5n();
|
const a5n = new NFBR.a5n();
|
||||||
await a5n.a5s(content, "configuration", a6l);
|
await a5n.a5s(content, "configuration", a6l);
|
||||||
|
|
||||||
const files: Array<{
|
const imageFiles: Array<ImageFile> = [];
|
||||||
url: string;
|
|
||||||
blocks: [];
|
|
||||||
width: number;
|
|
||||||
height: number;
|
|
||||||
}> = [];
|
|
||||||
|
|
||||||
for (const index of Object.keys(content.files)) {
|
for (const index of Object.keys(content.files)) {
|
||||||
const file = content.files[index];
|
const file = content.files[index];
|
||||||
|
@ -67,7 +68,7 @@ async function getFiles() {
|
||||||
|
|
||||||
const url = `${a5w.url}${page.url}`;
|
const url = `${a5w.url}${page.url}`;
|
||||||
|
|
||||||
files.push({
|
imageFiles.push({
|
||||||
url,
|
url,
|
||||||
blocks,
|
blocks,
|
||||||
width: Width,
|
width: Width,
|
||||||
|
@ -75,24 +76,19 @@ async function getFiles() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return files;
|
return imageFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function drawImage(file: {
|
async function drawImage(imageFile: ImageFile) {
|
||||||
url: string;
|
|
||||||
blocks: Array<Record<string, number>>;
|
|
||||||
width: number;
|
|
||||||
height: number;
|
|
||||||
}) {
|
|
||||||
const canvas = Object.assign(document.createElement("canvas"), {
|
const canvas = Object.assign(document.createElement("canvas"), {
|
||||||
width: file.width,
|
width: imageFile.width,
|
||||||
height: file.height,
|
height: imageFile.height,
|
||||||
});
|
});
|
||||||
|
|
||||||
const image = (await new Promise((resolve) => {
|
const image = (await new Promise((resolve) => {
|
||||||
Object.assign(new Image(), {
|
Object.assign(new Image(), {
|
||||||
crossOrigin: "use-credentials",
|
crossOrigin: "use-credentials",
|
||||||
src: file.url,
|
src: imageFile.url,
|
||||||
onload() {
|
onload() {
|
||||||
resolve(this);
|
resolve(this);
|
||||||
},
|
},
|
||||||
|
@ -101,7 +97,7 @@ async function drawImage(file: {
|
||||||
|
|
||||||
const ctx = canvas.getContext("2d")!;
|
const ctx = canvas.getContext("2d")!;
|
||||||
|
|
||||||
for (const q of file.blocks) {
|
for (const q of imageFile.blocks) {
|
||||||
ctx.drawImage(
|
ctx.drawImage(
|
||||||
image,
|
image,
|
||||||
q.destX,
|
q.destX,
|
||||||
|
@ -241,38 +237,21 @@ export function DmmBooks(browser: Browser) {
|
||||||
process.stderr.write(`\n`);
|
process.stderr.write(`\n`);
|
||||||
},
|
},
|
||||||
|
|
||||||
async download(dir: string, book: Book) {
|
async getFiles(book: Book): Promise<Array<() => Promise<string>>> {
|
||||||
const ctx = await browser.loadBrowserContext("dmm-books");
|
const ctx = await browser.loadBrowserContext("dmm-books");
|
||||||
const page = await ctx.newPage();
|
const page = await ctx.newPage();
|
||||||
|
|
||||||
await page.goto(book.readerUrl);
|
await page.goto(book.readerUrl);
|
||||||
|
|
||||||
const files = await page.evaluate(getFiles);
|
const imageFiles = await page.evaluate(getImageFiles);
|
||||||
const digits = String(files.length).length;
|
|
||||||
|
|
||||||
function pad(n: string) {
|
return imageFiles.map((imageFile) => async () => {
|
||||||
return n.padStart(digits, "0");
|
const dataUrl = await page.evaluate(drawImage, imageFile);
|
||||||
}
|
|
||||||
|
|
||||||
for (const [n, file] of Object.entries(files)) {
|
|
||||||
const dataUrl = await page.evaluate(drawImage, file);
|
|
||||||
const [prefix, base64] = dataUrl.split(",", 2);
|
|
||||||
|
|
||||||
if (!prefix.startsWith("data:image/png;")) {
|
|
||||||
throw new Error("Only image/png is supported.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!prefix.endsWith(";base64")) {
|
|
||||||
throw new Error("Only base64 is supported.");
|
|
||||||
}
|
|
||||||
|
|
||||||
const buffer = Buffer.from(base64, "base64");
|
|
||||||
await fs.writeFile(`${dir}/${pad(n)}.png`, buffer);
|
|
||||||
|
|
||||||
process.stderr.write(".");
|
process.stderr.write(".");
|
||||||
}
|
|
||||||
|
|
||||||
process.stderr.write(`\n`);
|
return dataUrl;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
import fs from "node:fs/promises";
|
|
||||||
import type { Book } from "../library";
|
import type { Book } from "../library";
|
||||||
import type { Browser } from "../browser";
|
import type { Browser } from "../browser";
|
||||||
|
|
||||||
async function getFiles(): Promise<Array<{ url: string }>> {
|
type ImageFile = {
|
||||||
|
url: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
async function getImageFiles(): Promise<Array<ImageFile>> {
|
||||||
const pages: NodeListOf<HTMLElement> = await new Promise(async function (
|
const pages: NodeListOf<HTMLElement> = await new Promise(async function (
|
||||||
resolve,
|
resolve,
|
||||||
reject,
|
reject,
|
||||||
|
@ -35,12 +38,11 @@ async function getFiles(): Promise<Array<{ url: string }>> {
|
||||||
(el) => el.querySelector("svg image")!,
|
(el) => el.querySelector("svg image")!,
|
||||||
);
|
);
|
||||||
|
|
||||||
const files = [...images].map((image) => ({ url: image.href.baseVal }));
|
return [...images].map((image) => ({ url: image.href.baseVal }));
|
||||||
return files;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function drawImage(file: { url: string }): Promise<string> {
|
async function fetchImage(imageFile: ImageFile): Promise<string> {
|
||||||
const res = await fetch(file.url);
|
const res = await fetch(imageFile.url);
|
||||||
const blob = await res.blob();
|
const blob = await res.blob();
|
||||||
const dataUrl: string = await new Promise((resolve, reject) => {
|
const dataUrl: string = await new Promise((resolve, reject) => {
|
||||||
const fileReader = Object.assign(new FileReader(), {
|
const fileReader = Object.assign(new FileReader(), {
|
||||||
|
@ -98,7 +100,7 @@ export function GooglePlayBooks(browser: Browser) {
|
||||||
process.stderr.write(`\n`);
|
process.stderr.write(`\n`);
|
||||||
},
|
},
|
||||||
|
|
||||||
async download(dir: string, book: Book) {
|
async getFiles(book: Book): Promise<Array<() => Promise<string>>> {
|
||||||
const ctx = await browser.loadBrowserContext("google-play-books");
|
const ctx = await browser.loadBrowserContext("google-play-books");
|
||||||
const page = await ctx.newPage();
|
const page = await ctx.newPage();
|
||||||
|
|
||||||
|
@ -140,43 +142,23 @@ export function GooglePlayBooks(browser: Browser) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileMap: Map<string, { url: string; dataUrl: string }> = new Map();
|
const fileMap: Map<string, () => Promise<string>> = new Map();
|
||||||
|
|
||||||
while (await next()) {
|
while (await next()) {
|
||||||
const files = await frame.evaluate(getFiles);
|
const imageFiles = await frame.evaluate(getImageFiles);
|
||||||
|
|
||||||
for (const file of files) {
|
for (const imageFile of imageFiles) {
|
||||||
if (fileMap.has(file.url)) continue;
|
if (fileMap.has(imageFile.url)) continue;
|
||||||
|
|
||||||
|
const dataUrl = await frame.evaluate(fetchImage, imageFile);
|
||||||
|
|
||||||
const dataUrl = await frame.evaluate(drawImage, file);
|
|
||||||
fileMap.set(file.url, { ...file, dataUrl });
|
|
||||||
process.stderr.write(".");
|
process.stderr.write(".");
|
||||||
|
|
||||||
|
fileMap.set(imageFile.url, async () => dataUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const files = [...fileMap.values()];
|
return [...fileMap.values()];
|
||||||
const digits = String(files.length).length;
|
|
||||||
|
|
||||||
function pad(n: string) {
|
|
||||||
return n.padStart(digits, "0");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const [n, file] of Object.entries(files)) {
|
|
||||||
const [prefix, base64] = file.dataUrl.split(",", 2);
|
|
||||||
|
|
||||||
if (!prefix.startsWith("data:image/jpeg;")) {
|
|
||||||
throw new Error("Only image/jpeg is supported.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!prefix.endsWith(";base64")) {
|
|
||||||
throw new Error("Only base64 is supported.");
|
|
||||||
}
|
|
||||||
|
|
||||||
const buffer = Buffer.from(base64, "base64");
|
|
||||||
await fs.writeFile(`${dir}/${pad(n)}.jpeg`, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
process.stderr.write(`\n`);
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue