diff --git a/components/converter/FileConverter.tsx b/components/converter/FileConverter.tsx
index e594006..8df8f97 100644
--- a/components/converter/FileConverter.tsx
+++ b/components/converter/FileConverter.tsx
@@ -9,6 +9,7 @@ import { FormatSelector } from './FormatSelector';
import { ConversionPreview } from './ConversionPreview';
import { ConversionOptionsPanel } from './ConversionOptions';
import { FileInfo } from './FileInfo';
+import { FormatPresets } from './FormatPresets';
import { useToast } from '@/components/ui/Toast';
import {
SUPPORTED_FORMATS,
@@ -20,6 +21,7 @@ import { convertWithFFmpeg } from '@/lib/converters/ffmpegService';
import { convertWithImageMagick } from '@/lib/converters/imagemagickService';
import { addToHistory } from '@/lib/storage/history';
import { downloadBlobsAsZip, generateOutputFilename } from '@/lib/utils/fileUtils';
+import { getPresetById, type FormatPreset } from '@/lib/utils/formatPresets';
import type { ConversionJob, ConversionFormat, ConversionOptions } from '@/types/conversion';
export function FileConverter() {
@@ -209,6 +211,17 @@ export function FileConverter() {
setSelectedFiles((prev) => prev.filter((_, i) => i !== index));
};
+ const handlePresetSelect = (preset: FormatPreset) => {
+ // Find the output format that matches the preset
+ const format = compatibleFormats.find(f => f.extension === preset.outputFormat);
+
+ if (format) {
+ setOutputFormat(format);
+ setConversionOptions(preset.options);
+ addToast(`Applied ${preset.name} preset`, 'success');
+ }
+ };
+
const handleDownloadAll = async () => {
if (!outputFormat) return;
@@ -375,6 +388,15 @@ export function FileConverter() {
)}
+ {/* Format Presets */}
+ {inputFormat && (
+
+ )}
+
{/* Format selection */}
{inputFormat && compatibleFormats.length > 0 && (
diff --git a/components/converter/FormatPresets.tsx b/components/converter/FormatPresets.tsx
new file mode 100644
index 0000000..96bf136
--- /dev/null
+++ b/components/converter/FormatPresets.tsx
@@ -0,0 +1,67 @@
+'use client';
+
+import * as React from 'react';
+import { Sparkles } from 'lucide-react';
+import { Card } from '@/components/ui/Card';
+import { Button } from '@/components/ui/Button';
+import { cn } from '@/lib/utils/cn';
+import { getPresetsByCategory, type FormatPreset } from '@/lib/utils/formatPresets';
+import type { ConversionFormat } from '@/types/conversion';
+
+interface FormatPresetsProps {
+ inputFormat: ConversionFormat;
+ onPresetSelect: (preset: FormatPreset) => void;
+ disabled?: boolean;
+}
+
+export function FormatPresets({ inputFormat, onPresetSelect, disabled = false }: FormatPresetsProps) {
+ const [selectedPresetId, setSelectedPresetId] = React.useState
(null);
+
+ // Get presets for the input format's category
+ const presets = getPresetsByCategory(inputFormat.category);
+
+ if (presets.length === 0) {
+ return null;
+ }
+
+ const handlePresetClick = (preset: FormatPreset) => {
+ setSelectedPresetId(preset.id);
+ onPresetSelect(preset);
+ };
+
+ return (
+
+
+
+
Quick Presets
+
+
+
+ {presets.map((preset) => (
+
+ ))}
+
+
+
+ Select a preset to automatically configure optimal settings for your use case
+
+
+ );
+}
diff --git a/lib/utils/formatPresets.ts b/lib/utils/formatPresets.ts
new file mode 100644
index 0000000..666137b
--- /dev/null
+++ b/lib/utils/formatPresets.ts
@@ -0,0 +1,188 @@
+import type { ConversionOptions } from '@/types/conversion';
+
+export interface FormatPreset {
+ id: string;
+ name: string;
+ description: string;
+ icon: string;
+ category: 'video' | 'audio' | 'image';
+ outputFormat: string;
+ options: ConversionOptions;
+}
+
+/**
+ * Predefined format presets for common use cases
+ */
+export const FORMAT_PRESETS: FormatPreset[] = [
+ // Video Presets
+ {
+ id: 'youtube-video',
+ name: 'YouTube Video',
+ description: '1080p MP4, optimized for YouTube',
+ icon: '🎬',
+ category: 'video',
+ outputFormat: 'mp4',
+ options: {
+ videoCodec: 'libx264',
+ videoBitrate: '5M',
+ videoResolution: '1920x-1',
+ videoFps: 30,
+ audioCodec: 'aac',
+ audioBitrate: '192k',
+ },
+ },
+ {
+ id: 'instagram-video',
+ name: 'Instagram Video',
+ description: 'Square 1:1 format for Instagram',
+ icon: '📸',
+ category: 'video',
+ outputFormat: 'mp4',
+ options: {
+ videoCodec: 'libx264',
+ videoBitrate: '3M',
+ videoResolution: '1080x-1', // Will be cropped to square
+ videoFps: 30,
+ audioCodec: 'aac',
+ audioBitrate: '128k',
+ },
+ },
+ {
+ id: 'twitter-video',
+ name: 'Twitter Video',
+ description: '720p, optimized for Twitter',
+ icon: '🐦',
+ category: 'video',
+ outputFormat: 'mp4',
+ options: {
+ videoCodec: 'libx264',
+ videoBitrate: '2M',
+ videoResolution: '1280x-1',
+ videoFps: 30,
+ audioCodec: 'aac',
+ audioBitrate: '128k',
+ },
+ },
+ {
+ id: 'web-video',
+ name: 'Web Optimized',
+ description: 'Small file size for web streaming',
+ icon: '🌐',
+ category: 'video',
+ outputFormat: 'mp4',
+ options: {
+ videoCodec: 'libx264',
+ videoBitrate: '1.5M',
+ videoResolution: '854x-1',
+ videoFps: 24,
+ audioCodec: 'aac',
+ audioBitrate: '96k',
+ },
+ },
+
+ // Audio Presets
+ {
+ id: 'podcast-audio',
+ name: 'Podcast',
+ description: 'MP3, optimized for voice',
+ icon: '🎙️',
+ category: 'audio',
+ outputFormat: 'mp3',
+ options: {
+ audioCodec: 'libmp3lame',
+ audioBitrate: '128k',
+ audioSampleRate: 44100,
+ audioChannels: 2,
+ },
+ },
+ {
+ id: 'music-high-quality',
+ name: 'High Quality Music',
+ description: 'MP3, 320kbps for music',
+ icon: '🎵',
+ category: 'audio',
+ outputFormat: 'mp3',
+ options: {
+ audioCodec: 'libmp3lame',
+ audioBitrate: '320k',
+ audioSampleRate: 48000,
+ audioChannels: 2,
+ },
+ },
+ {
+ id: 'audiobook',
+ name: 'Audiobook',
+ description: 'Mono, small file size',
+ icon: '📚',
+ category: 'audio',
+ outputFormat: 'mp3',
+ options: {
+ audioCodec: 'libmp3lame',
+ audioBitrate: '64k',
+ audioSampleRate: 22050,
+ audioChannels: 1,
+ },
+ },
+
+ // Image Presets
+ {
+ id: 'web-thumbnail',
+ name: 'Web Thumbnail',
+ description: 'JPG, 800px width, optimized',
+ icon: '🖼️',
+ category: 'image',
+ outputFormat: 'jpg',
+ options: {
+ imageQuality: 85,
+ imageWidth: 800,
+ },
+ },
+ {
+ id: 'hd-image',
+ name: 'HD Image',
+ description: 'PNG, high quality, lossless',
+ icon: '🎨',
+ category: 'image',
+ outputFormat: 'png',
+ options: {
+ imageQuality: 100,
+ },
+ },
+ {
+ id: 'social-media-image',
+ name: 'Social Media',
+ description: 'JPG, 1200px, optimized',
+ icon: '📱',
+ category: 'image',
+ outputFormat: 'jpg',
+ options: {
+ imageQuality: 90,
+ imageWidth: 1200,
+ },
+ },
+ {
+ id: 'web-optimized-image',
+ name: 'Web Optimized',
+ description: 'WebP, small file size',
+ icon: '⚡',
+ category: 'image',
+ outputFormat: 'webp',
+ options: {
+ imageQuality: 80,
+ },
+ },
+];
+
+/**
+ * Get presets by category
+ */
+export function getPresetsByCategory(category: 'video' | 'audio' | 'image'): FormatPreset[] {
+ return FORMAT_PRESETS.filter(preset => preset.category === category);
+}
+
+/**
+ * Get preset by ID
+ */
+export function getPresetById(id: string): FormatPreset | undefined {
+ return FORMAT_PRESETS.find(preset => preset.id === id);
+}