import { Component, ContextType } from "preact"; import { GlobalCtx } from "./GlobalContext.tsx"; import Fab from "preact-material-components/Fab.js"; import Icon from "preact-material-components/Icon.js"; import { set_state } from "../server/state.ts"; import t from "../server/i18n.ts"; import BSelect from "./BSelect.tsx"; import { StateUpdater, useEffect, useRef, useState } from "preact/hooks"; import { TaskType } from "../task.ts"; import BTextField from "./BTextField.tsx"; import { parseUrl, UrlType } from "../url.ts"; import { cfg, generate_download_cfg, generate_export_zip_cfg, } from "../server/cfg.ts"; import BCheckbox from "./BCheckbox.tsx"; import BContext from "./BContext.tsx"; import Button from "preact-material-components/Button.js"; import { sendTaskMessage } from "../islands/TaskManager.tsx"; import Snackbar from "preact-material-components/Snackbar.js"; import type { GalleryResult } from "../server/gallery.ts"; import { tw } from "twind"; import type { ExportZipConfig } from "../tasks/export_zip.ts"; import type { GMeta } from "../db.ts"; import type { GalleryListResult } from "../server/gallery.ts"; export type NewTaskProps = { show: boolean; }; type State = { gids?: GMeta[]; }; export default class NewTask extends Component { static contextType = GlobalCtx; declare context: ContextType; render() { if (!this.props.show) return null; const [task_type, set_task_type] = useState(TaskType.Download); let config_div = null; const close = () => { set_state((p) => p.slice(0, p.length - 4)); }; let submit: (() => boolean) | null = null; let clean: (() => void) | null = null; const snack = useRef(); const show_snack = (message: string) => { snack.current?.MDComponent?.show({ message }); }; const [dgid, set_dgid1] = useState(); const [token, set_token1] = useState(); const [url, set_url1] = useState(); const [dcfg, set_dcfg] = useState(generate_download_cfg()); const [overwrite_cfg, set_overwrite_cfg1] = useState(false); const [ezgid, set_ezgid1] = useState(); const [ginfo, set_ginfo] = useState(); const [abort, set_abort] = useState(); const [ezcfg, set_ezcfg1] = useState(generate_export_zip_cfg()); const [overwrite_ezcfg, set_overwrite_ezcfg] = useState(false); const onPasteGid = (clipboard: string) => { const p = parseUrl(clipboard); if (p) { return { text: p.gid.toString(), overwrite: true }; } return; }; const onPasteToken = (clipboard: string) => { const p = parseUrl(clipboard); if (p && p.type !== UrlType.Single) { return { text: p.token, overwrite: true }; } return; }; const fetchGidsData = async () => { const re = await fetch( "/api/gallery/list?all=1&fields=gid,title,title_jpn", ); const d: GalleryListResult = await re.json(); if (d.ok) { this.setState({ ...this.state, gids: d.data }); } }; useEffect(() => { if (task_type === TaskType.ExportZip) { fetchGidsData().catch((e) => console.error(e)); } }, [task_type]); if (task_type === TaskType.Download) { const set_url: StateUpdater = (u) => { const n = typeof u === "string" ? u : u ? u(url) : u; set_url1(n); if (n) { const p = parseUrl(n); if (p && p.type !== UrlType.Single) { set_dgid(p.gid); set_token1(p.token); } } }; const set_dgid: StateUpdater = (u) => { const g = typeof u === "number" ? u : u ? u(dgid) : u; set_dgid1(g); if (g && token) { set_url1(`https://e-hentai.org/g/${g}/${token}/`); } }; const set_token: StateUpdater = (u) => { const n = typeof u === "string" ? u : u ? u(url) : u; set_token1(n); if (dgid && n) { set_url1(`https://e-hentai.org/g/${dgid}/${n}/`); } }; const set_overwrite_cfg = (n: boolean) => { set_overwrite_cfg1(n); if (n) { set_dcfg(generate_download_cfg()); } }; let cfg_div = null; if (overwrite_cfg) { cfg_div = (
); } config_div = (
{cfg_div}
); if (dgid && token) { submit = () => { return sendTaskMessage({ type: "new_download_task", gid: dgid, token, cfg: overwrite_cfg ? dcfg : undefined, }); }; clean = () => { set_dgid1(undefined); set_token1(undefined); set_url1(undefined); }; } } else if (task_type === TaskType.ExportZip) { const export_ad = overwrite_ezcfg ? ezcfg.export_ad || false : false; const jpn_title = overwrite_ezcfg ? ezcfg.jpn_title || false : cfg.value ? cfg.value.export_zip_jpn_title : false; const fetch_ginfo = (gid: number) => { set_abort(new AbortController()); fetch(`/api/gallery/${gid}`).then(async (res) => { try { set_ginfo(await res.json()); } catch (e) { set_ginfo({ ok: false, status: -1, error: e.toString(), }); } }).catch((e) => { set_ginfo({ ok: false, status: -1, error: e.toString() }); }).finally(() => { set_abort(undefined); }); }; const set_ezgid = (g: number | undefined) => { if (abort) abort.abort(); set_ezgid1(g); if (g !== undefined && !isNaN(g)) fetch_ginfo(g); }; let ginfo_div = null; if (ginfo?.ok) { let title = ginfo.data.meta.title; if (jpn_title && ginfo.data.meta.title_jpn) { title = ginfo.data.meta.title_jpn; } const count = export_ad ? ginfo.data.pages.length : ginfo.data.pages.reduce((p, c) => c.is_ad ? p : p + 1, 0); ginfo_div = (
{t("task.gallery_title")} {title}
{t("task.gallery_page")} {count}
); } else if (ginfo?.ok === false) { ginfo_div = (
{ginfo.error}
); } const set_ezcfg: StateUpdater = (v) => { set_ezcfg1(v); this.forceUpdate(); }; const set_overwrite_cfg = (v: boolean) => { set_overwrite_ezcfg(v); if (v) { set_ezcfg(Object.assign(ezcfg, generate_export_zip_cfg())); } }; let cfg_div = null; if (overwrite_ezcfg) { cfg_div = (
); } const datalist: { value: number; label?: string }[] = []; if (this.state.gids) { this.state.gids.forEach((g) => { const t = jpn_title && g.title_jpn ? g.title_jpn : g.title; datalist.push({ value: g.gid, label: t }); }); } config_div = (
{ginfo_div} {cfg_div}
); if (ezgid && ginfo?.ok && ginfo.data.meta.gid === ezgid) { submit = () => { return sendTaskMessage({ type: "new_export_zip_task", gid: ezgid, cfg: overwrite_ezcfg ? ezcfg : undefined, }); }; clean = () => { set_ezcfg((c) => { c.output = undefined; return c; }); set_ginfo(undefined); set_ezgid1(undefined); }; } } const sub = () => { if (submit) { const re = submit(); if (re) { if (clean) clean(); close(); } else { show_snack(t("task.submit_failed")); } } }; return (
{t("task.add")}
close
{t("task.type")}
{config_div}
); } }