mirror of https://github.com/VERT-sh/VERT.git
feat: more conversion settings
This commit is contained in:
parent
1ef2639ca5
commit
3e4ff6bdbe
|
|
@ -88,19 +88,32 @@
|
||||||
"quality": "Quality",
|
"quality": "Quality",
|
||||||
"depth": "Color depth",
|
"depth": "Color depth",
|
||||||
"color_space": "Color space",
|
"color_space": "Color space",
|
||||||
"transparency": "Transparency",
|
"transparency": "Transparency"
|
||||||
"metadata": "Metadata"
|
|
||||||
},
|
},
|
||||||
"audio": {
|
"audio": {
|
||||||
"quality": "Quality",
|
"bitrate": "Bitrate",
|
||||||
"rate": "Sample rate",
|
"sample_rate": "Sample rate",
|
||||||
"metadata": "Metadata"
|
"channels": "Audio channels"
|
||||||
},
|
},
|
||||||
"video": {
|
"video": {
|
||||||
"quality": "Quality",
|
"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": {
|
"document": {
|
||||||
|
"something": "Something"
|
||||||
|
},
|
||||||
|
"common": {
|
||||||
"metadata": "Metadata"
|
"metadata": "Metadata"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,7 @@
|
||||||
checked={file.conversionSettings[
|
checked={file.conversionSettings[
|
||||||
setting.key
|
setting.key
|
||||||
] ?? setting.default}
|
] ?? setting.default}
|
||||||
|
placeholder={setting.placeholder}
|
||||||
onchange={(e) =>
|
onchange={(e) =>
|
||||||
handleSettingChange(
|
handleSettingChange(
|
||||||
setting.key,
|
setting.key,
|
||||||
|
|
@ -120,6 +121,7 @@
|
||||||
value={file.conversionSettings[
|
value={file.conversionSettings[
|
||||||
setting.key
|
setting.key
|
||||||
] ?? setting.default}
|
] ?? setting.default}
|
||||||
|
placeholder={setting.placeholder}
|
||||||
oninput={(e) =>
|
oninput={(e) =>
|
||||||
handleSettingChange(
|
handleSettingChange(
|
||||||
setting.key,
|
setting.key,
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ export class Converter {
|
||||||
* Can be overridden per converter for format-specific settings.
|
* Can be overridden per converter for format-specific settings.
|
||||||
* @param input The input file.
|
* @param input The input file.
|
||||||
*/
|
*/
|
||||||
public getAvailableSettings(input: VertFile): SettingDefinition[] {
|
public async getAvailableSettings(): Promise<SettingDefinition[]> {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,9 +63,10 @@ export class Converter {
|
||||||
* Get default settings for a conversion.
|
* Get default settings for a conversion.
|
||||||
* @param input The input file.
|
* @param input The input file.
|
||||||
*/
|
*/
|
||||||
public getDefaultSettings(input: VertFile): ConversionSettings {
|
public async getDefaultSettings(): Promise<ConversionSettings> {
|
||||||
const defaults: ConversionSettings = {};
|
const defaults: ConversionSettings = {};
|
||||||
this.getAvailableSettings(input).forEach((setting) => {
|
const settings = await this.getAvailableSettings();
|
||||||
|
settings.forEach((setting) => {
|
||||||
defaults[setting.key] = setting.default;
|
defaults[setting.key] = setting.default;
|
||||||
});
|
});
|
||||||
return defaults;
|
return defaults;
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import { error, log } from "$lib/util/logger";
|
||||||
import { m } from "$lib/paraglide/messages";
|
import { m } from "$lib/paraglide/messages";
|
||||||
import { Settings } from "$lib/sections/settings/index.svelte";
|
import { Settings } from "$lib/sections/settings/index.svelte";
|
||||||
import { ToastManager } from "$lib/util/toast.svelte";
|
import { ToastManager } from "$lib/util/toast.svelte";
|
||||||
|
import type { SettingDefinition, ConversionSettings } from "$lib/types/conversion-settings";
|
||||||
|
|
||||||
// TODO: differentiate in UI? (not native formats)
|
// TODO: differentiate in UI? (not native formats)
|
||||||
const videoFormats = [
|
const videoFormats = [
|
||||||
|
|
@ -105,6 +106,63 @@ export class FFmpegConverter extends Converter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async getAvailableSettings(): Promise<SettingDefinition[]> {
|
||||||
|
// 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<ConversionSettings> {
|
||||||
|
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<VertFile> {
|
public async convert(input: VertFile, to: string): Promise<VertFile> {
|
||||||
if (!to.startsWith(".")) to = `.${to}`;
|
if (!to.startsWith(".")) to = `.${to}`;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -116,8 +116,7 @@ export class MagickConverter extends Converter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
public async getAvailableSettings(): Promise<SettingDefinition[]> {
|
||||||
public getAvailableSettings(input: VertFile): SettingDefinition[] {
|
|
||||||
// images - quality/compression/quantize/interlace/depth-DPI, resize, crop, rotate, flip/flop, autoOrient?, color space/bit depth, transparency settings
|
// images - quality/compression/quantize/interlace/depth-DPI, resize, crop, rotate, flip/flop, autoOrient?, color space/bit depth, transparency settings
|
||||||
|
|
||||||
const quality: SettingDefinition = {
|
const quality: SettingDefinition = {
|
||||||
|
|
@ -173,7 +172,7 @@ export class MagickConverter extends Converter {
|
||||||
|
|
||||||
const metadata: SettingDefinition = {
|
const metadata: SettingDefinition = {
|
||||||
key: "metadata",
|
key: "metadata",
|
||||||
label: m["convert.settings.image.metadata"](),
|
label: m["convert.settings.common.metadata"](),
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
default: true,
|
default: true,
|
||||||
};
|
};
|
||||||
|
|
@ -183,9 +182,10 @@ export class MagickConverter extends Converter {
|
||||||
return [quality, depth, colorSpace, transparency, metadata];
|
return [quality, depth, colorSpace, transparency, metadata];
|
||||||
}
|
}
|
||||||
|
|
||||||
public getDefaultSettings(input: VertFile): ConversionSettings {
|
public async getDefaultSettings(): Promise<ConversionSettings> {
|
||||||
const defaults: ConversionSettings = {};
|
const defaults: ConversionSettings = {};
|
||||||
this.getAvailableSettings(input).forEach((setting) => {
|
const settings = await this.getAvailableSettings();
|
||||||
|
settings.forEach((setting) => {
|
||||||
defaults[setting.key] = setting.default;
|
defaults[setting.key] = setting.default;
|
||||||
});
|
});
|
||||||
return defaults;
|
return defaults;
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,10 @@ import { Converter, FormatInfo } from "./converter.svelte";
|
||||||
import { PUB_DISABLE_FAILURE_BLOCKS } from "$env/static/public";
|
import { PUB_DISABLE_FAILURE_BLOCKS } from "$env/static/public";
|
||||||
import { ToastManager } from "$lib/util/toast.svelte";
|
import { ToastManager } from "$lib/util/toast.svelte";
|
||||||
import { converters } from "./index";
|
import { converters } from "./index";
|
||||||
|
import type {
|
||||||
|
SettingDefinition,
|
||||||
|
ConversionSettings,
|
||||||
|
} from "$lib/types/conversion-settings";
|
||||||
|
|
||||||
interface UploadResponse {
|
interface UploadResponse {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
@ -266,7 +270,7 @@ export class VertdConverter extends Converter {
|
||||||
new FormatInfo("mov", true, true),
|
new FormatInfo("mov", true, true),
|
||||||
new FormatInfo("gif", true, true),
|
new FormatInfo("gif", true, true),
|
||||||
new FormatInfo("apng", true, true),
|
new FormatInfo("apng", true, true),
|
||||||
new FormatInfo("webp", true, true),
|
new FormatInfo("webp", true, true),
|
||||||
new FormatInfo("mts", true, true),
|
new FormatInfo("mts", true, true),
|
||||||
new FormatInfo("ts", true, true),
|
new FormatInfo("ts", true, true),
|
||||||
new FormatInfo("m2ts", true, true),
|
new FormatInfo("m2ts", true, true),
|
||||||
|
|
@ -347,6 +351,77 @@ export class VertdConverter extends Converter {
|
||||||
Settings.instance.save();
|
Settings.instance.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async getAvailableSettings(): Promise<SettingDefinition[]> {
|
||||||
|
// 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<ConversionSettings> {
|
||||||
|
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<VertFile> {
|
public async convert(input: VertFile, to: string): Promise<VertFile> {
|
||||||
if (to.startsWith(".")) to = to.slice(1);
|
if (to.startsWith(".")) to = to.slice(1);
|
||||||
|
|
||||||
|
|
@ -357,10 +432,17 @@ export class VertdConverter extends Converter {
|
||||||
// https://trac.ffmpeg.org/ticket/4907
|
// https://trac.ffmpeg.org/ticket/4907
|
||||||
if (input.from === ".webp") {
|
if (input.from === ".webp") {
|
||||||
this.log(`animated webp detected, converting to gif first`);
|
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) {
|
if (magickConverter) {
|
||||||
try {
|
try {
|
||||||
fileUpload = await magickConverter.convert(input, ".gif", 100);
|
fileUpload = await magickConverter.convert(
|
||||||
|
input,
|
||||||
|
".gif",
|
||||||
|
input.conversionSettings,
|
||||||
|
100,
|
||||||
|
);
|
||||||
this.log(`successfully converted webp to gif`);
|
this.log(`successfully converted webp to gif`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.log(`failed to convert webp to gif: ${e}`);
|
this.log(`failed to convert webp to gif: ${e}`);
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,10 @@ export type SettingType = "number" | "select" | "boolean" | "string" | "range";
|
||||||
|
|
||||||
export interface SettingDefinition {
|
export interface SettingDefinition {
|
||||||
key: string;
|
key: string;
|
||||||
label: () => string;
|
label: string;
|
||||||
type: SettingType;
|
type: SettingType;
|
||||||
default: any;
|
default?: any;
|
||||||
|
placeholder?: string;
|
||||||
min?: number;
|
min?: number;
|
||||||
max?: number;
|
max?: number;
|
||||||
step?: number;
|
step?: number;
|
||||||
|
|
|
||||||
|
|
@ -69,4 +69,4 @@ export default defineConfig(({ command }) => {
|
||||||
__COMMIT_HASH__: JSON.stringify(commitHash),
|
__COMMIT_HASH__: JSON.stringify(commitHash),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
Loading…
Reference in New Issue