feat: add server API client module
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -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)}`);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user