diff --git a/db.ts b/db.ts index 737d49c..cd58e3c 100644 --- a/db.ts +++ b/db.ts @@ -18,6 +18,40 @@ export enum SqliteTransactionType { IMMEDIATE = "IMMEDIATE", EXCLUSIVE = "EXCLUSIVE", } +export type GMeta = { + gid: number; + token: string; + title: string; + title_jpn: string; + category: string; + uploader: string; + posted: number; + filecount: number; + filesize: number; + expunged: boolean; + rating: number; + parent_gid: number | null; + parent_key: string | null; + first_gid: number | null; + first_key: string | null; +}; +export type GMetaRaw = { + gid: number; + token: string; + title: string; + title_jpn: string; + category: string; + uploader: string; + posted: number; + filecount: number; + filesize: number; + expunged: number; + rating: number; + parent_gid: number | null; + parent_key: string | null; + first_gid: number | null; + first_key: string | null; +}; const ALL_TABLES = ["version"]; const VERSION_TABLE = `CREATE TABLE version ( id TEXT, @@ -32,6 +66,24 @@ const TASK_TABLE = `CREATE TABLE task ( pn INT, pid INT );`; +const GMETA_TABLE = `CREATE TABLE gmeta ( + gid INT, + token TEXT, + title TEXT, + title_jpn TEXT, + category TEXT, + uploader TEXT, + posted INT, + filecount INT, + filesize INT, + expunged BOOLEAN, + rating REAL, + parent_gid INT, + parent_key TEXT, + first_gid INT, + first_key TEXT, + PRIMARY KEY (gid) +);`; export class EhDb { db; @@ -73,6 +125,9 @@ export class EhDb { if (!this._exist_table.has("task")) { this.db.execute(TASK_TABLE); } + if (!this._exist_table.has("gmeta")) { + this.db.execute(GMETA_TABLE); + } this._updateExistsTable(); } _read_version() { @@ -105,6 +160,12 @@ export class EhDb { ]); }); } + add_gmeta(gmeta: GMeta) { + this.db.queryEntries( + "INSERT OR REPLACE INTO gmeta VALUES (:gid, :token, :title, :title_jpn, :category, :uploader, :posted, :filecount, :filesize, :expunged, :rating, :parent_gid, :parent_key, :first_gid, :first_key);", + gmeta, + ); + } add_task(task: Task) { return this.transaction(() => { this.db.query( @@ -157,6 +218,14 @@ export class EhDb { } } } + convert_gmeta(m: GMetaRaw[]): GMeta[] { + return m.map((m) => { + const b = m.expunged === 1; + const t = m; + t.expunged = b; + return t; + }); + } delete_task(task: Task) { return this.transaction(() => { this.db.query("DELETE FROM task WHERE id = ?;", [task.id]); @@ -170,6 +239,15 @@ export class EhDb { if (!this.file) return; await eval(`Deno.funlock(${this.file.rid});`); } + get_gmeta_by_gid(gid: number) { + const s = this.convert_gmeta( + this.db.queryEntries( + "SELECT * FROM gmeta WHERE gid = ?;", + [gid], + ), + ); + return s.length ? s[0] : undefined; + } get_tasks_by_pid(pid: number) { return this.transaction(() => this.db.queryEntries("SELECT * FROM task WHERE pid = ?;", [ diff --git a/db_test.ts b/db_test.ts index a8fe66f..c7ee856 100644 --- a/db_test.ts +++ b/db_test.ts @@ -1,4 +1,5 @@ -import { EhDb } from "./db.ts"; +import { assertEquals } from "https://deno.land/std@0.188.0/testing/asserts.ts"; +import { EhDb, GMeta } from "./db.ts"; import { TaskType } from "./task.ts"; import { remove_if_exists } from "./test_base.ts"; import { sure_dir } from "./utils.ts"; @@ -17,5 +18,27 @@ Deno.test("DbTest", async () => { id: 0, }), ); + const gmeta: GMeta = { + gid: 1, + token: "test", + title: "s", + title_jpn: "sd", + category: "Non-H", + uploader: "ss", + posted: 123, + filecount: 23, + filesize: 132334, + expunged: true, + rating: 3.45, + parent_gid: null, + parent_key: null, + first_gid: null, + first_key: null, + }; + db.add_gmeta(gmeta); + assertEquals( + gmeta, + db.get_gmeta_by_gid(1), + ); db.close(); }); diff --git a/deno.lock b/deno.lock index 40059fb..bc06504 100644 --- a/deno.lock +++ b/deno.lock @@ -3,6 +3,7 @@ "remote": { "https://deno.land/std@0.188.0/_util/asserts.ts": "178dfc49a464aee693a7e285567b3d0b555dc805ff490505a8aae34f9cfb1462", "https://deno.land/std@0.188.0/_util/os.ts": "d932f56d41e4f6a6093d56044e29ce637f8dcc43c5a90af43504a889cf1775e3", + "https://deno.land/std@0.188.0/flags/mod.ts": "17f444ddbee43c5487568de0c6a076c7729cfe90d96d2ffcd2b8f8adadafb6e8", "https://deno.land/std@0.188.0/fmt/colors.ts": "d67e3cd9f472535241a8e410d33423980bec45047e343577554d3356e1f0ef4e", "https://deno.land/std@0.188.0/fs/exists.ts": "29c26bca8584a22876be7cb8844f1b6c8fc35e9af514576b78f5c6884d7ed02d", "https://deno.land/std@0.188.0/path/_constants.ts": "e49961f6f4f48039c0dfed3c3f93e963ca3d92791c9d478ac5b43183413136e0", diff --git a/page/GalleryMetadata.ts b/page/GalleryMetadata.ts index 8ea779c..c5d6baa 100644 --- a/page/GalleryMetadata.ts +++ b/page/GalleryMetadata.ts @@ -1,3 +1,5 @@ +import { GMeta } from "../db.ts"; + export type GalleryMetadataTorrentInfo = { hash: string; added: string; @@ -31,8 +33,32 @@ export type GalleryMetadataSingle = { class GalleryMetadata { obj; + map: Map; constructor(text: string) { this.obj = JSON.parse(text); + this.map = new Map(); + for (const m of this.obj["gmetadata"]) { + this.map.set(m.gid, m.error ? m.error : m); + } + } + convert(g: GalleryMetadataSingle): GMeta { + return { + gid: g.gid, + token: g.token, + title: g.title, + title_jpn: g.title_jpn, + category: g.category, + uploader: g.uploader, + posted: parseInt(g.posted), + filecount: parseInt(g.filecount), + filesize: g.filesize, + expunged: g.expunged, + rating: parseFloat(g.rating), + parent_gid: g.parent_gid ? parseInt(g.parent_gid) : null, + parent_key: g.parent_key ? g.parent_key : null, + first_gid: g.first_gid ? parseInt(g.first_gid) : null, + first_key: g.first_key ? g.first_key : null, + }; } } diff --git a/page/GalleryPage.ts b/page/GalleryPage.ts index f1b6c06..34018ca 100644 --- a/page/GalleryPage.ts +++ b/page/GalleryPage.ts @@ -11,6 +11,9 @@ class GalleryPage { client; #tags: Set | undefined = undefined; #gdd_data: Map | undefined = undefined; + #meta_script: string | undefined = undefined; + #gid: number | undefined = undefined; + #token: string | undefined = undefined; constructor(html: string, client: Client) { const dom = (new DOMParser()).parseFromString(html, "text/html"); if (!dom) { @@ -47,6 +50,14 @@ class GalleryPage { return g; } else return this.#gdd_data; } + get gid() { + if (this.#gid === undefined) { + const gid: number = eval(`${this.meta_script};gid`); + this.#gid = gid; + return gid; + } + return this.#gid; + } get language() { const o = this.gdd_data.get("Language")?.innerText; if (!o) return undefined; @@ -60,6 +71,19 @@ class GalleryPage { const p = o.slice(0, o.length - 6); return parseInt(p); } + get meta_script() { + if (this.#meta_script === undefined) { + const c = this.doc.getElementsByTagName("script"); + for (const e of c) { + const t = e.innerHTML.trim(); + if (t.startsWith("var ")) { + this.#meta_script = t; + return t; + } + } + throw Error("Failed to locate meta script."); + } else return this.#meta_script; + } get name() { const ele = this.doc.getElementById("gn"); if (!ele) throw Error("Failed to find gallery's name."); @@ -78,6 +102,14 @@ class GalleryPage { return tags; } else return this.#tags; } + get token() { + if (this.#token === undefined) { + const token: string = eval(`${this.meta_script};token`); + this.#token = token; + return token; + } + return this.#token; + } get visible() { const s = this.gdd_data.get("Visible")?.innerText; if (s === undefined) return undefined; diff --git a/page/GalleryPage_test.ts b/page/GalleryPage_test.ts index 82dbae3..d46cccd 100644 --- a/page/GalleryPage_test.ts +++ b/page/GalleryPage_test.ts @@ -37,4 +37,6 @@ Deno.test({ console.log(re.favorited); assert(typeof re.favorited === "number"); assertEquals(re.language, "Chinese"); + assertEquals(re.gid, 2552611); + assertEquals(re.token, "3132307627"); });