Skip to content

Instantly share code, notes, and snippets.

@gianpaj
Created February 7, 2026 02:48
Show Gist options
  • Select an option

  • Save gianpaj/f722903768ebf39652e10e8e259d57bb to your computer and use it in GitHub Desktop.

Select an option

Save gianpaj/f722903768ebf39652e10e8e259d57bb to your computer and use it in GitHub Desktop.

AudioSlim - Full App Implementation Plan

Context

AudioSlim is a Tauri v2 desktop app for converting/compressing audio files using ffmpeg. The current state is a minimal scaffold: a single convert_to_mp3 Rust command with a hardcoded file path in the React frontend. The goal is to build a complete, usable app that supports multiple files, multiple output formats, and ffmpeg compression options.

Approach: System ffmpeg (not bundled). Output files saved alongside input files. Sequential file processing (ffmpeg is already multi-threaded internally). Show before/after file sizes after conversion.


Phase 1: Configuration & Dependencies

1.1 Update src-tauri/tauri.conf.json

  • productName"AudioSlim", identifier"com.audioslim.app"
  • Window: title → "AudioSlim", size 900x700, add minWidth: 600, minHeight: 500

1.2 Update src-tauri/Cargo.toml

  • name"audioslim", description"Audio file converter and compressor"
  • [lib] name"audioslim_lib"
  • Add dep: tauri-plugin-dialog = "2"

1.3 Update src-tauri/src/main.rs

  • Change tauri_app_lib::run()audioslim_lib::run()

1.4 Update package.json

  • name"audioslim"
  • Add dep: @tauri-apps/plugin-dialog: "~2"

1.5 Run pnpm add @tauri-apps/plugin-dialog

1.6 Update index.html title → "AudioSlim"

1.7 Update src-tauri/capabilities/default.json

  • Add "dialog:default" to permissions array

Phase 2: Rust Backend (src-tauri/src/lib.rs)

Rewrite the file completely. Remove commented-out template code, remove duplicate windows_subsystem attr.

2.1 Data structures

  • OutputFormat enum: mp3, wav, aac, ogg, flac, m4a, mp4 (with extension() method)
  • ConversionOptions struct: format, bitrate (Option), sample_rate (Option), channels (Option), quality (Option)
  • ConversionProgress struct: file_path, status, output_path, error, index, total, input_size (Option), output_size (Option)

2.2 check_ffmpeg command

  • Run ffmpeg -version, return first line or error if not found

2.3 build_ffmpeg_args helper function

  • Build ffmpeg CLI args from ConversionOptions
  • Handle format-specific codecs: aac/m4a/mp4 → -c:a aac, ogg → -c:a libvorbis, mp4 → also -vn
  • Handle quality: mp3/ogg → -q:a, flac → -compression_level
  • Always include -y (overwrite) flag

2.4 convert_audio command

  • Takes input_paths: Vec<String>, options: ConversionOptions, output_dir: Option<String>
  • Process files sequentially using tokio::spawn_blocking for the ffmpeg call
  • Emit conversion-progress events via app.emit() after each file
  • Include input/output file sizes in progress events (using std::fs::metadata)
  • Handle same-format collision: append _converted to output filename
  • Validate input file exists before converting
  • Continue processing on per-file errors (don't abort batch)

2.5 Update run() function

  • Register plugins: tauri_plugin_fs, tauri_plugin_dialog, tauri_plugin_shell
  • Register commands: check_ffmpeg, convert_audio

Phase 3: React Frontend

3.1 Create src/types.ts

  • Types: OutputFormat, ConversionOptions, FileStatus, AudioFile (includes inputSize/outputSize), ConversionProgress
  • FORMAT_CONFIGS map: per-format config for which options are available, default values, ranges
    • mp3: bitrate (64k-320k, default 192k), VBR quality (0-9)
    • wav: no bitrate, no quality
    • aac/m4a/mp4: bitrate only
    • ogg: bitrate, quality (-1 to 10)
    • flac: compression level (0-8)
    • All formats: sample rate, channels

3.2 Create src/components/DropZone.tsx

  • Tauri native drag-and-drop via getCurrentWebview().onDragDropEvent()
  • "Choose Files" button using open() from @tauri-apps/plugin-dialog
  • Filter by audio extensions: wav, mp3, ogg, flac, aac, m4a, mp4, wma, aiff
  • Returns full filesystem paths (not browser File objects)

3.3 Create src/components/FormatSelector.tsx

  • Row of buttons for: MP3, WAV, AAC, OGG, FLAC, M4A, MP4
  • Highlighted active selection

3.4 Create src/components/OptionsPanel.tsx

  • Dynamically shows relevant options based on selected format (uses FORMAT_CONFIGS)
  • Bitrate: dropdown (64k, 128k, 192k, 256k, 320k) — only for lossy formats
  • Sample rate: dropdown (22050, 44100, 48000, 96000) + "Default" option
  • Channels: dropdown (Mono, Stereo) + "Default" option
  • Quality: range slider — only when format supports it, with format-specific label

3.5 Create src/components/FileList.tsx

  • Shows selected files with per-file status (Ready, Converting..., Done, Error)
  • When done: show original size → output size (e.g. "4.2 MB → 1.1 MB") with human-readable formatting
  • Remove button per file (when pending)
  • "Clear All" button
  • Color-coded status indicators

3.6 Create src/components/ConvertButton.tsx

  • Disabled when no files or converting in progress
  • Shows file count in label

3.7 Rewrite src/App.tsx

  • State: files[], format, options, isConverting, ffmpegStatus/Error
  • useEffect on mount: invoke check_ffmpeg, show error banner if missing
  • useEffect: listen to conversion-progress events, update file statuses
  • handleFormatChange: reset options to format defaults
  • handleFilesSelected: deduplicate by path, append to list
  • handleConvert: invoke convert_audio with all file paths + options
  • Compose all components in order: DropZone → FileList → FormatSelector → OptionsPanel → ConvertButton

Phase 4: Styling (src/App.css)

Rewrite completely. Clean, minimal design:

  • CSS custom properties for theming (colors, spacing, border-radius)
  • Dark mode via prefers-color-scheme: dark
  • .dropzone: dashed border, centered content, active state (blue) when dragging
  • .format-buttons: horizontal row, pill-shaped buttons, active state filled
  • .options-panel: 2-column grid for option groups
  • .file-list: scrollable list, status color-coding (gray/blue/green/red)
  • .convert-btn: large prominent button
  • .error-banner: red-tinted box for ffmpeg-missing state

Phase 5: Polish

5.1 Same-format collision handling (in Rust)

5.2 Input file existence validation (in Rust)

5.3 Update README.md — add ffmpeg prerequisite, supported formats, usage

5.4 Update AGENTS.md if needed


Files Summary

File Action
src-tauri/tauri.conf.json Modify
src-tauri/Cargo.toml Modify
src-tauri/src/main.rs Modify
src-tauri/src/lib.rs Rewrite
src-tauri/capabilities/default.json Modify
package.json Modify
index.html Modify
src/types.ts Create
src/App.tsx Rewrite
src/App.css Rewrite
src/components/DropZone.tsx Create
src/components/FormatSelector.tsx Create
src/components/OptionsPanel.tsx Create
src/components/FileList.tsx Create
src/components/ConvertButton.tsx Create

Verification

  1. pnpm tauri dev — app launches without errors
  2. ffmpeg version shown on startup (or error banner if not installed)
  3. Drag audio files onto window — they appear in file list
  4. Click "Choose Files" — native dialog opens, filtered to audio files
  5. Select different formats — options panel updates dynamically
  6. Click Convert — files process sequentially with real-time status updates
  7. Output files appear in same directory as inputs
  8. Test error case: select a non-existent file path, verify graceful error per-file
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment