Compare commits

..

No commits in common. "a40f7ad795aa700ed788dc6adf874c9e221006d5" and "db3530072308fb423f7534e39e6fa8fdc0d49d42" have entirely different histories.

2 changed files with 41 additions and 78 deletions

View File

@ -234,7 +234,7 @@ func (g *Generator) generateIndividual(ctx context.Context, config Config, durat
seconds := int(ts) % 60
timeStr := fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds)
drawTextFilter := fmt.Sprintf("scale=%d:%d,drawtext=text='%s':fontcolor=white:fontsize=20:font='DejaVu Sans Mono':box=1:boxcolor=black@0.5:boxborderw=5:x=(w-text_w)/2:y=h-th-10",
drawTextFilter := fmt.Sprintf("scale=%d:%d,drawtext=text='%s':fontcolor=white:fontsize=20:box=1:boxcolor=black@0.5:boxborderw=5:x=(w-text_w)/2:y=h-th-10",
thumbWidth, thumbHeight, timeStr)
// Replace scale filter with combined filter
@ -363,12 +363,12 @@ func (g *Generator) buildMetadataFilter(config Config, duration float64, thumbWi
// Create filter that:
// 1. Generates contact sheet from selected frames
// 2. Creates a blank header area
// 3. Draws metadata text on header (using monospace font)
// 3. Draws metadata text on header
// 4. Stacks header on top of contact sheet
filter := fmt.Sprintf(
"%s,%s,pad=%d:%d:0:%d:black,"+
"drawtext=text='%s':fontcolor=white:fontsize=14:font='DejaVu Sans Mono':x=10:y=10,"+
"drawtext=text='%s':fontcolor=white:fontsize=12:font='DejaVu Sans Mono':x=10:y=35",
"drawtext=text='%s':fontcolor=white:fontsize=14:x=10:y=10,"+
"drawtext=text='%s':fontcolor=white:fontsize=12:x=10:y=35",
selectFilter,
tileFilter,
sheetWidth,

111
main.go
View File

@ -9504,16 +9504,12 @@ func buildThumbView(state *appState) fyne.CanvasObject {
state.thumbRows = 6 // 4x6 = 24 thumbnails
}
// File label and video preview
// File label
fileLabel := widget.NewLabel("No file loaded")
fileLabel.TextStyle = fyne.TextStyle{Bold: true}
var videoContainer fyne.CanvasObject
if state.thumbFile != nil {
fileLabel.SetText(fmt.Sprintf("File: %s", filepath.Base(state.thumbFile.Path)))
videoContainer = buildVideoPane(state, fyne.NewSize(640, 360), state.thumbFile, nil)
} else {
videoContainer = container.NewCenter(widget.NewLabel("No video loaded"))
}
// Load button
@ -9544,6 +9540,26 @@ func buildThumbView(state *appState) fyne.CanvasObject {
})
clearBtn.Importance = widget.LowImportance
// Thumbnail count slider
countLabel := widget.NewLabel(fmt.Sprintf("Thumbnail Count: %d", state.thumbCount))
countSlider := widget.NewSlider(3, 50)
countSlider.Value = float64(state.thumbCount)
countSlider.Step = 1
countSlider.OnChanged = func(val float64) {
state.thumbCount = int(val)
countLabel.SetText(fmt.Sprintf("Thumbnail Count: %d", int(val)))
}
// Thumbnail width slider
widthLabel := widget.NewLabel(fmt.Sprintf("Thumbnail Width: %d px", state.thumbWidth))
widthSlider := widget.NewSlider(160, 640)
widthSlider.Value = float64(state.thumbWidth)
widthSlider.Step = 32
widthSlider.OnChanged = func(val float64) {
state.thumbWidth = int(val)
widthLabel.SetText(fmt.Sprintf("Thumbnail Width: %d px", int(val)))
}
// Contact sheet checkbox
contactSheetCheck := widget.NewCheck("Generate Contact Sheet (single image)", func(checked bool) {
state.thumbContactSheet = checked
@ -9551,10 +9567,9 @@ func buildThumbView(state *appState) fyne.CanvasObject {
})
contactSheetCheck.Checked = state.thumbContactSheet
// Conditional settings based on contact sheet mode
var settingsOptions fyne.CanvasObject
// Contact sheet grid options (only show if contact sheet is enabled)
var gridOptions fyne.CanvasObject
if state.thumbContactSheet {
// Contact sheet mode: show columns and rows
colLabel := widget.NewLabel(fmt.Sprintf("Columns: %d", state.thumbColumns))
colSlider := widget.NewSlider(2, 12)
colSlider.Value = float64(state.thumbColumns)
@ -9573,47 +9588,16 @@ func buildThumbView(state *appState) fyne.CanvasObject {
rowLabel.SetText(fmt.Sprintf("Rows: %d", int(val)))
}
totalThumbs := state.thumbColumns * state.thumbRows
totalLabel := widget.NewLabel(fmt.Sprintf("Total thumbnails: %d", totalThumbs))
totalLabel.TextStyle = fyne.TextStyle{Italic: true}
settingsOptions = container.NewVBox(
gridOptions = container.NewVBox(
widget.NewSeparator(),
widget.NewLabel("Contact Sheet Grid:"),
colLabel,
colSlider,
rowLabel,
rowSlider,
totalLabel,
)
} else {
// Individual thumbnails mode: show count and width
countLabel := widget.NewLabel(fmt.Sprintf("Thumbnail Count: %d", state.thumbCount))
countSlider := widget.NewSlider(3, 50)
countSlider.Value = float64(state.thumbCount)
countSlider.Step = 1
countSlider.OnChanged = func(val float64) {
state.thumbCount = int(val)
countLabel.SetText(fmt.Sprintf("Thumbnail Count: %d", int(val)))
}
widthLabel := widget.NewLabel(fmt.Sprintf("Thumbnail Width: %d px", state.thumbWidth))
widthSlider := widget.NewSlider(160, 640)
widthSlider.Value = float64(state.thumbWidth)
widthSlider.Step = 32
widthSlider.OnChanged = func(val float64) {
state.thumbWidth = int(val)
widthLabel.SetText(fmt.Sprintf("Thumbnail Width: %d px", int(val)))
}
settingsOptions = container.NewVBox(
widget.NewSeparator(),
widget.NewLabel("Individual Thumbnails:"),
countLabel,
countSlider,
widthLabel,
widthSlider,
)
gridOptions = container.NewVBox()
}
// Generate button
@ -9627,30 +9611,15 @@ func buildThumbView(state *appState) fyne.CanvasObject {
state.showThumbView()
go func() {
// Create output directory in same folder as video
videoDir := filepath.Dir(state.thumbFile.Path)
videoBaseName := strings.TrimSuffix(filepath.Base(state.thumbFile.Path), filepath.Ext(state.thumbFile.Path))
outputDir := filepath.Join(videoDir, fmt.Sprintf("%s_thumbnails", videoBaseName))
// Create temp directory for thumbnails
outputDir := filepath.Join(os.TempDir(), fmt.Sprintf("videotools_thumbs_%d", time.Now().Unix()))
generator := thumbnail.NewGenerator(platformConfig.FFmpegPath)
// Configure based on mode
var count, width int
if state.thumbContactSheet {
// Contact sheet: count is determined by grid, use default width
count = state.thumbColumns * state.thumbRows
width = 320 // Fixed width for contact sheets
} else {
// Individual thumbnails: use user settings
count = state.thumbCount
width = state.thumbWidth
}
config := thumbnail.Config{
VideoPath: state.thumbFile.Path,
OutputDir: outputDir,
Count: count,
Width: width,
Count: state.thumbCount,
Width: state.thumbWidth,
Format: "jpg",
Quality: 85,
ContactSheet: state.thumbContactSheet,
@ -9712,30 +9681,24 @@ func buildThumbView(state *appState) fyne.CanvasObject {
settingsPanel := container.NewVBox(
widget.NewLabel("Settings:"),
widget.NewSeparator(),
countLabel,
countSlider,
widthLabel,
widthSlider,
widget.NewSeparator(),
contactSheetCheck,
settingsOptions,
gridOptions,
widget.NewSeparator(),
generateBtn,
)
// Main content - split layout with preview on left, settings on right
leftColumn := container.NewVBox(
videoContainer,
)
rightColumn := container.NewVBox(
settingsPanel,
)
mainContent := container.NewHSplit(leftColumn, rightColumn)
mainContent.Offset = 0.55 // Give more space to preview
// Main content
content := container.NewBorder(
container.NewVBox(instructions, widget.NewSeparator(), fileLabel, container.NewHBox(loadBtn, clearBtn)),
nil,
nil,
nil,
mainContent,
settingsPanel,
)
return container.NewBorder(topBar, nil, nil, nil, content)