mirror of https://github.com/VERT-sh/VERT.git
feat: add converter chaining for multi-step format conversions
This commit is contained in:
parent
916e67357d
commit
aaf667d5a7
|
|
@ -93,3 +93,61 @@ export class Converter {
|
||||||
return this.supportedFormats.map((f) => f.name);
|
return this.supportedFormats.map((f) => f.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ChainStep {
|
||||||
|
converter: Converter;
|
||||||
|
to: string; // intermediate format (last step uses the final target)
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ChainedConverter extends Converter {
|
||||||
|
public override name: string;
|
||||||
|
private steps: ChainStep[];
|
||||||
|
|
||||||
|
constructor(steps: ChainStep[]) {
|
||||||
|
super(0);
|
||||||
|
if (steps.length < 2) throw new Error("Chain requires at least 2 steps");
|
||||||
|
this.steps = steps;
|
||||||
|
this.name = steps.map((s) => s.converter.name).join("+");
|
||||||
|
this.clearTimeout();
|
||||||
|
this.status = this.deriveStatus();
|
||||||
|
this.supportedFormats = [
|
||||||
|
...steps[0].converter.supportedFormats.filter((f) => f.fromSupported),
|
||||||
|
...steps[steps.length - 1].converter.supportedFormats.filter((f) => f.toSupported),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private deriveStatus(): WorkerStatus {
|
||||||
|
const statuses = this.steps.map((s) => s.converter.status);
|
||||||
|
if (statuses.some((s) => s === "error")) return "error";
|
||||||
|
if (statuses.every((s) => s === "ready")) return "ready";
|
||||||
|
if (statuses.some((s) => s === "downloading")) return "downloading";
|
||||||
|
return "not-ready";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async convert(input: VertFile, to: string): Promise<VertFile> {
|
||||||
|
this.status = this.deriveStatus();
|
||||||
|
const { VertFile: VF } = await import("$lib/types");
|
||||||
|
let current: VertFile = input;
|
||||||
|
|
||||||
|
for (let i = 0; i < this.steps.length; i++) {
|
||||||
|
const { converter, to: stepTo } = this.steps[i];
|
||||||
|
const isLast = i === this.steps.length - 1;
|
||||||
|
const target = isLast ? to : stepTo;
|
||||||
|
const result = await converter.convert(current, target);
|
||||||
|
if (!isLast) {
|
||||||
|
current = new VF(
|
||||||
|
new File([await result.file.arrayBuffer()], input.name.replace(/\.[^/.]+$/, target)),
|
||||||
|
target,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
current = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async cancel(input: VertFile): Promise<void> {
|
||||||
|
await Promise.allSettled(this.steps.map((s) => s.converter.cancel(input)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { byNative, converters } from "$lib/converters";
|
import { byNative, converters } from "$lib/converters";
|
||||||
import type { Converter } from "$lib/converters/converter.svelte";
|
import type { Converter } from "$lib/converters/converter.svelte";
|
||||||
|
import { ChainedConverter } from "$lib/converters/converter.svelte";
|
||||||
import { m } from "$lib/paraglide/messages";
|
import { m } from "$lib/paraglide/messages";
|
||||||
import { ToastManager } from "$lib/util/toast.svelte";
|
import { ToastManager } from "$lib/util/toast.svelte";
|
||||||
import type { Component } from "svelte";
|
import type { Component } from "svelte";
|
||||||
|
|
@ -65,7 +66,29 @@ export class VertFile {
|
||||||
if (!theirFrom.isNative && !theirTo.isNative) return false;
|
if (!theirFrom.isNative && !theirTo.isNative) return false;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
return converter;
|
if (converter) return converter;
|
||||||
|
|
||||||
|
for (const a of this.converters) {
|
||||||
|
for (const fmt of a.supportedFormats) {
|
||||||
|
if (!fmt.toSupported) continue;
|
||||||
|
const b = converters.find((c) => {
|
||||||
|
const cFrom = c.supportedFormats.find(
|
||||||
|
(f) => f.name === fmt.name && f.fromSupported,
|
||||||
|
);
|
||||||
|
const cTo = c.supportedFormats.find(
|
||||||
|
(f) => f.name === this.to && f.toSupported,
|
||||||
|
);
|
||||||
|
return cFrom && cTo;
|
||||||
|
});
|
||||||
|
if (b)
|
||||||
|
return new ChainedConverter([
|
||||||
|
{ converter: a, to: fmt.name },
|
||||||
|
{ converter: b, to: this.to },
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
public isLarge(): boolean {
|
public isLarge(): boolean {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue