major refactor
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* API client for FastAPI backend
|
||||
* GraphQL API client
|
||||
*/
|
||||
|
||||
import type {
|
||||
@@ -8,34 +8,51 @@ import type {
|
||||
TranscodeJob,
|
||||
CreateJobRequest,
|
||||
SystemStatus,
|
||||
WorkerStatus,
|
||||
} from "./types";
|
||||
|
||||
const API_BASE = "/api";
|
||||
const GRAPHQL_URL = "/api/graphql";
|
||||
|
||||
async function request<T>(path: string, options?: RequestInit): Promise<T> {
|
||||
const response = await fetch(`${API_BASE}${path}`, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
...options,
|
||||
async function gql<T>(query: string, variables?: Record<string, unknown>): Promise<T> {
|
||||
const response = await fetch(GRAPHQL_URL, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ query, variables }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.text();
|
||||
throw new Error(`API error: ${response.status} - ${error}`);
|
||||
const json = await response.json();
|
||||
|
||||
if (json.errors?.length) {
|
||||
throw new Error(json.errors[0].message);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
return json.data as T;
|
||||
}
|
||||
|
||||
// Assets
|
||||
export async function getAssets(): Promise<MediaAsset[]> {
|
||||
return request("/assets/");
|
||||
const data = await gql<{ assets: MediaAsset[] }>(`
|
||||
query {
|
||||
assets {
|
||||
id filename file_path status error_message file_size duration
|
||||
video_codec audio_codec width height framerate bitrate
|
||||
properties comments tags created_at updated_at
|
||||
}
|
||||
}
|
||||
`);
|
||||
return data.assets;
|
||||
}
|
||||
|
||||
export async function getAsset(id: string): Promise<MediaAsset> {
|
||||
return request(`/assets/${id}`);
|
||||
const data = await gql<{ asset: MediaAsset }>(`
|
||||
query($id: UUID!) {
|
||||
asset(id: $id) {
|
||||
id filename file_path status error_message file_size duration
|
||||
video_codec audio_codec width height framerate bitrate
|
||||
properties comments tags created_at updated_at
|
||||
}
|
||||
}
|
||||
`, { id });
|
||||
return data.asset;
|
||||
}
|
||||
|
||||
export async function scanMediaFolder(): Promise<{
|
||||
@@ -44,43 +61,95 @@ export async function scanMediaFolder(): Promise<{
|
||||
skipped: number;
|
||||
files: string[];
|
||||
}> {
|
||||
return request("/assets/scan", {
|
||||
method: "POST",
|
||||
});
|
||||
const data = await gql<{ scan_media_folder: { found: number; registered: number; skipped: number; files: string[] } }>(`
|
||||
mutation {
|
||||
scan_media_folder { found registered skipped files }
|
||||
}
|
||||
`);
|
||||
return data.scan_media_folder;
|
||||
}
|
||||
|
||||
// Presets
|
||||
export async function getPresets(): Promise<TranscodePreset[]> {
|
||||
return request("/presets/");
|
||||
const data = await gql<{ presets: TranscodePreset[] }>(`
|
||||
query {
|
||||
presets {
|
||||
id name description is_builtin container
|
||||
video_codec video_bitrate video_crf video_preset resolution framerate
|
||||
audio_codec audio_bitrate audio_channels audio_samplerate
|
||||
extra_args created_at updated_at
|
||||
}
|
||||
}
|
||||
`);
|
||||
return data.presets;
|
||||
}
|
||||
|
||||
// Jobs
|
||||
export async function getJobs(): Promise<TranscodeJob[]> {
|
||||
return request("/jobs/");
|
||||
const data = await gql<{ jobs: TranscodeJob[] }>(`
|
||||
query {
|
||||
jobs {
|
||||
id source_asset_id preset_id preset_snapshot trim_start trim_end
|
||||
output_filename output_path output_asset_id status progress
|
||||
current_frame current_time speed error_message celery_task_id
|
||||
execution_arn priority created_at started_at completed_at
|
||||
}
|
||||
}
|
||||
`);
|
||||
return data.jobs;
|
||||
}
|
||||
|
||||
export async function getJob(id: string): Promise<TranscodeJob> {
|
||||
return request(`/jobs/${id}`);
|
||||
const data = await gql<{ job: TranscodeJob }>(`
|
||||
query($id: UUID!) {
|
||||
job(id: $id) {
|
||||
id source_asset_id preset_id preset_snapshot trim_start trim_end
|
||||
output_filename output_path output_asset_id status progress
|
||||
current_frame current_time speed error_message celery_task_id
|
||||
execution_arn priority created_at started_at completed_at
|
||||
}
|
||||
}
|
||||
`, { id });
|
||||
return data.job;
|
||||
}
|
||||
|
||||
export async function createJob(data: CreateJobRequest): Promise<TranscodeJob> {
|
||||
return request("/jobs/", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(data),
|
||||
export async function createJob(req: CreateJobRequest): Promise<TranscodeJob> {
|
||||
const data = await gql<{ create_job: TranscodeJob }>(`
|
||||
mutation($input: CreateJobInput!) {
|
||||
create_job(input: $input) {
|
||||
id source_asset_id status output_filename progress created_at
|
||||
}
|
||||
}
|
||||
`, {
|
||||
input: {
|
||||
source_asset_id: req.source_asset_id,
|
||||
preset_id: req.preset_id,
|
||||
trim_start: req.trim_start,
|
||||
trim_end: req.trim_end,
|
||||
output_filename: req.output_filename ?? null,
|
||||
priority: req.priority ?? 0,
|
||||
},
|
||||
});
|
||||
return data.create_job;
|
||||
}
|
||||
|
||||
export async function cancelJob(id: string): Promise<TranscodeJob> {
|
||||
return request(`/jobs/${id}/cancel`, {
|
||||
method: "POST",
|
||||
});
|
||||
const data = await gql<{ cancel_job: TranscodeJob }>(`
|
||||
mutation($id: UUID!) {
|
||||
cancel_job(id: $id) {
|
||||
id status
|
||||
}
|
||||
}
|
||||
`, { id });
|
||||
return data.cancel_job;
|
||||
}
|
||||
|
||||
// System
|
||||
export async function getSystemStatus(): Promise<SystemStatus> {
|
||||
return request("/system/status");
|
||||
}
|
||||
|
||||
export async function getWorkerStatus(): Promise<WorkerStatus> {
|
||||
return request("/system/worker");
|
||||
const data = await gql<{ system_status: SystemStatus }>(`
|
||||
query {
|
||||
system_status { status version }
|
||||
}
|
||||
`);
|
||||
return data.system_status;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user