initial commit
This commit is contained in:
101
frontend/src/api/client.ts
Normal file
101
frontend/src/api/client.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
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<T>(path: string, init?: RequestInit): Promise<T> {
|
||||
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<Library[]>("/libraries"),
|
||||
create: (name: string, path: string) =>
|
||||
request<Library>("/libraries", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ name, path }),
|
||||
}),
|
||||
delete: (id: number) =>
|
||||
request<void>(`/libraries/${id}`, { method: "DELETE" }),
|
||||
browse: (id: number, path = "") =>
|
||||
request<BrowseResult>(`/libraries/${id}/browse?path=${encodeURIComponent(path)}`),
|
||||
},
|
||||
|
||||
media: {
|
||||
get: (id: number) => request<MediaItem>(`/media/${id}`),
|
||||
fileUrl: (id: number) => `${BASE}/media/${id}/file`,
|
||||
thumbnailUrl: (id: number) => `${BASE}/media/${id}/thumbnail`,
|
||||
setTags: (id: number, tagIds: number[]) =>
|
||||
request<MediaItem>(`/media/${id}/tags`, {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({ tag_ids: tagIds }),
|
||||
}),
|
||||
},
|
||||
|
||||
tags: {
|
||||
list: () => request<TagsByCategory[]>("/tags"),
|
||||
create: (name: string, category: string) =>
|
||||
request<Tag>("/tags", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ name, category }),
|
||||
}),
|
||||
delete: (id: number) =>
|
||||
request<void>(`/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<MediaItem[]>(`/search?${p}`);
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user