- Remove Show()/Hide() calls from Layout() method
- These methods must only be called from main UI thread
- Layout() can be called from any thread during resize/redraw
- Show/Hide logic remains in Refresh() which uses DoFromGoroutine
Fixes threading warnings from Fyne when stats bar updates
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Update LoadAppIcon() to search for PNG first (better Linux support)
- Add FyneApp.toml for icon metadata and Windows embedding
- Create VideoTools.desktop for Linux application launcher integration
- Change default window size from 1200x700 to 800x600
- Icon now appears in taskbar, app switcher, and Windows title bar
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
In Progress Tab Enhancements:
- Added animated striped progress bars to in-progress jobs
- Exported ModuleColor function for reuse across modules
- Shows real-time progress (0-100%) with module-specific colors
- Progress updates automatically as jobs run
- Maintains consistent visual style with queue view
Lossless Quality Preset Improvements:
- H.265 and AV1 now support all bitrate modes with lossless quality
- Lossless with Target Size mode now works for H.265/AV1
- H.264 and MPEG-2 no longer show "Lossless" option (codec limitation)
- Dynamic quality dropdown updates based on selected codec
- Automatic fallback to "Near-Lossless" when switching from lossless-capable
codec to non-lossless codec
Quality Options Logic:
- Base options: Draft, Standard, Balanced, High, Near-Lossless
- "Lossless" only appears for H.265 and AV1
- codecSupportsLossless() helper function checks compatibility
- updateQualityOptions() refreshes dropdown when codec changes
Lossless + Bitrate Mode Combinations:
- Lossless + CRF: Forces CRF 0 for perfect quality
- Lossless + CBR: Constant bitrate with lossless quality
- Lossless + VBR: Variable bitrate with lossless quality
- Lossless + Target Size: Calculates bitrate for exact file size with
best possible quality (now allowed for H.265/AV1)
Technical Implementation:
- Added Progress field to ui.HistoryEntry struct
- Exported StripedProgress widget and ModuleColor function
- updateQualityOptions() function dynamically filters quality presets
- updateEncodingControls() handles lossless modes per codec
- Descriptive hints explain each lossless+bitrate combination
This allows professional workflows where lossless quality is desired
but file size constraints still need to be met using Target Size mode.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Features:
- New "In Progress" tab shows running/pending jobs
- Displays active jobs without opening full queue
- Tab positioned first for quick visibility
- Shows "Running..." or "Pending" status
- No delete button on active jobs (only completed/failed)
Implementation:
- Updated BuildHistorySidebar to accept activeJobs parameter
- Converts queue.Job to ui.HistoryEntry for display
- Filters running/pending jobs from queue
- Conditional delete button (nil check)
- Dynamic status text based on job state
UX Improvements:
- Quick glance at current activity without queue view
- Three-tab layout: In Progress → Completed → Failed
- Consistent styling with existing history entries
- Tappable entries to view full job details
This allows users to monitor active conversions directly
from the history sidebar, reducing the need to constantly
check the full job queue view.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Features:
- Add "×" delete button to each history entry in sidebar
- Click to remove individual entries from history
- Automatically saves and refreshes sidebar after deletion
Bug Fixes:
- Fix nil pointer crash when opening Convert module
- Fixed widget initialization order: bitrateContainer now created
AFTER bitratePresetSelect is initialized
- Prevented "invalid memory address" panic in tabs layout
Technical Details:
- Added deleteHistoryEntry() method to remove entries by ID
- Updated BuildHistorySidebar signature to accept onEntryDelete callback
- Moved bitrateContainer creation from line 5742 to 5794
- All Select widgets now properly initialized before container creation
The crash was caused by bitrateContainer containing a nil
bitratePresetSelect widget, which crashed when Fyne's layout system
called .Visible() during tab initialization.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Integrated history sidebar into main menu with toggle button and split
view layout. Added history details dialog with FFmpeg command copy.
Changes:
- internal/ui/mainmenu.go:
* Updated BuildMainMenu() signature to accept sidebar parameters
* Added "☰ History" toggle button to header
* Implemented HSplit layout (20% sidebar, 80% main) when sidebar visible
- main.go:
* Added "sort" import for showHistoryDetails
* Added showHistoryDetails() method to display job details dialog
* Shows timestamps, config, error messages, FFmpeg command
* "Show in Folder" button (only if output file exists)
* "View Log" button (only if log file exists)
* Updated showMainMenu() to build and pass sidebar
* Implemented sidebar toggle that refreshes main menu
The sidebar can be toggled on/off from the main menu, shows history
entries with filtering by status (Completed vs Failed/Cancelled), and
clicking an entry opens a detailed view with all job information and
the ability to copy the FFmpeg command for manual execution.
🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Added history sidebar UI with tabs for completed and failed jobs.
Created reusable UI components and helpers for displaying history entries.
Changes:
- internal/ui/mainmenu.go:
* Added HistoryEntry type definition
* Added BuildHistorySidebar() for main sidebar UI with tabs
* Added buildHistoryList() and buildHistoryItem() helpers
* Added imports for queue and utils packages
- internal/ui/components.go:
* Moved GetStatusColor() and BuildModuleBadge() here as shared functions
* Added queue and utils imports for shared helpers
- internal/ui/queueview.go:
* Updated to use shared GetStatusColor() and BuildModuleBadge()
* Removed duplicate function definitions
- main.go:
* Updated to use ui.HistoryEntry type throughout
* Updated historyConfig, appState, and all methods to use ui.HistoryEntry
The sidebar displays history entries with:
- Status-colored indicators (green/red/orange)
- Module type badges with colors
- Shortened titles and formatted timestamps
- Separate tabs for "Completed" and "Failed" (includes cancelled)
- Empty state messages when no entries exist
🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Added "Copy Command" button to queue view for running and pending jobs,
allowing users to copy the FFmpeg command to clipboard for manual execution.
Changes:
- internal/ui/queueview.go: Add onCopyCommand parameter and buttons
- main.go: Implement onCopyCommand handler in showQueue()
The handler retrieves the job, generates the FFmpeg command with
INPUT/OUTPUT placeholders using buildFFmpegCommandFromJob(), and copies
it to the clipboard with a confirmation dialog.
🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Implemented the foundation for FFmpeg command copy functionality:
1. Created FFmpegCommandWidget (components.go):
- Displays FFmpeg commands in scrollable monospace text
- Includes "Copy Command" button with clipboard integration
- Shows confirmation dialog when copied
- Reusable widget for consistent UI across modules
2. Created buildFFmpegCommandFromJob() function (main.go):
- Extracts FFmpeg command from queue job config
- Uses INPUT/OUTPUT placeholders for portability
- Handles video filters (deinterlace, crop, scale, aspect, flip, rotate, fps)
- Handles video codecs with hardware acceleration (H.264, H.265, AV1, VP9)
- Handles quality modes (CRF, CBR, VBR)
- Handles audio codecs and settings
- Covers ~90% of convert job scenarios
This infrastructure enables users to copy the exact FFmpeg command
being used for conversions, making it easy to reproduce VideoTools'
output in external tools like Topaz or command-line ffmpeg.
Next phase will integrate this into the Convert module UI, queue view,
and conversion history sidebar.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The queue Stats() method was grouping cancelled and failed jobs together,
causing cancelled jobs to be displayed as "failed" in the status bar.
Updated Stats() to return a separate cancelled count and modified all
callers (updateStatsBar, queueProgressCounts, showMainMenu) to handle
the new return value. Also updated ConversionStatsBar to display
cancelled jobs separately in the status bar.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Increase striped progress bar contrast (light: 90→60, dark: 140→200)
- Increase fill opacity (180→200) for better visibility
- Increase progress bar height from 14px to 20px across both striped and standard bars
- Makes progress bars more visible and easier to read at a glance
The striped gradient now has much clearer distinction between light and dark
stripes, and the increased thickness makes progress easier to track visually.
Removed cancelRunningLocked() call from Clear() method.
Now 'Clear Completed' only removes completed/failed/cancelled jobs
and preserves pending/running/paused jobs.
Previously it was cancelling active jobs before filtering, causing
running jobs (like merges) to be removed from the queue.
Enhances screenshot module with comprehensive technical metadata display including audio bitrate, adds 8px padding between thumbnails for professional contact sheets. Implements new Player module for video playback access. Adds complete Filters and Upscale modules with traditional FFmpeg scaling methods (Lanczos, Bicubic, Spline, Bilinear) and resolution presets (720p-8K). Introduces configurable snippet length (5-60s, default 20s) with batch generation capability for all loaded videos. Fixes snippet duration precision by re-encoding instead of stream copy to ensure frame-accurate cutting at configured length.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Fixed Thumbnail Count Issue:
- Changed frame selection from hardcoded 30fps to timestamp-based
- Now uses gte(t,timestamp) filter for accurate frame selection
- This fixes the issue where 5x8 grid only generated 34 instead of 40 thumbnails
Improved Contact Sheet Display:
- Reduced thumbnail width from 320px to 200px for better window fit
- Changed background color from black to app theme (#0B0F1A)
- Contact sheets now match the VideoTools dark blue theme
Added Viewing Capability:
- New "View Results" button in thumbnail module
- Contact sheet mode: Shows image in full-screen dialog (900x700)
- Individual mode: Opens thumbnail folder in file manager
- Button checks if output exists before showing
- Provides user-friendly messages when no results found
Benefits:
- Correct number of thumbnails generated for any grid size
- Contact sheets fit better in display window
- Visual consistency with app theme
- Easy access to view generated results within the app
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Fixed Issues:
- Exit 234 error: Added font parameter to drawtext filter for individual
thumbnails (was missing, causing FFmpeg to fail)
- Output directory: Changed from temp to video's directory, creating a
folder named "{video}_thumbnails" next to the source file
New Features:
- Added video preview window to thumbnail module (640x360)
- Split layout: preview on left (55%), settings on right (45%)
- Preview uses same buildVideoPane as other modules for consistency
The thumbnail module now has a proper preview window for reviewing
the loaded video before generating thumbnails, and outputs are saved
in a logical location next to the source file.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Updated FFmpeg drawtext filter to use DejaVu Sans Mono for metadata
text on contact sheets. This matches the monospace font style used
throughout the VideoTools UI.
DejaVu Sans Mono is widely available across Linux, macOS, and Windows,
ensuring consistent appearance across platforms.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Implemented metadata header rendering on contact sheets showing:
- Filename and file size
- Video resolution and duration
Uses FFmpeg pad and drawtext filters to create an 80px header area
with white text on black background.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
New Features:
- Thumbnail extraction package with FFmpeg integration
- Individual thumbnails or contact sheet generation
- Configurable thumbnail count (3-50 thumbnails)
- Adjustable thumbnail width (160-640 pixels)
- Contact sheet mode with customizable grid (2-10 columns/rows)
- Timestamp overlay on thumbnails
- Auto-open generated thumbnails folder
Technical Implementation:
- internal/thumbnail package with generator
- FFmpeg-based frame extraction
- Video duration and dimension detection
- Aspect ratio preservation
- JPEG quality control
- PNG lossless option support
UI Features:
- Thumbnail module in main menu (Orange tile)
- Load video via file picker
- Real-time configuration sliders
- Contact sheet toggle with grid controls
- Generate button with progress feedback
- Success dialog with folder open option
Integration:
- Added to module routing system
- State management for thumb module
- Proper Fyne threading with DoFromGoroutine
- Cross-platform folder opening support
Module is fully functional and ready for testing.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Created core interlacing detection system using FFmpeg's idet filter.
Features:
- Analyze videos for interlacing using FFmpeg idet filter
- Parse TFF, BFF, Progressive, and Undetermined frame counts
- Calculate interlacing percentage and confidence level
- Determine field order (TFF/BFF/Mixed/Progressive)
- Generate recommendations for deinterlacing
- Quick analysis mode (first 500 frames) for speed
- Full video analysis option
- Preview generation: deinterlaced frame or side-by-side comparison
Detection Results include:
- Status: Progressive / Interlaced / Mixed Content
- Interlacing %: Portion of frames that are interlaced
- Field Order: Top Field First, Bottom Field First, or Unknown
- Confidence: High/Medium/Low based on undetermined frames
- Recommendation: Human-readable guidance
- Suggested filter: yadif, bwdif, etc.
Next: UI integration in Convert and Inspect modules
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The progress bar was configured with Max=100 but we were setting
values in the 0.0-1.0 range, causing it to always show ~0%.
Fixed by multiplying the percentage by 100 before setting the value,
so 4/22 = 0.18 becomes 18% instead of 0.18%.
Also fixed SetComplete() to set 100.0 instead of 1.0.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
All UI updates from the benchmark goroutine were causing threading
errors because they weren't wrapped in DoFromGoroutine. Fixed:
- UpdateProgress: progress bar and label updates
- AddResult: adding result cards to the display
- SetComplete: final status updates
These methods are called from background goroutines running the
benchmark tests, so all UI updates must be dispatched to the main
thread using fyne.CurrentApp().Driver().DoFromGoroutine().
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Extended the benchmark system to maintain a complete history of all
benchmark runs (up to last 10) with full results for each encoder/preset
combination tested.
Features:
- Stores complete benchmark run data including all test results
- History browser UI to view past benchmark runs
- Click any run to see detailed results for all encoders tested
- Compare performance across different presets and encoders
- Apply recommendations from past benchmarks
- Automatic history limit (keeps last 10 runs)
UI Changes:
- Renamed "Benchmark" button to "Run Benchmark"
- Added "View Results" button to main menu
- New benchmark history view showing all past runs
- Each run displays timestamp, recommended encoder, and test count
- Clicking a run shows full results with all encoder/preset combinations
Data Structure:
- benchmarkRun: stores single test run with all results
- benchmarkConfig: maintains array of benchmark runs
- Saves to ~/.config/VideoTools/benchmark.json
This allows users to review past benchmark results and make informed
decisions about which encoder settings to use by comparing FPS across
all available options on their hardware.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Implemented a full benchmark system that automatically detects available
hardware encoders, tests them with different presets, measures FPS
performance, and recommends optimal settings for the user's system.
Features:
- Automatic test video generation (30s 1080p test pattern)
- Hardware encoder detection (NVENC, QSV, AMF, VideoToolbox)
- Comprehensive encoder testing across multiple presets
- Real-time progress UI with live results
- Performance scoring based on FPS metrics
- Top 10 results display with recommendation
- Config persistence for benchmark results
- One-click apply to use recommended settings
UI Components:
- Benchmark button in main menu header
- Progress view showing current test and results
- Final results view with ranked encoders
- Apply/Close actions for recommendation
Integration:
- Added to main menu between "Benchmark" and "Logs" buttons
- Saves results to ~/.config/VideoTools/benchmark.json
- Comprehensive debug logging for troubleshooting
This allows users to optimize their encoding settings based on their
specific hardware capabilities rather than guessing which encoder
will work best.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The issue was that FFmpeg's out_time_ms field is actually in microseconds
(not milliseconds despite the name). We were dividing by 1,000 when we
should have been dividing by 1,000,000 to convert to seconds.
This caused the progress calculation to be off by 1000x, making it
immediately jump to 100% even though the job was just starting.
Also added comprehensive debug logging to track progress samples and
identify calculation issues in the future.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Long FFmpeg error messages were pushing the queue UI off screen, making
the interface unusable when jobs failed with verbose errors.
Changes:
- Truncate error messages to 150 characters maximum in status text
- Add helpful message indicating full error is available via Copy Error button
- Enable text wrapping on status labels to handle multi-line content gracefully
- Prevents UI layout breakage while maintaining error visibility
Users can still access the full error message via:
- Copy Error button (copies full error to clipboard)
- View Log button (opens per-job conversion log)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>