import { exists } from "@std/fs/exists"; import { JsonValue, parse } from "@std/jsonc"; import { isDocker, toJSON } from "./utils.ts"; export type ConfigType = { cookies: boolean; db_path?: string; ua?: string; ex: boolean; base: string; max_task_count: number; mpv: boolean; max_retry_count: number; max_download_img_count: number; download_original_img: boolean; port: number; export_zip_jpn_title: boolean; hostname: string; meili_host?: string; meili_search_api_key?: string; meili_update_api_key?: string; ffmpeg_path: string; thumbnail_method: ThumbnailMethod; thumbnail_dir: string; remove_previous_gallery: boolean; img_verify_secret?: string; meili_hosts?: Record; cors_credentials_hosts: Array; flutter_frontend?: string; fetch_timeout: number; download_timeout: number; ffprobe_path: string; redirect_to_flutter: boolean; download_timeout_check_interval: number; /** EH metadata cache time in hours */ eh_metadata_cache_time: number; random_file_secret?: string; use_path_based_img_url: boolean; check_file_hash: boolean; import_method: ImportMethod; max_import_img_count: number; enable_server_timing: boolean; thumbnail_format: ThumbnailFormat; }; export enum ThumbnailMethod { FFMPEG_BINARY, FFMPEG_API, } export enum ThumbnailFormat { JPEG, WEBP, } export enum ImportMethod { Copy, CopyThenDelete, Move, Keep, } export enum ImportSize { Original, X780 = 780, X980 = 980, X1280 = 1280, Resampled = X1280, X1600 = 1600, X2400 = 2400, } export class Config { _data; constructor(data: JsonValue) { this._data = <{ [x: string]: unknown }> Object.assign( {}, data, ); } _return_string(key: string) { const v = this._data[key]; if (v === undefined || typeof v === "string") { return v; } throw new Error(`Config ${key} value ${v} is not a string`); } _return_number(key: string) { const v = this._data[key]; if (v === undefined) return undefined; if (typeof v === "number") { return v; } throw new Error(`Config ${key} value ${v} is not a number`); } _return_bool(key: string) { const v = this._data[key]; if (v === undefined) { return v; } if (typeof v === "boolean") { return v; } else if (typeof v === "string") { if (v === "true") { return true; } else if (v === "false") { return false; } } else if (typeof v === "number") { return v != 0; } throw new Error(`Config ${key} value ${v} is not a boolean`); } get cookies() { return this._return_string("cookies"); } get db_path() { if (isDocker()) { return this._return_string("db_path") || "./data"; } return this._return_string("db_path"); } get ua() { return this._return_string("ua"); } get ex() { return this._return_bool("ex") || false; } get base() { return this._return_string("base") || "./downloads"; } get max_task_count() { return this._return_number("max_task_count") || 1; } get mpv() { return this._return_bool("mpv") || false; } get max_retry_count() { return this._return_number("max_retry_count") || 3; } get max_download_img_count() { return this._return_number("max_download_img_count") || 3; } get download_original_img() { return this._return_bool("download_original_img") || false; } get port() { if (isDocker()) { return 8000; } return this._return_number("port") || 8000; } get export_zip_jpn_title() { return this._return_bool("export_zip_jpn_title") || false; } get hostname() { if (isDocker()) { return "0.0.0.0"; } return this._return_string("hostname") || "127.0.0.1"; } get meili_host() { return this._return_string("meili_host"); } get meili_search_api_key() { return this._return_string("meili_search_api_key"); } get meili_update_api_key() { return this._return_string("meili_update_api_key"); } get ffmpeg_path() { return this._return_string("ffmpeg_path") || "ffmpeg"; } get thumbnail_method() { const n = this._return_number("thumbnail_method") || 0; if (n < 0 || n > 1) return ThumbnailMethod.FFMPEG_BINARY; return n as ThumbnailMethod; } get thumbnail_dir() { return this._return_string("thumbnail_dir") || "./thumbnails"; } get thumbnail_format() { const n = this._return_number("thumbnail_format") || 0; if (n < 0 || n > 1) return ThumbnailFormat.JPEG; return n as ThumbnailFormat; } get remove_previous_gallery() { return this._return_bool("remove_previous_gallery") || false; } get img_verify_secret() { return this._return_string("img_verify_secret"); } get meili_hosts() { if (typeof this._data.meili_hosts === "object") { const hosts: Record = {}; for (const i in this._data.meili_hosts) { /**@ts-ignore Object*/ const v = this._data.meili_hosts[i]; if (typeof v === "string") hosts[i] = v; } return hosts; } return undefined; } get cors_credentials_hosts(): Array { if (Array.isArray(this._data.cors_credentials_hosts)) { const hosts: Array = []; for (const i of this._data.cors_credentials_hosts) { if (typeof i === "string") hosts.push(i); } return hosts; } return []; } get flutter_frontend() { return this._return_string("flutter_frontend"); } get fetch_timeout() { return this._return_number("fetch_timeout") || 10000; } get download_timeout() { return this._return_number("download_timeout") || 2000; } get ffprobe_path() { return this._return_string("ffprobe_path") || "ffprobe"; } get redirect_to_flutter() { return this._return_bool("redirect_to_flutter") ?? true; } get download_timeout_check_interval() { return this._return_number("download_timeout_check_interval") || 10; } /** EH metadata cache time in hours */ get eh_metadata_cache_time() { return this._return_number("eh_metadata_cache_time") || 168; } get random_file_secret() { return this._return_string("random_file_secret"); } get use_path_based_img_url() { return this._return_bool("use_path_based_img_url") ?? true; } get check_file_hash() { return this._return_bool("check_file_hash") ?? true; } get import_method() { const n = this._return_number("import_method") ?? 1; if (n < 0 || n > 3) return ImportMethod.CopyThenDelete; return n as ImportMethod; } get max_import_img_count() { return this._return_number("max_import_img_count") || 3; } get enable_server_timing() { return this._return_bool("enable_server_timing") ?? false; } to_json(): ConfigType { return { cookies: typeof this.cookies === "string", db_path: this.db_path, ua: this.ua, ex: this.ex, base: this.base, max_task_count: this.max_task_count, mpv: this.mpv, max_retry_count: this.max_retry_count, max_download_img_count: this.max_download_img_count, download_original_img: this.download_original_img, port: this.port, export_zip_jpn_title: this.export_zip_jpn_title, hostname: this.hostname, meili_host: this.meili_host, meili_search_api_key: this.meili_search_api_key, meili_update_api_key: this.meili_update_api_key, ffmpeg_path: this.ffmpeg_path, thumbnail_method: this.thumbnail_method, thumbnail_dir: this.thumbnail_dir, remove_previous_gallery: this.remove_previous_gallery, img_verify_secret: this.img_verify_secret, meili_hosts: this.meili_hosts, cors_credentials_hosts: this.cors_credentials_hosts, flutter_frontend: this.flutter_frontend, fetch_timeout: this.fetch_timeout, download_timeout: this.download_timeout, ffprobe_path: this.ffprobe_path, redirect_to_flutter: this.redirect_to_flutter, download_timeout_check_interval: this.download_timeout_check_interval, eh_metadata_cache_time: this.eh_metadata_cache_time, random_file_secret: this.random_file_secret, use_path_based_img_url: this.use_path_based_img_url, check_file_hash: this.check_file_hash, import_method: this.import_method, max_import_img_count: this.max_import_img_count, enable_server_timing: this.enable_server_timing, thumbnail_format: this.thumbnail_format, }; } } export async function load_settings(path: string) { if (!await exists(path)) return new Config({}); let s = (new TextDecoder()).decode(await Deno.readFile(path)); while (!s.length) { s = (new TextDecoder()).decode(await Deno.readFile(path)); } return new Config(parse(s)); } export function save_settings(path: string, cfg: Config, signal?: AbortSignal) { return Deno.writeTextFile(path, toJSON(cfg._data), { signal }); }