feat: add server API client module

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-16 18:34:23 +02:00
parent 1e65fd6b0f
commit 12dae93671
+139
View File
@@ -0,0 +1,139 @@
const DEFAULT_SERVER = "http://192.168.1.51:8000";
let serverUrl = DEFAULT_SERVER;
export function setServer(url: string) {
serverUrl = url.replace(/\/+$/, "");
}
export function getServer(): string {
return serverUrl;
}
async function get<T>(path: string): Promise<T> {
const res = await fetch(`${serverUrl}${path}`);
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
return res.json();
}
async function post<T>(path: string, body?: unknown): Promise<T> {
const res = await fetch(`${serverUrl}${path}`, {
method: "POST",
headers: body ? { "Content-Type": "application/json" } : {},
body: body ? JSON.stringify(body) : undefined,
});
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
return res.json();
}
async function del<T>(path: string): Promise<T> {
const res = await fetch(`${serverUrl}${path}`, { method: "DELETE" });
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
return res.json();
}
// --- Files ---
export interface VideoFile {
name: string;
path: string;
root: string;
size: number;
}
export function getRoots(): Promise<string[]> {
return get("/api/roots");
}
export function getFiles(root?: string): Promise<VideoFile[]> {
const q = root ? `?root=${encodeURIComponent(root)}` : "";
return get(`/api/files${q}`);
}
// For {path:path} routes, encode each segment individually to preserve slashes
function encodePath(p: string): string {
return p.split("/").map(encodeURIComponent).join("/");
}
export function streamUrl(path: string, root: string, quality: string): string {
return `${serverUrl}/api/stream/${encodePath(path)}?root=${encodeURIComponent(root)}&quality=${quality}`;
}
export function audioUrl(path: string, root: string): string {
return `${serverUrl}/api/audio/${encodePath(path)}?root=${encodeURIComponent(root)}`;
}
export function cacheStatus(path: string, root: string): Promise<Record<string, string>> {
return get(`/api/cache/status/${encodePath(path)}?root=${encodeURIComponent(root)}`);
}
// --- Markers & Profiles ---
export interface Marker {
start_time: number;
marker_number: number;
output_path: string;
}
export function getMarkers(filename: string, profile: string = "default"): Promise<Marker[]> {
return get(`/api/markers/${encodeURIComponent(filename)}?profile=${encodeURIComponent(profile)}`);
}
export function getProfiles(): Promise<string[]> {
return get("/api/profiles");
}
export function getLabels(): Promise<string[]> {
return get("/api/labels");
}
// --- Export ---
export interface ExportRequest {
input_path: string;
cursor: number;
name: string;
clips?: number;
spread?: number;
short_side?: number | null;
portrait_ratio?: string | null;
crop_center?: number;
format?: string;
label?: string;
category?: string;
profile?: string;
folder_suffix?: string;
encoder?: string;
}
export function startExport(req: ExportRequest): Promise<{ job_id: string }> {
return post("/api/export", req);
}
export function getExportStatus(jobId: string): Promise<{
status: string;
total: number;
completed: number;
outputs: string[];
error?: string;
}> {
return get(`/api/export/${jobId}`);
}
export function deleteExport(outputPath: string): Promise<{ deleted: string }> {
return del(`/api/export?output_path=${encodeURIComponent(outputPath)}`);
}
// --- Hidden ---
export function hideFile(filename: string, profile: string = "default"): Promise<unknown> {
return post(`/api/hidden/${encodeURIComponent(filename)}?profile=${encodeURIComponent(profile)}`);
}
export function unhideFile(filename: string, profile: string = "default"): Promise<unknown> {
return del(`/api/hidden/${encodeURIComponent(filename)}?profile=${encodeURIComponent(profile)}`);
}
export function getHidden(profile: string = "default"): Promise<string[]> {
return get(`/api/hidden?profile=${encodeURIComponent(profile)}`);
}