mirror of https://github.com/VERT-sh/VERT.git
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:
parent
343fb34a0e
commit
96da202e6c
9
bun.lock
9
bun.lock
|
|
@ -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=="],
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
},
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
}),
|
}),
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -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(".")) {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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"}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue