diff --git a/messages/en.json b/messages/en.json index 2dbbfb3..84e724c 100644 --- a/messages/en.json +++ b/messages/en.json @@ -88,19 +88,32 @@ "quality": "Quality", "depth": "Color depth", "color_space": "Color space", - "transparency": "Transparency", - "metadata": "Metadata" + "transparency": "Transparency" }, "audio": { - "quality": "Quality", - "rate": "Sample rate", - "metadata": "Metadata" + "bitrate": "Bitrate", + "sample_rate": "Sample rate", + "channels": "Audio channels" }, "video": { "quality": "Quality", - "metadata": "Metadata" + "metadata": "Metadata", + "speed": "Conversion speed", + "speed_very_slow": "Very Slow", + "speed_slower": "Slower", + "speed_slow": "Slow", + "speed_medium": "Medium", + "speed_fast": "Fast", + "speed_ultra_fast": "Ultra Fast", + "fps": "Frame rate (FPS)", + "fps_placeholder": "Auto", + "resolution": "Resolution", + "resolution_placeholder": "Auto (e.g., 1920x1080)" }, "document": { + "something": "Something" + }, + "common": { "metadata": "Metadata" } }, diff --git a/src/lib/components/functional/SettingsModal.svelte b/src/lib/components/functional/SettingsModal.svelte index 084e332..09d7fe6 100644 --- a/src/lib/components/functional/SettingsModal.svelte +++ b/src/lib/components/functional/SettingsModal.svelte @@ -107,6 +107,7 @@ checked={file.conversionSettings[ setting.key ] ?? setting.default} + placeholder={setting.placeholder} onchange={(e) => handleSettingChange( setting.key, @@ -120,6 +121,7 @@ value={file.conversionSettings[ setting.key ] ?? setting.default} + placeholder={setting.placeholder} oninput={(e) => handleSettingChange( setting.key, diff --git a/src/lib/converters/converter.svelte.ts b/src/lib/converters/converter.svelte.ts index b864d87..8c0448d 100644 --- a/src/lib/converters/converter.svelte.ts +++ b/src/lib/converters/converter.svelte.ts @@ -55,7 +55,7 @@ export class Converter { * Can be overridden per converter for format-specific settings. * @param input The input file. */ - public getAvailableSettings(input: VertFile): SettingDefinition[] { + public async getAvailableSettings(): Promise { return []; } @@ -63,9 +63,10 @@ export class Converter { * Get default settings for a conversion. * @param input The input file. */ - public getDefaultSettings(input: VertFile): ConversionSettings { + public async getDefaultSettings(): Promise { const defaults: ConversionSettings = {}; - this.getAvailableSettings(input).forEach((setting) => { + const settings = await this.getAvailableSettings(); + settings.forEach((setting) => { defaults[setting.key] = setting.default; }); return defaults; diff --git a/src/lib/converters/ffmpeg.svelte.ts b/src/lib/converters/ffmpeg.svelte.ts index 434526b..59937da 100644 --- a/src/lib/converters/ffmpeg.svelte.ts +++ b/src/lib/converters/ffmpeg.svelte.ts @@ -6,6 +6,7 @@ import { error, log } from "$lib/util/logger"; import { m } from "$lib/paraglide/messages"; import { Settings } from "$lib/sections/settings/index.svelte"; import { ToastManager } from "$lib/util/toast.svelte"; +import type { SettingDefinition, ConversionSettings } from "$lib/types/conversion-settings"; // TODO: differentiate in UI? (not native formats) const videoFormats = [ @@ -105,6 +106,63 @@ export class FFmpegConverter extends Converter { } } + public async getAvailableSettings(): Promise { + // audio - bitrate, sample rate, channels, normalize, trim silence + + // TODO: detect bitrate, sample rate, audio channels and set default/max accordingly + + const bitrate: SettingDefinition = { + key: "bitrate", + label: m["convert.settings.audio.bitrate"](), + type: "select", + default: "auto", + options: CONVERSION_BITRATES.map((b) => ({ + value: b.toString(), + label: b.toString(), + })), + }; + + const sampleRate: SettingDefinition = { + key: "sampleRate", + label: m["convert.settings.audio.sample_rate"](), + type: "select", + default: "auto", + options: SAMPLE_RATES.map((r) => ({ + value: r.toString(), + label: r.toString(), + })), + }; + + const channels: SettingDefinition = { + key: "channels", + label: m["convert.settings.audio.channels"](), + type: "number", + default: 2, + min: 1, + max: 8, + }; + + const metadata: SettingDefinition = { + key: "metadata", + label: m["convert.settings.common.metadata"](), + type: "boolean", + default: true, + }; + + // resize, crop, rotate - prob want a ui + + return [bitrate, sampleRate, channels, metadata]; + } + + public async getDefaultSettings(): Promise { + const defaults: ConversionSettings = {}; + const settings = await this.getAvailableSettings(); + settings.forEach((setting) => { + defaults[setting.key] = setting.default; + }); + return defaults; + } + public async convert(input: VertFile, to: string): Promise { if (!to.startsWith(".")) to = `.${to}`; diff --git a/src/lib/converters/magick.svelte.ts b/src/lib/converters/magick.svelte.ts index 2655e28..3a51433 100644 --- a/src/lib/converters/magick.svelte.ts +++ b/src/lib/converters/magick.svelte.ts @@ -116,8 +116,7 @@ export class MagickConverter extends Converter { } } - // eslint-disable-next-line @typescript-eslint/no-unused-vars - public getAvailableSettings(input: VertFile): SettingDefinition[] { + public async getAvailableSettings(): Promise { // images - quality/compression/quantize/interlace/depth-DPI, resize, crop, rotate, flip/flop, autoOrient?, color space/bit depth, transparency settings const quality: SettingDefinition = { @@ -173,7 +172,7 @@ export class MagickConverter extends Converter { const metadata: SettingDefinition = { key: "metadata", - label: m["convert.settings.image.metadata"](), + label: m["convert.settings.common.metadata"](), type: "boolean", default: true, }; @@ -183,9 +182,10 @@ export class MagickConverter extends Converter { return [quality, depth, colorSpace, transparency, metadata]; } - public getDefaultSettings(input: VertFile): ConversionSettings { + public async getDefaultSettings(): Promise { const defaults: ConversionSettings = {}; - this.getAvailableSettings(input).forEach((setting) => { + const settings = await this.getAvailableSettings(); + settings.forEach((setting) => { defaults[setting.key] = setting.default; }); return defaults; diff --git a/src/lib/converters/vertd.svelte.ts b/src/lib/converters/vertd.svelte.ts index 02f9476..66969b2 100644 --- a/src/lib/converters/vertd.svelte.ts +++ b/src/lib/converters/vertd.svelte.ts @@ -8,6 +8,10 @@ import { Converter, FormatInfo } from "./converter.svelte"; import { PUB_DISABLE_FAILURE_BLOCKS } from "$env/static/public"; import { ToastManager } from "$lib/util/toast.svelte"; import { converters } from "./index"; +import type { + SettingDefinition, + ConversionSettings, +} from "$lib/types/conversion-settings"; interface UploadResponse { id: string; @@ -266,7 +270,7 @@ export class VertdConverter extends Converter { new FormatInfo("mov", true, true), new FormatInfo("gif", true, true), new FormatInfo("apng", true, true), - new FormatInfo("webp", true, true), + new FormatInfo("webp", true, true), new FormatInfo("mts", true, true), new FormatInfo("ts", true, true), new FormatInfo("m2ts", true, true), @@ -347,6 +351,77 @@ export class VertdConverter extends Converter { Settings.instance.save(); } + public async getAvailableSettings(): Promise { + // video - bitrate, fps, resolution, trim, crop, rotate, flip/flop, audio settings? + + const qualityOptions = [ + { + value: "verySlow", + label: m["convert.settings.video.speed_very_slow"](), + }, + { + value: "slower", + label: m["convert.settings.video.speed_slower"](), + }, + { value: "slow", label: m["convert.settings.video.speed_slow"]() }, + { + value: "medium", + label: m["convert.settings.video.speed_medium"](), + }, + { value: "fast", label: m["convert.settings.video.speed_fast"]() }, + { + value: "ultraFast", + label: m["convert.settings.video.speed_ultra_fast"](), + }, + ]; + + const quality: SettingDefinition = { + key: "vertdSpeed", + label: m["convert.settings.video.speed"](), + type: "select", + default: "medium", + options: qualityOptions, + }; + + // TODO: for fps and resolution, set placeholder to detected values + const fps: SettingDefinition = { + key: "fps", + label: m["convert.settings.video.fps"](), + placeholder: m["convert.settings.video.fps_placeholder"](), + type: "number", + min: 1, + }; + + const resolution: SettingDefinition = { + key: "resolution", + label: m["convert.settings.video.resolution"](), + placeholder: m["convert.settings.video.resolution_placeholder"](), + type: "string", + }; + + const metadata: SettingDefinition = { + key: "metadata", + label: m["convert.settings.common.metadata"](), + type: "boolean", + default: true, + }; + + // trim/crop/rotate - also have another ui for this prob + + // import all audio settings? + + return [quality, fps, resolution, metadata]; + } + + public async getDefaultSettings(): Promise { + const defaults: ConversionSettings = {}; + const settings = await this.getAvailableSettings(); + settings.forEach((setting) => { + defaults[setting.key] = setting.default; + }); + return defaults; + } + public async convert(input: VertFile, to: string): Promise { if (to.startsWith(".")) to = to.slice(1); @@ -357,10 +432,17 @@ export class VertdConverter extends Converter { // https://trac.ffmpeg.org/ticket/4907 if (input.from === ".webp") { this.log(`animated webp detected, converting to gif first`); - const magickConverter = converters.find((c) => c.name === "imagemagick"); + const magickConverter = converters.find( + (c) => c.name === "imagemagick", + ); if (magickConverter) { try { - fileUpload = await magickConverter.convert(input, ".gif", 100); + fileUpload = await magickConverter.convert( + input, + ".gif", + input.conversionSettings, + 100, + ); this.log(`successfully converted webp to gif`); } catch (e) { this.log(`failed to convert webp to gif: ${e}`); diff --git a/src/lib/types/conversion-settings.ts b/src/lib/types/conversion-settings.ts index 69dbbef..0a8fc7a 100644 --- a/src/lib/types/conversion-settings.ts +++ b/src/lib/types/conversion-settings.ts @@ -3,9 +3,10 @@ export type SettingType = "number" | "select" | "boolean" | "string" | "range"; export interface SettingDefinition { key: string; - label: () => string; + label: string; type: SettingType; - default: any; + default?: any; + placeholder?: string; min?: number; max?: number; step?: number; diff --git a/vite.config.ts b/vite.config.ts index d6ebd1e..b23b344 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -69,4 +69,4 @@ export default defineConfig(({ command }) => { __COMMIT_HASH__: JSON.stringify(commitHash), }, }; -}); +}); \ No newline at end of file