import { useState } from "react"; import { useTranslation } from "react-i18next"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { Lock, Pencil, Plus, Trash2 } from "lucide-react"; import Modal from "./Modal"; import { useConfirm } from "./ConfirmProvider"; import { api, type DownloadProfile, type DownloadSpec } from "../lib/api"; const inputCls = "w-full rounded-lg bg-surface border border-border px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-accent/40"; const HEIGHTS = [null, 2160, 1440, 1080, 720, 480, 360]; const BLANK: DownloadSpec = { mode: "av", max_height: 1080, container: "mp4", audio_format: "m4a", vcodec: null, embed_subs: false, embed_chapters: true, embed_thumbnail: true, sponsorblock: false, }; function Check({ label, checked, onChange, }: { label: string; checked: boolean; onChange: (v: boolean) => void; }) { return ( ); } export default function ProfileEditor({ onClose }: { onClose: () => void }) { const { t } = useTranslation(); const qc = useQueryClient(); const confirm = useConfirm(); const profilesQ = useQuery({ queryKey: ["download-profiles"], queryFn: api.downloadProfiles }); const profiles = profilesQ.data ?? []; const builtins = profiles.filter((p) => p.is_builtin); const mine = profiles.filter((p) => !p.is_builtin); const [editing, setEditing] = useState(null); const [name, setName] = useState(""); const [spec, setSpec] = useState(BLANK); const [formOpen, setFormOpen] = useState(false); const invalidate = () => qc.invalidateQueries({ queryKey: ["download-profiles"] }); const startNew = () => { setEditing(null); setName(""); setSpec(BLANK); setFormOpen(true); }; const startEdit = (p: DownloadProfile) => { setEditing(p); setName(p.name); setSpec({ ...BLANK, ...p.spec }); setFormOpen(true); }; const save = useMutation({ mutationFn: () => editing ? api.updateDownloadProfile(editing.id, { name, spec }) : api.createDownloadProfile({ name, spec }), onSuccess: () => { invalidate(); setFormOpen(false); }, }); const del = useMutation({ mutationFn: (id: number) => api.deleteDownloadProfile(id), onSuccess: invalidate, }); const onDelete = async (p: DownloadProfile) => { if (await confirm({ title: t("downloads.profiles.delete"), message: t("downloads.profiles.deleteConfirm", { name: p.name }), confirmLabel: t("downloads.profiles.delete"), danger: true })) { del.mutate(p.id); } }; const patch = (p: Partial) => setSpec((s) => ({ ...s, ...p })); const set = (k: keyof DownloadSpec) => (e: React.ChangeEvent) => patch({ [k]: e.target.value === "" ? null : e.target.value } as Partial); return ( {/* Existing formats */}
{t("downloads.profiles.builtin")}
{builtins.map((p) => (
{p.name}
))} {mine.length > 0 && (
{t("downloads.profiles.yours")}
)} {mine.map((p) => (
{p.name}
))}
{!formOpen ? ( ) : (
setName(e.target.value)} placeholder={t("downloads.profiles.namePlaceholder")} className={inputCls} />
{spec.mode !== "a" ? (
) : (
)} {spec.mode !== "a" && ( <>
)}
{spec.mode !== "a" && ( patch({ embed_subs: v })} /> )} patch({ embed_chapters: v })} /> patch({ embed_thumbnail: v })} /> patch({ sponsorblock: v })} />
)}
); }