mirror of
https://github.com/lifegpc/eh-downloader.git
synced 2026-06-06 05:38:44 +08:00
Add a new api
This commit is contained in:
21
client.ts
21
client.ts
@@ -1,6 +1,7 @@
|
||||
import type { Config } from "./config.ts";
|
||||
import { load_gallery_metadata } from "./page/GalleryMetadata.ts";
|
||||
import { load_gallery_page } from "./page/GalleryPage.ts";
|
||||
import { load_home_overview_page } from "./page/HomeOverviewPage.ts";
|
||||
import { load_mpv_page } from "./page/MPVPage.ts";
|
||||
import { load_single_page } from "./page/SinglePage.ts";
|
||||
import { RecoverableError } from "./task_manager.ts";
|
||||
@@ -200,4 +201,24 @@ export class Client {
|
||||
}
|
||||
return load_mpv_page(await re.text(), this);
|
||||
}
|
||||
/**
|
||||
* Fetch home page overview
|
||||
* @returns null if not logged in
|
||||
*/
|
||||
async fetchHomeOverviewPage() {
|
||||
const url = `https://${this.host}/home.php`;
|
||||
const re = await this.get(url);
|
||||
if (re.redirected) {
|
||||
const u = new URL(re.url);
|
||||
if (u.pathname.startsWith("/login")) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (re.status != 200) {
|
||||
throw new Error(
|
||||
`Fetch ${url} failed, status ${re.status} ${re.statusText}`,
|
||||
);
|
||||
}
|
||||
return load_home_overview_page(await re.text());
|
||||
}
|
||||
}
|
||||
|
||||
17
deno.json
17
deno.json
@@ -3,15 +3,15 @@
|
||||
"importMap": "./import_map.json",
|
||||
"tasks": {
|
||||
"cache": "deno cache main.ts server-dev.ts",
|
||||
"server-dev": "deno run -A --unstable \"--watch=static/*.css,static/*.ts,static/*/,routes/,translation/\" server-dev.ts",
|
||||
"server": "deno run -A --unstable server-run.ts",
|
||||
"test": "deno test --allow-read=./ --allow-net --allow-write=./ --allow-run=tasklist.exe --allow-env --unstable",
|
||||
"run": "deno run --allow-read=./ --allow-write=./ --allow-run=tasklist.exe --allow-env=DENO_DEPLOYMENT_ID --allow-net --unstable",
|
||||
"compile": "deno compile --allow-read=./ --allow-write=./ --allow-run=tasklist.exe --allow-env=DENO_DEPLOYMENT_ID --allow-net --unstable",
|
||||
"compile_full": "deno compile --allow-read --allow-write --allow-run=tasklist.exe --allow-env=DENO_DEPLOYMENT_ID --allow-net --unstable",
|
||||
"server-dev": "deno run -A \"--watch=static/*.css,static/*.ts,static/*/,routes/,translation/\" server-dev.ts",
|
||||
"server": "deno run -A server-run.ts",
|
||||
"test": "deno test --allow-read=./ --allow-net --allow-write=./ --allow-run=tasklist.exe --allow-env",
|
||||
"run": "deno run --allow-read=./ --allow-write=./ --allow-run=tasklist.exe --allow-env=DENO_DEPLOYMENT_ID,DOCKER,DB_USE_FFI --allow-ffi --allow-net",
|
||||
"compile": "deno compile --allow-read=./ --allow-write=./ --allow-run=tasklist.exe --allow-env=DENO_DEPLOYMENT_ID --allow-net",
|
||||
"compile_full": "deno compile --allow-read --allow-write --allow-run=tasklist.exe --allow-env=DENO_DEPLOYMENT_ID --allow-net",
|
||||
"fetch": "deno run --allow-read=./ --allow-write=./ --allow-net fetch_static_files.ts",
|
||||
"gen_meili_server_key": "deno run --allow-net scripts/gen_meili_server_key.ts",
|
||||
"server-build": "deno run -A --unstable server-dev.ts build",
|
||||
"server-build": "deno run -A server-dev.ts build",
|
||||
"prebuild": "deno run -A scripts/prebuild.ts"
|
||||
},
|
||||
"fmt": {
|
||||
@@ -34,5 +34,6 @@
|
||||
"tags": ["fresh", "recommended"]
|
||||
},
|
||||
"exclude": ["_fresh"]
|
||||
}
|
||||
},
|
||||
"unstable": ["ffi", "fs"]
|
||||
}
|
||||
|
||||
102
fresh.gen.ts
102
fresh.gen.ts
@@ -6,31 +6,32 @@ import * as $0 from "./routes/_middleware.ts";
|
||||
import * as $1 from "./routes/api/_middleware.ts";
|
||||
import * as $2 from "./routes/api/config.ts";
|
||||
import * as $3 from "./routes/api/deploy_id.ts";
|
||||
import * as $4 from "./routes/api/exit.ts";
|
||||
import * as $5 from "./routes/api/export/gallery/zip/[gid].ts";
|
||||
import * as $6 from "./routes/api/file/[id].ts";
|
||||
import * as $7 from "./routes/api/file/random.ts";
|
||||
import * as $8 from "./routes/api/file/upload.ts";
|
||||
import * as $9 from "./routes/api/filemeta.ts";
|
||||
import * as $10 from "./routes/api/filemeta/[token].ts";
|
||||
import * as $11 from "./routes/api/files/[token].ts";
|
||||
import * as $12 from "./routes/api/gallery/[gid].ts";
|
||||
import * as $13 from "./routes/api/gallery/list.ts";
|
||||
import * as $14 from "./routes/api/health_check.ts";
|
||||
import * as $15 from "./routes/api/status.ts";
|
||||
import * as $16 from "./routes/api/tag/[id].ts";
|
||||
import * as $17 from "./routes/api/tag/rows.ts";
|
||||
import * as $18 from "./routes/api/task.ts";
|
||||
import * as $19 from "./routes/api/thumbnail/[id].ts";
|
||||
import * as $20 from "./routes/api/token.ts";
|
||||
import * as $21 from "./routes/api/user.ts";
|
||||
import * as $22 from "./routes/file/[id].ts";
|
||||
import * as $23 from "./routes/file/_middleware.ts";
|
||||
import * as $24 from "./routes/index.tsx";
|
||||
import * as $25 from "./routes/manifest.json.ts";
|
||||
import * as $26 from "./routes/thumbnail/[id].ts";
|
||||
import * as $27 from "./routes/thumbnail/_middleware.ts";
|
||||
import * as $28 from "./routes/upload.tsx";
|
||||
import * as $4 from "./routes/api/eh/image_limit.ts";
|
||||
import * as $5 from "./routes/api/exit.ts";
|
||||
import * as $6 from "./routes/api/export/gallery/zip/[gid].ts";
|
||||
import * as $7 from "./routes/api/file/[id].ts";
|
||||
import * as $8 from "./routes/api/file/random.ts";
|
||||
import * as $9 from "./routes/api/file/upload.ts";
|
||||
import * as $10 from "./routes/api/filemeta.ts";
|
||||
import * as $11 from "./routes/api/filemeta/[token].ts";
|
||||
import * as $12 from "./routes/api/files/[token].ts";
|
||||
import * as $13 from "./routes/api/gallery/[gid].ts";
|
||||
import * as $14 from "./routes/api/gallery/list.ts";
|
||||
import * as $15 from "./routes/api/health_check.ts";
|
||||
import * as $16 from "./routes/api/status.ts";
|
||||
import * as $17 from "./routes/api/tag/[id].ts";
|
||||
import * as $18 from "./routes/api/tag/rows.ts";
|
||||
import * as $19 from "./routes/api/task.ts";
|
||||
import * as $20 from "./routes/api/thumbnail/[id].ts";
|
||||
import * as $21 from "./routes/api/token.ts";
|
||||
import * as $22 from "./routes/api/user.ts";
|
||||
import * as $23 from "./routes/file/[id].ts";
|
||||
import * as $24 from "./routes/file/_middleware.ts";
|
||||
import * as $25 from "./routes/index.tsx";
|
||||
import * as $26 from "./routes/manifest.json.ts";
|
||||
import * as $27 from "./routes/thumbnail/[id].ts";
|
||||
import * as $28 from "./routes/thumbnail/_middleware.ts";
|
||||
import * as $29 from "./routes/upload.tsx";
|
||||
import * as $$0 from "./islands/Container.tsx";
|
||||
import * as $$1 from "./islands/Settings.tsx";
|
||||
import * as $$2 from "./islands/TaskManager.tsx";
|
||||
@@ -42,31 +43,32 @@ const manifest = {
|
||||
"./routes/api/_middleware.ts": $1,
|
||||
"./routes/api/config.ts": $2,
|
||||
"./routes/api/deploy_id.ts": $3,
|
||||
"./routes/api/exit.ts": $4,
|
||||
"./routes/api/export/gallery/zip/[gid].ts": $5,
|
||||
"./routes/api/file/[id].ts": $6,
|
||||
"./routes/api/file/random.ts": $7,
|
||||
"./routes/api/file/upload.ts": $8,
|
||||
"./routes/api/filemeta.ts": $9,
|
||||
"./routes/api/filemeta/[token].ts": $10,
|
||||
"./routes/api/files/[token].ts": $11,
|
||||
"./routes/api/gallery/[gid].ts": $12,
|
||||
"./routes/api/gallery/list.ts": $13,
|
||||
"./routes/api/health_check.ts": $14,
|
||||
"./routes/api/status.ts": $15,
|
||||
"./routes/api/tag/[id].ts": $16,
|
||||
"./routes/api/tag/rows.ts": $17,
|
||||
"./routes/api/task.ts": $18,
|
||||
"./routes/api/thumbnail/[id].ts": $19,
|
||||
"./routes/api/token.ts": $20,
|
||||
"./routes/api/user.ts": $21,
|
||||
"./routes/file/[id].ts": $22,
|
||||
"./routes/file/_middleware.ts": $23,
|
||||
"./routes/index.tsx": $24,
|
||||
"./routes/manifest.json.ts": $25,
|
||||
"./routes/thumbnail/[id].ts": $26,
|
||||
"./routes/thumbnail/_middleware.ts": $27,
|
||||
"./routes/upload.tsx": $28,
|
||||
"./routes/api/eh/image_limit.ts": $4,
|
||||
"./routes/api/exit.ts": $5,
|
||||
"./routes/api/export/gallery/zip/[gid].ts": $6,
|
||||
"./routes/api/file/[id].ts": $7,
|
||||
"./routes/api/file/random.ts": $8,
|
||||
"./routes/api/file/upload.ts": $9,
|
||||
"./routes/api/filemeta.ts": $10,
|
||||
"./routes/api/filemeta/[token].ts": $11,
|
||||
"./routes/api/files/[token].ts": $12,
|
||||
"./routes/api/gallery/[gid].ts": $13,
|
||||
"./routes/api/gallery/list.ts": $14,
|
||||
"./routes/api/health_check.ts": $15,
|
||||
"./routes/api/status.ts": $16,
|
||||
"./routes/api/tag/[id].ts": $17,
|
||||
"./routes/api/tag/rows.ts": $18,
|
||||
"./routes/api/task.ts": $19,
|
||||
"./routes/api/thumbnail/[id].ts": $20,
|
||||
"./routes/api/token.ts": $21,
|
||||
"./routes/api/user.ts": $22,
|
||||
"./routes/file/[id].ts": $23,
|
||||
"./routes/file/_middleware.ts": $24,
|
||||
"./routes/index.tsx": $25,
|
||||
"./routes/manifest.json.ts": $26,
|
||||
"./routes/thumbnail/[id].ts": $27,
|
||||
"./routes/thumbnail/_middleware.ts": $28,
|
||||
"./routes/upload.tsx": $29,
|
||||
},
|
||||
islands: {
|
||||
"./islands/Container.tsx": $$0,
|
||||
|
||||
71
page/HomeOverviewPage.ts
Normal file
71
page/HomeOverviewPage.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { DOMParser, Element } from "deno_dom/deno-dom-wasm-noinit.ts";
|
||||
import { initDOMParser } from "../utils.ts";
|
||||
|
||||
export class HomeOverviewPage {
|
||||
dom;
|
||||
doc;
|
||||
#panel: Map<string, Element> | undefined;
|
||||
#current_image_limit: number | undefined;
|
||||
#max_image_limit: number | undefined;
|
||||
constructor(html: string) {
|
||||
const dom = (new DOMParser()).parseFromString(html, "text/html");
|
||||
if (!dom) {
|
||||
throw Error("Failed to parse HTML document.");
|
||||
}
|
||||
this.dom = dom;
|
||||
const doc = this.dom.documentElement;
|
||||
if (!doc) {
|
||||
throw Error("HTML document don't have a document element.");
|
||||
}
|
||||
this.doc = doc;
|
||||
}
|
||||
get panel() {
|
||||
if (this.#panel === undefined) {
|
||||
const panel = new Map<string, Element>();
|
||||
const keys = this.doc.querySelectorAll(".stuffbox > h2");
|
||||
for (const key of keys) {
|
||||
const k = key as Element;
|
||||
const v = k.nextElementSibling;
|
||||
if (v) {
|
||||
panel.set(k.innerText, v as Element);
|
||||
}
|
||||
}
|
||||
this.#panel = panel;
|
||||
return panel;
|
||||
} else return this.#panel;
|
||||
}
|
||||
get current_image_limit() {
|
||||
if (this.#current_image_limit === undefined) {
|
||||
const panel = this.panel.get("Image Limits");
|
||||
if (!panel) {
|
||||
throw Error('Failed to find panel "Image Limits".');
|
||||
}
|
||||
const limits = panel.querySelectorAll("p:nth-child(1) > strong");
|
||||
if (!limits.length) {
|
||||
throw Error("Failed to find limits.");
|
||||
}
|
||||
const current = limits[0] as Element;
|
||||
const max = limits[1] as Element;
|
||||
const current_image_limit = parseInt(current.innerText);
|
||||
const max_image_limit = parseInt(max.innerText);
|
||||
if (isNaN(current_image_limit) || isNaN(max_image_limit)) {
|
||||
throw Error("Failed to parse limits.");
|
||||
}
|
||||
this.#current_image_limit = current_image_limit;
|
||||
this.#max_image_limit = max_image_limit;
|
||||
return current_image_limit;
|
||||
} else return this.#current_image_limit;
|
||||
}
|
||||
get max_image_limit(): number {
|
||||
if (this.#max_image_limit === undefined) {
|
||||
this.current_image_limit;
|
||||
// @ts-ignore Already assigned in current_image_limit.
|
||||
return this.#max_image_limit;
|
||||
} else return this.#max_image_limit;
|
||||
}
|
||||
}
|
||||
|
||||
export async function load_home_overview_page(html: string) {
|
||||
await initDOMParser();
|
||||
return new HomeOverviewPage(html);
|
||||
}
|
||||
24
page/HomeOverviewPage_test.ts
Normal file
24
page/HomeOverviewPage_test.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { assert } from "std/assert/mod.ts";
|
||||
import { Client } from "../client.ts";
|
||||
import { load_settings } from "../config.ts";
|
||||
import { API_PERMISSION } from "../test_base.ts";
|
||||
|
||||
const MAX_IMAGE_LIMITS = [5000, 10000, 25000, 50000];
|
||||
|
||||
Deno.test({
|
||||
name: "HomeOverviewPage_test",
|
||||
permissions: API_PERMISSION,
|
||||
}, async () => {
|
||||
const cfg = await load_settings("./config.json");
|
||||
const client = new Client(cfg);
|
||||
const re = await client.fetchHomeOverviewPage();
|
||||
if (re === null) return;
|
||||
console.log(
|
||||
"Image limit:",
|
||||
re.current_image_limit,
|
||||
"/",
|
||||
re.max_image_limit,
|
||||
);
|
||||
assert(re.current_image_limit <= re.max_image_limit);
|
||||
assert(MAX_IMAGE_LIMITS.includes(re.max_image_limit));
|
||||
});
|
||||
28
routes/api/eh/image_limit.ts
Normal file
28
routes/api/eh/image_limit.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { Handlers } from "$fresh/server.ts";
|
||||
import { User } from "../../../db.ts";
|
||||
import { get_task_manager } from "../../../server.ts";
|
||||
import { EHImageLimit } from "../../../server/eh.ts";
|
||||
import { return_data, return_error } from "../../../server/utils.ts";
|
||||
|
||||
export const handler: Handlers = {
|
||||
async GET(_req, ctx) {
|
||||
const user = <User | undefined> ctx.state.user;
|
||||
if (user && !user.is_admin) {
|
||||
return return_error(403, "Permission denied.");
|
||||
}
|
||||
const m = get_task_manager();
|
||||
try {
|
||||
const re = await m.client.fetchHomeOverviewPage();
|
||||
if (re === null) {
|
||||
return return_error(1, "Not logged in.");
|
||||
}
|
||||
|
||||
return return_data<EHImageLimit>({
|
||||
max: re.max_image_limit,
|
||||
current: re.current_image_limit,
|
||||
});
|
||||
} catch (e) {
|
||||
return return_error(500, e.message);
|
||||
}
|
||||
},
|
||||
};
|
||||
4
server/eh.ts
Normal file
4
server/eh.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export type EHImageLimit = {
|
||||
current: number;
|
||||
max: number;
|
||||
};
|
||||
Reference in New Issue
Block a user