Converzen is a cross-platform desktop application built with Wails.js that converts video and image files between different formats. The application uses Go for the backend, SvelteKit with Svelte 5 for the frontend, and SQLite for persistent storage.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Desktop Application β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Frontend (SvelteKit) β β
β β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ ββββββββββββββ β β
β β β File Picker β βFormat Select β β Options β β Progress β β β
β β β Component β β Component β β Component β β Component β β β
β β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ ββββββββββββββ β β
β β β β
β β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β Wails Runtime Bridge β β β
β β β (Auto-generated TypeScript bindings) β β β
β β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Backend (Go) β β
β β β β
β β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β App Controller β β β
β β β (Wails-bound methods, request handling) β β β
β β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β β β
β β ββββββββββββββββββββββββΌβββββββββββββββββββββββ β β
β β βΌ βΌ βΌ β β
β β ββββββββββββββ ββββββββββββββ ββββββββββββββ β β
β β β File β β Converter β β Settings β β β
β β β Service β β Service β β Service β β β
β β ββββββββββββββ ββββββββββββββ ββββββββββββββ β β
β β β β β β β
β β βΌ βΌ βΌ β β
β β ββββββββββββββ ββββββββββββββ ββββββββββββββ β β
β β β File Type β β FFmpeg β β Database β β β
β β β Detector β β Wrapper β β Repositoryβ β β
β β ββββββββββββββ ββββββββββββββ ββββββββββββββ β β
β β β β β
β β βΌ β β
β β ββββββββββββββββββ β β
β β β SQLite DB β β β
β β β (via GORM) β β β
β β ββββββββββββββββββ β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
User selects files β Frontend validates file types β Backend receives file list
β
βΌ
User selects output format β Frontend shows compatible formats β Backend returns supported formats
β
βΌ
User configures options (filename, output dir, copy/replace)
β
βΌ
User clicks Convert β Frontend sends conversion request β Backend queues conversion
β
βΌ
Frontend displays progress β Backend emits progress events β Converter processes files
β β
βΌ βΌ
Conversion complete β Frontend shows result β Backend saves to DB & returns result
βββ main.go # Application entry point
βββ app.go # Main app controller (Wails bindings)
βββ internal/
β βββ config/
β β βββ config.go # Application configuration
β βββ logger/
β β βββ logger.go # Logging service with file output
β βββ models/
β β βββ file.go # File model
β β βββ conversion.go # Conversion job model
β β βββ settings.go # User settings model
β βββ services/
β β βββ interfaces.go # Service interfaces (SOLID: Interface Segregation)
β β βββ file_service.go # File operations service
β β βββ converter_service.go # Conversion orchestration
β β βββ video_converter.go # Video conversion (FFmpeg)
β β βββ image_converter.go # Image conversion
β β βββ settings_service.go # Settings management
β βββ repository/
β β βββ interfaces.go # Repository interfaces
β β βββ conversion_repo.go # Conversion history repository
β β βββ settings_repo.go # Settings repository
β βββ database/
β βββ database.go # SQLite connection and migrations
βββ pkg/
βββ ffmpeg/
βββ ffmpeg.go # FFmpeg wrapper
-
Single Responsibility Principle (SRP)
- Each service handles one concern (file operations, conversion, settings)
- Repositories handle only data persistence
- Logger handles only logging concerns
-
Open/Closed Principle (OCP)
- Converter interface allows adding new format converters without modifying existing code
- File type detectors can be extended via interface implementation
-
Liskov Substitution Principle (LSP)
- All converter implementations are interchangeable via the Converter interface
- Repository implementations can be swapped (e.g., mock for testing)
-
Interface Segregation Principle (ISP)
- Small, focused interfaces (FileReader, FileWriter, Converter)
- Clients depend only on methods they use
-
Dependency Inversion Principle (DIP)
- High-level modules depend on abstractions (interfaces)
- Dependencies injected via constructors
// Converter defines the contract for file conversion
type Converter interface {
Convert(input ConversionJob) (ConversionResult, error)
SupportedInputFormats() []string
SupportedOutputFormats(inputFormat string) []string
CanConvert(inputFormat, outputFormat string) bool
}
// FileService handles file operations
type FileService interface {
SelectFiles() ([]FileInfo, error)
SelectDirectory() (string, error)
GetFileType(path string) (FileType, error)
ValidateFiles(paths []string) ([]FileInfo, error)
}
// ConversionRepository handles conversion history
type ConversionRepository interface {
Save(conversion *Conversion) error
GetHistory(limit int) ([]Conversion, error)
GetByID(id uint) (*Conversion, error)
}frontend/
βββ src/
β βββ lib/
β β βββ components/
β β β βββ ui/ # shadcn-svelte components
β β β βββ FileDropzone.svelte
β β β βββ FormatSelector.svelte
β β β βββ ConversionOptions.svelte
β β β βββ ProgressDisplay.svelte
β β β βββ ConversionHistory.svelte
β β β βββ Header.svelte
β β βββ stores/
β β β βββ files.svelte.ts # File selection state (Svelte 5 runes)
β β β βββ conversion.svelte.ts # Conversion state
β β β βββ settings.svelte.ts # User settings state
β β βββ types/
β β β βββ index.ts # TypeScript type definitions
β β βββ utils/
β β β βββ index.ts # Utility functions
β β βββ wailsjs/ # Auto-generated Wails bindings
β βββ routes/
β β βββ +layout.svelte # Root layout with theme
β β βββ +layout.ts # Layout config (prerender, ssr: false)
β β βββ +page.svelte # Main converter page
β β βββ history/
β β βββ +page.svelte # Conversion history page
β βββ app.html # HTML template
βββ static/
βββ ...
// Using Svelte 5's $state rune for reactive state
class FilesStore {
files = $state<FileInfo[]>([]);
selectedFormat = $state<string>("");
outputDirectory = $state<string>("");
addFiles(newFiles: FileInfo[]) {
this.files = [...this.files, ...newFiles];
}
clear() {
this.files = [];
}
}
export const filesStore = new FilesStore();-- Conversion history
CREATE TABLE conversions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
input_path TEXT NOT NULL,
output_path TEXT NOT NULL,
input_format TEXT NOT NULL,
output_format TEXT NOT NULL,
file_size INTEGER,
status TEXT NOT NULL, -- 'pending', 'processing', 'completed', 'failed'
error_message TEXT,
started_at DATETIME,
completed_at DATETIME,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- User settings
CREATE TABLE settings (
id INTEGER PRIMARY KEY AUTOINCREMENT,
key TEXT UNIQUE NOT NULL,
value TEXT NOT NULL,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);type Conversion struct {
gorm.Model
InputPath string
OutputPath string
InputFormat string
OutputFormat string
FileSize int64
Status string
ErrorMessage string
StartedAt *time.Time
CompletedAt *time.Time
}
type Setting struct {
gorm.Model
Key string `gorm:"uniqueIndex"`
Value string
}- DEBUG: Detailed information for debugging
- INFO: General operational information
- WARN: Warning messages for potential issues
- ERROR: Error conditions that should be addressed
- Console output for development
- File output (
~/.converzen/logs/app.log) for production - Automatic log rotation (configurable size limit)
2024-01-15 10:30:45 [INFO] [converter] Starting conversion: input.mp4 -> output.webm
2024-01-15 10:30:46 [DEBUG] [ffmpeg] Command: ffmpeg -i input.mp4 -c:v libvpx-vp9 output.webm
2024-01-15 10:31:15 [INFO] [converter] Conversion completed successfully
| Input | Output Options |
|---|---|
| MP4 | WebM, AVI, MKV, MOV, GIF |
| WebM | MP4, AVI, MKV, MOV, GIF |
| AVI | MP4, WebM, MKV, MOV, GIF |
| MKV | MP4, WebM, AVI, MOV, GIF |
| MOV | MP4, WebM, AVI, MKV, GIF |
| Input | Output Options |
|---|---|
| PNG | JPG, JPEG, WebP, GIF, BMP, TIFF |
| JPG/JPEG | PNG, WebP, GIF, BMP, TIFF |
| WebP | PNG, JPG, JPEG, GIF, BMP, TIFF |
| GIF | PNG, JPG, JPEG, WebP, BMP, TIFF |
| BMP | PNG, JPG, JPEG, WebP, GIF, TIFF |
| TIFF | PNG, JPG, JPEG, WebP, GIF, BMP |
- Validation Errors: Return structured error with field-specific messages
- Conversion Errors: Log full stack trace, return user-friendly message
- System Errors: Log with context, attempt recovery or graceful degradation
- Display toast notifications for user-actionable errors
- Show detailed error dialogs for conversion failures
- Provide retry options where applicable
- Uses native file dialogs via Wails
- FFmpeg installed via Homebrew or bundled
- App bundle (.app) for distribution
- Uses native file dialogs via Wails
- FFmpeg bundled or installed separately
- NSIS installer for distribution
- Uses native file dialogs via Wails
- FFmpeg installed via package manager
- AppImage or .deb/.rpm for distribution
- File Path Validation: Sanitize all file paths to prevent directory traversal
- Input Validation: Validate file types before processing
- Subprocess Execution: Use proper escaping for FFmpeg commands
- No Network Access: Application operates entirely offline