From 64c7780b606d34a1b225adfebd951c74111a5e1a Mon Sep 17 00:00:00 2001 From: xuanerwa <58063798+xuanerwa@users.noreply.github.com> Date: Thu, 27 Feb 2025 11:10:36 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Feat:=20add=20`yinliang`=20plugin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/translation.json | 28 ++++++ internal/internal.go | 3 +- plugin/yinliang/yinliang.go | 195 ++++++++++++++++++++++++++++++++++++ 3 files changed, 225 insertions(+), 1 deletion(-) create mode 100644 plugin/yinliang/yinliang.go diff --git a/assets/translation.json b/assets/translation.json index e5b1248..8593ff5 100644 --- a/assets/translation.json +++ b/assets/translation.json @@ -555,6 +555,34 @@ "plugin.wshub.webinfo_text": { "en": "Obs browser output", "zh-CN": "OBS网页输出: " + }, + "plugin.yinliang.title": { + "en": "Volume Control", + "zh-CN": "音量控制" + }, + "plugin.yinliang.description": { + "en": "Control volume via danmaku", + "zh-CN": "通过弹幕控制音量" + }, + "plugin.yinliang.admin_permission": { + "en": "Admin only", + "zh-CN": "仅房管可操作" + }, + "plugin.yinliang.volume_up_cmd": { + "en": "Volume increase command", + "zh-CN": "音量增加命令" + }, + "plugin.yinliang.volume_down_cmd": { + "en": "Volume decrease command", + "zh-CN": "音量减少命令" + }, + "plugin.yinliang.volume_step": { + "en": "Adjustment step (%)", + "zh-CN": "每次音量调整 (%)" + }, + "plugin.yinliang.max_volume": { + "en": "Maximum volume (%)", + "zh-CN": "最大音量限制 (%)" } } } diff --git a/internal/internal.go b/internal/internal.go index e1bde86..0c066c5 100644 --- a/internal/internal.go +++ b/internal/internal.go @@ -16,6 +16,7 @@ import ( "AynaLivePlayer/plugin/sourcelogin" "AynaLivePlayer/plugin/textinfo" "AynaLivePlayer/plugin/wshub" + "AynaLivePlayer/plugin/yinliang" ) func Initialize() { @@ -26,7 +27,7 @@ func Initialize() { liveroom.Initialize() plugins.Initialize() plugins.LoadPlugins( - diange.NewDiange(), qiege.NewQiege(), sourcelogin.NewSourceLogin(), + diange.NewDiange(), qiege.NewQiege(), yinliang.NewYinliang(), sourcelogin.NewSourceLogin(), textinfo.NewTextInfo(), durationmgmt.NewMaxDuration(), wshub.NewWsHub(), diff --git a/plugin/yinliang/yinliang.go b/plugin/yinliang/yinliang.go new file mode 100644 index 0000000..2a05f1e --- /dev/null +++ b/plugin/yinliang/yinliang.go @@ -0,0 +1,195 @@ +package yinliang + +import ( + "AynaLivePlayer/core/events" + "AynaLivePlayer/global" + "AynaLivePlayer/gui" + "AynaLivePlayer/gui/component" + "AynaLivePlayer/gui/xfyne" + "AynaLivePlayer/pkg/config" + "AynaLivePlayer/pkg/event" + "AynaLivePlayer/pkg/i18n" + "fmt" + "strconv" + "strings" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/data/binding" + "fyne.io/fyne/v2/widget" +) + +type Yinliang struct { + config.BaseConfig + AdminPermission bool + VolumeUpCMD string + VolumeDownCMD string + VolumeStep float64 + MaxVolume float64 + currentVolume float64 + panel fyne.CanvasObject +} + +func NewYinliang() *Yinliang { + return &Yinliang{ + AdminPermission: true, + VolumeUpCMD: "音量调大", + VolumeDownCMD: "音量调小", + VolumeStep: 5.0, + MaxVolume: 50.0, + currentVolume: 50.0, + } +} + +func (y *Yinliang) Name() string { + return "Yinliang" +} + +func (y *Yinliang) Enable() error { + config.LoadConfig(y) + + // 配置校验 + if y.VolumeStep > 25 { + y.VolumeStep = 25 + } else if y.VolumeStep < 0 { + y.VolumeStep = 5 + } + if y.MaxVolume > 100 { + y.MaxVolume = 100 + } else if y.MaxVolume < 0 { + y.MaxVolume = 0 + } + + gui.AddConfigLayout(y) + + global.EventManager.RegisterA( + events.LiveRoomMessageReceive, + "plugin.yinliang.message", + y.handleMessage) + + global.EventManager.RegisterA( + events.PlayerVolumeChangeCmd, + "plugin.yinliang.volume_tracker", + func(e *event.Event) { + data := e.Data.(events.PlayerVolumeChangeCmdEvent) + y.currentVolume = data.Volume + }) + return nil +} + +func (y *Yinliang) Disable() error { + return nil +} + +func (y *Yinliang) handleMessage(event *event.Event) { + message := event.Data.(events.LiveRoomMessageReceiveEvent).Message + cmd := strings.TrimSpace(message.Message) + + if cmd != y.VolumeUpCMD && cmd != y.VolumeDownCMD { + return + } + + if !y.AdminPermission || !message.User.Admin { + return + } + + delta := y.VolumeStep + if cmd == y.VolumeDownCMD { + delta = -y.VolumeStep + } + + newVolume := y.currentVolume + delta + if newVolume > y.MaxVolume { + newVolume = y.MaxVolume + } else if newVolume < 0 { + newVolume = 0 + } + + global.EventManager.CallA( + events.PlayerVolumeChangeCmd, + events.PlayerVolumeChangeCmdEvent{ + Volume: newVolume, + }) +} + +func (y *Yinliang) Title() string { + return i18n.T("plugin.yinliang.title") +} + +func (y *Yinliang) Description() string { + return i18n.T("plugin.yinliang.description") +} + +// 在CreatePanel方法中修改控件创建方式 +func (y *Yinliang) CreatePanel() fyne.CanvasObject { + if y.panel != nil { + return y.panel + } + + permCheck := component.NewCheckOneWayBinding( + i18n.T("plugin.yinliang.admin_permission"), + &y.AdminPermission, + y.AdminPermission) + + cmdConfig := container.NewGridWithColumns(2, + widget.NewLabel(i18n.T("plugin.yinliang.volume_up_cmd")), + xfyne.EntryDisableUndoRedo(widget.NewEntryWithData(binding.BindString(&y.VolumeUpCMD))), + widget.NewLabel(i18n.T("plugin.yinliang.volume_down_cmd")), + xfyne.EntryDisableUndoRedo(widget.NewEntryWithData(binding.BindString(&y.VolumeDownCMD))), + ) + + stepEntry := widget.NewEntryWithData(binding.FloatToStringWithFormat(binding.BindFloat(&y.VolumeStep), "%.1f")) + stepEntry.Validator = createFloatValidator(0, 25) + stepEntry.OnChanged = func(s string) { + if v, err := strconv.ParseFloat(s, 64); err == nil { + if v > 25 { + y.VolumeStep = 25 + stepEntry.SetText("25") + } else if v < 0 { + y.VolumeStep = 5 + stepEntry.SetText("5") + } + } + } + + maxVolEntry := widget.NewEntryWithData(binding.FloatToStringWithFormat(binding.BindFloat(&y.MaxVolume), "%.1f")) + maxVolEntry.Validator = createFloatValidator(0, 100) + maxVolEntry.OnChanged = func(s string) { + if v, err := strconv.ParseFloat(s, 64); err == nil { + if v > 100 { + y.MaxVolume = 100 + maxVolEntry.SetText("100") + } else if v < 0 { + y.MaxVolume = 0 + maxVolEntry.SetText("0") + } + } + } + + volumeControlConfig := container.NewGridWithColumns(2, + widget.NewLabel(i18n.T("plugin.yinliang.volume_step")), + xfyne.EntryDisableUndoRedo(stepEntry), + widget.NewLabel(i18n.T("plugin.yinliang.max_volume")), + xfyne.EntryDisableUndoRedo(maxVolEntry), + ) + + y.panel = container.NewVBox( + permCheck, + cmdConfig, + volumeControlConfig, + ) + return y.panel +} + +func createFloatValidator(min, max float64) func(string) error { + return func(s string) error { + v, err := strconv.ParseFloat(s, 64) + if err != nil { + return fmt.Errorf(i18n.T("validation.number_required")) + } + if v < min || v > max { + return fmt.Errorf(i18n.T("validation.range_error")) + } + return nil + } +}