diff --git a/BUGS.md b/BUGS.md index a145447..a68a568 100644 --- a/BUGS.md +++ b/BUGS.md @@ -2,7 +2,7 @@ Track all bugs, issues, and behavioral problems here. Update this file whenever you discover or fix a bug. -**Last Updated**: 2026-01-05 16:05 UTC +**Last Updated**: 2026-01-06 19:35 UTC --- @@ -59,7 +59,22 @@ Track all bugs, issues, and behavioral problems here. Update this file whenever ## 🟠 High Priority Bugs (Major Issues) -None currently open. +### BUG-010: Upscale jobs show no progress during FFmpeg conversions +- **Status**: ✅ FIXED (2026-01-06, needs verification) +- **Reporter**: Jake (2026-01-06) +- **Module**: Upscale / Queue +- **Description**: Upscale jobs that rely on FFmpeg conversions stay at 0.0% progress even while running; status updates do not advance until completion. +- **Steps to Reproduce**: + 1. Run Upscale job that uses FFmpeg conversion + 2. Observe queue progress + 3. Expected: Progress updates during conversion + 4. Actual: Progress remains 0.0% until completion +- **Impact**: High - No feedback during long-running jobs +- **Root Cause**: FFmpeg progress parsing relied on stderr time updates; piped output used CR-only updates. +- **Files to Check**: + - `main.go:executeUpscaleJob` (progress pipe parsing) +- **Fixed By**: Codex +- **Verified**: No --- @@ -75,6 +90,26 @@ None currently open. --- +## 🧭 Feature Requests (Planned) + +### FEAT-003: Enhancement module blur control +- **Status**: 🧭 PLANNED +- **Reporter**: Jake (2026-01-06) +- **Module**: Enhancement +- **Description**: Enhancement panel should include a blur control in addition to sharpen/denoise. +- **Impact**: Medium - expected control in enhancement workflow +- **Notes**: Add to enhancement UI alongside existing sliders. + +### FEAT-004: Upscale output quality should use Bitrate Mode controls +- **Status**: 🧭 PLANNED +- **Reporter**: Jake (2026-01-06) +- **Module**: Upscale +- **Description**: Replace Upscale "Output Quality" with the Bitrate Mode controls used in Convert Advanced. +- **Impact**: Medium - consistent workflow across modules +- **Notes**: Reuse Convert bitrate UI pattern once state manager is stable. + +--- + ## ✅ Recently Fixed (Last 7 Days) ### BUG-001: Quality Preset showing in CBR/VBR modes (should only show in CRF) diff --git a/WORKING_ON.md b/WORKING_ON.md index 0d6f365..3cb9837 100644 --- a/WORKING_ON.md +++ b/WORKING_ON.md @@ -2,13 +2,13 @@ This file tracks what each agent is currently working on to prevent conflicts and coordinate changes. -**Last Updated**: 2026-01-04 21:10 UTC +**Last Updated**: 2026-01-06 19:05 UTC --- ## 🔴 Current Blockers -- **Build Status**: ✅ PASSING +- **Build Status**: ❌ FAILING (main.go syntax errors introduced by unified player changes) - **Critical Bug**: BUG-005 - CRF quality settings not showing when CRF mode selected (see BUGS.md) --- @@ -59,7 +59,7 @@ This file tracks what each agent is currently working on to prevent conflicts an --- ### 🤖 opencode -**Status**: 🎯 PRIORITY HANDOFF - Fix critical bug + widget deduplication +**Status**: 🧩 IN PROGRESS - Unified player integration + CRF fixes **🔥 IMMEDIATE TASKS** (from Claude): 1. **FIX BUG-005** (CRITICAL): CRF quality settings not showing @@ -116,6 +116,20 @@ This file tracks what each agent is currently working on to prevent conflicts an --- +### 🤖 Codex (UI focus) +**Status**: 🧱 ACTIVE - UI palette separation + state manager scaffolding + +**Working On Now** (2026-01-06): +- ✅ Added `internal/state/convert_manager.go` (state manager scaffolding for Convert) +- ✅ Updated codec palette separation to make format/audio/video colors more distinct + +**Next for Codex**: +1. Wire `ConvertManager` into convert UI (quality + bitrate mode visibility) +2. Validate CRF visibility paths once build passes +3. Review any cross-category color clashes in dropdown lists + +--- + ## 📝 Shared Files - Coordinate Before Modifying! These files are touched by multiple agents - check this file before editing: diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index be520eb..d5a24a8 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -28,11 +28,16 @@ This roadmap is intentionally lightweight. It captures the next few high-priorit - **Enhancement module foundation** - DEPENDS ON PLAYER - Unified Filters + Upscale workflow - Content-type aware processing (general/anime/film) + - Add blur control alongside sharpen/denoise - AI model management system (extensible for future models) - Multi-pass processing pipeline - Before/after preview system - Real-time enhancement feedback +- **Upscale workflow parity** + - Replace Upscale output quality with Convert-style Bitrate Mode controls + - Ensure FFmpeg-based upscale jobs report progress in queue + ## Next (dev25+) - **Enhancement module completion** - DEPENDS ON PLAYER diff --git a/internal/state/convert_manager.go b/internal/state/convert_manager.go new file mode 100644 index 0000000..dfaad65 --- /dev/null +++ b/internal/state/convert_manager.go @@ -0,0 +1,117 @@ +package state + +import ( + "strings" + "sync" +) + +// ConvertManager centralizes convert UI state and change notifications. +// It is intentionally UI-agnostic; widgets should subscribe via callbacks. +type ConvertManager struct { + mu sync.RWMutex + quality string + bitrateMode string + manualQualityOption string + onQualityChange []func(string) + onBitrateModeChange []func(string) +} + +func NewConvertManager(quality, bitrateMode, manualQualityOption string) *ConvertManager { + if strings.TrimSpace(manualQualityOption) == "" { + manualQualityOption = "Manual (CRF)" + } + return &ConvertManager{ + quality: quality, + bitrateMode: bitrateMode, + manualQualityOption: manualQualityOption, + } +} + +func (m *ConvertManager) Quality() string { + m.mu.RLock() + defer m.mu.RUnlock() + return m.quality +} + +func (m *ConvertManager) BitrateMode() string { + m.mu.RLock() + defer m.mu.RUnlock() + return m.bitrateMode +} + +func (m *ConvertManager) ManualQualityOption() string { + m.mu.RLock() + defer m.mu.RUnlock() + return m.manualQualityOption +} + +func (m *ConvertManager) SetQuality(val string) bool { + m.mu.Lock() + if m.quality == val { + m.mu.Unlock() + return false + } + m.quality = val + callbacks := append([]func(string){}, m.onQualityChange...) + m.mu.Unlock() + + for _, cb := range callbacks { + cb(val) + } + return true +} + +func (m *ConvertManager) SetBitrateMode(val string) bool { + m.mu.Lock() + if m.bitrateMode == val { + m.mu.Unlock() + return false + } + m.bitrateMode = val + callbacks := append([]func(string){}, m.onBitrateModeChange...) + m.mu.Unlock() + + for _, cb := range callbacks { + cb(val) + } + return true +} + +func (m *ConvertManager) OnQualityChange(fn func(string)) { + if fn == nil { + return + } + m.mu.Lock() + m.onQualityChange = append(m.onQualityChange, fn) + m.mu.Unlock() +} + +func (m *ConvertManager) OnBitrateModeChange(fn func(string)) { + if fn == nil { + return + } + m.mu.Lock() + m.onBitrateModeChange = append(m.onBitrateModeChange, fn) + m.mu.Unlock() +} + +func (m *ConvertManager) IsManualQuality() bool { + m.mu.RLock() + defer m.mu.RUnlock() + return m.quality == m.manualQualityOption +} + +func NormalizeBitrateMode(mode string) string { + switch { + case strings.HasPrefix(mode, "CRF"): + return "CRF" + case strings.HasPrefix(mode, "CBR"): + return "CBR" + case strings.HasPrefix(mode, "VBR"): + return "VBR" + case strings.HasPrefix(mode, "Target Size"): + return "Target Size" + default: + return mode + } +} diff --git a/internal/ui/colors.go b/internal/ui/colors.go index d34268f..dba4094 100644 --- a/internal/ui/colors.go +++ b/internal/ui/colors.go @@ -12,43 +12,43 @@ import ( // Container / Format Colors (File Wrapper) var ( - ColorMKV = utils.MustHex("#0EA5E9") // Blue-Sky - Flexible container + ColorMKV = utils.MustHex("#2563EB") // Deep Blue - Flexible container ColorRemux = utils.MustHex("#9CA3AF") // Neutral Grey - Lossless remux - ColorMP4 = utils.MustHex("#2563EB") // Deep Blue - Consumer-friendly - ColorMOV = utils.MustHex("#7C3AED") // Violet - Pro / Apple lineage - ColorAVI = utils.MustHex("#6B7280") // Grey - Legacy container - ColorWEBM = utils.MustHex("#10B981") // Emerald - Web-native - ColorTS = utils.MustHex("#F59E0B") // Amber - Broadcast / transport streams - ColorM2TS = utils.MustHex("#F97316") // Orange - Broadcast / transport streams + ColorMP4 = utils.MustHex("#1D4ED8") // Navy Blue - Consumer-friendly + ColorMOV = utils.MustHex("#6366F1") // Indigo - Pro / Apple lineage + ColorAVI = utils.MustHex("#64748B") // Slate - Legacy container + ColorWEBM = utils.MustHex("#059669") // Emerald - Web-native + ColorTS = utils.MustHex("#D97706") // Amber - Broadcast / transport streams + ColorM2TS = utils.MustHex("#EA580C") // Orange - Broadcast / transport streams ) // Video Codec Colors (Compression Method) // Modern / Efficient Codecs var ( ColorAV1 = utils.MustHex("#22C55E") // Green - Modern, efficient - ColorHEVC = utils.MustHex("#A855F7") // Purple - Modern, efficient - ColorH265 = utils.MustHex("#A855F7") // Purple - Same as HEVC - ColorVP9 = utils.MustHex("#14B8A6") // Teal - Modern, efficient + ColorHEVC = utils.MustHex("#0D9488") // Teal - Modern, efficient + ColorH265 = utils.MustHex("#0D9488") // Teal - Same as HEVC + ColorVP9 = utils.MustHex("#06B6D4") // Cyan - Modern, efficient ) // Established / Legacy Video Codecs var ( - ColorH264 = utils.MustHex("#3B82F6") // Blue - Compatibility - ColorAVC = utils.MustHex("#3B82F6") // Blue - Same as H.264 - ColorMPEG2 = utils.MustHex("#EAB308") // Yellow-Amber - Legacy / broadcast - ColorDivX = utils.MustHex("#F97316") // Orange - Legacy - ColorXviD = utils.MustHex("#F97316") // Orange - Legacy - ColorMPEG4 = utils.MustHex("#F97316") // Orange - Legacy + ColorH264 = utils.MustHex("#38BDF8") // Sky - Compatibility + ColorAVC = utils.MustHex("#38BDF8") // Sky - Same as H.264 + ColorMPEG2 = utils.MustHex("#FBBF24") // Amber - Legacy / broadcast + ColorDivX = utils.MustHex("#FB7185") // Rose - Legacy + ColorXviD = utils.MustHex("#FB7185") // Rose - Legacy + ColorMPEG4 = utils.MustHex("#FB7185") // Rose - Legacy ) // Audio Codec Colors (Secondary but Distinct) var ( - ColorOpus = utils.MustHex("#EC4899") // Magenta - Modern audio - ColorAAC = utils.MustHex("#F59E0B") // Amber - Common audio - ColorFLAC = utils.MustHex("#8B5CF6") // Violet - Lossless audio + ColorOpus = utils.MustHex("#DB2777") // Magenta - Modern audio + ColorAAC = utils.MustHex("#FB7185") // Rose - Common audio + ColorFLAC = utils.MustHex("#C084FC") // Violet - Lossless audio ColorMP3 = utils.MustHex("#EF4444") // Red - Legacy audio - ColorAC3 = utils.MustHex("#22C55E") // Green - Surround audio - ColorVorbis = utils.MustHex("#06B6D4") // Cyan - Open codec + ColorAC3 = utils.MustHex("#F59E0B") // Amber - Surround audio + ColorVorbis = utils.MustHex("#F97316") // Orange - Open codec ) // Pixel Format / Colour Data (Technical Metadata)