const BASE = "/api"; export interface Library { id: number; name: string; path: string; } export interface Tag { id: number; name: string; category: string; } export interface TagsByCategory { category: string; tags: Tag[]; } export interface MediaItem { id: number; library_id: number; rel_path: string; filename: string; media_type: "image" | "video"; size_bytes: number | null; missing: boolean; tags: Tag[]; created_at: string; updated_at: string; } export interface BrowseEntry { name: string; type: "dir" | "image" | "video"; rel_path: string; media_item_id: number | null; } export interface BrowseResult { path: string; entries: BrowseEntry[]; } async function request(path: string, init?: RequestInit): Promise { const res = await fetch(`${BASE}${path}`, { headers: { "Content-Type": "application/json" }, ...init, }); if (!res.ok) { const text = await res.text().catch(() => ""); throw new Error(`${res.status}: ${text}`); } if (res.status === 204) return undefined as T; return res.json(); } export const api = { libraries: { list: () => request("/libraries"), create: (name: string, path: string) => request("/libraries", { method: "POST", body: JSON.stringify({ name, path }), }), delete: (id: number) => request(`/libraries/${id}`, { method: "DELETE" }), browse: (id: number, path = "") => request(`/libraries/${id}/browse?path=${encodeURIComponent(path)}`), scanStatus: (id: number) => request<{ scanning: boolean }>(`/libraries/${id}/scan-status`), rescan: (id: number) => request<{ scanning: boolean }>(`/libraries/${id}/rescan`, { method: "POST" }), }, media: { get: (id: number) => request(`/media/${id}`), fileUrl: (id: number) => `${BASE}/media/${id}/file`, thumbnailUrl: (id: number) => `${BASE}/media/${id}/thumbnail`, setTags: (id: number, tagIds: number[]) => request(`/media/${id}/tags`, { method: "PUT", body: JSON.stringify({ tag_ids: tagIds }), }), }, tags: { list: () => request("/tags"), create: (name: string, category: string) => request("/tags", { method: "POST", body: JSON.stringify({ name, category }), }), delete: (id: number) => request(`/tags/${id}`, { method: "DELETE" }), }, search: (params: { q?: string; tags?: number[]; library_id?: number }) => { const p = new URLSearchParams(); if (params.q) p.set("q", params.q); if (params.tags?.length) p.set("tags", params.tags.join(",")); if (params.library_id != null) p.set("library_id", String(params.library_id)); return request(`/search?${p}`); }, };