From 8bee6ac54fe370979cceb4b1541872c20cbdb086 Mon Sep 17 00:00:00 2001 From: Dmitrii Okunev Date: Mon, 29 Jul 2024 01:48:26 +0100 Subject: [PATCH] Initial commit, pt. 59 --- cmd/streampanel/main.go | 2 +- pkg/player/mpv.go | 9 ++++- pkg/streampanel/image.go | 81 +++++++++++++++++++++++++++++++++++++- pkg/streampanel/monitor.go | 41 ++++++++++++------- pkg/streampanel/panel.go | 32 ++++++++------- 5 files changed, 133 insertions(+), 32 deletions(-) diff --git a/cmd/streampanel/main.go b/cmd/streampanel/main.go index 2285592..ba56e58 100644 --- a/cmd/streampanel/main.go +++ b/cmd/streampanel/main.go @@ -30,7 +30,7 @@ func main() { return } - if flags.SplitProcess { + if flags.SplitProcess && flags.RemoteAddr == "" { runSplitProcesses(ctx, flags) return } diff --git a/pkg/player/mpv.go b/pkg/player/mpv.go index b750efa..fbc858e 100644 --- a/pkg/player/mpv.go +++ b/pkg/player/mpv.go @@ -37,7 +37,14 @@ type MPV struct { var _ Player = (*MPV)(nil) -func NewMPV(title string, pathToMPV string) (*MPV, error) { +func NewMPV(title string, pathToMPV string) (_ret *MPV, _err error) { + defer func() { + if r := recover(); r != nil { + _err = fmt.Errorf("got panic: %v", r) + _ret = nil + return + } + }() if pathToMPV == "" { pathToMPV = "mpv" switch runtime.GOOS { diff --git a/pkg/streampanel/image.go b/pkg/streampanel/image.go index 1e40dbf..8b8549d 100644 --- a/pkg/streampanel/image.go +++ b/pkg/streampanel/image.go @@ -121,7 +121,7 @@ func (p *Panel) getImage( } func imgFitTo(src image.Image, size image.Point) image.Image { - sizeCur := src.Bounds().Max + sizeCur := src.Bounds().Size() factor := math.MaxFloat64 factor = math.Min(factor, float64(size.X)/float64(sizeCur.X)) factor = math.Min(factor, float64(size.Y)/float64(sizeCur.Y)) @@ -130,6 +130,85 @@ func imgFitTo(src image.Image, size image.Point) image.Image { return resize.Resize(newWidth, newHeight, src, resize.Lanczos3) } +type align int + +const ( + alignCenter = align(iota) + alignStart + alignEnd +) + +func imgFillTo( + ctx context.Context, + src image.Image, + size image.Point, + alignX align, + alignY align, +) image.Image { + sizeCur := src.Bounds().Size() + ratioCur := float64(sizeCur.X) / float64(sizeCur.Y) + ratioNew := float64(size.X) / float64(size.Y) + + if ratioCur == ratioNew { + return src + } + if math.IsNaN(ratioNew) { + return src + } + + var sizeNew image.Point + if ratioCur < ratioNew { + sizeNew = image.Point{ + X: int(float64(sizeCur.Y) * ratioNew), + Y: sizeCur.Y, + } + } else { + sizeNew = image.Point{ + X: sizeCur.X, + Y: int(float64(sizeCur.X) / ratioNew), + } + } + + logger.Tracef(ctx, "ratio: %v -> %v; size: %#+v -> %#+v", ratioCur, ratioNew, sizeCur, sizeNew) + img := image.NewRGBA(image.Rectangle{ + Max: sizeNew, + }) + + var offsetX, offsetY int + if ratioCur < ratioNew { + offsetX = sizeNew.X - sizeCur.X + switch alignX { + case alignStart: + offsetX *= 0 + case alignCenter: + offsetX /= 2 + case alignEnd: + offsetX /= 1 + } + } else { + offsetY = sizeNew.Y - sizeCur.Y + switch alignY { + case alignStart: + offsetY *= 0 + case alignCenter: + offsetY /= 2 + case alignEnd: + offsetY /= 1 + } + } + + for x := 0; x < sizeCur.X; x++ { + for y := 0; y < sizeCur.Y; y++ { + xNew := x + offsetX + yNew := y + offsetY + + img.Set(xNew, yNew, src.At(x, y)) + } + } + + return img +} + const ( ScreenshotMaxWidth = 384 ScreenshotMaxHeight = 216 diff --git a/pkg/streampanel/monitor.go b/pkg/streampanel/monitor.go index c335236..29ae9b4 100644 --- a/pkg/streampanel/monitor.go +++ b/pkg/streampanel/monitor.go @@ -2,14 +2,14 @@ package streampanel import ( "context" + "runtime" "sync" "image" "time" + "fyne.io/fyne/v2" "fyne.io/fyne/v2/canvas" - "fyne.io/fyne/v2/container" - "fyne.io/fyne/v2/layout" "fyne.io/fyne/v2/widget" "github.com/anthonynsimon/bild/adjust" "github.com/facebookincubator/go-belt/tool/logger" @@ -85,6 +85,18 @@ func (p *Panel) updateMonitorPageImages( logger.Tracef(ctx, "updateMonitorPageImages") defer logger.Tracef(ctx, "/updateMonitorPageImages") + var winSize fyne.Size + switch runtime.GOOS { + default: + winSize = p.monitorPage.Size() + } + lastWinSize := p.monitorLastWinSize + p.monitorLastWinSize = winSize + + if lastWinSize != winSize { + logger.Debugf(ctx, "window size changed %#+v -> %#+v", lastWinSize, winSize) + } + p.monitorPageUpdaterLocker.Lock() defer p.monitorPageUpdaterLocker.Unlock() @@ -98,16 +110,17 @@ func (p *Panel) updateMonitorPageImages( if err != nil { logger.Error(ctx, err) } else { - if !changed { + if !changed && lastWinSize == winSize { return } - //s := p.mainWindow.Canvas().Size() - //img = imgFitTo(img, image.Point{X: 1450, Y: 1450}) + logger.Tracef(ctx, "updating the screenshot image: %v %#+v %#+v", changed, lastWinSize, winSize) + //img = imgFitTo(img, image.Point{X: int(winSize.Width), Y: int(winSize.Height)}) + img = imgFillTo(ctx, img, image.Point{X: int(winSize.Width), Y: int(winSize.Height)}, alignStart, alignStart) img = adjust.Brightness(img, -0.5) imgFyne := canvas.NewImageFromImage(img) - imgFyne.FillMode = canvas.ImageFillOriginal + imgFyne.FillMode = canvas.ImageFillContain + logger.Tracef(ctx, "screenshot image size: %#+v", img.Bounds().Size()) - p.screenshotContainer.Layout = layout.NewBorderLayout(imgFyne, nil, nil, nil) p.screenshotContainer.Objects = p.screenshotContainer.Objects[:0] p.screenshotContainer.Objects = append(p.screenshotContainer.Objects, imgFyne) p.screenshotContainer.Refresh() @@ -121,18 +134,18 @@ func (p *Panel) updateMonitorPageImages( if err != nil { logger.Error(ctx, err) } else { - if !changed { + if !changed && lastWinSize == winSize { return } - //s := p.mainWindow.Canvas().Size() - //img = imgFitTo(img, image.Point{X: int(s.Width), Y: int(s.Height)}) - img = imgFitTo(img, image.Point{X: 1450, Y: 1450}) + logger.Tracef(ctx, "updating the chat image: %v %#+v %#+v", changed, lastWinSize, winSize) + //img = imgFitTo(img, image.Point{X: int(winSize.Width), Y: int(winSize.Height)}) + img = imgFillTo(ctx, img, image.Point{X: int(winSize.Width), Y: int(winSize.Height)}, alignStart, alignEnd) imgFyne := canvas.NewImageFromImage(img) - imgFyne.FillMode = canvas.ImageFillOriginal + imgFyne.FillMode = canvas.ImageFillContain + logger.Tracef(ctx, "chat image size: %#+v", img.Bounds().Size()) - p.chatContainer.Layout = layout.NewVBoxLayout() p.chatContainer.Objects = p.chatContainer.Objects[:0] - p.chatContainer.Objects = append(p.chatContainer.Objects, layout.NewSpacer(), container.NewHBox(imgFyne, layout.NewSpacer())) + p.chatContainer.Objects = append(p.chatContainer.Objects, imgFyne) p.chatContainer.Refresh() } }() diff --git a/pkg/streampanel/panel.go b/pkg/streampanel/panel.go index ddc3f9b..c5530d0 100644 --- a/pkg/streampanel/panel.go +++ b/pkg/streampanel/panel.go @@ -88,8 +88,10 @@ type Panel struct { streamTitleField *widget.Entry streamDescriptionField *widget.Entry + monitorPage *fyne.Container monitorPageUpdaterLocker sync.Mutex monitorPageUpdaterCancel context.CancelFunc + monitorLastWinSize fyne.Size screenshotContainer *fyne.Container chatContainer *fyne.Container @@ -1394,6 +1396,7 @@ func (p *Panel) initMainWindow( startingPage consts.Page, ) { w := p.app.NewWindow(appName) + p.mainWindow = w w.SetMaster() resizeWindow(w, fyne.NewSize(400, 600)) @@ -1538,28 +1541,28 @@ func (p *Panel) initMainWindow( monitorBackgroundFyne := canvas.NewImageFromImage(monitorBackground) monitorBackgroundFyne.FillMode = canvas.ImageFillStretch - p.screenshotContainer = container.NewBorder(nil, nil, nil, nil) + p.screenshotContainer = container.NewStack() obsLabel := widget.NewLabel("OBS:") - obsLabel.Importance = widget.LowImportance + obsLabel.Importance = widget.HighImportance p.streamStatus[obs.ID] = widget.NewLabel("") twLabel := widget.NewLabel("TW:") - twLabel.Importance = widget.LowImportance + twLabel.Importance = widget.HighImportance p.streamStatus[twitch.ID] = widget.NewLabel("") ytLabel := widget.NewLabel("YT:") - ytLabel.Importance = widget.LowImportance + ytLabel.Importance = widget.HighImportance p.streamStatus[youtube.ID] = widget.NewLabel("") streamInfoContainer := container.NewBorder( nil, nil, nil, container.NewVBox( - container.NewHBox(obsLabel, p.streamStatus[obs.ID]), - container.NewHBox(twLabel, p.streamStatus[twitch.ID]), - container.NewHBox(ytLabel, p.streamStatus[youtube.ID]), + container.NewHBox(layout.NewSpacer(), obsLabel, p.streamStatus[obs.ID]), + container.NewHBox(layout.NewSpacer(), twLabel, p.streamStatus[twitch.ID]), + container.NewHBox(layout.NewSpacer(), ytLabel, p.streamStatus[youtube.ID]), ), ) - p.chatContainer = container.NewBorder(nil, nil, nil, nil) - monitorPage := container.NewStack( + p.chatContainer = container.NewStack() + p.monitorPage = container.NewStack( monitorBackgroundFyne, p.screenshotContainer, streamInfoContainer, @@ -1660,7 +1663,7 @@ func (p *Panel) initMainWindow( switch page { case consts.PageControl: - monitorPage.Hide() + p.monitorPage.Hide() obsPage.Hide() restreamPage.Hide() profileControl.Show() @@ -1670,18 +1673,18 @@ func (p *Panel) initMainWindow( profileControl.Hide() restreamPage.Hide() obsPage.Hide() - monitorPage.Show() + p.monitorPage.Show() p.startMonitorPage(ctx) case consts.PageOBS: controlPage.Hide() profileControl.Hide() - monitorPage.Hide() + p.monitorPage.Hide() restreamPage.Hide() obsPage.Show() case consts.PageRestream: controlPage.Hide() profileControl.Hide() - monitorPage.Hide() + p.monitorPage.Hide() obsPage.Hide() restreamPage.Show() p.startRestreamPage(ctx) @@ -1708,11 +1711,10 @@ func (p *Panel) initMainWindow( nil, nil, nil, - container.NewStack(controlPage, monitorPage, obsPage, restreamPage), + container.NewStack(controlPage, p.monitorPage, obsPage, restreamPage), )) w.Show() - p.mainWindow = w p.profilesListWidget = profilesList if _, ok := p.StreamD.(*client.Client); ok {