Compare commits
3 Commits
83ad75e04d
...
1a04cab1d6
| Author | SHA1 | Date | |
|---|---|---|---|
| 1a04cab1d6 | |||
| 727bbd9097 | |||
| 6315524a6e |
110
main.go
110
main.go
|
|
@ -301,7 +301,8 @@ func (s *appState) openLogViewer(title, path string, live bool) {
|
|||
text.Disable()
|
||||
bg := canvas.NewRectangle(color.NRGBA{0x15, 0x1a, 0x24, 0xff}) // slightly lighter than app bg
|
||||
scroll := container.NewVScroll(container.NewMax(bg, text))
|
||||
scroll.SetMinSize(fyne.NewSize(700, 450))
|
||||
// Adaptive min size - allows proper scaling on small screens
|
||||
scroll.SetMinSize(fyne.NewSize(600, 350))
|
||||
|
||||
stop := make(chan struct{})
|
||||
if live {
|
||||
|
|
@ -3366,15 +3367,19 @@ func (s *appState) executeSnippetJob(ctx context.Context, job *queue.Job, progre
|
|||
if useSourceFormat {
|
||||
// Source format mode: Use stream copy for clean extraction
|
||||
// Note: This uses keyframe cutting, so duration may not be frame-perfect
|
||||
// Calculate end time for more accurate cutting
|
||||
endTime := center + float64(snippetLength)
|
||||
args = []string{
|
||||
"-y",
|
||||
"-hide_banner",
|
||||
"-loglevel", "error",
|
||||
"-accurate_seek", // Seek accurately to keyframes
|
||||
"-ss", start,
|
||||
"-i", inputPath,
|
||||
"-t", fmt.Sprintf("%d", snippetLength),
|
||||
"-c", "copy", // Stream copy - no re-encoding
|
||||
"-map", "0", // Include all streams
|
||||
"-to", fmt.Sprintf("%.2f", endTime), // Use -to instead of -t for better accuracy
|
||||
"-c", "copy", // Stream copy - no re-encoding
|
||||
"-map", "0", // Include all streams
|
||||
"-avoid_negative_ts", "make_zero", // Fix timestamp issues
|
||||
outputPath,
|
||||
}
|
||||
} else {
|
||||
|
|
@ -3728,11 +3733,15 @@ func runGUI() {
|
|||
} else {
|
||||
logging.Debug(logging.CatUI, "app icon not found; continuing without custom icon")
|
||||
}
|
||||
// Use a generous default window size that fits typical desktops without overflowing.
|
||||
w.Resize(fyne.NewSize(1280, 800))
|
||||
w.SetFixedSize(false) // Allow manual resizing
|
||||
// Adaptive window sizing for professional cross-resolution support
|
||||
w.SetFixedSize(false) // Allow manual resizing and maximizing
|
||||
|
||||
// Use conservative default size that fits on small laptop screens (1280x768)
|
||||
// Window can be maximized by user using window manager controls
|
||||
w.Resize(fyne.NewSize(1200, 700))
|
||||
w.CenterOnScreen()
|
||||
logging.Debug(logging.CatUI, "window initialized with manual resizing and centering enabled")
|
||||
|
||||
logging.Debug(logging.CatUI, "window initialized at 1200x700 (fits 1280x768+ screens), manual resizing enabled")
|
||||
|
||||
state := &appState{
|
||||
window: w,
|
||||
|
|
@ -6078,7 +6087,8 @@ Metadata: %s`,
|
|||
|
||||
previewImg := canvas.NewImageFromResource(img)
|
||||
previewImg.FillMode = canvas.ImageFillContain
|
||||
previewImg.SetMinSize(fyne.NewSize(800, 450))
|
||||
// Adaptive size for small screens
|
||||
previewImg.SetMinSize(fyne.NewSize(640, 360))
|
||||
|
||||
infoLabel := widget.NewLabel("Left: Original | Right: Deinterlaced")
|
||||
infoLabel.Alignment = fyne.TextAlignCenter
|
||||
|
|
@ -6989,10 +6999,11 @@ func (s *appState) handleDrop(pos fyne.Position, items []fyne.URI) {
|
|||
return
|
||||
}
|
||||
|
||||
// If multiple videos, add all to queue
|
||||
// Load all videos into memory (don't auto-queue)
|
||||
// This allows users to adjust settings or generate snippets before manually queuing
|
||||
if len(videoPaths) > 1 {
|
||||
logging.Debug(logging.CatUI, "multiple videos dropped in convert module; adding all to queue")
|
||||
go s.batchAddToQueue(videoPaths)
|
||||
logging.Debug(logging.CatUI, "multiple videos dropped in convert module; loading all into memory")
|
||||
go s.loadMultipleVideos(videoPaths)
|
||||
} else {
|
||||
// Single video: load it
|
||||
logging.Debug(logging.CatUI, "single video dropped in convert module; loading: %s", videoPaths[0])
|
||||
|
|
@ -7396,6 +7407,65 @@ func (s *appState) loadVideo(path string) {
|
|||
}, false)
|
||||
}
|
||||
|
||||
// loadMultipleVideos loads multiple videos into memory without auto-queuing
|
||||
func (s *appState) loadMultipleVideos(paths []string) {
|
||||
logging.Debug(logging.CatModule, "loading %d videos into memory", len(paths))
|
||||
|
||||
var validVideos []*videoSource
|
||||
var failedFiles []string
|
||||
|
||||
for _, path := range paths {
|
||||
src, err := probeVideo(path)
|
||||
if err != nil {
|
||||
logging.Debug(logging.CatFFMPEG, "ffprobe failed for %s: %v", path, err)
|
||||
failedFiles = append(failedFiles, filepath.Base(path))
|
||||
continue
|
||||
}
|
||||
validVideos = append(validVideos, src)
|
||||
}
|
||||
|
||||
if len(validVideos) == 0 {
|
||||
fyne.CurrentApp().Driver().DoFromGoroutine(func() {
|
||||
msg := fmt.Sprintf("Failed to analyze %d file(s):\n%s", len(failedFiles), strings.Join(failedFiles, ", "))
|
||||
s.showErrorWithCopy("Load Failed", fmt.Errorf("%s", msg))
|
||||
}, false)
|
||||
return
|
||||
}
|
||||
|
||||
// Load all videos into loadedVideos array
|
||||
s.loadedVideos = validVideos
|
||||
s.currentIndex = 0
|
||||
|
||||
// Load the first video to display
|
||||
firstVideo := validVideos[0]
|
||||
if frames, err := capturePreviewFrames(firstVideo.Path, firstVideo.Duration); err == nil {
|
||||
firstVideo.PreviewFrames = frames
|
||||
if len(frames) > 0 {
|
||||
s.currentFrame = frames[0]
|
||||
}
|
||||
}
|
||||
|
||||
s.applyInverseDefaults(firstVideo)
|
||||
s.convert.OutputBase = s.resolveOutputBase(firstVideo, false)
|
||||
if firstVideo.EmbeddedCoverArt != "" {
|
||||
s.convert.CoverArtPath = firstVideo.EmbeddedCoverArt
|
||||
} else {
|
||||
s.convert.CoverArtPath = ""
|
||||
}
|
||||
s.convert.AspectHandling = "Auto"
|
||||
|
||||
fyne.CurrentApp().Driver().DoFromGoroutine(func() {
|
||||
msg := fmt.Sprintf("Loaded %d video(s) into memory.\nUse arrow buttons or Convert/Snippet buttons to process.", len(validVideos))
|
||||
if len(failedFiles) > 0 {
|
||||
msg += fmt.Sprintf("\n\n%d file(s) failed to analyze:\n%s", len(failedFiles), strings.Join(failedFiles, ", "))
|
||||
}
|
||||
dialog.ShowInformation("Videos Loaded", msg, s.window)
|
||||
s.showConvertView(firstVideo)
|
||||
}, false)
|
||||
|
||||
logging.Debug(logging.CatModule, "loaded %d videos into memory", len(validVideos))
|
||||
}
|
||||
|
||||
func (s *appState) clearVideo() {
|
||||
logging.Debug(logging.CatModule, "clearing loaded video")
|
||||
s.stopPlayer()
|
||||
|
|
@ -10263,11 +10333,15 @@ func buildThumbView(state *appState) fyne.CanvasObject {
|
|||
go func() {
|
||||
img := canvas.NewImageFromFile(contactSheetPath)
|
||||
img.FillMode = canvas.ImageFillContain
|
||||
img.SetMinSize(fyne.NewSize(800, 600))
|
||||
// Adaptive size for small screens - use scrollable dialog
|
||||
img.SetMinSize(fyne.NewSize(640, 480))
|
||||
|
||||
fyne.CurrentApp().Driver().DoFromGoroutine(func() {
|
||||
d := dialog.NewCustom("Contact Sheet", "Close", img, state.window)
|
||||
d.Resize(fyne.NewSize(900, 700))
|
||||
// Wrap in scroll container for large contact sheets
|
||||
scroll := container.NewScroll(img)
|
||||
d := dialog.NewCustom("Contact Sheet", "Close", scroll, state.window)
|
||||
// Adaptive dialog size that fits on 1280x768 screens
|
||||
d.Resize(fyne.NewSize(700, 600))
|
||||
d.Show()
|
||||
}, false)
|
||||
}()
|
||||
|
|
@ -10545,7 +10619,8 @@ func buildFiltersView(state *appState) fyne.CanvasObject {
|
|||
)
|
||||
|
||||
settingsScroll := container.NewVScroll(settingsPanel)
|
||||
settingsScroll.SetMinSize(fyne.NewSize(400, 600))
|
||||
// Adaptive height for small screens - allow content to flow
|
||||
settingsScroll.SetMinSize(fyne.NewSize(350, 400))
|
||||
|
||||
mainContent := container.NewHSplit(
|
||||
container.NewVBox(leftPanel, videoContainer),
|
||||
|
|
@ -10850,7 +10925,8 @@ func buildUpscaleView(state *appState) fyne.CanvasObject {
|
|||
)
|
||||
|
||||
settingsScroll := container.NewVScroll(settingsPanel)
|
||||
settingsScroll.SetMinSize(fyne.NewSize(450, 600))
|
||||
// Adaptive height for small screens
|
||||
settingsScroll.SetMinSize(fyne.NewSize(400, 400))
|
||||
|
||||
mainContent := container.NewHSplit(
|
||||
container.NewVBox(leftPanel, videoContainer),
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user