Normalize MP4 format label, improve log readability, and prep reduction display
This commit is contained in:
parent
6ad72ecc46
commit
bd49952800
|
|
@ -145,7 +145,7 @@ func ProbeVideo(path string) (*VideoSource, error) {
|
||||||
src := &VideoSource{
|
src := &VideoSource{
|
||||||
Path: path,
|
Path: path,
|
||||||
DisplayName: filepath.Base(path),
|
DisplayName: filepath.Base(path),
|
||||||
Format: utils.FirstNonEmpty(result.Format.Format, result.Format.FormatName),
|
Format: humanFriendlyFormat(result.Format.Format, result.Format.FormatName),
|
||||||
}
|
}
|
||||||
if rate, err := utils.ParseInt(result.Format.BitRate); err == nil {
|
if rate, err := utils.ParseInt(result.Format.BitRate); err == nil {
|
||||||
src.Bitrate = rate
|
src.Bitrate = rate
|
||||||
|
|
|
||||||
21
internal/convert/format_name.go
Normal file
21
internal/convert/format_name.go
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
package convert
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
// humanFriendlyFormat normalizes format names to less confusing labels.
|
||||||
|
func humanFriendlyFormat(format, formatLong string) string {
|
||||||
|
f := strings.ToLower(strings.TrimSpace(format))
|
||||||
|
fl := strings.ToLower(strings.TrimSpace(formatLong))
|
||||||
|
|
||||||
|
// Treat common QuickTime/MOV wording as MP4 when the extension is typically mp4
|
||||||
|
if strings.Contains(f, "mov") || strings.Contains(fl, "quicktime") {
|
||||||
|
return "MP4"
|
||||||
|
}
|
||||||
|
if f != "" {
|
||||||
|
return format
|
||||||
|
}
|
||||||
|
if formatLong != "" {
|
||||||
|
return formatLong
|
||||||
|
}
|
||||||
|
return "Unknown"
|
||||||
|
}
|
||||||
27
internal/utils/formatting.go
Normal file
27
internal/utils/formatting.go
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import "math"
|
||||||
|
|
||||||
|
// ReductionText returns a string like "965 MB (24% reduction)" given original bytes and new bytes.
|
||||||
|
func ReductionText(origBytes, newBytes int64) string {
|
||||||
|
if origBytes <= 0 || newBytes <= 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if newBytes >= origBytes {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
reduction := 100.0 * (1.0 - float64(newBytes)/float64(origBytes))
|
||||||
|
if reduction <= 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return formatFileSize(newBytes) + " (" + formatPercent(reduction) + " reduction)"
|
||||||
|
}
|
||||||
|
|
||||||
|
// formatPercent renders a percentage with no trailing zeros after decimal.
|
||||||
|
func formatPercent(val float64) string {
|
||||||
|
val = math.Round(val*10) / 10 // one decimal
|
||||||
|
if val == math.Trunc(val) {
|
||||||
|
return formatInt(int(val)) + "%"
|
||||||
|
}
|
||||||
|
return formatFloat(val) + "%"
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,6 @@ package utils
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"image/color"
|
"image/color"
|
||||||
"math"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
|
||||||
35
main.go
35
main.go
|
|
@ -165,9 +165,11 @@ func (s *appState) openLogViewer(title, path string, live bool) {
|
||||||
text := widget.NewMultiLineEntry()
|
text := widget.NewMultiLineEntry()
|
||||||
text.SetText(string(data))
|
text.SetText(string(data))
|
||||||
text.Wrapping = fyne.TextWrapWord
|
text.Wrapping = fyne.TextWrapWord
|
||||||
|
text.TextStyle = fyne.TextStyle{Monospace: true}
|
||||||
text.Disable()
|
text.Disable()
|
||||||
scroll := container.NewVScroll(text)
|
bg := canvas.NewRectangle(color.NRGBA{0x15, 0x1a, 0x24, 0xff}) // slightly lighter than app bg
|
||||||
scroll.SetMinSize(fyne.NewSize(600, 400))
|
scroll := container.NewVScroll(container.NewMax(bg, text))
|
||||||
|
scroll.SetMinSize(fyne.NewSize(700, 450))
|
||||||
|
|
||||||
stop := make(chan struct{})
|
stop := make(chan struct{})
|
||||||
if live {
|
if live {
|
||||||
|
|
@ -195,8 +197,13 @@ func (s *appState) openLogViewer(title, path string, live bool) {
|
||||||
closeBtn := widget.NewButton("Close", func() {
|
closeBtn := widget.NewButton("Close", func() {
|
||||||
close(stop)
|
close(stop)
|
||||||
})
|
})
|
||||||
content := container.NewBorder(nil, container.NewHBox(layout.NewSpacer(), closeBtn), nil, nil, scroll)
|
copyBtn := widget.NewButton("Copy All", func() {
|
||||||
d := dialog.NewCustomWithoutButtons(title, content, s.window)
|
s.window.Clipboard().SetContent(text.Text)
|
||||||
|
})
|
||||||
|
buttons := container.NewHBox(copyBtn, layout.NewSpacer(), closeBtn)
|
||||||
|
content := container.NewBorder(nil, buttons, nil, nil, scroll)
|
||||||
|
d := dialog.NewCustom(title, "Close", content, s.window)
|
||||||
|
d.SetOnClosed(func() { close(stop) })
|
||||||
d.Show()
|
d.Show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3596,6 +3603,9 @@ func buildMetadataPanel(state *appState, src *videoSource, min fyne.Size) (fyne.
|
||||||
}
|
}
|
||||||
|
|
||||||
colorSpace := utils.FirstNonEmpty(src.ColorSpace, "Unknown")
|
colorSpace := utils.FirstNonEmpty(src.ColorSpace, "Unknown")
|
||||||
|
if strings.EqualFold(colorSpace, "unknown") && strings.Contains(strings.ToLower(src.Format), "mp4") {
|
||||||
|
colorSpace = "MP4 (ISO BMFF family)"
|
||||||
|
}
|
||||||
colorRange := utils.FirstNonEmpty(src.ColorRange, "Unknown")
|
colorRange := utils.FirstNonEmpty(src.ColorRange, "Unknown")
|
||||||
if colorRange == "tv" {
|
if colorRange == "tv" {
|
||||||
colorRange = "Limited (TV)"
|
colorRange = "Limited (TV)"
|
||||||
|
|
@ -3668,7 +3678,7 @@ Metadata: %s`,
|
||||||
|
|
||||||
info := widget.NewForm(
|
info := widget.NewForm(
|
||||||
widget.NewFormItem("File", widget.NewLabel(src.DisplayName)),
|
widget.NewFormItem("File", widget.NewLabel(src.DisplayName)),
|
||||||
widget.NewFormItem("Format", widget.NewLabel(utils.FirstNonEmpty(src.Format, "Unknown"))),
|
widget.NewFormItem("Format Family", widget.NewLabel(utils.FirstNonEmpty(src.Format, "Unknown"))),
|
||||||
widget.NewFormItem("Resolution", widget.NewLabel(fmt.Sprintf("%dx%d", src.Width, src.Height))),
|
widget.NewFormItem("Resolution", widget.NewLabel(fmt.Sprintf("%dx%d", src.Width, src.Height))),
|
||||||
widget.NewFormItem("Aspect Ratio", widget.NewLabel(src.AspectRatioString())),
|
widget.NewFormItem("Aspect Ratio", widget.NewLabel(src.AspectRatioString())),
|
||||||
widget.NewFormItem("Pixel Aspect Ratio", widget.NewLabel(par)),
|
widget.NewFormItem("Pixel Aspect Ratio", widget.NewLabel(par)),
|
||||||
|
|
@ -3691,6 +3701,7 @@ Metadata: %s`,
|
||||||
for _, item := range info.Items {
|
for _, item := range info.Items {
|
||||||
if lbl, ok := item.Widget.(*widget.Label); ok {
|
if lbl, ok := item.Widget.(*widget.Label); ok {
|
||||||
lbl.Wrapping = fyne.TextWrapWord
|
lbl.Wrapping = fyne.TextWrapWord
|
||||||
|
lbl.TextStyle = fyne.TextStyle{} // prevent selection
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -6786,14 +6797,18 @@ func buildCompareView(state *appState) fyne.CanvasObject {
|
||||||
// Info labels
|
// Info labels
|
||||||
file1Info := widget.NewLabel("No file loaded")
|
file1Info := widget.NewLabel("No file loaded")
|
||||||
file1Info.Wrapping = fyne.TextWrapWord
|
file1Info.Wrapping = fyne.TextWrapWord
|
||||||
|
file1Info.TextStyle = fyne.TextStyle{} // non-selectable label
|
||||||
|
|
||||||
file2Info := widget.NewLabel("No file loaded")
|
file2Info := widget.NewLabel("No file loaded")
|
||||||
file2Info.Wrapping = fyne.TextWrapWord
|
file2Info.Wrapping = fyne.TextWrapWord
|
||||||
|
file2Info.TextStyle = fyne.TextStyle{} // non-selectable label
|
||||||
|
|
||||||
// Helper function to format metadata
|
// Helper function to format metadata
|
||||||
formatMetadata := func(src *videoSource) string {
|
formatMetadata := func(src *videoSource) string {
|
||||||
fileSize := "Unknown"
|
fileSize := "Unknown"
|
||||||
|
origBytes := int64(0)
|
||||||
if fi, err := os.Stat(src.Path); err == nil {
|
if fi, err := os.Stat(src.Path); err == nil {
|
||||||
|
origBytes = fi.Size()
|
||||||
sizeMB := float64(fi.Size()) / (1024 * 1024)
|
sizeMB := float64(fi.Size()) / (1024 * 1024)
|
||||||
if sizeMB >= 1024 {
|
if sizeMB >= 1024 {
|
||||||
fileSize = fmt.Sprintf("%.2f GB", sizeMB/1024)
|
fileSize = fmt.Sprintf("%.2f GB", sizeMB/1024)
|
||||||
|
|
@ -6801,12 +6816,18 @@ func buildCompareView(state *appState) fyne.CanvasObject {
|
||||||
fileSize = fmt.Sprintf("%.2f MB", sizeMB)
|
fileSize = fmt.Sprintf("%.2f MB", sizeMB)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var bitrateStr string
|
||||||
|
if src.Bitrate > 0 {
|
||||||
|
bitrateStr = formatBitrate(src.Bitrate)
|
||||||
|
} else {
|
||||||
|
bitrateStr = "--"
|
||||||
|
}
|
||||||
|
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"━━━ FILE INFO ━━━\n"+
|
"━━━ FILE INFO ━━━\n"+
|
||||||
"Path: %s\n"+
|
"Path: %s\n"+
|
||||||
"File Size: %s\n"+
|
"File Size: %s\n"+
|
||||||
"Format: %s\n"+
|
"Format Family: %s\n"+
|
||||||
"\n━━━ VIDEO ━━━\n"+
|
"\n━━━ VIDEO ━━━\n"+
|
||||||
"Codec: %s\n"+
|
"Codec: %s\n"+
|
||||||
"Resolution: %dx%d\n"+
|
"Resolution: %dx%d\n"+
|
||||||
|
|
@ -6835,7 +6856,7 @@ func buildCompareView(state *appState) fyne.CanvasObject {
|
||||||
src.Width, src.Height,
|
src.Width, src.Height,
|
||||||
src.AspectRatioString(),
|
src.AspectRatioString(),
|
||||||
src.FrameRate,
|
src.FrameRate,
|
||||||
formatBitrate(src.Bitrate),
|
bitrateStr,
|
||||||
src.PixelFormat,
|
src.PixelFormat,
|
||||||
src.ColorSpace,
|
src.ColorSpace,
|
||||||
src.ColorRange,
|
src.ColorRange,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user