import fs from "fs-extra"; import path from "path"; import inquirer from "inquirer"; import { fileURLToPath } from "url"; import dotenv from "dotenv"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const rootDir = path.resolve(__dirname, ".."); const CACHE_DIR = path.join(rootDir, ".cache"); const CONFIG_PATH = path.join(CACHE_DIR, "config.json"); export const MEDIA_TYPES = [ { key: "movie", label: "movie", folder: "movies" }, { key: "show", label: "tv show", folder: "shows" } ]; const ASSET_TYPES = ["poster", "backdrop"]; dotenv.config({ path: path.resolve(__dirname, "..", "..", ".env") }); export const initConfig = async () => { const existingConfig = (await fs.pathExists(CONFIG_PATH)) ? await fs.readJson(CONFIG_PATH) : {}; const config = { ...existingConfig }; if (config.storageDir) { const { updateStorage } = await inquirer.prompt([ { type: "confirm", name: "updateStorage", message: `Storage directory is already set to "${config.storageDir}". Do you want to update it?`, default: false } ]); if (updateStorage) { const { storageDir } = await inquirer.prompt([ { name: "storageDir", message: "Where is your storage root directory?", validate: fs.pathExists } ]); config.storageDir = storageDir; } } else { const { storageDir } = await inquirer.prompt([ { name: "storageDir", message: "Where is your storage root directory?", validate: fs.pathExists } ]); config.storageDir = storageDir; } const { customize } = await inquirer.prompt([ { type: "confirm", name: "customize", message: "Do you want to customize default media paths?", default: false } ]); config.mediaPaths = {}; for (const { key, label, folder } of MEDIA_TYPES) { config.mediaPaths[key] = {}; for (const assetType of ASSET_TYPES) { const assetFolder = assetType === "poster" ? "" : `/${assetType}s`; const defaultPath = `Media assets/${folder}${assetFolder}`.replace(/\/$/, ""); let subpath = defaultPath; if (customize) { const response = await inquirer.prompt([ { name: "subpath", message: `Subpath for ${label}/${assetType} (relative to storage root):`, default: defaultPath } ]); subpath = response.subpath; } config.mediaPaths[key][assetType] = subpath; } } config.artistPath = customize ? ( await inquirer.prompt([ { name: "artistPath", message: "Subpath for artist images (relative to storage root):", default: "Media assets/artists" } ]) ).artistPath : "Media assets/artists"; config.albumPath = customize ? ( await inquirer.prompt([ { name: "albumPath", message: "Subpath for album images (relative to storage root):", default: "Media assets/albums" } ]) ).albumPath : "Media assets/albums"; config.bookPath = customize ? ( await inquirer.prompt([ { name: "bookPath", message: "Subpath for book images (relative to storage root):", default: "Media assets/books" } ]) ).bookPath : "Media assets/books"; if (config.directus?.apiUrl) { const { updateApiUrl } = await inquirer.prompt([ { type: "confirm", name: "updateApiUrl", message: `Directus API URL is already set to "${config.directus.apiUrl}". Do you want to update it?`, default: false } ]); if (updateApiUrl) { const { apiUrl } = await inquirer.prompt([ { name: "apiUrl", message: "Enter your Directus instance URL:", validate: (input) => input.startsWith("http") || "Must be a valid URL" } ]); config.directus.apiUrl = apiUrl; } } else { const { apiUrl } = await inquirer.prompt([ { name: "apiUrl", message: "Enter your Directus URL:", validate: (input) => input.startsWith("http") || "Must be a valid URL" } ]); config.directus = { ...(config.directus || {}), apiUrl }; } const globals = await fetchGlobals(); config.url = globals.url; await fs.ensureDir(CACHE_DIR); await fs.writeJson(CONFIG_PATH, config, { spaces: 2 }); console.log(`✅ Config saved to ${CONFIG_PATH}`); }; export const loadConfig = async () => { if (!(await fs.pathExists(CONFIG_PATH))) { console.error("❌ Config not found. Run \`coryd init\` first."); process.exit(1); } return await fs.readJson(CONFIG_PATH); }; const fetchGlobals = async () => { const POSTGREST_URL = process.env.POSTGREST_URL; const POSTGREST_API_KEY = process.env.POSTGREST_API_KEY; if (!POSTGREST_URL || !POSTGREST_API_KEY) { console.warn("⚠️ Missing POSTGREST_URL or POSTGREST_API_KEY in env, skipping globals fetch."); return {}; } try { const res = await fetch(`${POSTGREST_URL}/optimized_globals?select=*`, { method: "GET", headers: { "Content-Type": "application/json", Authorization: `Bearer ${POSTGREST_API_KEY}` } }); if (!res.ok) throw new Error(await res.text()); const data = await res.json(); return data[0] || {}; } catch (err) { console.error("❌ Error fetching globals:", err.message); return {}; } };