Few fixes as result of a test in the field
Some checks failed
rolling-release / build (push) Has been cancelled
rolling-release / rolling-release (push) Has been cancelled

This commit is contained in:
Dmitrii Okunev
2025-06-14 22:04:15 +01:00
parent 3a4648303c
commit 1b832f66ef
7 changed files with 129 additions and 22 deletions

View File

@@ -5,4 +5,4 @@ Website = "https://github.com/xaionaro/streamctl"
Name = "streampanel"
ID = "center.dx.streampanel"
Version = "0.1.0"
Build = 368
Build = 372

View File

@@ -1,9 +1,13 @@
package main
import (
"time"
"github.com/xaionaro-go/xpath"
"github.com/xaionaro-go/xsync"
)
func init() {
xpath.HomeDirOverride = "/data/user/0/center.dx.streampanel/files"
xsync.DefaultDeadlockTimeout = time.Hour
}

12
go.mod
View File

@@ -233,10 +233,10 @@ require (
golang.org/x/image v0.18.0 // indirect
golang.org/x/mobile v0.0.0-20240404231514-09dbf07665ed // indirect
golang.org/x/net v0.39.0 // indirect
golang.org/x/sync v0.13.0 // indirect
golang.org/x/sys v0.32.0 // indirect
golang.org/x/term v0.31.0 // indirect
golang.org/x/text v0.24.0 // indirect
golang.org/x/sync v0.14.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/term v0.32.0 // indirect
golang.org/x/text v0.25.0 // indirect
golang.org/x/time v0.9.0 // indirect
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250409194420-de1ac958c67a // indirect
@@ -313,9 +313,9 @@ require (
github.com/xaionaro-go/xfyne v0.0.0-20241018233531-26123724a6c6
github.com/xaionaro-go/xlogrus v0.0.0-20250111150201-60557109545a
github.com/xaionaro-go/xpath v0.0.0-20250111145115-55f5728f643f
github.com/xaionaro-go/xsync v0.0.0-20250420144932-1e27f4332d4d
github.com/xaionaro-go/xsync v0.0.0-20250614210231-b74f647f859f
github.com/yutopp/go-flv v0.3.1
golang.org/x/crypto v0.37.0
golang.org/x/crypto v0.38.0
google.golang.org/grpc v1.71.1
google.golang.org/protobuf v1.36.6
gopkg.in/yaml.v2 v2.4.0

24
go.sum
View File

@@ -1184,8 +1184,8 @@ github.com/xaionaro-go/xlogrus v0.0.0-20250111150201-60557109545a h1:EoNRdOtBMnZ
github.com/xaionaro-go/xlogrus v0.0.0-20250111150201-60557109545a/go.mod h1:RPfWNuwqJykkA2TEvisXqHgy1ypA/1H2HBdIRSeVJ9o=
github.com/xaionaro-go/xpath v0.0.0-20250111145115-55f5728f643f h1:ofxY1akRlVdJ/AEDj0EakK4Aez8fzeWTTe2mCAZiJ0A=
github.com/xaionaro-go/xpath v0.0.0-20250111145115-55f5728f643f/go.mod h1:f0DVcqddOy1RALOgXJHwpQnkp1u1yeBX/+A2+Bf4EGc=
github.com/xaionaro-go/xsync v0.0.0-20250420144932-1e27f4332d4d h1:paN6zI8tpStL7gEbt4m24vbOFdkNUwnDqXtT3B2dzSo=
github.com/xaionaro-go/xsync v0.0.0-20250420144932-1e27f4332d4d/go.mod h1:FCpywNAl4a4hgzE8j7Z+TpdhBQi5WHxnI35jOrFpoQw=
github.com/xaionaro-go/xsync v0.0.0-20250614210231-b74f647f859f h1:Yn/hgHYgZ05zaTo6cK+Fmx46ah0O8ey0JMsWQ4TsgnY=
github.com/xaionaro-go/xsync v0.0.0-20250614210231-b74f647f859f/go.mod h1:FCpywNAl4a4hgzE8j7Z+TpdhBQi5WHxnI35jOrFpoQw=
github.com/xaionaro-go/zerolog2belt v0.0.0-20241103164018-a3bc1ea487e5 h1:jAy7VLg8y8XE1R8jBte4PRDJzOaAE+sUfmttfB9ZcAY=
github.com/xaionaro-go/zerolog2belt v0.0.0-20241103164018-a3bc1ea487e5/go.mod h1:KJuX7yl27vU+KV6CpsWOe5ZMY4zSg70hvEhwoYdr17w=
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
@@ -1284,8 +1284,8 @@ golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -1451,8 +1451,8 @@ golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -1565,8 +1565,8 @@ golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -1579,8 +1579,8 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1598,8 +1598,8 @@ golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=

View File

@@ -7,10 +7,12 @@ import (
"image/color"
"image/draw"
"math"
"os"
"runtime"
"slices"
"sort"
"strconv"
"strings"
"sync"
"sync/atomic"
@@ -42,6 +44,7 @@ import (
"github.com/xaionaro-go/streamctl/pkg/streampanel/consts"
"github.com/xaionaro-go/streamctl/pkg/ximage"
xfyne "github.com/xaionaro-go/xfyne/widget"
"github.com/xaionaro-go/xpath"
"github.com/xaionaro-go/xsync"
)
@@ -50,6 +53,9 @@ const (
dashboardFullUpdatesInterval = 2 * time.Second
)
// TODO: DELETE ME:
var qualityFilePath = must(xpath.Expand(`~/quality`))
func (p *Panel) focusDashboardWindow(
ctx context.Context,
) {
@@ -92,6 +98,82 @@ type imageInfo struct {
Image *image.NRGBA
}
func (w *dashboardWindow) renderLocalStatus(ctx context.Context) {
// TODO: remove the ugly hardcode above, and make it generic (support different use cases)
b, err := os.ReadFile(qualityFilePath)
if err != nil {
logger.Debugf(ctx, "unable to open the 'quality' file: %v", err)
return
}
words := strings.Split(strings.Trim(string(b), "\n\r\t"), " ")
if len(words) != 3 {
logger.Debugf(ctx, "expected 3 words, but received %d", len(words))
return
}
aQ, err := strconv.ParseInt(words[0], 10, 64)
if err != nil {
logger.Debugf(ctx, "unable to parse aQ '%s': %v", words[0], err)
return
}
pQ, err := strconv.ParseInt(words[1], 10, 64)
if err != nil {
logger.Debugf(ctx, "unable to parse pQ '%s': %v", words[0], err)
return
}
wQ, err := strconv.ParseInt(words[2], 10, 64)
if err != nil {
logger.Debugf(ctx, "unable to parse wQ '%s': %v", words[0], err)
return
}
qToImportance := func(in int64) widget.Importance {
switch {
case in <= -5:
return widget.DangerImportance
case in <= 0:
return widget.MediumImportance
default:
return widget.SuccessImportance
}
}
qToStr := func(in int64) string {
if in <= -30 {
return "DEAD"
}
if in <= -5 {
return "BAD"
}
if in <= 0 {
return "SO-SO"
}
if in > 0 {
return "GOOD"
}
return "UNKNOWN"
}
qToLabel := func(name string, q int64) *widget.Label {
l := widget.NewLabel(name + ":" + qToStr(q))
l.Importance = qToImportance(q)
l.TextStyle.Bold = true
return l
}
w.localStatus.Objects = []fyne.CanvasObject{
container.NewHBox(
layout.NewSpacer(),
qToLabel("A", aQ),
qToLabel("P", pQ),
qToLabel("W", wQ),
),
}
}
func (w *dashboardWindow) renderStreamStatus(ctx context.Context) {
w.streamStatusLocker.Do(ctx, func() {
streamDClient, ok := w.StreamD.(*client.Client)
@@ -180,6 +262,7 @@ func (p *Panel) newDashboardWindow(
bgFyne := canvas.NewImageFromImage(bg)
bgFyne.FillMode = canvas.ImageFillStretch
p.localStatus = container.NewStack()
p.appStatus = widget.NewLabel("")
obsLabel := widget.NewLabel("OBS:")
obsLabel.Importance = widget.HighImportance
@@ -197,8 +280,13 @@ func (p *Panel) newDashboardWindow(
if _, ok := p.StreamD.(*client.Client); ok {
appLabel := widget.NewLabel("App:")
appLabel.Importance = widget.HighImportance
streamInfoItems.Add(container.NewHBox(layout.NewSpacer(), appLabel, p.appStatus))
streamInfoItems.Add(container.NewHBox(
layout.NewSpacer(),
appLabel,
p.appStatus,
))
}
streamInfoItems.Add(container.NewHBox(layout.NewSpacer(), p.localStatus))
streamInfoItems.Add(container.NewHBox(layout.NewSpacer(), obsLabel, w.streamStatus[obs.ID]))
streamInfoItems.Add(container.NewHBox(layout.NewSpacer(), twLabel, w.streamStatus[twitch.ID]))
streamInfoItems.Add(container.NewHBox(layout.NewSpacer(), kcLabel, w.streamStatus[kick.ID]))
@@ -575,6 +663,20 @@ func (w *dashboardWindow) startUpdatingNoLock(
ctx, cancelFunc := context.WithCancel(ctx)
w.stopUpdatingFunc = cancelFunc
w.renderLocalStatus(ctx)
observability.Go(ctx, func() {
t := time.NewTicker(2 * time.Second)
for {
select {
case <-ctx.Done():
return
case <-t.C:
}
w.renderLocalStatus(ctx)
}
})
cfg, err := w.GetStreamDConfig(ctx)
if err != nil {
w.DisplayError(fmt.Errorf("unable to get the current config: %w", err))

View File

@@ -92,6 +92,7 @@ type Panel struct {
dashboardLocker xsync.Mutex
dashboardShowHideButton *widget.Button
localStatus *fyne.Container
appStatus *widget.Label
appStatusData struct {
prevUpdateTS time.Time

View File

@@ -909,8 +909,8 @@ func (p *StreamPlayerHandler) controllerLoop(
return
}
speed = float64(uint(speed*10)) / 10 // to avoid flickering (for example between 1.0001 and 1.0)
if speed < 0.5 {
speed = 0.5
if speed < 0.8 {
speed = 0.8
}
if speed == curSpeed {
return