Remove logs dialog from main menu
This commit is contained in:
parent
e1f5ab9d27
commit
a7439c0d5d
228
main.go
228
main.go
|
|
@ -694,8 +694,8 @@ type appState struct {
|
||||||
compareFile2 *videoSource
|
compareFile2 *videoSource
|
||||||
inspectFile *videoSource
|
inspectFile *videoSource
|
||||||
inspectInterlaceResult *interlace.DetectionResult
|
inspectInterlaceResult *interlace.DetectionResult
|
||||||
inspectInterlaceAnalyzing bool
|
inspectInterlaceAnalyzing bool
|
||||||
autoCompare bool // Auto-load Compare module after conversion
|
autoCompare bool // Auto-load Compare module after conversion
|
||||||
convertCommandPreviewShow bool // Show FFmpeg command preview in Convert module
|
convertCommandPreviewShow bool // Show FFmpeg command preview in Convert module
|
||||||
|
|
||||||
// Merge state
|
// Merge state
|
||||||
|
|
@ -1350,38 +1350,7 @@ func (s *appState) showMainMenu() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
menu := ui.BuildMainMenu(mods, s.showModule, s.handleModuleDrop, s.showQueue, func() {
|
menu := ui.BuildMainMenu(mods, s.showModule, s.handleModuleDrop, s.showQueue, nil, s.showBenchmark, s.showBenchmarkHistory, func() {
|
||||||
logDir := getLogsDir()
|
|
||||||
_ = os.MkdirAll(logDir, 0o755)
|
|
||||||
|
|
||||||
openFolderBtn := widget.NewButton("Open Logs Folder", func() {
|
|
||||||
if err := openFolder(logDir); err != nil {
|
|
||||||
dialog.ShowError(fmt.Errorf("failed to open logs folder: %w", err), s.window)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
appLogPath := strings.TrimSpace(logging.FilePath())
|
|
||||||
viewAppLogBtn := widget.NewButton("View App Log", func() {
|
|
||||||
if appLogPath == "" {
|
|
||||||
dialog.ShowInformation("No Log", "No app log file found yet.", s.window)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.openLogViewer("App Log", appLogPath, false)
|
|
||||||
})
|
|
||||||
if appLogPath == "" {
|
|
||||||
viewAppLogBtn.Disable()
|
|
||||||
}
|
|
||||||
|
|
||||||
infoLabel := widget.NewLabel(fmt.Sprintf("Logs directory: %s", logDir))
|
|
||||||
infoLabel.Wrapping = fyne.TextWrapWord
|
|
||||||
|
|
||||||
logOptions := container.NewVBox(
|
|
||||||
infoLabel,
|
|
||||||
openFolderBtn,
|
|
||||||
viewAppLogBtn,
|
|
||||||
)
|
|
||||||
dialog.ShowCustom("Logs", "Close", logOptions, s.window)
|
|
||||||
}, s.showBenchmark, s.showBenchmarkHistory, func() {
|
|
||||||
// Toggle sidebar
|
// Toggle sidebar
|
||||||
s.sidebarVisible = !s.sidebarVisible
|
s.sidebarVisible = !s.sidebarVisible
|
||||||
s.showMainMenu()
|
s.showMainMenu()
|
||||||
|
|
@ -5144,6 +5113,9 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
|
||||||
qualitySectionSimple fyne.CanvasObject
|
qualitySectionSimple fyne.CanvasObject
|
||||||
qualitySectionAdv fyne.CanvasObject
|
qualitySectionAdv fyne.CanvasObject
|
||||||
simpleBitrateSelect *widget.Select
|
simpleBitrateSelect *widget.Select
|
||||||
|
crfContainer *fyne.Container
|
||||||
|
bitrateContainer *fyne.Container
|
||||||
|
targetSizeContainer *fyne.Container
|
||||||
)
|
)
|
||||||
var (
|
var (
|
||||||
updateEncodingControls func()
|
updateEncodingControls func()
|
||||||
|
|
@ -5707,6 +5679,9 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
|
||||||
if updateEncodingControls != nil {
|
if updateEncodingControls != nil {
|
||||||
updateEncodingControls()
|
updateEncodingControls()
|
||||||
}
|
}
|
||||||
|
if buildCommandPreview != nil {
|
||||||
|
buildCommandPreview()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
bitrateModeSelect.SetSelected(state.convert.BitrateMode)
|
bitrateModeSelect.SetSelected(state.convert.BitrateMode)
|
||||||
|
|
||||||
|
|
@ -5716,6 +5691,9 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
|
||||||
crfEntry.SetText(state.convert.CRF)
|
crfEntry.SetText(state.convert.CRF)
|
||||||
crfEntry.OnChanged = func(val string) {
|
crfEntry.OnChanged = func(val string) {
|
||||||
state.convert.CRF = val
|
state.convert.CRF = val
|
||||||
|
if buildCommandPreview != nil {
|
||||||
|
buildCommandPreview()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Video Bitrate entry (for CBR/VBR)
|
// Video Bitrate entry (for CBR/VBR)
|
||||||
|
|
@ -5724,8 +5702,24 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
|
||||||
videoBitrateEntry.SetText(state.convert.VideoBitrate)
|
videoBitrateEntry.SetText(state.convert.VideoBitrate)
|
||||||
videoBitrateEntry.OnChanged = func(val string) {
|
videoBitrateEntry.OnChanged = func(val string) {
|
||||||
state.convert.VideoBitrate = val
|
state.convert.VideoBitrate = val
|
||||||
|
if buildCommandPreview != nil {
|
||||||
|
buildCommandPreview()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create containers for hideable sections
|
||||||
|
crfContainer = container.NewVBox(
|
||||||
|
widget.NewLabelWithStyle("Manual CRF (overrides Quality preset)", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),
|
||||||
|
crfEntry,
|
||||||
|
)
|
||||||
|
|
||||||
|
bitrateContainer = container.NewVBox(
|
||||||
|
widget.NewLabelWithStyle("Video Bitrate (for CBR/VBR)", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),
|
||||||
|
videoBitrateEntry,
|
||||||
|
widget.NewLabelWithStyle("Recommended Bitrate Preset", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),
|
||||||
|
bitratePresetSelect,
|
||||||
|
)
|
||||||
|
|
||||||
type bitratePreset struct {
|
type bitratePreset struct {
|
||||||
Label string
|
Label string
|
||||||
Bitrate string
|
Bitrate string
|
||||||
|
|
@ -5869,8 +5863,18 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
|
||||||
targetFileSizeEntry.SetText(state.convert.TargetFileSize)
|
targetFileSizeEntry.SetText(state.convert.TargetFileSize)
|
||||||
targetFileSizeEntry.OnChanged = func(val string) {
|
targetFileSizeEntry.OnChanged = func(val string) {
|
||||||
state.convert.TargetFileSize = val
|
state.convert.TargetFileSize = val
|
||||||
|
if buildCommandPreview != nil {
|
||||||
|
buildCommandPreview()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create target size container
|
||||||
|
targetSizeContainer = container.NewVBox(
|
||||||
|
widget.NewLabelWithStyle("Target File Size", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),
|
||||||
|
targetFileSizeSelect,
|
||||||
|
targetFileSizeEntry,
|
||||||
|
)
|
||||||
|
|
||||||
encodingHint := widget.NewLabel("")
|
encodingHint := widget.NewLabel("")
|
||||||
encodingHint.Wrapping = fyne.TextWrapWord
|
encodingHint.Wrapping = fyne.TextWrapWord
|
||||||
|
|
||||||
|
|
@ -5909,17 +5913,10 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
|
||||||
mode := state.convert.BitrateMode
|
mode := state.convert.BitrateMode
|
||||||
isLossless := state.convert.Quality == "Lossless"
|
isLossless := state.convert.Quality == "Lossless"
|
||||||
|
|
||||||
// Default: enable everything
|
|
||||||
crfEntry.Enable()
|
|
||||||
videoBitrateEntry.Enable()
|
|
||||||
targetFileSizeEntry.Enable()
|
|
||||||
targetFileSizeSelect.Enable()
|
|
||||||
bitratePresetSelect.Enable()
|
|
||||||
|
|
||||||
hint := ""
|
hint := ""
|
||||||
|
|
||||||
if isLossless {
|
if isLossless {
|
||||||
// Lossless forces CRF 0; ignore bitrate/preset/target size to reduce confusion
|
// Lossless forces CRF 0; hide bitrate/target size
|
||||||
if mode != "CRF" {
|
if mode != "CRF" {
|
||||||
state.convert.BitrateMode = "CRF"
|
state.convert.BitrateMode = "CRF"
|
||||||
bitrateModeSelect.SetSelected("CRF")
|
bitrateModeSelect.SetSelected("CRF")
|
||||||
|
|
@ -5930,35 +5927,44 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
|
||||||
}
|
}
|
||||||
state.convert.CRF = "0"
|
state.convert.CRF = "0"
|
||||||
crfEntry.Disable()
|
crfEntry.Disable()
|
||||||
videoBitrateEntry.Disable()
|
crfContainer.Show()
|
||||||
targetFileSizeEntry.Disable()
|
bitrateContainer.Hide()
|
||||||
targetFileSizeSelect.Disable()
|
targetSizeContainer.Hide()
|
||||||
bitratePresetSelect.Disable()
|
|
||||||
hint = "Lossless forces CRF 0 for H.265/AV1; bitrate and target size are ignored."
|
hint = "Lossless forces CRF 0 for H.265/AV1; bitrate and target size are ignored."
|
||||||
} else {
|
} else {
|
||||||
|
crfEntry.Enable()
|
||||||
switch mode {
|
switch mode {
|
||||||
case "CRF", "":
|
case "CRF", "":
|
||||||
videoBitrateEntry.Disable()
|
// Show only CRF controls
|
||||||
targetFileSizeEntry.Disable()
|
crfContainer.Show()
|
||||||
targetFileSizeSelect.Disable()
|
bitrateContainer.Hide()
|
||||||
bitratePresetSelect.Disable()
|
targetSizeContainer.Hide()
|
||||||
hint = "CRF mode uses the quality preset/CRF only."
|
hint = "CRF mode: Constant quality - file size varies. Lower CRF = better quality."
|
||||||
case "CBR", "VBR":
|
case "CBR":
|
||||||
crfEntry.Disable()
|
// Show only bitrate controls
|
||||||
targetFileSizeEntry.Disable()
|
crfContainer.Hide()
|
||||||
targetFileSizeSelect.Disable()
|
bitrateContainer.Show()
|
||||||
hint = "Bitrate mode uses the value above; presets auto-fill common choices."
|
targetSizeContainer.Hide()
|
||||||
|
hint = "CBR mode: Constant bitrate - predictable file size, variable quality. Use for strict size requirements or streaming."
|
||||||
|
case "VBR":
|
||||||
|
// Show only bitrate controls
|
||||||
|
crfContainer.Hide()
|
||||||
|
bitrateContainer.Show()
|
||||||
|
targetSizeContainer.Hide()
|
||||||
|
hint = "VBR mode: Variable bitrate - targets average bitrate. More efficient than CBR. Use 2-pass for accuracy."
|
||||||
case "Target Size":
|
case "Target Size":
|
||||||
crfEntry.Disable()
|
// Show only target size controls
|
||||||
videoBitrateEntry.Disable()
|
crfContainer.Hide()
|
||||||
bitratePresetSelect.Disable()
|
bitrateContainer.Hide()
|
||||||
targetFileSizeEntry.Enable()
|
targetSizeContainer.Show()
|
||||||
targetFileSizeSelect.Enable()
|
hint = "Target Size mode: Calculates bitrate to hit exact file size. Best for strict size limits."
|
||||||
hint = "Target size calculates bitrate automatically from duration."
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
encodingHint.SetText(hint)
|
encodingHint.SetText(hint)
|
||||||
|
if buildCommandPreview != nil {
|
||||||
|
buildCommandPreview()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
updateEncodingControls()
|
updateEncodingControls()
|
||||||
|
|
||||||
|
|
@ -6319,16 +6325,10 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
|
||||||
qualitySectionAdv,
|
qualitySectionAdv,
|
||||||
widget.NewLabelWithStyle("Bitrate Mode", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),
|
widget.NewLabelWithStyle("Bitrate Mode", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),
|
||||||
bitrateModeSelect,
|
bitrateModeSelect,
|
||||||
widget.NewLabelWithStyle("Manual CRF (overrides Quality preset)", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),
|
crfContainer,
|
||||||
crfEntry,
|
bitrateContainer,
|
||||||
widget.NewLabelWithStyle("Video Bitrate (for CBR/VBR)", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),
|
targetSizeContainer,
|
||||||
videoBitrateEntry,
|
|
||||||
widget.NewLabelWithStyle("Recommended Bitrate Preset", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),
|
|
||||||
bitratePresetSelect,
|
|
||||||
encodingHint,
|
encodingHint,
|
||||||
widget.NewLabelWithStyle("Target File Size", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),
|
|
||||||
targetFileSizeSelect,
|
|
||||||
targetFileSizeEntry,
|
|
||||||
widget.NewLabelWithStyle("Target Resolution", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),
|
widget.NewLabelWithStyle("Target Resolution", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),
|
||||||
resolutionSelect,
|
resolutionSelect,
|
||||||
widget.NewLabelWithStyle("Frame Rate", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),
|
widget.NewLabelWithStyle("Frame Rate", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),
|
||||||
|
|
@ -6780,41 +6780,41 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
|
||||||
// Build command from current state
|
// Build command from current state
|
||||||
cfg := state.convert
|
cfg := state.convert
|
||||||
config := map[string]interface{}{
|
config := map[string]interface{}{
|
||||||
"quality": cfg.Quality,
|
"quality": cfg.Quality,
|
||||||
"videoCodec": cfg.VideoCodec,
|
"videoCodec": cfg.VideoCodec,
|
||||||
"encoderPreset": cfg.EncoderPreset,
|
"encoderPreset": cfg.EncoderPreset,
|
||||||
"crf": cfg.CRF,
|
"crf": cfg.CRF,
|
||||||
"bitrateMode": cfg.BitrateMode,
|
"bitrateMode": cfg.BitrateMode,
|
||||||
"videoBitrate": cfg.VideoBitrate,
|
"videoBitrate": cfg.VideoBitrate,
|
||||||
"targetFileSize": cfg.TargetFileSize,
|
"targetFileSize": cfg.TargetFileSize,
|
||||||
"targetResolution": cfg.TargetResolution,
|
"targetResolution": cfg.TargetResolution,
|
||||||
"frameRate": cfg.FrameRate,
|
"frameRate": cfg.FrameRate,
|
||||||
"useMotionInterpolation": cfg.UseMotionInterpolation,
|
"useMotionInterpolation": cfg.UseMotionInterpolation,
|
||||||
"pixelFormat": cfg.PixelFormat,
|
"pixelFormat": cfg.PixelFormat,
|
||||||
"hardwareAccel": cfg.HardwareAccel,
|
"hardwareAccel": cfg.HardwareAccel,
|
||||||
"h264Profile": cfg.H264Profile,
|
"h264Profile": cfg.H264Profile,
|
||||||
"h264Level": cfg.H264Level,
|
"h264Level": cfg.H264Level,
|
||||||
"deinterlace": cfg.Deinterlace,
|
"deinterlace": cfg.Deinterlace,
|
||||||
"deinterlaceMethod": cfg.DeinterlaceMethod,
|
"deinterlaceMethod": cfg.DeinterlaceMethod,
|
||||||
"autoCrop": cfg.AutoCrop,
|
"autoCrop": cfg.AutoCrop,
|
||||||
"cropWidth": cfg.CropWidth,
|
"cropWidth": cfg.CropWidth,
|
||||||
"cropHeight": cfg.CropHeight,
|
"cropHeight": cfg.CropHeight,
|
||||||
"cropX": cfg.CropX,
|
"cropX": cfg.CropX,
|
||||||
"cropY": cfg.CropY,
|
"cropY": cfg.CropY,
|
||||||
"flipHorizontal": cfg.FlipHorizontal,
|
"flipHorizontal": cfg.FlipHorizontal,
|
||||||
"flipVertical": cfg.FlipVertical,
|
"flipVertical": cfg.FlipVertical,
|
||||||
"rotation": cfg.Rotation,
|
"rotation": cfg.Rotation,
|
||||||
"audioCodec": cfg.AudioCodec,
|
"audioCodec": cfg.AudioCodec,
|
||||||
"audioBitrate": cfg.AudioBitrate,
|
"audioBitrate": cfg.AudioBitrate,
|
||||||
"audioChannels": cfg.AudioChannels,
|
"audioChannels": cfg.AudioChannels,
|
||||||
"normalizeAudio": cfg.NormalizeAudio,
|
"normalizeAudio": cfg.NormalizeAudio,
|
||||||
"coverArtPath": cfg.CoverArtPath,
|
"coverArtPath": cfg.CoverArtPath,
|
||||||
"aspectHandling": cfg.AspectHandling,
|
"aspectHandling": cfg.AspectHandling,
|
||||||
"outputAspect": cfg.OutputAspect,
|
"outputAspect": cfg.OutputAspect,
|
||||||
"sourceWidth": src.Width,
|
"sourceWidth": src.Width,
|
||||||
"sourceHeight": src.Height,
|
"sourceHeight": src.Height,
|
||||||
"sourceDuration": src.Duration,
|
"sourceDuration": src.Duration,
|
||||||
"fieldOrder": src.FieldOrder,
|
"fieldOrder": src.FieldOrder,
|
||||||
}
|
}
|
||||||
|
|
||||||
job := &queue.Job{
|
job := &queue.Job{
|
||||||
|
|
@ -9399,9 +9399,21 @@ func (s *appState) startConvert(status *widget.Label, btn, cancelBtn *widget.But
|
||||||
}
|
}
|
||||||
args = append(args, "-b:v", vb, "-minrate", vb, "-maxrate", vb, "-bufsize", vb)
|
args = append(args, "-b:v", vb, "-minrate", vb, "-maxrate", vb, "-bufsize", vb)
|
||||||
} else if cfg.BitrateMode == "VBR" {
|
} else if cfg.BitrateMode == "VBR" {
|
||||||
// Variable bitrate (2-pass if enabled)
|
// Variable bitrate - use 2-pass for accuracy
|
||||||
if cfg.VideoBitrate != "" {
|
vb := cfg.VideoBitrate
|
||||||
args = append(args, "-b:v", cfg.VideoBitrate)
|
if vb == "" {
|
||||||
|
vb = defaultBitrate(cfg.VideoCodec, src.Width, sourceBitrate)
|
||||||
|
}
|
||||||
|
args = append(args, "-b:v", vb)
|
||||||
|
// VBR uses maxrate at ~1.5x target for quality peaks
|
||||||
|
bitrateVal, err := utils.ParseInt(strings.TrimSuffix(vb, "k"))
|
||||||
|
if err == nil {
|
||||||
|
maxBitrate := fmt.Sprintf("%dk", int(float64(bitrateVal)*1.5))
|
||||||
|
args = append(args, "-maxrate", maxBitrate)
|
||||||
|
}
|
||||||
|
// Force 2-pass for VBR accuracy
|
||||||
|
if !cfg.TwoPass {
|
||||||
|
cfg.TwoPass = true
|
||||||
}
|
}
|
||||||
} else if cfg.BitrateMode == "Target Size" {
|
} else if cfg.BitrateMode == "Target Size" {
|
||||||
// Calculate bitrate from target file size
|
// Calculate bitrate from target file size
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user