diff --git a/bun.lock b/bun.lock index 355ea6b..fbdab17 100644 --- a/bun.lock +++ b/bun.lock @@ -1,5 +1,6 @@ { "lockfileVersion": 1, + "configVersion": 0, "workspaces": { "": { "name": "vert", @@ -17,7 +18,8 @@ "clsx": "^2.1.1", "fflate": "^0.8.2", "lucide-svelte": "^0.554.0", - "music-metadata": "^11.10.1", + "mediabunny": "^1.35.1", + "music-metadata": "^11.10.3", "overlayscrollbars": "^2.12.0", "overlayscrollbars-svelte": "^0.5.5", "p-queue": "^9.0.1", @@ -31,7 +33,7 @@ "@inlang/paraglide-js": "^2.5.0", "@poppanator/sveltekit-svg": "^5.0.1", "@sveltejs/adapter-static": "^3.0.10", - "@sveltejs/kit": "^2.48.5", + "@sveltejs/kit": "^2.49.0", "@sveltejs/vite-plugin-svelte": "^4.0.4", "@types/eslint": "^9.6.1", "@types/sanitize-html": "^2.16.0", @@ -44,8 +46,8 @@ "prettier": "^3.6.2", "prettier-plugin-svelte": "^3.4.0", "prettier-plugin-tailwindcss": "^0.6.14", - "sass": "^1.94.1", - "svelte": "^5.43.12", + "sass": "^1.94.2", + "svelte": "^5.43.14", "svelte-check": "^4.3.4", "tailwindcss": "^3.4.18", "typescript": "^5.9.3", @@ -314,6 +316,10 @@ "@types/cookie": ["@types/cookie@0.6.0", "", {}, "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="], + "@types/dom-mediacapture-transform": ["@types/dom-mediacapture-transform@0.1.11", "", { "dependencies": { "@types/dom-webcodecs": "*" } }, "sha512-Y2p+nGf1bF2XMttBnsVPHUWzRRZzqUoJAKmiP10b5umnO6DDrWI0BrGDJy1pOHoOULVmGSfFNkQrAlC5dcj6nQ=="], + + "@types/dom-webcodecs": ["@types/dom-webcodecs@0.1.13", "", {}, "sha512-O5hkiFIcjjszPIYyUSyvScyvrBoV3NOEEZx/pMlsu44TKzWNkLVBBxnxJz42in5n3QIolYOcBYFCPZZ0h8SkwQ=="], + "@types/eslint": ["@types/eslint@9.6.1", "", { "dependencies": { "@types/estree": "*", "@types/json-schema": "*" } }, "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag=="], "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], @@ -628,6 +634,8 @@ "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=="], + "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], diff --git a/package.json b/package.json index 4698882..46e573e 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "clsx": "^2.1.1", "fflate": "^0.8.2", "lucide-svelte": "^0.554.0", + "mediabunny": "^1.35.1", "music-metadata": "^11.10.3", "overlayscrollbars": "^2.12.0", "overlayscrollbars-svelte": "^0.5.5", diff --git a/src/lib/converters/index.ts b/src/lib/converters/index.ts index 11089ae..82c4a7b 100644 --- a/src/lib/converters/index.ts +++ b/src/lib/converters/index.ts @@ -5,6 +5,7 @@ import { PandocConverter } from "./pandoc.svelte"; import { VertdConverter } from "./vertd.svelte"; import { MagickConverter } from "./magick.svelte"; import { DISABLE_ALL_EXTERNAL_REQUESTS } from "$lib/util/consts"; +import { MediabunnyConverter } from "./mediabunny.svelte"; const getConverters = (): Converter[] => { const converters: Converter[] = [ @@ -12,10 +13,12 @@ const getConverters = (): Converter[] => { new FFmpegConverter(), ]; - if (!DISABLE_ALL_EXTERNAL_REQUESTS) { + if (DISABLE_ALL_EXTERNAL_REQUESTS) { converters.push(new VertdConverter()); } + converters.push(new MediabunnyConverter()); + converters.push(new PandocConverter()); return converters; }; @@ -45,7 +48,7 @@ categories.audio.formats = .map((f) => f.name) || []; categories.video.formats = converters - .find((c) => c.name === "vertd") + .find((c) => c.name === "mediabunny") ?.supportedFormats.filter((f) => f.toSupported && f.isNative) .map((f) => f.name) || []; categories.image.formats = diff --git a/src/lib/converters/mediabunny.svelte.ts b/src/lib/converters/mediabunny.svelte.ts index fbd7654..006e093 100644 --- a/src/lib/converters/mediabunny.svelte.ts +++ b/src/lib/converters/mediabunny.svelte.ts @@ -1,16 +1,19 @@ import { VertFile } from "$lib/types"; import { - ALL_FORMATS, + BlobSource, BufferTarget, Conversion, Input, + MATROSKA, MkvOutputFormat, MovOutputFormat, - Mp4InputFormat, + MP4, Mp4OutputFormat, + MPEG_TS, + MpegTsOutputFormat, Output, - ReadableStreamSource, - WebMInputFormat, + QTFF, + WEBM, WebMOutputFormat, } from "mediabunny"; import { Converter, FormatInfo, type WorkerStatus } from "./converter.svelte"; @@ -22,9 +25,16 @@ export class MediabunnyConverter extends Converter { public supportedFormats: FormatInfo[] = [ new FormatInfo("mp4", true, true), - new FormatInfo("mkv", false, true), + new FormatInfo("m4v", true, true), + new FormatInfo("mkv", true, true), new FormatInfo("webm", true, true), - new FormatInfo("mov", false, true), + new FormatInfo("mov", true, true), + + // mp4-based formats (should work) + new FormatInfo("f4v", true, true), + new FormatInfo("3gp", true, true), + new FormatInfo("3g2", true, true), + new FormatInfo("ts", true, true), ]; constructor() { @@ -32,10 +42,10 @@ export class MediabunnyConverter extends Converter { } public async convert(file: VertFile, to: string): Promise { - const stream = file.file.stream(); // ReadableStream> const input = new Input({ - formats: [new Mp4InputFormat(), new WebMInputFormat()], - source: new ReadableStreamSource(stream), + // TODO: add settings & special handling for certain formats & codecs + formats: [MP4, QTFF, MATROSKA, WEBM, MPEG_TS], + source: new BlobSource(file.file) }); const toFormat = to.startsWith(".") ? to.slice(1) : to; @@ -81,7 +91,12 @@ export class MediabunnyConverter extends Converter { private format(ext: string) { switch (ext) { + // i'm seeing this "ISMV" format from microsoft, so maybe? case ".mp4": + case ".m4v": + case ".f4v": + case ".3gp": + case ".3g2": return new Mp4OutputFormat(); case ".mkv": return new MkvOutputFormat(); @@ -89,6 +104,8 @@ export class MediabunnyConverter extends Converter { return new WebMOutputFormat(); case ".mov": return new MovOutputFormat(); + case ".ts": + return new MpegTsOutputFormat(); default: throw new Error(`Unsupported format: ${ext}`); }