feat: use & rework findConverters()

adds a priority to FormatInfo which ensures that we can have certain formats prioritize certain converters (mp4 supports mediabunny/local so use that, then fallback to next if fails)
This commit is contained in:
Maya 2026-03-06 12:00:43 +03:00
parent 343fb34a0e
commit 96da202e6c
No known key found for this signature in database
12 changed files with 260 additions and 102 deletions

View File

@ -12,17 +12,18 @@
"@fontsource/lexend": "^5.2.11", "@fontsource/lexend": "^5.2.11",
"@fontsource/radio-canada-big": "^5.2.7", "@fontsource/radio-canada-big": "^5.2.7",
"@imagemagick/magick-wasm": "^0.0.37", "@imagemagick/magick-wasm": "^0.0.37",
"@stripe/stripe-js": "^8.7.0",
"@mediabunny/ac3": "^1.35.1", "@mediabunny/ac3": "^1.35.1",
"@mediabunny/flac-encoder": "^1.37.0",
"@mediabunny/mp3-encoder": "^1.35.1", "@mediabunny/mp3-encoder": "^1.35.1",
"@stripe/stripe-js": "^8.7.0",
"byte-data": "^19.0.1", "byte-data": "^19.0.1",
"client-zip": "^2.5.0", "client-zip": "^2.5.0",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"fflate": "^0.8.2", "fflate": "^0.8.2",
"lucide-svelte": "^0.554.0", "lucide-svelte": "^0.554.0",
"mediabunny": "^1.37.0",
"music-metadata": "^11.12.0", "music-metadata": "^11.12.0",
"overlayscrollbars": "^2.14.0", "overlayscrollbars": "^2.14.0",
"mediabunny": "^1.35.1",
"overlayscrollbars-svelte": "^0.5.5", "overlayscrollbars-svelte": "^0.5.5",
"p-queue": "^9.1.0", "p-queue": "^9.1.0",
"riff-file": "^1.0.3", "riff-file": "^1.0.3",
@ -180,6 +181,8 @@
"@mediabunny/ac3": ["@mediabunny/ac3@1.35.1", "", { "peerDependencies": { "mediabunny": "^1.0.0" } }, "sha512-gLx3mFfs58/cdz2/f5Fp+6ZOrX5Jli3AZMXw/5EJcgm2VpnC/2oxtJyP1x/00PIS4UCE770slwIdz7U+2CQ31g=="], "@mediabunny/ac3": ["@mediabunny/ac3@1.35.1", "", { "peerDependencies": { "mediabunny": "^1.0.0" } }, "sha512-gLx3mFfs58/cdz2/f5Fp+6ZOrX5Jli3AZMXw/5EJcgm2VpnC/2oxtJyP1x/00PIS4UCE770slwIdz7U+2CQ31g=="],
"@mediabunny/flac-encoder": ["@mediabunny/flac-encoder@1.37.0", "", { "peerDependencies": { "mediabunny": "^1.0.0" } }, "sha512-VwKIL5p1WZE4dSwZ1SVv/bd2ksul8a4run4S1eEbPRysnG87nmCXddO5ajD3b2k2478XWitKnVDXl/kxdIIWBw=="],
"@mediabunny/mp3-encoder": ["@mediabunny/mp3-encoder@1.35.1", "", { "peerDependencies": { "mediabunny": "^1.0.0" } }, "sha512-iY6FcPs7GbHMs/ASPmdzwojKcBN4AfMa+zFh4KNZNaLToyR7aEZILj9FsPVJA11bshaoo80dTaBcn69i33JHVA=="], "@mediabunny/mp3-encoder": ["@mediabunny/mp3-encoder@1.35.1", "", { "peerDependencies": { "mediabunny": "^1.0.0" } }, "sha512-iY6FcPs7GbHMs/ASPmdzwojKcBN4AfMa+zFh4KNZNaLToyR7aEZILj9FsPVJA11bshaoo80dTaBcn69i33JHVA=="],
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
@ -640,7 +643,7 @@
"media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], "media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="],
"mediabunny": ["mediabunny@1.35.1", "", { "dependencies": { "@types/dom-mediacapture-transform": "^0.1.11", "@types/dom-webcodecs": "0.1.13" } }, "sha512-VrprpjkLTZyIyhzBAc9D3HqgXarAE+le7+6x0Sdu9WN2SD86L8bUy0hz06Xwf14dVPqS7OwpY2KOhlUyqmI2eQ=="], "mediabunny": ["mediabunny@1.37.0", "", { "dependencies": { "@types/dom-mediacapture-transform": "^0.1.11", "@types/dom-webcodecs": "0.1.13" } }, "sha512-eV7M9IJ29pr/8RNL1sYtIxNbdMfDMN1hMwMaOFfNLhwuKKGSC+eKwiJFpdVjEJ3zrMA4LGerF4Hps0SENFSAlg=="],
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],

View File

@ -1,33 +1,39 @@
import prettier from 'eslint-config-prettier'; import prettier from "eslint-config-prettier";
import js from '@eslint/js'; import js from "@eslint/js";
import svelte from 'eslint-plugin-svelte'; import svelte from "eslint-plugin-svelte";
import globals from 'globals'; import globals from "globals";
import ts from 'typescript-eslint'; import ts from "typescript-eslint";
export default ts.config( export default ts.config(
js.configs.recommended, js.configs.recommended,
...ts.configs.recommended, ...ts.configs.recommended,
...svelte.configs['flat/recommended'], ...svelte.configs["flat/recommended"],
prettier, prettier,
...svelte.configs['flat/prettier'], ...svelte.configs["flat/prettier"],
{ {
languageOptions: { languageOptions: {
globals: { globals: {
...globals.browser, ...globals.browser,
...globals.node ...globals.node,
} },
} },
}, },
{ {
files: ['**/*.svelte'], files: ["**/*.svelte"],
languageOptions: { languageOptions: {
parserOptions: { parserOptions: {
parser: ts.parser parser: ts.parser,
} },
} },
}, },
{ {
ignores: ['build/', '.svelte-kit/', 'dist/'] ignores: ["build/", ".svelte-kit/", "dist/"],
} },
{
files: ["**/*.ts", "**/*.svelte.ts"],
rules: {
"no-at-html-tags": "off",
},
},
); );

View File

@ -45,18 +45,19 @@
"@fontsource/lexend": "^5.2.11", "@fontsource/lexend": "^5.2.11",
"@fontsource/radio-canada-big": "^5.2.7", "@fontsource/radio-canada-big": "^5.2.7",
"@imagemagick/magick-wasm": "^0.0.37", "@imagemagick/magick-wasm": "^0.0.37",
"@stripe/stripe-js": "^8.7.0",
"@mediabunny/ac3": "^1.35.1", "@mediabunny/ac3": "^1.35.1",
"@mediabunny/flac-encoder": "^1.37.0",
"@mediabunny/mp3-encoder": "^1.35.1", "@mediabunny/mp3-encoder": "^1.35.1",
"@stripe/stripe-js": "^8.7.0",
"byte-data": "^19.0.1", "byte-data": "^19.0.1",
"client-zip": "^2.5.0", "client-zip": "^2.5.0",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"fflate": "^0.8.2", "fflate": "^0.8.2",
"lucide-svelte": "^0.554.0", "lucide-svelte": "^0.554.0",
"mediabunny": "^1.37.0",
"music-metadata": "^11.12.0", "music-metadata": "^11.12.0",
"overlayscrollbars": "^2.14.0", "overlayscrollbars": "^2.14.0",
"overlayscrollbars-svelte": "^0.5.5", "overlayscrollbars-svelte": "^0.5.5",
"mediabunny": "^1.35.1",
"p-queue": "^9.1.0", "p-queue": "^9.1.0",
"riff-file": "^1.0.3", "riff-file": "^1.0.3",
"sanitize-html": "^2.17.0", "sanitize-html": "^2.17.0",

View File

@ -72,9 +72,10 @@
// decide which converters to use to detect category: // decide which converters to use to detect category:
// - if file provided, prefer its primary converter -- individual file dropdown // - if file provided, prefer its primary converter -- individual file dropdown
// - if no file provided, use all converters from all files -- "set all to" dropdown // - if no file provided, use all converters from all files -- "set all to" dropdown
const primaryConverter = file ? (file.isZip() ? file.converters[0] : file.findConverters()[0]) : null;
const convertersToCheck = file const convertersToCheck = file
? file.findConverter() ? primaryConverter
? [file.findConverter()!] ? [primaryConverter]
: file.converters : file.converters
: files.files.flatMap((f) => f.converters); : files.files.flatMap((f) => f.converters);

View File

@ -1,4 +1,5 @@
<script lang="ts"> <script lang="ts">
/* eslint-disable @typescript-eslint/no-explicit-any */
import { SearchIcon } from "lucide-svelte"; import { SearchIcon } from "lucide-svelte";
import Dropdown from "./Dropdown.svelte"; import Dropdown from "./Dropdown.svelte";
import FancyInput from "./FancyInput.svelte"; import FancyInput from "./FancyInput.svelte";
@ -26,7 +27,9 @@
const applySettings = async () => { const applySettings = async () => {
onclose?.(); onclose?.();
if (!file) return; if (!file) return;
const converter = file.findConverter(); const converter = file.isZip()
? file.converters[0]
: file.findConverters()[0];
if (!converter) { if (!converter) {
log( log(
["settings", "modal"], ["settings", "modal"],
@ -72,8 +75,10 @@
<p class="text-base"> <p class="text-base">
{@html sanitize( {@html sanitize(
m["convert.settings.description"]({ m["convert.settings.description"]({
converter: converter: file.isZip()
file.findConverter()?.name || "unknown", ? file.converters[0].name
: file.findConverters()[0].name ||
"unknown",
filename: file.name, filename: file.name,
}), }),
)} )}

View File

@ -16,6 +16,7 @@ export class FormatInfo {
public fromSupported = true, public fromSupported = true,
public toSupported = true, public toSupported = true,
public isNative = true, public isNative = true,
public priority = 1,
) { ) {
this.name = name; this.name = name;
if (!this.name.startsWith(".")) { if (!this.name.startsWith(".")) {

View File

@ -74,7 +74,7 @@ export class FFmpegConverter extends Converter {
new FormatInfo("m4b", true, true), new FormatInfo("m4b", true, true),
new FormatInfo("voc", true, true), new FormatInfo("voc", true, true),
new FormatInfo("weba", true, true), new FormatInfo("weba", true, true),
...videoFormats.map((f) => new FormatInfo(f, true, true, false)), ...videoFormats.map((f) => new FormatInfo(f, true, true, false, 0)),
]; ];
public readonly reportsProgress = true; public readonly reportsProgress = true;

View File

@ -11,15 +11,12 @@ const getConverters = (): Converter[] => {
const converters: Converter[] = [ const converters: Converter[] = [
new MagickConverter(), new MagickConverter(),
new FFmpegConverter(), new FFmpegConverter(),
new PandocConverter(),
new MediabunnyConverter(),
]; ];
if (DISABLE_ALL_EXTERNAL_REQUESTS) { if (!DISABLE_ALL_EXTERNAL_REQUESTS) converters.push(new VertdConverter());
converters.push(new VertdConverter());
}
converters.push(new MediabunnyConverter());
converters.push(new PandocConverter());
return converters; return converters;
}; };

View File

@ -22,31 +22,147 @@ import { registerAc3Decoder, registerAc3Encoder } from "@mediabunny/ac3";
import { Converter, FormatInfo, type WorkerStatus } from "./converter.svelte"; import { Converter, FormatInfo, type WorkerStatus } from "./converter.svelte";
import { ToastManager } from "$lib/util/toast.svelte"; import { ToastManager } from "$lib/util/toast.svelte";
import { error, log } from "$lib/util/logger"; import { error, log } from "$lib/util/logger";
import { registerFlacEncoder } from "@mediabunny/flac-encoder";
// codec compatibility object, based on docs // codec compatibility object, based on docs
// https://mediabunny.dev/guide/supported-formats-and-codecs#compatibility-table // https://mediabunny.dev/guide/supported-formats-and-codecs#compatibility-table
const codecCompatibility = { const codecCompatibility = {
video: { video: {
mp4: ['avc', 'hevc', 'vp8', 'vp9', 'av1'], mp4: ["avc", "hevc", "vp8", "vp9", "av1"],
m4v: ['avc', 'hevc', 'vp8', 'vp9', 'av1'], m4v: ["avc", "hevc", "vp8", "vp9", "av1"],
f4v: ['avc', 'hevc', 'vp8', 'vp9', 'av1'], f4v: ["avc", "hevc", "vp8", "vp9", "av1"],
'3gp': ['avc', 'hevc', 'vp8', 'vp9', 'av1'], "3gp": ["avc", "hevc", "vp8", "vp9", "av1"],
'3g2': ['avc', 'hevc', 'vp8', 'vp9', 'av1'], "3g2": ["avc", "hevc", "vp8", "vp9", "av1"],
mkv: ['avc', 'hevc', 'vp8', 'vp9', 'av1'], mkv: ["avc", "hevc", "vp8", "vp9", "av1"],
webm: ['vp8', 'vp9', 'av1'], webm: ["vp8", "vp9", "av1"],
mov: ['avc', 'hevc', 'vp8', 'vp9', 'av1'], mov: ["avc", "hevc", "vp8", "vp9", "av1"],
ts: ['avc', 'hevc'], ts: ["avc", "hevc"],
}, },
audio: { audio: {
mp4: ['aac', 'opus', 'mp3', 'vorbis', 'flac', 'ac3', 'eac3', 'pcm-s16', 'pcm-s16be', 'pcm-s24', 'pcm-s24be', 'pcm-s32', 'pcm-s32be', 'pcm-f32', 'pcm-f64'], mp4: [
m4v: ['aac', 'opus', 'mp3', 'vorbis', 'flac', 'ac3', 'eac3', 'pcm-s16', 'pcm-s16be', 'pcm-s24', 'pcm-s24be', 'pcm-s32', 'pcm-s32be', 'pcm-f32', 'pcm-f64'], "aac",
f4v: ['aac', 'opus', 'mp3', 'vorbis', 'flac', 'ac3', 'eac3', 'pcm-s16', 'pcm-s16be', 'pcm-s24', 'pcm-s24be', 'pcm-s32', 'pcm-s32be', 'pcm-f32', 'pcm-f64'], "opus",
'3gp': ['aac', 'opus', 'mp3', 'vorbis', 'flac', 'ac3', 'eac3', 'pcm-s16', 'pcm-s16be', 'pcm-s24', 'pcm-s24be', 'pcm-s32', 'pcm-s32be', 'pcm-f32', 'pcm-f64'], "mp3",
'3g2': ['aac', 'opus', 'mp3', 'vorbis', 'flac', 'ac3', 'eac3', 'pcm-s16', 'pcm-s16be', 'pcm-s24', 'pcm-s24be', 'pcm-s32', 'pcm-s32be', 'pcm-f32', 'pcm-f64'], "vorbis",
mkv: ['aac', 'opus', 'mp3', 'vorbis', 'flac', 'ac3', 'eac3', 'pcm-u8', 'pcm-s16', 'pcm-s24', 'pcm-s32', 'pcm-f32', 'pcm-f64'], "flac",
webm: ['opus', 'vorbis'], "ac3",
mov: ['aac', 'opus', 'mp3', 'vorbis', 'flac', 'ac3', 'eac3', 'pcm-u8', 'pcm-s8', 'pcm-s16', 'pcm-s16be', 'pcm-s24', 'pcm-s24be', 'pcm-s32', 'pcm-s32be', 'pcm-f32', 'pcm-f32be', 'pcm-f64', 'ulaw', 'alaw'], "eac3",
ts: ['aac', 'mp3', 'ac3', 'eac3'], "pcm-s16",
"pcm-s16be",
"pcm-s24",
"pcm-s24be",
"pcm-s32",
"pcm-s32be",
"pcm-f32",
"pcm-f64",
],
m4v: [
"aac",
"opus",
"mp3",
"vorbis",
"flac",
"ac3",
"eac3",
"pcm-s16",
"pcm-s16be",
"pcm-s24",
"pcm-s24be",
"pcm-s32",
"pcm-s32be",
"pcm-f32",
"pcm-f64",
],
f4v: [
"aac",
"opus",
"mp3",
"vorbis",
"flac",
"ac3",
"eac3",
"pcm-s16",
"pcm-s16be",
"pcm-s24",
"pcm-s24be",
"pcm-s32",
"pcm-s32be",
"pcm-f32",
"pcm-f64",
],
"3gp": [
"aac",
"opus",
"mp3",
"vorbis",
"flac",
"ac3",
"eac3",
"pcm-s16",
"pcm-s16be",
"pcm-s24",
"pcm-s24be",
"pcm-s32",
"pcm-s32be",
"pcm-f32",
"pcm-f64",
],
"3g2": [
"aac",
"opus",
"mp3",
"vorbis",
"flac",
"ac3",
"eac3",
"pcm-s16",
"pcm-s16be",
"pcm-s24",
"pcm-s24be",
"pcm-s32",
"pcm-s32be",
"pcm-f32",
"pcm-f64",
],
mkv: [
"aac",
"opus",
"mp3",
"vorbis",
"flac",
"ac3",
"eac3",
"pcm-u8",
"pcm-s16",
"pcm-s24",
"pcm-s32",
"pcm-f32",
"pcm-f64",
],
webm: ["opus", "vorbis"],
mov: [
"aac",
"opus",
"mp3",
"vorbis",
"flac",
"ac3",
"eac3",
"pcm-u8",
"pcm-s8",
"pcm-s16",
"pcm-s16be",
"pcm-s24",
"pcm-s24be",
"pcm-s32",
"pcm-s32be",
"pcm-f32",
"pcm-f32be",
"pcm-f64",
"ulaw",
"alaw",
],
ts: ["aac", "mp3", "ac3", "eac3"],
}, },
} as const; } as const;
@ -57,18 +173,21 @@ export class MediabunnyConverter extends Converter {
private activeConversions = new Map<string, Conversion>(); private activeConversions = new Map<string, Conversion>();
public supportedFormats: FormatInfo[] = [ private formats: string[] = [
new FormatInfo("mp4", true, true), "mp4",
new FormatInfo("m4v", true, true), "m4v",
new FormatInfo("mkv", true, true), "mkv",
new FormatInfo("webm", true, true), "webm",
new FormatInfo("mov", true, true), "mov",
"f4v",
"3gp",
"3g2",
"mts",
"ts",
];
// mp4-based formats (should work) public supportedFormats: FormatInfo[] = [
new FormatInfo("f4v", true, true), ...this.formats.map((f) => new FormatInfo(f, true, true, true, 2)),
new FormatInfo("3gp", true, true),
new FormatInfo("3g2", true, true),
new FormatInfo("ts", true, true),
]; ];
constructor() { constructor() {
@ -81,9 +200,11 @@ export class MediabunnyConverter extends Converter {
private async initializeCodecs(): Promise<void> { private async initializeCodecs(): Promise<void> {
if (!(await canEncodeAudio("mp3"))) { if (!(await canEncodeAudio("mp3"))) {
// Only register the custom encoder if there's no native support
registerMp3Encoder(); registerMp3Encoder();
} }
if (!(await canEncodeAudio("flac"))) {
registerFlacEncoder();
}
registerAc3Decoder(); registerAc3Decoder();
registerAc3Encoder(); registerAc3Encoder();
} }

View File

@ -298,8 +298,8 @@ export class VertdConverter extends Converter {
>(); >();
public supportedFormats = [ public supportedFormats = [
new FormatInfo("mkv", true, true),
new FormatInfo("mp4", true, true), new FormatInfo("mp4", true, true),
new FormatInfo("mkv", true, true),
new FormatInfo("webm", true, true), new FormatInfo("webm", true, true),
new FormatInfo("avi", true, true), new FormatInfo("avi", true, true),
new FormatInfo("wmv", true, true), new FormatInfo("wmv", true, true),

View File

@ -23,7 +23,7 @@ export class VertFile {
return this.file.name; return this.file.name;
} }
public conversionSettings = $state<ConversionSettings>({}); // empty object = defaults public conversionSettings = $state<ConversionSettings>({}); // empty object / key = default
public progress = $state(0); public progress = $state(0);
public result = $state<VertFile | null>(null); public result = $state<VertFile | null>(null);
@ -40,45 +40,55 @@ export class VertFile {
public isZip = $state(() => this.from === ".zip"); public isZip = $state(() => this.from === ".zip");
public getAvailableSettings(input: VertFile): Promise<SettingDefinition[]> { public getAvailableSettings(input: VertFile): Promise<SettingDefinition[]> {
const converter = this.findConverter(); const converter = this.findConverters()[0];
if (!converter) return Promise.resolve([]); if (!converter) return Promise.resolve([]);
return converter.getAvailableSettings(input); return converter.getAvailableSettings(input);
} }
public findConverters(supportedFormats: string[] = [this.from]) { public findConverters(supportedFormats: string[] = [this.from]) {
const converter = this.converters return this.converters
.filter((converter) => .filter((converter) => {
converter if (
.formatStrings() !converter
.map((f) => supportedFormats.includes(f)), .formatStrings()
) .some((f) => supportedFormats.includes(f))
.sort(byNative(this.from)); ) {
return converter; return false;
} }
public findConverter() { if (
// zip will always only be added if there's one converter that supports all files - handled in store's _handleZipFile() supportedFormats.includes(this.from) &&
if (this.isZip()) return this.converters[0]; supportedFormats.includes(this.to)
) {
if (!converter.formatStrings().includes(this.to)) {
return false;
}
const converter = this.converters.find((converter) => { const theirFrom = converter.supportedFormats.find(
if ( (f) => f.name === this.from,
!converter.formatStrings().includes(this.from) || );
!converter.formatStrings().includes(this.to) const theirTo = converter.supportedFormats.find(
) { (f) => f.name === this.to,
return false; );
} if (!theirFrom || !theirTo) return false;
if (!theirFrom.isNative && !theirTo.isNative) return false;
}
const theirFrom = converter.supportedFormats.find( return true;
(f) => f.name === this.from, })
); .sort(byNative(this.from))
const theirTo = converter.supportedFormats.find( .sort((a, b) => {
(f) => f.name === this.to, // sort by priority of format
); const aFrom = a.supportedFormats.find(
if (!theirFrom || !theirTo) return false; (f) => f.name === this.from,
if (!theirFrom.isNative && !theirTo.isNative) return false; );
return true; const bFrom = b.supportedFormats.find(
}); (f) => f.name === this.from,
return converter; );
const aPriority = aFrom ? aFrom.priority : 1;
const bPriority = bFrom ? bFrom.priority : 1;
return bPriority - aPriority;
});
} }
public isLarge(): boolean { public isLarge(): boolean {
@ -88,7 +98,9 @@ export class VertFile {
public supportsStreaming(): boolean { public supportsStreaming(): boolean {
// only vertd (video/gif -> video/gif) supports streaming // only vertd (video/gif -> video/gif) supports streaming
// rest of converters need entire file in memory, limited by ArrayBuffer limits // rest of converters need entire file in memory, limited by ArrayBuffer limits
const converter = this.findConverter(); const converter = this.isZip()
? this.converters[0]
: this.findConverters()[0];
return converter?.name === "vertd"; return converter?.name === "vertd";
} }
@ -106,12 +118,21 @@ export class VertFile {
this.convert = this.convert.bind(this); this.convert = this.convert.bind(this);
this.download = this.download.bind(this); this.download = this.download.bind(this);
this.blobUrl = blobUrl; this.blobUrl = blobUrl;
console.log(`VertFile: ${this.name}`);
console.log(
`findConverters: ${this.findConverters()
.map((c) => c.name)
.join(", ")}`,
);
} }
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
public async convert(...args: any[]) { public async convert(...args: any[]) {
if (!this.converters.length) throw new Error("No converters found"); if (!this.converters.length) throw new Error("No converters found");
const converter = this.findConverter(); const converter = this.isZip()
? this.converters[0]
: this.findConverters()[0];
if (!converter) throw new Error("No converter found"); if (!converter) throw new Error("No converter found");
this.result = null; this.result = null;
this.progress = 0; this.progress = 0;
@ -231,7 +252,9 @@ export class VertFile {
public async cancel() { public async cancel() {
if (!this.processing) return; if (!this.processing) return;
const converter = this.findConverter(); const converter = this.isZip()
? this.converters[0]
: this.findConverters()[0];
if (!converter) throw new Error("No converter found"); if (!converter) throw new Error("No converter found");
this.cancelled = true; this.cancelled = true;
try { try {

View File

@ -42,7 +42,7 @@
const settings = Settings.instance.settings; const settings = Settings.instance.settings;
if (processedFileIds.has(file.id)) return; if (processedFileIds.has(file.id)) return;
const converter = file.findConverter(); const converter = file.isZip() ? file.converters[0] : file.findConverters()[0];
if (!converter) return; if (!converter) return;
let category: string | undefined; let category: string | undefined;
@ -108,7 +108,7 @@
let type = ""; let type = "";
if (files.files.length) { if (files.files.length) {
const converters = files.files.map( const converters = files.files.map(
(file) => file.findConverter()?.name, (file) => (file.isZip() ? file.converters[0] : file.findConverters()[0])?.name,
); );
const uniqueTypes = new Set(converters); const uniqueTypes = new Set(converters);
@ -130,7 +130,7 @@
</script> </script>
{#snippet fileItem(file: VertFile, index: number)} {#snippet fileItem(file: VertFile, index: number)}
{@const currentConverter = file.findConverter()} {@const currentConverter = file.isZip() ? file.converters[0] : file.findConverters()[0]}
{@const isImage = currentConverter?.name === "imagemagick"} {@const isImage = currentConverter?.name === "imagemagick"}
{@const isAudio = currentConverter?.name === "ffmpeg"} {@const isAudio = currentConverter?.name === "ffmpeg"}
{@const isVideo = currentConverter?.name === "vertd"} {@const isVideo = currentConverter?.name === "vertd"}