Created step-by-step guide for modularizing main.go: - 9 modules to extract in priority order (least → most important) - Filters first (easiest), Convert last (most critical) - Clear instructions for each extraction - Reference patterns from existing modules - Success criteria and testing steps - Emergency rollback procedures Module extraction order: 1. filters_module.go (~236 lines) - Simple UI 2. upscale_module.go (~1200 lines) - AI integration 3. thumb_module.go (~400 lines) - Thumbnail generation 4. player_module.go (~800 lines) - Playback system 5. compare_module.go (~550 lines) - File comparison 6. merge_module.go (~700 lines) - File merging 7. benchmark_module.go (~400 lines) - Encoder benchmarks 8. queue_module.go (~500 lines) - Job queue 9. convert_module.go (~6400 lines) - Most critical, do last Goal: Reduce main.go from 14,116 → ~4,000 lines Expected: Windows build time 5+ min → <2 min Each module extraction is independent and testable. Pattern established with inspect_module.go (already done). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
11 KiB
Main.go Modularization - Incremental Refactoring Prompt
Current State
Problem: main.go is 14,116 lines (420KB) causing:
- 5+ minute builds on Windows
- Poor code maintainability
- Difficult to navigate and modify
Goal: Extract modules into separate files following established patterns
Already Extracted:
- ✅
author_module.go(1,421 lines) - Pattern reference - ✅
subtitles_module.go(756 lines) - Pattern reference - ✅
inspect_module.go(292 lines) - Pattern reference
Remaining: 9 modules to extract (~10,000 lines)
Extraction Order (Least Important → Most Important)
Work through these one module at a time, testing after each extraction:
Phase 1: Simple Modules (Start Here)
-
filters_module.go (~236 lines)
- Lines: ~13261-13497
- Functions:
showFiltersView(),buildFiltersView() - State fields:
filtersFile,filterBrightness,filterContrast, etc. - Why first: Simple UI-only, no job execution
-
upscale_module.go (~889 lines + job executor)
- Lines: ~13498-14387 + job executor at ~4568-5023
- Functions:
showUpscaleView(),buildUpscaleView(),executeUpscaleJob(), AI helpers - State fields: All
upscale*fields (~25 fields) - Includes: AI backend detection, model helpers
-
thumb_module.go (~335 lines + job executor)
- Lines: ~12837-13172 + executeThumbJob at ~4222-4264
- Functions:
showThumbView(),buildThumbView(),executeThumbJob() - State fields:
thumbFile,thumbCount,thumbWidth, etc.
Phase 2: Moderate Complexity
-
player_module.go (~87 lines + playSession ~450 lines)
- Lines: ~13173-13260 + playSession at ~8929-9329
- Functions:
showPlayerView(),buildPlayerView(),stopPlayer(), entireplaySessiontype - State fields:
playerFile,player,playerReady,playerVolume, etc. - Types:
playSession,playerSurface,playSessionmethods - Note: Includes recent performance improvements
-
compare_module.go (~503 lines + fullscreen)
- Lines: ~12068-12571 + fullscreen at ~14277-14387
- Functions:
showCompareView(),buildCompareView(),buildCompareFullscreenView(),showCompareFullscreen() - State fields:
compareFile1,compareFile2,autoCompare
Phase 3: Complex Infrastructure
-
merge_module.go (~374 lines + job executor)
- Lines: ~2752-3126 + executeMergeJob at ~3232-3564
- Functions:
showMergeView()(inline UI builder),addMergeToQueue(),executeMergeJob() - State fields:
mergeClips,mergeFormat,mergeOutput, etc. - Types:
mergeClipstruct - Note: UI builder is inline, needs extraction to
buildMergeView()
-
benchmark_module.go (~326 lines)
- Lines: ~1938-2264 + config persistence at ~700-729
- Functions:
showBenchmark(),showBenchmarkHistory(), benchmark helpers - Types:
benchmarkConfig,benchmarkRun
-
queue_module.go (~scattered functions)
- Functions:
showQueue(),refreshQueueView(),jobExecutor(),buildFFmpegCommandFromJob() - Lines: Various, needs gathering
- Functions:
Phase 4: Most Critical (Do Last)
- convert_module.go (~6,384 lines - THE BIG ONE)
- Lines: ~5683-12067
- Functions: 50+ functions including
buildConvertView(),showConvertView(), all convert helpers - State fields: All
convert*fields,source,loadedVideos, etc. - Types:
convertConfig,formatOption - Shared components:
buildMetadataPanel(),buildVideoPane()(used by other modules) - May need to split into multiple files if > 3000 lines
Instructions for Each Module Extraction
Step-by-Step Process
For each module (do ONE at a time):
1. Create the Module File
File: {module}_module.go (e.g., filters_module.go)
Template:
package main
import (
// Copy imports from main.go that this module needs
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/container"
// ... etc
)
// Move the show{Module}View() method here
func (s *appState) show{Module}View() {
s.stopPreview()
s.lastModule = s.active
s.active = "{module}"
s.setContent(build{Module}View(s))
}
// Move the build{Module}View() function here
func build{Module}View(state *appState) fyne.CanvasObject {
// ... entire function body ...
}
// Move any helper functions specific to this module
// Move any job executor functions (execute{Module}Job)
2. Remove from main.go
Delete the exact same functions you just moved. Use line numbers as guide.
IMPORTANT: Do NOT remove:
- Shared functions used by multiple modules (e.g.,
moduleColor(),probeVideo()) - State fields in
appStatestruct (leave all state in main.go) - Type definitions used across modules
3. Build and Test
# Must succeed
go build -o VideoTools .
# Check line count reduction
wc -l main.go {module}_module.go
# Test the module works
./VideoTools # Navigate to the module and test basic functionality
4. Commit
git add {module}_module.go main.go
git commit -m "Extract {module} module from main.go
- Create {module}_module.go (XXX lines)
- Move show{Module}View() and build{Module}View()
- Reduce main.go by XXX lines
- All tests pass, module functions correctly
"
5. Move to Next Module
Repeat the process for the next module in the order above.
Reference Patterns
Look at these existing extracted modules for the pattern:
Pattern 1: Simple Module (inspect_module.go)
package main
import (
// Necessary imports
)
func (s *appState) showInspectView() {
s.stopPreview()
s.lastModule = s.active
s.active = "inspect"
s.setContent(buildInspectView(s))
}
func buildInspectView(state *appState) fyne.CanvasObject {
// UI building code
}
Pattern 2: Module with Job Executor (subtitles_module.go)
package main
import (
// Necessary imports
)
func (s *appState) showSubtitlesView() {
// ...
}
func buildSubtitlesView(state *appState) fyne.CanvasObject {
// ...
}
func (s *appState) executeSubtitlesJob(ctx context.Context, job *queue.Job, progressCallback func(float64)) error {
// Job execution logic
}
// Helper functions specific to subtitles
Pattern 3: Module with Types (author_module.go)
package main
import (
// ...
)
// Types specific to this module
type authorClip struct {
// ...
}
func (s *appState) showAuthorView() {
// ...
}
// Many helper functions specific to author module
What Stays in main.go
DO NOT MOVE these to module files:
Core Application
main()functionrunGUI()functiontype appState structdefinition (all fields stay)- Window setup and initialization
Shared Utilities (Used by 3+ modules)
moduleColor()- Color scheme helpermoduleFooter()- Footer bar builderstatusStrip()- Status barprobeVideo()- Video file analysis (CRITICAL - used everywhere)buildMetadataPanel()- Used by convert and other modulesbuildVideoPane()- Video preview pane (used by many modules)formatBitrate(),formatClock(), etc. - Format helpers
Navigation & State
showMainMenu()- Main menu buildersetContent()- Content switcher- History sidebar code
- Stats bar updates
- Drop handlers
Shared Types
videoSourcetype and methods- Shared constants and enums
Special Cases & Gotchas
Convert Module (Do Last!)
The convert module is massive and may need splitting:
Option A: Single File (if < 3000 lines after extraction)
convert_module.go
Option B: Split into Multiple Files (if > 3000 lines)
convert_module.go- Main UI and show functionconvert_config.go- Configuration types and persistenceconvert_job.go- Job execution logicconvert_helpers.go- Codec/format helpers
Shared Components:
buildMetadataPanel()andbuildVideoPane()might need to move toshared_ui.goif used by many modules
Merge Module Inline UI
The merge module has UI building inline in showMergeView(). You'll need to:
- Extract inline UI to
buildMergeView()function - Then follow standard pattern
Player Module with playSession
The playSession type and all its methods should move to player_module.go together.
Import Adjustments
Some modules might need internal package imports that aren't in main.go:
- Check for missing imports after extraction
- Run
go buildto catch import errors - Add necessary imports to the module file
Success Criteria for Each Extraction
Before moving to next module, verify:
- ✅
go buildsucceeds with no errors - ✅ Module file has clear structure (show function, build function, helpers)
- ✅ main.go reduced by expected lines
- ✅ Module works when tested in GUI
- ✅ No duplicate code between main.go and module file
- ✅ Git commit created with clear message
- ✅ Can navigate to module and use basic features
Tracking Progress
After each extraction, update this checklist:
- 1. filters_module.go (~236 lines)
- 2. upscale_module.go (~1200 lines)
- 3. thumb_module.go (~400 lines)
- 4. player_module.go (~800 lines)
- 5. compare_module.go (~550 lines)
- 6. merge_module.go (~700 lines)
- 7. benchmark_module.go (~400 lines)
- 8. queue_module.go (~500 lines)
- 9. convert_module.go (~6400 lines - may split)
Target: main.go from 14,116 lines → ~4,000 lines
Expected Timeline
- Simple modules (1-3): 20-30 min each
- Moderate modules (4-5): 30-45 min each
- Complex modules (6-8): 45-60 min each
- Convert module (9): 2-3 hours (largest, most critical)
Total: ~8-12 hours of incremental work
Final Build Performance Goal
After all extractions:
Before:
- main.go: 14,329 lines (426KB)
- Build time (Windows): 5+ minutes
After:
- main.go: ~4,000 lines (~120KB)
- Module files: 10-12 files (~800-1500 lines each)
- Build time (Windows): < 2 minutes (hopefully < 1 minute)
Questions to Ask If Stuck
-
"Does this function use state from multiple modules?"
- Yes → Keep in main.go
- No → Move to module file
-
"Is this function called by 3+ different modules?"
- Yes → Keep in main.go as shared utility
- No → Move to the module that uses it
-
"Is this a type used across modules?"
- Yes → Keep type definition in main.go
- No → Move to module file
-
"Where are the line numbers for this module?"
- Check this document's module listing
- Use grep to find function:
grep -n "func buildXView" main.go
Emergency Rollback
If an extraction breaks the build:
# Restore main.go from backup
git checkout HEAD -- main.go
# Remove the broken module file
rm {module}_module.go
# Try again with more care
Start Here
First module to extract: filters_module.go
- Find lines ~13261-13497 in main.go
- Create
filters_module.go - Copy
showFiltersView()andbuildFiltersView() - Remove from main.go
- Build, test, commit
- Move to next module
Good luck! Take it one module at a time, test after each extraction, and the convert module will be much easier once you've established the pattern with the simpler modules.