diff --git a/src/lib/components/functional/ConversionPanel.svelte b/src/lib/components/functional/ConversionPanel.svelte index 35165f3..49f7eaf 100644 --- a/src/lib/components/functional/ConversionPanel.svelte +++ b/src/lib/components/functional/ConversionPanel.svelte @@ -69,7 +69,7 @@ {#if files.requiredConverters.length === 1} {@const supported = files.files[0]?.converters - .flatMap((c) => c.supportedFormats) + .flatMap((c) => c.formatStrings((f) => f.toSupported)) ?.filter( (format) => format !== ".svg" && format !== ".heif", )} diff --git a/src/lib/components/functional/Dropdown.svelte b/src/lib/components/functional/Dropdown.svelte index d7f064c..102b14d 100644 --- a/src/lib/components/functional/Dropdown.svelte +++ b/src/lib/components/functional/Dropdown.svelte @@ -62,8 +62,8 @@ : 'justify-center'} overflow-hidden relative cursor-pointer {settingsStyle ? 'px-4' : 'px-3'} py-3.5 bg-button {disabled - ? 'opacity-50' - : ''} flex items-center {settingsStyle + ? 'opacity-50 cursor-auto' + : 'cursor-pointer'} flex items-center {settingsStyle ? 'rounded-xl' : 'rounded-full'} focus:!outline-none" onclick={toggle} diff --git a/src/lib/components/functional/Uploader.svelte b/src/lib/components/functional/Uploader.svelte index 6bd1221..6c17f11 100644 --- a/src/lib/components/functional/Uploader.svelte +++ b/src/lib/components/functional/Uploader.svelte @@ -31,7 +31,7 @@ ) ).filter((c) => typeof c !== "undefined"); acceptedTypes = filteredConverters - .map((c) => c.supportedFormats.join(",")) + .map((c) => c.formatStrings((f) => f.fromSupported).join(",")) .join(","); }; diff --git a/src/lib/converters/converter.svelte.ts b/src/lib/converters/converter.svelte.ts index 5482bd8..4c0fc85 100644 --- a/src/lib/converters/converter.svelte.ts +++ b/src/lib/converters/converter.svelte.ts @@ -1,5 +1,24 @@ import type { VertFile } from "$lib/types"; +export class FormatInfo { + public name: string; + + constructor( + name: string, + public fromSupported: boolean, + public toSupported: boolean, + ) { + this.name = name; + if (!this.name.startsWith(".")) { + this.name = `.${this.name}`; + } + + if (!this.fromSupported && !this.toSupported) { + throw new Error("Format must support at least one direction"); + } + } +} + /** * Base class for all converters. */ @@ -11,7 +30,7 @@ export class Converter { /** * List of supported formats. */ - public supportedFormats: string[] = []; + public supportedFormats: FormatInfo[] = []; /** * Convert a file to a different format. * @param input The input file. @@ -34,4 +53,11 @@ export class Converter { public async valid(): Promise { return true; } + + public formatStrings(predicate?: (f: FormatInfo) => boolean) { + if (predicate) { + return this.supportedFormats.filter(predicate).map((f) => f.name); + } + return this.supportedFormats.map((f) => f.name); + } } diff --git a/src/lib/converters/ffmpeg.svelte.ts b/src/lib/converters/ffmpeg.svelte.ts index 9a1d0c2..9ce3e69 100644 --- a/src/lib/converters/ffmpeg.svelte.ts +++ b/src/lib/converters/ffmpeg.svelte.ts @@ -1,5 +1,5 @@ import { VertFile } from "$lib/types"; -import { Converter } from "./converter.svelte"; +import { Converter, FormatInfo } from "./converter.svelte"; import { FFmpeg } from "@ffmpeg/ffmpeg"; import { browser } from "$app/environment"; import { error, log } from "$lib/logger"; @@ -11,17 +11,17 @@ export class FFmpegConverter extends Converter { public ready = $state(false); public supportedFormats = [ - ".mp3", - ".wav", - ".flac", - ".ogg", - ".aac", - ".m4a", - ".wma", - ".amr", - ".ac3", - ".alac", - ".aiff", + new FormatInfo("mp3", true, true), + new FormatInfo("wav", true, true), + new FormatInfo("flac", true, true), + new FormatInfo("ogg", true, true), + new FormatInfo("aac", true, true), + new FormatInfo("m4a", true, true), + new FormatInfo("wma", true, true), + new FormatInfo("amr", true, true), + new FormatInfo("ac3", true, true), + new FormatInfo("alac", true, true), + new FormatInfo("aiff", true, true), ]; public readonly reportsProgress = true; diff --git a/src/lib/converters/pandoc.svelte.ts b/src/lib/converters/pandoc.svelte.ts index 8b1326d..8984e25 100644 --- a/src/lib/converters/pandoc.svelte.ts +++ b/src/lib/converters/pandoc.svelte.ts @@ -1,5 +1,5 @@ import { VertFile } from "$lib/types"; -import { Converter } from "./converter.svelte"; +import { Converter, FormatInfo } from "./converter.svelte"; import { browser } from "$app/environment"; import PandocWorker from "$lib/workers/pandoc?worker"; @@ -61,23 +61,19 @@ export class PandocConverter extends Converter { ); } - // public name = "pandoc"; - // public ready = $state(false); - // public wasm: ArrayBuffer = null!; - public supportedFormats = [ - ".docx", - ".doc", - ".md", - ".html", - ".rtf", - ".csv", - ".tsv", - ".json", - ".rst", - ".epub", - ".odt", - ".docbook", + new FormatInfo("docx", true, true), + new FormatInfo("doc", true, true), + new FormatInfo("md", true, true), + new FormatInfo("html", true, true), + new FormatInfo("rtf", true, true), + new FormatInfo("csv", true, true), + new FormatInfo("tsv", true, true), + new FormatInfo("json", true, true), + new FormatInfo("rst", true, true), + new FormatInfo("epub", true, true), + new FormatInfo("odt", true, true), + new FormatInfo("docbook", true, true), ]; } diff --git a/src/lib/converters/vertd.svelte.ts b/src/lib/converters/vertd.svelte.ts index d7adf9c..94f9d20 100644 --- a/src/lib/converters/vertd.svelte.ts +++ b/src/lib/converters/vertd.svelte.ts @@ -1,7 +1,7 @@ import { log } from "$lib/logger"; import { Settings } from "$lib/sections/settings/index.svelte"; import { VertFile } from "$lib/types"; -import { Converter } from "./converter.svelte"; +import { Converter, FormatInfo } from "./converter.svelte"; interface VertdError { type: "error"; @@ -200,16 +200,18 @@ export class VertdConverter extends Converter { public name = "vertd"; public ready = $state(false); public reportsProgress = true; + public supportedFormats = [ - ".mkv", - ".mp4", - ".webm", - ".avi", - ".wmv", - ".mov", - ".gif", - ".mts", + new FormatInfo("mkv", true, true), + new FormatInfo("mp4", true, true), + new FormatInfo("webm", true, true), + new FormatInfo("avi", true, true), + new FormatInfo("wmv", true, true), + new FormatInfo("mov", true, true), + new FormatInfo("gif", true, true), + new FormatInfo("mts", true, true), ]; + // eslint-disable-next-line @typescript-eslint/no-explicit-any private log: (...msg: any[]) => void = () => {}; diff --git a/src/lib/converters/vips.svelte.ts b/src/lib/converters/vips.svelte.ts index bdba091..d8b4e41 100644 --- a/src/lib/converters/vips.svelte.ts +++ b/src/lib/converters/vips.svelte.ts @@ -4,7 +4,7 @@ import { addToast } from "$lib/store/ToastProvider"; import type { OmitBetterStrict, WorkerMessage } from "$lib/types"; import { VertFile } from "$lib/types"; import VipsWorker from "$lib/workers/vips?worker&url"; -import { Converter } from "./converter.svelte"; +import { Converter, FormatInfo } from "./converter.svelte"; export class VipsConverter extends Converter { private worker: Worker = browser @@ -15,34 +15,32 @@ export class VipsConverter extends Converter { private id = 0; public name = "libvips"; public ready = $state(false); - public static supportedFormatsStatic = [ - ...new Set([ - ".png", - ".jpeg", - ".jpg", - ".webp", - ".gif", - ".ico", - ".cur", - ".ani", - ".heic", - ".hdr", - ".jpe", - ".dng", - ".mat", - ".pbm", - ".pfm", - ".pgm", - ".pnm", - ".ppm", - ".raw", - ".tif", - ".tiff", - ".jfif", - ]), - ]; - public supportedFormats = VipsConverter.supportedFormatsStatic; + public supportedFormats = [ + new FormatInfo("png", true, true), + new FormatInfo("jpeg", true, true), + new FormatInfo("jpg", true, true), + new FormatInfo("webp", true, true), + new FormatInfo("gif", true, true), + new FormatInfo("ico", true, false), + new FormatInfo("cur", true, false), + new FormatInfo("ani", true, false), + new FormatInfo("heic", true, false), + new FormatInfo("hdr", true, true), + new FormatInfo("jpe", true, true), + new FormatInfo("dng", true, false), + new FormatInfo("mat", true, true), + new FormatInfo("pbm", true, true), + new FormatInfo("pfm", true, true), + new FormatInfo("pgm", true, true), + new FormatInfo("pnm", true, true), + new FormatInfo("ppm", true, true), + new FormatInfo("raw", false, true), + new FormatInfo("tif", true, true), + new FormatInfo("tiff", true, true), + new FormatInfo("jfif", true, true), + new FormatInfo("avif", true, true), + ]; public readonly reportsProgress = false; diff --git a/src/lib/store/index.svelte.ts b/src/lib/store/index.svelte.ts index 2d9e8e3..bf99690 100644 --- a/src/lib/store/index.svelte.ts +++ b/src/lib/store/index.svelte.ts @@ -32,10 +32,12 @@ class Files { this.thumbnailQueue.add(async () => { const isAudio = converters .find((c) => c.name === "ffmpeg") - ?.supportedFormats?.includes(file.from.toLowerCase()); + ?.formatStrings() + ?.includes(file.from.toLowerCase()); const isVideo = converters .find((c) => c.name === "vertd") - ?.supportedFormats?.includes(file.from.toLowerCase()); + ?.formatStrings() + ?.includes(file.from.toLowerCase()); try { if (isAudio) { @@ -119,16 +121,16 @@ class Files { return; } const converter = converters.find((c) => - c.supportedFormats.includes( - format || ".somenonexistentextension", - ), + c + .formatStrings() + .includes(format || ".somenonexistentextension"), ); if (!converter) { log(["files"], `no converter found for ${file.name}`); this.files.push(new VertFile(file, format)); return; } - const to = converter.supportedFormats.find((f) => f !== format); + const to = converter.formatStrings().find((f) => f !== format); if (!to) { log(["files"], `no output format found for ${file.name}`); return; diff --git a/src/lib/types/file.svelte.ts b/src/lib/types/file.svelte.ts index 5b9fc6d..f77156c 100644 --- a/src/lib/types/file.svelte.ts +++ b/src/lib/types/file.svelte.ts @@ -28,7 +28,7 @@ export class VertFile { public findConverters(supportedFormats: string[] = [this.from]) { const converter = this.converters.filter((converter) => - converter.supportedFormats.map((f) => supportedFormats.includes(f)), + converter.formatStrings().map((f) => supportedFormats.includes(f)), ); return converter; } @@ -36,8 +36,8 @@ export class VertFile { public findConverter() { const converter = this.converters.find( (converter) => - converter.supportedFormats.includes(this.from) && - converter.supportedFormats.includes(this.to), + converter.formatStrings().includes(this.from) && + converter.formatStrings().includes(this.to), ); return converter; } @@ -51,7 +51,7 @@ export class VertFile { this.file = newFile; this.to = to; this.converters = converters.filter((c) => - c.supportedFormats.includes(this.from), + c.formatStrings().includes(this.from), ); this.convert = this.convert.bind(this); this.download = this.download.bind(this); diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 3001f7d..4c7f77c 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -8,8 +8,13 @@ const { data } = $props(); const getSupportedFormats = (name: string) => - converters.find((c) => c.name === name)?.supportedFormats.join(", ") || - "none"; + converters + .find((c) => c.name === name) + ?.supportedFormats.map( + (f) => + `${f.name}${f.fromSupported && f.toSupported ? "" : "*"}`, + ) + .join(", ") || "none"; const status: { [key: string]: { diff --git a/src/routes/convert/+page.svelte b/src/routes/convert/+page.svelte index c13bad9..a058220 100644 --- a/src/routes/convert/+page.svelte +++ b/src/routes/convert/+page.svelte @@ -89,21 +89,25 @@ {@const availableConverters = file.findConverters()} {@const currentConverter = converters.find( (c) => - c.supportedFormats.includes(file.from) && - c.supportedFormats.includes(file.to), + c.formatStrings((f) => f.fromSupported).includes(file.from) && + c.formatStrings((f) => f.toSupported).includes(file.to), )} {@const isAudio = converters .find((c) => c.name === "ffmpeg") - ?.supportedFormats.includes(file.from)} + ?.formatStrings((f) => f.fromSupported) + .includes(file.from)} {@const isVideo = converters .find((c) => c.name === "vertd") - ?.supportedFormats.includes(file.from)} + ?.formatStrings((f) => f.fromSupported) + .includes(file.from)} {@const isImage = converters .find((c) => c.name === "libvips") - ?.supportedFormats.includes(file.from)} + ?.formatStrings((f) => f.fromSupported) + .includes(file.from)} {@const isDocument = converters .find((c) => c.name === "pandoc") - ?.supportedFormats.includes(file.from)} + ?.formatStrings((f) => f.fromSupported) + .includes(file.from)}
{#if !converters.length} @@ -222,7 +226,9 @@ c.supportedFormats) + .flatMap((c) => + c.formatStrings((f) => f.toSupported), + ) .filter( (format) => format !== ".svg" && format !== ".heif",