chunker ui redo

This commit is contained in:
2026-03-15 16:03:53 -03:00
parent d5a3372d6b
commit b40bd68411
62 changed files with 5460 additions and 1493 deletions

24
ui/common/api/graphql.ts Normal file
View File

@@ -0,0 +1,24 @@
/**
* Shared GraphQL client for all MPR UI apps.
*/
const GRAPHQL_URL = "/api/graphql";
export 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 }),
});
const json = await response.json();
if (json.errors?.length) {
throw new Error(json.errors[0].message);
}
return json.data as T;
}

View File

@@ -0,0 +1,95 @@
// @generated by protobuf-ts 2.11.1
// @generated from protobuf file "worker.proto" (package "mpr.worker", syntax proto3)
// tslint:disable
//
// Protocol Buffer Definitions - GENERATED FILE
//
// Do not edit directly. Regenerate using modelgen.
//
import type { RpcTransport } from "@protobuf-ts/runtime-rpc";
import type { ServiceInfo } from "@protobuf-ts/runtime-rpc";
import { WorkerService } from "./worker";
import type { ChunkPipelineEvent } from "./worker";
import type { ChunkStreamRequest } from "./worker";
import type { WorkerStatus } from "./worker";
import type { Empty } from "./worker";
import type { CancelResponse } from "./worker";
import type { CancelRequest } from "./worker";
import type { ProgressUpdate } from "./worker";
import type { ProgressRequest } from "./worker";
import type { ServerStreamingCall } from "@protobuf-ts/runtime-rpc";
import { stackIntercept } from "@protobuf-ts/runtime-rpc";
import type { JobResponse } from "./worker";
import type { JobRequest } from "./worker";
import type { UnaryCall } from "@protobuf-ts/runtime-rpc";
import type { RpcOptions } from "@protobuf-ts/runtime-rpc";
/**
* @generated from protobuf service mpr.worker.WorkerService
*/
export interface IWorkerServiceClient {
/**
* @generated from protobuf rpc: SubmitJob
*/
submitJob(input: JobRequest, options?: RpcOptions): UnaryCall<JobRequest, JobResponse>;
/**
* @generated from protobuf rpc: StreamProgress
*/
streamProgress(input: ProgressRequest, options?: RpcOptions): ServerStreamingCall<ProgressRequest, ProgressUpdate>;
/**
* @generated from protobuf rpc: CancelJob
*/
cancelJob(input: CancelRequest, options?: RpcOptions): UnaryCall<CancelRequest, CancelResponse>;
/**
* @generated from protobuf rpc: GetWorkerStatus
*/
getWorkerStatus(input: Empty, options?: RpcOptions): UnaryCall<Empty, WorkerStatus>;
/**
* @generated from protobuf rpc: StreamChunkPipeline
*/
streamChunkPipeline(input: ChunkStreamRequest, options?: RpcOptions): ServerStreamingCall<ChunkStreamRequest, ChunkPipelineEvent>;
}
/**
* @generated from protobuf service mpr.worker.WorkerService
*/
export class WorkerServiceClient implements IWorkerServiceClient, ServiceInfo {
typeName = WorkerService.typeName;
methods = WorkerService.methods;
options = WorkerService.options;
constructor(private readonly _transport: RpcTransport) {
}
/**
* @generated from protobuf rpc: SubmitJob
*/
submitJob(input: JobRequest, options?: RpcOptions): UnaryCall<JobRequest, JobResponse> {
const method = this.methods[0], opt = this._transport.mergeOptions(options);
return stackIntercept<JobRequest, JobResponse>("unary", this._transport, method, opt, input);
}
/**
* @generated from protobuf rpc: StreamProgress
*/
streamProgress(input: ProgressRequest, options?: RpcOptions): ServerStreamingCall<ProgressRequest, ProgressUpdate> {
const method = this.methods[1], opt = this._transport.mergeOptions(options);
return stackIntercept<ProgressRequest, ProgressUpdate>("serverStreaming", this._transport, method, opt, input);
}
/**
* @generated from protobuf rpc: CancelJob
*/
cancelJob(input: CancelRequest, options?: RpcOptions): UnaryCall<CancelRequest, CancelResponse> {
const method = this.methods[2], opt = this._transport.mergeOptions(options);
return stackIntercept<CancelRequest, CancelResponse>("unary", this._transport, method, opt, input);
}
/**
* @generated from protobuf rpc: GetWorkerStatus
*/
getWorkerStatus(input: Empty, options?: RpcOptions): UnaryCall<Empty, WorkerStatus> {
const method = this.methods[3], opt = this._transport.mergeOptions(options);
return stackIntercept<Empty, WorkerStatus>("unary", this._transport, method, opt, input);
}
/**
* @generated from protobuf rpc: StreamChunkPipeline
*/
streamChunkPipeline(input: ChunkStreamRequest, options?: RpcOptions): ServerStreamingCall<ChunkStreamRequest, ChunkPipelineEvent> {
const method = this.methods[4], opt = this._transport.mergeOptions(options);
return stackIntercept<ChunkStreamRequest, ChunkPipelineEvent>("serverStreaming", this._transport, method, opt, input);
}
}

View File

@@ -0,0 +1,946 @@
// @generated by protobuf-ts 2.11.1
// @generated from protobuf file "worker.proto" (package "mpr.worker", syntax proto3)
// tslint:disable
//
// Protocol Buffer Definitions - GENERATED FILE
//
// Do not edit directly. Regenerate using modelgen.
//
import { ServiceType } from "@protobuf-ts/runtime-rpc";
import type { BinaryWriteOptions } from "@protobuf-ts/runtime";
import type { IBinaryWriter } from "@protobuf-ts/runtime";
import { WireType } from "@protobuf-ts/runtime";
import type { BinaryReadOptions } from "@protobuf-ts/runtime";
import type { IBinaryReader } from "@protobuf-ts/runtime";
import { UnknownFieldHandler } from "@protobuf-ts/runtime";
import type { PartialMessage } from "@protobuf-ts/runtime";
import { reflectionMergePartial } from "@protobuf-ts/runtime";
import { MessageType } from "@protobuf-ts/runtime";
/**
* @generated from protobuf message mpr.worker.JobRequest
*/
export interface JobRequest {
/**
* @generated from protobuf field: string job_id = 1
*/
jobId: string;
/**
* @generated from protobuf field: string source_path = 2
*/
sourcePath: string;
/**
* @generated from protobuf field: string output_path = 3
*/
outputPath: string;
/**
* @generated from protobuf field: string preset_json = 4
*/
presetJson: string;
/**
* @generated from protobuf field: optional float trim_start = 5
*/
trimStart?: number;
/**
* @generated from protobuf field: optional float trim_end = 6
*/
trimEnd?: number;
}
/**
* @generated from protobuf message mpr.worker.JobResponse
*/
export interface JobResponse {
/**
* @generated from protobuf field: string job_id = 1
*/
jobId: string;
/**
* @generated from protobuf field: bool accepted = 2
*/
accepted: boolean;
/**
* @generated from protobuf field: string message = 3
*/
message: string;
}
/**
* @generated from protobuf message mpr.worker.ProgressRequest
*/
export interface ProgressRequest {
/**
* @generated from protobuf field: string job_id = 1
*/
jobId: string;
}
/**
* @generated from protobuf message mpr.worker.ProgressUpdate
*/
export interface ProgressUpdate {
/**
* @generated from protobuf field: string job_id = 1
*/
jobId: string;
/**
* @generated from protobuf field: int32 progress = 2
*/
progress: number;
/**
* @generated from protobuf field: int32 current_frame = 3
*/
currentFrame: number;
/**
* @generated from protobuf field: float current_time = 4
*/
currentTime: number;
/**
* @generated from protobuf field: float speed = 5
*/
speed: number;
/**
* @generated from protobuf field: string status = 6
*/
status: string;
/**
* @generated from protobuf field: optional string error = 7
*/
error?: string;
}
/**
* @generated from protobuf message mpr.worker.CancelRequest
*/
export interface CancelRequest {
/**
* @generated from protobuf field: string job_id = 1
*/
jobId: string;
}
/**
* @generated from protobuf message mpr.worker.CancelResponse
*/
export interface CancelResponse {
/**
* @generated from protobuf field: string job_id = 1
*/
jobId: string;
/**
* @generated from protobuf field: bool cancelled = 2
*/
cancelled: boolean;
/**
* @generated from protobuf field: string message = 3
*/
message: string;
}
/**
* @generated from protobuf message mpr.worker.WorkerStatus
*/
export interface WorkerStatus {
/**
* @generated from protobuf field: bool available = 1
*/
available: boolean;
/**
* @generated from protobuf field: int32 active_jobs = 2
*/
activeJobs: number;
/**
* @generated from protobuf field: repeated string supported_codecs = 3
*/
supportedCodecs: string[];
/**
* @generated from protobuf field: bool gpu_available = 4
*/
gpuAvailable: boolean;
}
/**
* Empty
*
* @generated from protobuf message mpr.worker.Empty
*/
export interface Empty {
}
/**
* @generated from protobuf message mpr.worker.ChunkStreamRequest
*/
export interface ChunkStreamRequest {
/**
* @generated from protobuf field: string job_id = 1
*/
jobId: string;
}
/**
* @generated from protobuf message mpr.worker.ChunkPipelineEvent
*/
export interface ChunkPipelineEvent {
/**
* @generated from protobuf field: string job_id = 1
*/
jobId: string;
/**
* @generated from protobuf field: string event_type = 2
*/
eventType: string;
/**
* @generated from protobuf field: int32 sequence = 3
*/
sequence: number;
/**
* @generated from protobuf field: string worker_id = 4
*/
workerId: string;
/**
* @generated from protobuf field: string state = 5
*/
state: string;
/**
* @generated from protobuf field: int32 queue_size = 6
*/
queueSize: number;
/**
* @generated from protobuf field: float elapsed = 7
*/
elapsed: number;
/**
* @generated from protobuf field: float throughput_mbps = 8
*/
throughputMbps: number;
/**
* @generated from protobuf field: int32 total_chunks = 9
*/
totalChunks: number;
/**
* @generated from protobuf field: int32 processed_chunks = 10
*/
processedChunks: number;
/**
* @generated from protobuf field: int32 failed_chunks = 11
*/
failedChunks: number;
/**
* @generated from protobuf field: string error = 12
*/
error: string;
/**
* @generated from protobuf field: float processing_time = 13
*/
processingTime: number;
/**
* @generated from protobuf field: int32 retries = 14
*/
retries: number;
}
// @generated message type with reflection information, may provide speed optimized methods
class JobRequest$Type extends MessageType<JobRequest> {
constructor() {
super("mpr.worker.JobRequest", [
{ no: 1, name: "job_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 2, name: "source_path", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 3, name: "output_path", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 4, name: "preset_json", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 5, name: "trim_start", kind: "scalar", opt: true, T: 2 /*ScalarType.FLOAT*/ },
{ no: 6, name: "trim_end", kind: "scalar", opt: true, T: 2 /*ScalarType.FLOAT*/ }
]);
}
create(value?: PartialMessage<JobRequest>): JobRequest {
const message = globalThis.Object.create((this.messagePrototype!));
message.jobId = "";
message.sourcePath = "";
message.outputPath = "";
message.presetJson = "";
if (value !== undefined)
reflectionMergePartial<JobRequest>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: JobRequest): JobRequest {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* string job_id */ 1:
message.jobId = reader.string();
break;
case /* string source_path */ 2:
message.sourcePath = reader.string();
break;
case /* string output_path */ 3:
message.outputPath = reader.string();
break;
case /* string preset_json */ 4:
message.presetJson = reader.string();
break;
case /* optional float trim_start */ 5:
message.trimStart = reader.float();
break;
case /* optional float trim_end */ 6:
message.trimEnd = reader.float();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: JobRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* string job_id = 1; */
if (message.jobId !== "")
writer.tag(1, WireType.LengthDelimited).string(message.jobId);
/* string source_path = 2; */
if (message.sourcePath !== "")
writer.tag(2, WireType.LengthDelimited).string(message.sourcePath);
/* string output_path = 3; */
if (message.outputPath !== "")
writer.tag(3, WireType.LengthDelimited).string(message.outputPath);
/* string preset_json = 4; */
if (message.presetJson !== "")
writer.tag(4, WireType.LengthDelimited).string(message.presetJson);
/* optional float trim_start = 5; */
if (message.trimStart !== undefined)
writer.tag(5, WireType.Bit32).float(message.trimStart);
/* optional float trim_end = 6; */
if (message.trimEnd !== undefined)
writer.tag(6, WireType.Bit32).float(message.trimEnd);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message mpr.worker.JobRequest
*/
export const JobRequest = new JobRequest$Type();
// @generated message type with reflection information, may provide speed optimized methods
class JobResponse$Type extends MessageType<JobResponse> {
constructor() {
super("mpr.worker.JobResponse", [
{ no: 1, name: "job_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 2, name: "accepted", kind: "scalar", T: 8 /*ScalarType.BOOL*/ },
{ no: 3, name: "message", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
]);
}
create(value?: PartialMessage<JobResponse>): JobResponse {
const message = globalThis.Object.create((this.messagePrototype!));
message.jobId = "";
message.accepted = false;
message.message = "";
if (value !== undefined)
reflectionMergePartial<JobResponse>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: JobResponse): JobResponse {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* string job_id */ 1:
message.jobId = reader.string();
break;
case /* bool accepted */ 2:
message.accepted = reader.bool();
break;
case /* string message */ 3:
message.message = reader.string();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: JobResponse, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* string job_id = 1; */
if (message.jobId !== "")
writer.tag(1, WireType.LengthDelimited).string(message.jobId);
/* bool accepted = 2; */
if (message.accepted !== false)
writer.tag(2, WireType.Varint).bool(message.accepted);
/* string message = 3; */
if (message.message !== "")
writer.tag(3, WireType.LengthDelimited).string(message.message);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message mpr.worker.JobResponse
*/
export const JobResponse = new JobResponse$Type();
// @generated message type with reflection information, may provide speed optimized methods
class ProgressRequest$Type extends MessageType<ProgressRequest> {
constructor() {
super("mpr.worker.ProgressRequest", [
{ no: 1, name: "job_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
]);
}
create(value?: PartialMessage<ProgressRequest>): ProgressRequest {
const message = globalThis.Object.create((this.messagePrototype!));
message.jobId = "";
if (value !== undefined)
reflectionMergePartial<ProgressRequest>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ProgressRequest): ProgressRequest {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* string job_id */ 1:
message.jobId = reader.string();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: ProgressRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* string job_id = 1; */
if (message.jobId !== "")
writer.tag(1, WireType.LengthDelimited).string(message.jobId);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message mpr.worker.ProgressRequest
*/
export const ProgressRequest = new ProgressRequest$Type();
// @generated message type with reflection information, may provide speed optimized methods
class ProgressUpdate$Type extends MessageType<ProgressUpdate> {
constructor() {
super("mpr.worker.ProgressUpdate", [
{ no: 1, name: "job_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 2, name: "progress", kind: "scalar", T: 5 /*ScalarType.INT32*/ },
{ no: 3, name: "current_frame", kind: "scalar", T: 5 /*ScalarType.INT32*/ },
{ no: 4, name: "current_time", kind: "scalar", T: 2 /*ScalarType.FLOAT*/ },
{ no: 5, name: "speed", kind: "scalar", T: 2 /*ScalarType.FLOAT*/ },
{ no: 6, name: "status", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 7, name: "error", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }
]);
}
create(value?: PartialMessage<ProgressUpdate>): ProgressUpdate {
const message = globalThis.Object.create((this.messagePrototype!));
message.jobId = "";
message.progress = 0;
message.currentFrame = 0;
message.currentTime = 0;
message.speed = 0;
message.status = "";
if (value !== undefined)
reflectionMergePartial<ProgressUpdate>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ProgressUpdate): ProgressUpdate {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* string job_id */ 1:
message.jobId = reader.string();
break;
case /* int32 progress */ 2:
message.progress = reader.int32();
break;
case /* int32 current_frame */ 3:
message.currentFrame = reader.int32();
break;
case /* float current_time */ 4:
message.currentTime = reader.float();
break;
case /* float speed */ 5:
message.speed = reader.float();
break;
case /* string status */ 6:
message.status = reader.string();
break;
case /* optional string error */ 7:
message.error = reader.string();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: ProgressUpdate, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* string job_id = 1; */
if (message.jobId !== "")
writer.tag(1, WireType.LengthDelimited).string(message.jobId);
/* int32 progress = 2; */
if (message.progress !== 0)
writer.tag(2, WireType.Varint).int32(message.progress);
/* int32 current_frame = 3; */
if (message.currentFrame !== 0)
writer.tag(3, WireType.Varint).int32(message.currentFrame);
/* float current_time = 4; */
if (message.currentTime !== 0)
writer.tag(4, WireType.Bit32).float(message.currentTime);
/* float speed = 5; */
if (message.speed !== 0)
writer.tag(5, WireType.Bit32).float(message.speed);
/* string status = 6; */
if (message.status !== "")
writer.tag(6, WireType.LengthDelimited).string(message.status);
/* optional string error = 7; */
if (message.error !== undefined)
writer.tag(7, WireType.LengthDelimited).string(message.error);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message mpr.worker.ProgressUpdate
*/
export const ProgressUpdate = new ProgressUpdate$Type();
// @generated message type with reflection information, may provide speed optimized methods
class CancelRequest$Type extends MessageType<CancelRequest> {
constructor() {
super("mpr.worker.CancelRequest", [
{ no: 1, name: "job_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
]);
}
create(value?: PartialMessage<CancelRequest>): CancelRequest {
const message = globalThis.Object.create((this.messagePrototype!));
message.jobId = "";
if (value !== undefined)
reflectionMergePartial<CancelRequest>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: CancelRequest): CancelRequest {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* string job_id */ 1:
message.jobId = reader.string();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: CancelRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* string job_id = 1; */
if (message.jobId !== "")
writer.tag(1, WireType.LengthDelimited).string(message.jobId);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message mpr.worker.CancelRequest
*/
export const CancelRequest = new CancelRequest$Type();
// @generated message type with reflection information, may provide speed optimized methods
class CancelResponse$Type extends MessageType<CancelResponse> {
constructor() {
super("mpr.worker.CancelResponse", [
{ no: 1, name: "job_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 2, name: "cancelled", kind: "scalar", T: 8 /*ScalarType.BOOL*/ },
{ no: 3, name: "message", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
]);
}
create(value?: PartialMessage<CancelResponse>): CancelResponse {
const message = globalThis.Object.create((this.messagePrototype!));
message.jobId = "";
message.cancelled = false;
message.message = "";
if (value !== undefined)
reflectionMergePartial<CancelResponse>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: CancelResponse): CancelResponse {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* string job_id */ 1:
message.jobId = reader.string();
break;
case /* bool cancelled */ 2:
message.cancelled = reader.bool();
break;
case /* string message */ 3:
message.message = reader.string();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: CancelResponse, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* string job_id = 1; */
if (message.jobId !== "")
writer.tag(1, WireType.LengthDelimited).string(message.jobId);
/* bool cancelled = 2; */
if (message.cancelled !== false)
writer.tag(2, WireType.Varint).bool(message.cancelled);
/* string message = 3; */
if (message.message !== "")
writer.tag(3, WireType.LengthDelimited).string(message.message);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message mpr.worker.CancelResponse
*/
export const CancelResponse = new CancelResponse$Type();
// @generated message type with reflection information, may provide speed optimized methods
class WorkerStatus$Type extends MessageType<WorkerStatus> {
constructor() {
super("mpr.worker.WorkerStatus", [
{ no: 1, name: "available", kind: "scalar", T: 8 /*ScalarType.BOOL*/ },
{ no: 2, name: "active_jobs", kind: "scalar", T: 5 /*ScalarType.INT32*/ },
{ no: 3, name: "supported_codecs", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ },
{ no: 4, name: "gpu_available", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }
]);
}
create(value?: PartialMessage<WorkerStatus>): WorkerStatus {
const message = globalThis.Object.create((this.messagePrototype!));
message.available = false;
message.activeJobs = 0;
message.supportedCodecs = [];
message.gpuAvailable = false;
if (value !== undefined)
reflectionMergePartial<WorkerStatus>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: WorkerStatus): WorkerStatus {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* bool available */ 1:
message.available = reader.bool();
break;
case /* int32 active_jobs */ 2:
message.activeJobs = reader.int32();
break;
case /* repeated string supported_codecs */ 3:
message.supportedCodecs.push(reader.string());
break;
case /* bool gpu_available */ 4:
message.gpuAvailable = reader.bool();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: WorkerStatus, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* bool available = 1; */
if (message.available !== false)
writer.tag(1, WireType.Varint).bool(message.available);
/* int32 active_jobs = 2; */
if (message.activeJobs !== 0)
writer.tag(2, WireType.Varint).int32(message.activeJobs);
/* repeated string supported_codecs = 3; */
for (let i = 0; i < message.supportedCodecs.length; i++)
writer.tag(3, WireType.LengthDelimited).string(message.supportedCodecs[i]);
/* bool gpu_available = 4; */
if (message.gpuAvailable !== false)
writer.tag(4, WireType.Varint).bool(message.gpuAvailable);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message mpr.worker.WorkerStatus
*/
export const WorkerStatus = new WorkerStatus$Type();
// @generated message type with reflection information, may provide speed optimized methods
class Empty$Type extends MessageType<Empty> {
constructor() {
super("mpr.worker.Empty", []);
}
create(value?: PartialMessage<Empty>): Empty {
const message = globalThis.Object.create((this.messagePrototype!));
if (value !== undefined)
reflectionMergePartial<Empty>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: Empty): Empty {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: Empty, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message mpr.worker.Empty
*/
export const Empty = new Empty$Type();
// @generated message type with reflection information, may provide speed optimized methods
class ChunkStreamRequest$Type extends MessageType<ChunkStreamRequest> {
constructor() {
super("mpr.worker.ChunkStreamRequest", [
{ no: 1, name: "job_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }
]);
}
create(value?: PartialMessage<ChunkStreamRequest>): ChunkStreamRequest {
const message = globalThis.Object.create((this.messagePrototype!));
message.jobId = "";
if (value !== undefined)
reflectionMergePartial<ChunkStreamRequest>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ChunkStreamRequest): ChunkStreamRequest {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* string job_id */ 1:
message.jobId = reader.string();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: ChunkStreamRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* string job_id = 1; */
if (message.jobId !== "")
writer.tag(1, WireType.LengthDelimited).string(message.jobId);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message mpr.worker.ChunkStreamRequest
*/
export const ChunkStreamRequest = new ChunkStreamRequest$Type();
// @generated message type with reflection information, may provide speed optimized methods
class ChunkPipelineEvent$Type extends MessageType<ChunkPipelineEvent> {
constructor() {
super("mpr.worker.ChunkPipelineEvent", [
{ no: 1, name: "job_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 2, name: "event_type", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 3, name: "sequence", kind: "scalar", T: 5 /*ScalarType.INT32*/ },
{ no: 4, name: "worker_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 5, name: "state", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 6, name: "queue_size", kind: "scalar", T: 5 /*ScalarType.INT32*/ },
{ no: 7, name: "elapsed", kind: "scalar", T: 2 /*ScalarType.FLOAT*/ },
{ no: 8, name: "throughput_mbps", kind: "scalar", T: 2 /*ScalarType.FLOAT*/ },
{ no: 9, name: "total_chunks", kind: "scalar", T: 5 /*ScalarType.INT32*/ },
{ no: 10, name: "processed_chunks", kind: "scalar", T: 5 /*ScalarType.INT32*/ },
{ no: 11, name: "failed_chunks", kind: "scalar", T: 5 /*ScalarType.INT32*/ },
{ no: 12, name: "error", kind: "scalar", T: 9 /*ScalarType.STRING*/ },
{ no: 13, name: "processing_time", kind: "scalar", T: 2 /*ScalarType.FLOAT*/ },
{ no: 14, name: "retries", kind: "scalar", T: 5 /*ScalarType.INT32*/ }
]);
}
create(value?: PartialMessage<ChunkPipelineEvent>): ChunkPipelineEvent {
const message = globalThis.Object.create((this.messagePrototype!));
message.jobId = "";
message.eventType = "";
message.sequence = 0;
message.workerId = "";
message.state = "";
message.queueSize = 0;
message.elapsed = 0;
message.throughputMbps = 0;
message.totalChunks = 0;
message.processedChunks = 0;
message.failedChunks = 0;
message.error = "";
message.processingTime = 0;
message.retries = 0;
if (value !== undefined)
reflectionMergePartial<ChunkPipelineEvent>(this, message, value);
return message;
}
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ChunkPipelineEvent): ChunkPipelineEvent {
let message = target ?? this.create(), end = reader.pos + length;
while (reader.pos < end) {
let [fieldNo, wireType] = reader.tag();
switch (fieldNo) {
case /* string job_id */ 1:
message.jobId = reader.string();
break;
case /* string event_type */ 2:
message.eventType = reader.string();
break;
case /* int32 sequence */ 3:
message.sequence = reader.int32();
break;
case /* string worker_id */ 4:
message.workerId = reader.string();
break;
case /* string state */ 5:
message.state = reader.string();
break;
case /* int32 queue_size */ 6:
message.queueSize = reader.int32();
break;
case /* float elapsed */ 7:
message.elapsed = reader.float();
break;
case /* float throughput_mbps */ 8:
message.throughputMbps = reader.float();
break;
case /* int32 total_chunks */ 9:
message.totalChunks = reader.int32();
break;
case /* int32 processed_chunks */ 10:
message.processedChunks = reader.int32();
break;
case /* int32 failed_chunks */ 11:
message.failedChunks = reader.int32();
break;
case /* string error */ 12:
message.error = reader.string();
break;
case /* float processing_time */ 13:
message.processingTime = reader.float();
break;
case /* int32 retries */ 14:
message.retries = reader.int32();
break;
default:
let u = options.readUnknownField;
if (u === "throw")
throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`);
let d = reader.skip(wireType);
if (u !== false)
(u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d);
}
}
return message;
}
internalBinaryWrite(message: ChunkPipelineEvent, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter {
/* string job_id = 1; */
if (message.jobId !== "")
writer.tag(1, WireType.LengthDelimited).string(message.jobId);
/* string event_type = 2; */
if (message.eventType !== "")
writer.tag(2, WireType.LengthDelimited).string(message.eventType);
/* int32 sequence = 3; */
if (message.sequence !== 0)
writer.tag(3, WireType.Varint).int32(message.sequence);
/* string worker_id = 4; */
if (message.workerId !== "")
writer.tag(4, WireType.LengthDelimited).string(message.workerId);
/* string state = 5; */
if (message.state !== "")
writer.tag(5, WireType.LengthDelimited).string(message.state);
/* int32 queue_size = 6; */
if (message.queueSize !== 0)
writer.tag(6, WireType.Varint).int32(message.queueSize);
/* float elapsed = 7; */
if (message.elapsed !== 0)
writer.tag(7, WireType.Bit32).float(message.elapsed);
/* float throughput_mbps = 8; */
if (message.throughputMbps !== 0)
writer.tag(8, WireType.Bit32).float(message.throughputMbps);
/* int32 total_chunks = 9; */
if (message.totalChunks !== 0)
writer.tag(9, WireType.Varint).int32(message.totalChunks);
/* int32 processed_chunks = 10; */
if (message.processedChunks !== 0)
writer.tag(10, WireType.Varint).int32(message.processedChunks);
/* int32 failed_chunks = 11; */
if (message.failedChunks !== 0)
writer.tag(11, WireType.Varint).int32(message.failedChunks);
/* string error = 12; */
if (message.error !== "")
writer.tag(12, WireType.LengthDelimited).string(message.error);
/* float processing_time = 13; */
if (message.processingTime !== 0)
writer.tag(13, WireType.Bit32).float(message.processingTime);
/* int32 retries = 14; */
if (message.retries !== 0)
writer.tag(14, WireType.Varint).int32(message.retries);
let u = options.writeUnknownFields;
if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
return writer;
}
}
/**
* @generated MessageType for protobuf message mpr.worker.ChunkPipelineEvent
*/
export const ChunkPipelineEvent = new ChunkPipelineEvent$Type();
/**
* @generated ServiceType for protobuf service mpr.worker.WorkerService
*/
export const WorkerService = new ServiceType("mpr.worker.WorkerService", [
{ name: "SubmitJob", options: {}, I: JobRequest, O: JobResponse },
{ name: "StreamProgress", serverStreaming: true, options: {}, I: ProgressRequest, O: ProgressUpdate },
{ name: "CancelJob", options: {}, I: CancelRequest, O: CancelResponse },
{ name: "GetWorkerStatus", options: {}, I: Empty, O: WorkerStatus },
{ name: "StreamChunkPipeline", serverStreaming: true, options: {}, I: ChunkStreamRequest, O: ChunkPipelineEvent }
]);

42
ui/common/api/media.ts Normal file
View File

@@ -0,0 +1,42 @@
/**
* Shared media API functions — identical across all MPR UI apps.
*/
import type { MediaAsset } from "../types/generated";
import { gql } from "./graphql";
/** Fetch all media assets. */
export async function getAssets(): Promise<MediaAsset[]> {
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;
}
/** Scan media/in/ folder for new files. */
export async function scanMediaFolder(): Promise<{
found: number;
registered: number;
skipped: number;
files: string[];
}> {
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;
}