import type { MediaProfile, MediaKind, DownloadOptions } from '@shared/ipc' import { isProfileLike } from './core/validation' import { createJsonStore } from './jsonStore' import { PROFILES_MAX } from './constants' // Named download presets a Library Source can point at (PINCHFLAT Media // Profiles). Plain JSON in userData, same shape/pattern as templates.ts — // atomic writes / corruption backup / caching from the shared jsonStore (R1–R3). // A persisted row must at least be an object carrying an id (isProfileLike); // everything else is coerced by sanitize(), so a hand-edited profiles.json can't // inject malformed entries. (audit S5) const store = createJsonStore('profiles.json', isProfileLike, PROFILES_MAX) const KINDS: readonly MediaKind[] = ['video', 'audio'] /** Normalise a persisted/incoming profile so every field is well-formed. */ function sanitize(p: MediaProfile): MediaProfile { const out: MediaProfile = { id: String(p.id), name: (p.name ?? '').trim() || 'Untitled profile' } if (p.kind && KINDS.includes(p.kind)) out.kind = p.kind if (typeof p.quality === 'string' && p.quality.trim()) out.quality = p.quality.trim() // options is stored whole when present; the download path re-sanitizes it // through the settings schema before use, so a weak object check is enough here. if (p.options && typeof p.options === 'object') out.options = p.options as DownloadOptions if (typeof p.outputTemplate === 'string' && p.outputTemplate.trim()) { out.outputTemplate = p.outputTemplate.trim() } if (typeof p.extraArgs === 'string' && p.extraArgs.trim()) out.extraArgs = p.extraArgs.trim() return out } export function listProfiles(): MediaProfile[] { return store.read().map(sanitize) } /** Add a new profile, or update an existing one (matched by id). */ export function saveProfile(profile: MediaProfile): MediaProfile[] { const clean = sanitize(profile) return store.write([clean, ...listProfiles().filter((p) => p.id !== clean.id)]) } export function removeProfile(id: string): MediaProfile[] { return store.write(listProfiles().filter((p) => p.id !== id)) }