mirror of
https://github.com/xaionaro-go/streamctl.git
synced 2025-10-28 01:41:34 +08:00
Initial commit, pt. 59
This commit is contained in:
@@ -30,7 +30,7 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if flags.SplitProcess {
|
if flags.SplitProcess && flags.RemoteAddr == "" {
|
||||||
runSplitProcesses(ctx, flags)
|
runSplitProcesses(ctx, flags)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,14 @@ type MPV struct {
|
|||||||
|
|
||||||
var _ Player = (*MPV)(nil)
|
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 == "" {
|
if pathToMPV == "" {
|
||||||
pathToMPV = "mpv"
|
pathToMPV = "mpv"
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ func (p *Panel) getImage(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func imgFitTo(src image.Image, size image.Point) image.Image {
|
func imgFitTo(src image.Image, size image.Point) image.Image {
|
||||||
sizeCur := src.Bounds().Max
|
sizeCur := src.Bounds().Size()
|
||||||
factor := math.MaxFloat64
|
factor := math.MaxFloat64
|
||||||
factor = math.Min(factor, float64(size.X)/float64(sizeCur.X))
|
factor = math.Min(factor, float64(size.X)/float64(sizeCur.X))
|
||||||
factor = math.Min(factor, float64(size.Y)/float64(sizeCur.Y))
|
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)
|
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 (
|
const (
|
||||||
ScreenshotMaxWidth = 384
|
ScreenshotMaxWidth = 384
|
||||||
ScreenshotMaxHeight = 216
|
ScreenshotMaxHeight = 216
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ package streampanel
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"image"
|
"image"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
"fyne.io/fyne/v2/canvas"
|
"fyne.io/fyne/v2/canvas"
|
||||||
"fyne.io/fyne/v2/container"
|
|
||||||
"fyne.io/fyne/v2/layout"
|
|
||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
"github.com/anthonynsimon/bild/adjust"
|
"github.com/anthonynsimon/bild/adjust"
|
||||||
"github.com/facebookincubator/go-belt/tool/logger"
|
"github.com/facebookincubator/go-belt/tool/logger"
|
||||||
@@ -85,6 +85,18 @@ func (p *Panel) updateMonitorPageImages(
|
|||||||
logger.Tracef(ctx, "updateMonitorPageImages")
|
logger.Tracef(ctx, "updateMonitorPageImages")
|
||||||
defer 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()
|
p.monitorPageUpdaterLocker.Lock()
|
||||||
defer p.monitorPageUpdaterLocker.Unlock()
|
defer p.monitorPageUpdaterLocker.Unlock()
|
||||||
|
|
||||||
@@ -98,16 +110,17 @@ func (p *Panel) updateMonitorPageImages(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(ctx, err)
|
logger.Error(ctx, err)
|
||||||
} else {
|
} else {
|
||||||
if !changed {
|
if !changed && lastWinSize == winSize {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//s := p.mainWindow.Canvas().Size()
|
logger.Tracef(ctx, "updating the screenshot image: %v %#+v %#+v", changed, lastWinSize, winSize)
|
||||||
//img = imgFitTo(img, image.Point{X: 1450, Y: 1450})
|
//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)
|
img = adjust.Brightness(img, -0.5)
|
||||||
imgFyne := canvas.NewImageFromImage(img)
|
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 = p.screenshotContainer.Objects[:0]
|
||||||
p.screenshotContainer.Objects = append(p.screenshotContainer.Objects, imgFyne)
|
p.screenshotContainer.Objects = append(p.screenshotContainer.Objects, imgFyne)
|
||||||
p.screenshotContainer.Refresh()
|
p.screenshotContainer.Refresh()
|
||||||
@@ -121,18 +134,18 @@ func (p *Panel) updateMonitorPageImages(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(ctx, err)
|
logger.Error(ctx, err)
|
||||||
} else {
|
} else {
|
||||||
if !changed {
|
if !changed && lastWinSize == winSize {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//s := p.mainWindow.Canvas().Size()
|
logger.Tracef(ctx, "updating the chat image: %v %#+v %#+v", changed, lastWinSize, winSize)
|
||||||
//img = imgFitTo(img, image.Point{X: int(s.Width), Y: int(s.Height)})
|
//img = imgFitTo(img, image.Point{X: int(winSize.Width), Y: int(winSize.Height)})
|
||||||
img = imgFitTo(img, image.Point{X: 1450, Y: 1450})
|
img = imgFillTo(ctx, img, image.Point{X: int(winSize.Width), Y: int(winSize.Height)}, alignStart, alignEnd)
|
||||||
imgFyne := canvas.NewImageFromImage(img)
|
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 = 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()
|
p.chatContainer.Refresh()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|||||||
@@ -88,8 +88,10 @@ type Panel struct {
|
|||||||
streamTitleField *widget.Entry
|
streamTitleField *widget.Entry
|
||||||
streamDescriptionField *widget.Entry
|
streamDescriptionField *widget.Entry
|
||||||
|
|
||||||
|
monitorPage *fyne.Container
|
||||||
monitorPageUpdaterLocker sync.Mutex
|
monitorPageUpdaterLocker sync.Mutex
|
||||||
monitorPageUpdaterCancel context.CancelFunc
|
monitorPageUpdaterCancel context.CancelFunc
|
||||||
|
monitorLastWinSize fyne.Size
|
||||||
screenshotContainer *fyne.Container
|
screenshotContainer *fyne.Container
|
||||||
chatContainer *fyne.Container
|
chatContainer *fyne.Container
|
||||||
|
|
||||||
@@ -1394,6 +1396,7 @@ func (p *Panel) initMainWindow(
|
|||||||
startingPage consts.Page,
|
startingPage consts.Page,
|
||||||
) {
|
) {
|
||||||
w := p.app.NewWindow(appName)
|
w := p.app.NewWindow(appName)
|
||||||
|
p.mainWindow = w
|
||||||
w.SetMaster()
|
w.SetMaster()
|
||||||
resizeWindow(w, fyne.NewSize(400, 600))
|
resizeWindow(w, fyne.NewSize(400, 600))
|
||||||
|
|
||||||
@@ -1538,28 +1541,28 @@ func (p *Panel) initMainWindow(
|
|||||||
monitorBackgroundFyne := canvas.NewImageFromImage(monitorBackground)
|
monitorBackgroundFyne := canvas.NewImageFromImage(monitorBackground)
|
||||||
monitorBackgroundFyne.FillMode = canvas.ImageFillStretch
|
monitorBackgroundFyne.FillMode = canvas.ImageFillStretch
|
||||||
|
|
||||||
p.screenshotContainer = container.NewBorder(nil, nil, nil, nil)
|
p.screenshotContainer = container.NewStack()
|
||||||
obsLabel := widget.NewLabel("OBS:")
|
obsLabel := widget.NewLabel("OBS:")
|
||||||
obsLabel.Importance = widget.LowImportance
|
obsLabel.Importance = widget.HighImportance
|
||||||
p.streamStatus[obs.ID] = widget.NewLabel("")
|
p.streamStatus[obs.ID] = widget.NewLabel("")
|
||||||
twLabel := widget.NewLabel("TW:")
|
twLabel := widget.NewLabel("TW:")
|
||||||
twLabel.Importance = widget.LowImportance
|
twLabel.Importance = widget.HighImportance
|
||||||
p.streamStatus[twitch.ID] = widget.NewLabel("")
|
p.streamStatus[twitch.ID] = widget.NewLabel("")
|
||||||
ytLabel := widget.NewLabel("YT:")
|
ytLabel := widget.NewLabel("YT:")
|
||||||
ytLabel.Importance = widget.LowImportance
|
ytLabel.Importance = widget.HighImportance
|
||||||
p.streamStatus[youtube.ID] = widget.NewLabel("")
|
p.streamStatus[youtube.ID] = widget.NewLabel("")
|
||||||
streamInfoContainer := container.NewBorder(
|
streamInfoContainer := container.NewBorder(
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
container.NewVBox(
|
container.NewVBox(
|
||||||
container.NewHBox(obsLabel, p.streamStatus[obs.ID]),
|
container.NewHBox(layout.NewSpacer(), obsLabel, p.streamStatus[obs.ID]),
|
||||||
container.NewHBox(twLabel, p.streamStatus[twitch.ID]),
|
container.NewHBox(layout.NewSpacer(), twLabel, p.streamStatus[twitch.ID]),
|
||||||
container.NewHBox(ytLabel, p.streamStatus[youtube.ID]),
|
container.NewHBox(layout.NewSpacer(), ytLabel, p.streamStatus[youtube.ID]),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
p.chatContainer = container.NewBorder(nil, nil, nil, nil)
|
p.chatContainer = container.NewStack()
|
||||||
monitorPage := container.NewStack(
|
p.monitorPage = container.NewStack(
|
||||||
monitorBackgroundFyne,
|
monitorBackgroundFyne,
|
||||||
p.screenshotContainer,
|
p.screenshotContainer,
|
||||||
streamInfoContainer,
|
streamInfoContainer,
|
||||||
@@ -1660,7 +1663,7 @@ func (p *Panel) initMainWindow(
|
|||||||
|
|
||||||
switch page {
|
switch page {
|
||||||
case consts.PageControl:
|
case consts.PageControl:
|
||||||
monitorPage.Hide()
|
p.monitorPage.Hide()
|
||||||
obsPage.Hide()
|
obsPage.Hide()
|
||||||
restreamPage.Hide()
|
restreamPage.Hide()
|
||||||
profileControl.Show()
|
profileControl.Show()
|
||||||
@@ -1670,18 +1673,18 @@ func (p *Panel) initMainWindow(
|
|||||||
profileControl.Hide()
|
profileControl.Hide()
|
||||||
restreamPage.Hide()
|
restreamPage.Hide()
|
||||||
obsPage.Hide()
|
obsPage.Hide()
|
||||||
monitorPage.Show()
|
p.monitorPage.Show()
|
||||||
p.startMonitorPage(ctx)
|
p.startMonitorPage(ctx)
|
||||||
case consts.PageOBS:
|
case consts.PageOBS:
|
||||||
controlPage.Hide()
|
controlPage.Hide()
|
||||||
profileControl.Hide()
|
profileControl.Hide()
|
||||||
monitorPage.Hide()
|
p.monitorPage.Hide()
|
||||||
restreamPage.Hide()
|
restreamPage.Hide()
|
||||||
obsPage.Show()
|
obsPage.Show()
|
||||||
case consts.PageRestream:
|
case consts.PageRestream:
|
||||||
controlPage.Hide()
|
controlPage.Hide()
|
||||||
profileControl.Hide()
|
profileControl.Hide()
|
||||||
monitorPage.Hide()
|
p.monitorPage.Hide()
|
||||||
obsPage.Hide()
|
obsPage.Hide()
|
||||||
restreamPage.Show()
|
restreamPage.Show()
|
||||||
p.startRestreamPage(ctx)
|
p.startRestreamPage(ctx)
|
||||||
@@ -1708,11 +1711,10 @@ func (p *Panel) initMainWindow(
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
container.NewStack(controlPage, monitorPage, obsPage, restreamPage),
|
container.NewStack(controlPage, p.monitorPage, obsPage, restreamPage),
|
||||||
))
|
))
|
||||||
|
|
||||||
w.Show()
|
w.Show()
|
||||||
p.mainWindow = w
|
|
||||||
p.profilesListWidget = profilesList
|
p.profilesListWidget = profilesList
|
||||||
|
|
||||||
if _, ok := p.StreamD.(*client.Client); ok {
|
if _, ok := p.StreamD.(*client.Client); ok {
|
||||||
|
|||||||
Reference in New Issue
Block a user