mirror of
https://github.com/xaionaro-go/streamctl.git
synced 2025-10-05 15:37:00 +08:00
Disable buttons backing non-implemented functions
This commit is contained in:
11
pkg/streamcontrol/capability.go
Normal file
11
pkg/streamcontrol/capability.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package streamcontrol
|
||||||
|
|
||||||
|
type Capability uint
|
||||||
|
|
||||||
|
const (
|
||||||
|
CapabilityUndefined = Capability(iota)
|
||||||
|
CapabilitySendChatMessage
|
||||||
|
CapabilityDeleteChatMessage
|
||||||
|
CapabilityBanUser
|
||||||
|
EndOfCapability
|
||||||
|
)
|
@@ -179,3 +179,18 @@ func (k *Kick) StartStream(
|
|||||||
logger.Warnf(ctx, "not implemented yet")
|
logger.Warnf(ctx, "not implemented yet")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (k *Kick) IsCapable(
|
||||||
|
ctx context.Context,
|
||||||
|
cap streamcontrol.Capability,
|
||||||
|
) bool {
|
||||||
|
switch cap {
|
||||||
|
case streamcontrol.CapabilitySendChatMessage:
|
||||||
|
return false
|
||||||
|
case streamcontrol.CapabilityDeleteChatMessage:
|
||||||
|
return false
|
||||||
|
case streamcontrol.CapabilityBanUser:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
@@ -284,3 +284,10 @@ func (obs *OBS) BanUser(
|
|||||||
) error {
|
) error {
|
||||||
return fmt.Errorf("not implemented, yet")
|
return fmt.Errorf("not implemented, yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (obs *OBS) IsCapable(
|
||||||
|
ctx context.Context,
|
||||||
|
cap streamcontrol.Capability,
|
||||||
|
) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
@@ -131,6 +131,8 @@ type StreamControllerCommons interface {
|
|||||||
SendChatMessage(ctx context.Context, message string) error
|
SendChatMessage(ctx context.Context, message string) error
|
||||||
RemoveChatMessage(ctx context.Context, messageID ChatMessageID) error
|
RemoveChatMessage(ctx context.Context, messageID ChatMessageID) error
|
||||||
BanUser(ctx context.Context, userID ChatUserID, reason string, deadline time.Time) error
|
BanUser(ctx context.Context, userID ChatUserID, reason string, deadline time.Time) error
|
||||||
|
|
||||||
|
IsCapable(context.Context, Capability) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type StreamController[ProfileType StreamProfile] interface {
|
type StreamController[ProfileType StreamProfile] interface {
|
||||||
@@ -241,6 +243,9 @@ func (c *abstractStreamController) RemoveChatMessage(ctx context.Context, messag
|
|||||||
func (c *abstractStreamController) BanUser(ctx context.Context, userID ChatUserID, reason string, deadline time.Time) error {
|
func (c *abstractStreamController) BanUser(ctx context.Context, userID ChatUserID, reason string, deadline time.Time) error {
|
||||||
return c.StreamController.BanUser(ctx, userID, reason, deadline)
|
return c.StreamController.BanUser(ctx, userID, reason, deadline)
|
||||||
}
|
}
|
||||||
|
func (c *abstractStreamController) IsCapable(ctx context.Context, cap Capability) bool {
|
||||||
|
return c.StreamController.IsCapable(ctx, cap)
|
||||||
|
}
|
||||||
|
|
||||||
func ToAbstract[T StreamProfile](c StreamController[T]) AbstractStreamController {
|
func ToAbstract[T StreamProfile](c StreamController[T]) AbstractStreamController {
|
||||||
if c == nil {
|
if c == nil {
|
||||||
|
@@ -903,3 +903,18 @@ func (t *Twitch) BanUser(
|
|||||||
})
|
})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Twitch) IsCapable(
|
||||||
|
ctx context.Context,
|
||||||
|
cap streamcontrol.Capability,
|
||||||
|
) bool {
|
||||||
|
switch cap {
|
||||||
|
case streamcontrol.CapabilitySendChatMessage:
|
||||||
|
return true
|
||||||
|
case streamcontrol.CapabilityDeleteChatMessage:
|
||||||
|
return true
|
||||||
|
case streamcontrol.CapabilityBanUser:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
@@ -1400,3 +1400,18 @@ func (yt *YouTube) BanUser(
|
|||||||
) error {
|
) error {
|
||||||
return fmt.Errorf("not implemented, yet")
|
return fmt.Errorf("not implemented, yet")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (yt *YouTube) IsCapable(
|
||||||
|
ctx context.Context,
|
||||||
|
cap streamcontrol.Capability,
|
||||||
|
) bool {
|
||||||
|
switch cap {
|
||||||
|
case streamcontrol.CapabilitySendChatMessage:
|
||||||
|
return true
|
||||||
|
case streamcontrol.CapabilityDeleteChatMessage:
|
||||||
|
return true
|
||||||
|
case streamcontrol.CapabilityBanUser:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
10
pkg/streamd/api/backend_info.go
Normal file
10
pkg/streamd/api/backend_info.go
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/xaionaro-go/streamctl/pkg/streamcontrol"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BackendInfo struct {
|
||||||
|
Data any
|
||||||
|
Capabilities map[streamcontrol.Capability]struct{}
|
||||||
|
}
|
@@ -66,10 +66,10 @@ type StreamD interface {
|
|||||||
profile streamcontrol.AbstractStreamProfile,
|
profile streamcontrol.AbstractStreamProfile,
|
||||||
customArgs ...any,
|
customArgs ...any,
|
||||||
) error
|
) error
|
||||||
GetBackendData(
|
GetBackendInfo(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
platID streamcontrol.PlatformName,
|
platID streamcontrol.PlatformName,
|
||||||
) (any, error)
|
) (*BackendInfo, error)
|
||||||
EXPERIMENTAL_ReinitStreamControllers(ctx context.Context) error
|
EXPERIMENTAL_ReinitStreamControllers(ctx context.Context) error
|
||||||
GetStreamStatus(
|
GetStreamStatus(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
|
@@ -26,9 +26,6 @@ import (
|
|||||||
"github.com/xaionaro-go/streamctl/pkg/player"
|
"github.com/xaionaro-go/streamctl/pkg/player"
|
||||||
"github.com/xaionaro-go/streamctl/pkg/player/protobuf/go/player_grpc"
|
"github.com/xaionaro-go/streamctl/pkg/player/protobuf/go/player_grpc"
|
||||||
"github.com/xaionaro-go/streamctl/pkg/streamcontrol"
|
"github.com/xaionaro-go/streamctl/pkg/streamcontrol"
|
||||||
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/kick"
|
|
||||||
obs "github.com/xaionaro-go/streamctl/pkg/streamcontrol/obs/types"
|
|
||||||
twitch "github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch/types"
|
|
||||||
youtube "github.com/xaionaro-go/streamctl/pkg/streamcontrol/youtube/types"
|
youtube "github.com/xaionaro-go/streamctl/pkg/streamcontrol/youtube/types"
|
||||||
"github.com/xaionaro-go/streamctl/pkg/streamd/api"
|
"github.com/xaionaro-go/streamctl/pkg/streamd/api"
|
||||||
streamdconfig "github.com/xaionaro-go/streamctl/pkg/streamd/config"
|
streamdconfig "github.com/xaionaro-go/streamctl/pkg/streamd/config"
|
||||||
@@ -710,10 +707,10 @@ func (c *Client) EndStream(
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) GetBackendData(
|
func (c *Client) GetBackendInfo(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
platID streamcontrol.PlatformName,
|
platID streamcontrol.PlatformName,
|
||||||
) (any, error) {
|
) (*api.BackendInfo, error) {
|
||||||
reply, err := withStreamDClient(ctx, c, func(
|
reply, err := withStreamDClient(ctx, c, func(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
client streamd_grpc.StreamDClient,
|
client streamd_grpc.StreamDClient,
|
||||||
@@ -735,50 +732,17 @@ func (c *Client) GetBackendData(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
var data any
|
caps := goconv.CapabilitiesGRPC2Go(ctx, reply.Capabilities)
|
||||||
switch platID {
|
|
||||||
case obs.ID:
|
data, err := goconv.BackendDataGRPC2Go(platID, reply.GetData())
|
||||||
_data := api.BackendDataOBS{}
|
if err != nil {
|
||||||
err = json.Unmarshal(
|
return nil, fmt.Errorf("unable to deserialize data: %w", err)
|
||||||
[]byte(reply.GetData()),
|
|
||||||
&_data,
|
|
||||||
)
|
|
||||||
data = _data
|
|
||||||
case twitch.ID:
|
|
||||||
_data := api.BackendDataTwitch{}
|
|
||||||
err = json.Unmarshal(
|
|
||||||
[]byte(reply.GetData()),
|
|
||||||
&_data,
|
|
||||||
)
|
|
||||||
data = _data
|
|
||||||
case kick.ID:
|
|
||||||
_data := api.BackendDataKick{}
|
|
||||||
err = json.Unmarshal(
|
|
||||||
[]byte(reply.GetData()),
|
|
||||||
&_data,
|
|
||||||
)
|
|
||||||
data = _data
|
|
||||||
case youtube.ID:
|
|
||||||
_data := api.BackendDataYouTube{}
|
|
||||||
err = json.Unmarshal(
|
|
||||||
[]byte(reply.GetData()),
|
|
||||||
&_data,
|
|
||||||
)
|
|
||||||
data = _data
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf(
|
|
||||||
"unknown platform: '%s'",
|
|
||||||
platID,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
return &api.BackendInfo{
|
||||||
return nil, fmt.Errorf(
|
Data: data,
|
||||||
"unable to deserialize data: %w",
|
Capabilities: caps,
|
||||||
err,
|
}, nil
|
||||||
)
|
|
||||||
}
|
|
||||||
return data, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) Restart(ctx context.Context) error {
|
func (c *Client) Restart(ctx context.Context) error {
|
||||||
|
File diff suppressed because it is too large
Load Diff
45
pkg/streamd/grpc/goconv/backend_info.go
Normal file
45
pkg/streamd/grpc/goconv/backend_info.go
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package goconv
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/xaionaro-go/streamctl/pkg/streamcontrol"
|
||||||
|
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/kick"
|
||||||
|
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/obs"
|
||||||
|
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch"
|
||||||
|
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/youtube"
|
||||||
|
"github.com/xaionaro-go/streamctl/pkg/streamd/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
func BackendDataGRPC2Go(
|
||||||
|
platID streamcontrol.PlatformName,
|
||||||
|
dataString string,
|
||||||
|
) (any, error) {
|
||||||
|
var data any
|
||||||
|
var err error
|
||||||
|
switch platID {
|
||||||
|
case obs.ID:
|
||||||
|
_data := api.BackendDataOBS{}
|
||||||
|
err = json.Unmarshal([]byte(dataString), &_data)
|
||||||
|
data = _data
|
||||||
|
case twitch.ID:
|
||||||
|
_data := api.BackendDataTwitch{}
|
||||||
|
err = json.Unmarshal([]byte(dataString), &_data)
|
||||||
|
data = _data
|
||||||
|
case kick.ID:
|
||||||
|
_data := api.BackendDataKick{}
|
||||||
|
err = json.Unmarshal([]byte(dataString), &_data)
|
||||||
|
data = _data
|
||||||
|
case youtube.ID:
|
||||||
|
_data := api.BackendDataYouTube{}
|
||||||
|
err = json.Unmarshal([]byte(dataString), &_data)
|
||||||
|
data = _data
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"unknown platform: '%s'",
|
||||||
|
platID,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return data, err
|
||||||
|
}
|
57
pkg/streamd/grpc/goconv/capabilities.go
Normal file
57
pkg/streamd/grpc/goconv/capabilities.go
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
package goconv
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/facebookincubator/go-belt/tool/logger"
|
||||||
|
"github.com/xaionaro-go/streamctl/pkg/streamcontrol"
|
||||||
|
"github.com/xaionaro-go/streamctl/pkg/streamd/grpc/go/streamd_grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CapabilitiesGRPC2Go(
|
||||||
|
ctx context.Context,
|
||||||
|
caps []streamd_grpc.Capability,
|
||||||
|
) map[streamcontrol.Capability]struct{} {
|
||||||
|
m := map[streamcontrol.Capability]struct{}{}
|
||||||
|
|
||||||
|
for _, cap := range caps {
|
||||||
|
var r streamcontrol.Capability
|
||||||
|
switch cap {
|
||||||
|
case streamd_grpc.Capability_SendChatMessage:
|
||||||
|
r = streamcontrol.CapabilitySendChatMessage
|
||||||
|
case streamd_grpc.Capability_DeleteChatMessage:
|
||||||
|
r = streamcontrol.CapabilityDeleteChatMessage
|
||||||
|
case streamd_grpc.Capability_BanUser:
|
||||||
|
r = streamcontrol.CapabilityBanUser
|
||||||
|
default:
|
||||||
|
logger.Warnf(ctx, "unexpected capability: %v", cap)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
m[r] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func CapabilitiesGo2GRPC(
|
||||||
|
ctx context.Context,
|
||||||
|
caps map[streamcontrol.Capability]struct{},
|
||||||
|
) []streamd_grpc.Capability {
|
||||||
|
var result []streamd_grpc.Capability
|
||||||
|
for cap := range caps {
|
||||||
|
var item streamd_grpc.Capability
|
||||||
|
switch cap {
|
||||||
|
case streamcontrol.CapabilitySendChatMessage:
|
||||||
|
item = streamd_grpc.Capability_SendChatMessage
|
||||||
|
case streamcontrol.CapabilityDeleteChatMessage:
|
||||||
|
item = streamd_grpc.Capability_DeleteChatMessage
|
||||||
|
case streamcontrol.CapabilityBanUser:
|
||||||
|
item = streamd_grpc.Capability_BanUser
|
||||||
|
default:
|
||||||
|
logger.Warnf(ctx, "unexpected capability: %v", cap)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, item)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
@@ -160,6 +160,7 @@ message GetBackendInfoRequest {
|
|||||||
message GetBackendInfoReply {
|
message GetBackendInfoReply {
|
||||||
bool isInitialized = 1;
|
bool isInitialized = 1;
|
||||||
string data = 2;
|
string data = 2;
|
||||||
|
repeated Capability capabilities = 3;
|
||||||
}
|
}
|
||||||
message IsBackendEnabledRequest {
|
message IsBackendEnabledRequest {
|
||||||
string platID = 1;
|
string platID = 1;
|
||||||
@@ -167,6 +168,12 @@ message IsBackendEnabledRequest {
|
|||||||
message IsBackendEnabledReply {
|
message IsBackendEnabledReply {
|
||||||
bool isInitialized = 1;
|
bool isInitialized = 1;
|
||||||
}
|
}
|
||||||
|
enum Capability {
|
||||||
|
capabilityUndefined = 0;
|
||||||
|
SendChatMessage = 1;
|
||||||
|
DeleteChatMessage = 2;
|
||||||
|
BanUser = 3;
|
||||||
|
}
|
||||||
message RestartRequest {}
|
message RestartRequest {}
|
||||||
message RestartReply {}
|
message RestartReply {}
|
||||||
|
|
||||||
|
@@ -334,14 +334,15 @@ func (grpc *GRPCServer) GetBackendInfo(
|
|||||||
err,
|
err,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
data, err := grpc.StreamD.GetBackendData(ctx, platID)
|
info, err := grpc.StreamD.GetBackendInfo(ctx, platID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
"unable to get the backend info: %w",
|
"unable to get the backend info: %w",
|
||||||
err,
|
err,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
dataSerialized, err := json.Marshal(data)
|
|
||||||
|
dataSerialized, err := json.Marshal(info.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
"unable to serialize the backend info: %w",
|
"unable to serialize the backend info: %w",
|
||||||
@@ -352,6 +353,7 @@ func (grpc *GRPCServer) GetBackendInfo(
|
|||||||
return &streamd_grpc.GetBackendInfoReply{
|
return &streamd_grpc.GetBackendInfoReply{
|
||||||
IsInitialized: isEnabled,
|
IsInitialized: isEnabled,
|
||||||
Data: string(dataSerialized),
|
Data: string(dataSerialized),
|
||||||
|
Capabilities: goconv.CapabilitiesGo2GRPC(ctx, info.Capabilities),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -680,9 +680,37 @@ func (d *StreamD) EndStream(ctx context.Context, platID streamcontrol.PlatformNa
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *StreamD) GetBackendData(
|
func (d *StreamD) GetBackendInfo(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
platID streamcontrol.PlatformName,
|
platID streamcontrol.PlatformName,
|
||||||
|
) (*api.BackendInfo, error) {
|
||||||
|
ctrl, err := d.streamController(ctx, platID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to get stream controller for platform '%s': %w", platID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
caps := map[streamcontrol.Capability]struct{}{}
|
||||||
|
for cap := streamcontrol.CapabilityUndefined + 1; cap < streamcontrol.EndOfCapability; cap++ {
|
||||||
|
isCapable := ctrl.IsCapable(ctx, cap)
|
||||||
|
if isCapable {
|
||||||
|
caps[cap] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := d.getBackendData(ctx, platID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to get backend data: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &api.BackendInfo{
|
||||||
|
Data: data,
|
||||||
|
Capabilities: caps,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *StreamD) getBackendData(
|
||||||
|
_ context.Context,
|
||||||
|
platID streamcontrol.PlatformName,
|
||||||
) (any, error) {
|
) (any, error) {
|
||||||
switch platID {
|
switch platID {
|
||||||
case obs.ID:
|
case obs.ID:
|
||||||
|
@@ -31,6 +31,9 @@ type chatUI struct {
|
|||||||
MessagesHistoryLocker sync.Mutex
|
MessagesHistoryLocker sync.Mutex
|
||||||
MessagesHistory []api.ChatMessage
|
MessagesHistory []api.ChatMessage
|
||||||
|
|
||||||
|
CapabilitiesCacheLocker sync.Mutex
|
||||||
|
CapabilitiesCache map[streamcontrol.PlatformName]map[streamcontrol.Capability]struct{}
|
||||||
|
|
||||||
CurrentlyPlayingChatMessageSoundCount int32
|
CurrentlyPlayingChatMessageSoundCount int32
|
||||||
|
|
||||||
// TODO: do not store ctx in a struct:
|
// TODO: do not store ctx in a struct:
|
||||||
@@ -42,8 +45,9 @@ func newChatUI(
|
|||||||
panel *Panel,
|
panel *Panel,
|
||||||
) (*chatUI, error) {
|
) (*chatUI, error) {
|
||||||
ui := &chatUI{
|
ui := &chatUI{
|
||||||
Panel: panel,
|
Panel: panel,
|
||||||
ctx: ctx,
|
CapabilitiesCache: make(map[streamcontrol.PlatformName]map[streamcontrol.Capability]struct{}),
|
||||||
|
ctx: ctx,
|
||||||
}
|
}
|
||||||
if err := ui.init(ctx); err != nil {
|
if err := ui.init(ctx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -224,6 +228,28 @@ func (ui *chatUI) listCreateItem() fyne.CanvasObject {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ui *chatUI) getPlatformCapabilities(
|
||||||
|
ctx context.Context,
|
||||||
|
platID streamcontrol.PlatformName,
|
||||||
|
) (_ret map[streamcontrol.Capability]struct{}, _err error) {
|
||||||
|
logger.Debugf(ctx, "getPlatformCapabilities(ctx, '%s')", platID)
|
||||||
|
defer func() { logger.Debugf(ctx, "/getPlatformCapabilities(ctx, '%s'): %#+v, %v", platID, _ret, _err) }()
|
||||||
|
ui.CapabilitiesCacheLocker.Lock()
|
||||||
|
defer ui.CapabilitiesCacheLocker.Unlock()
|
||||||
|
|
||||||
|
if m, ok := ui.CapabilitiesCache[platID]; ok {
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := ui.Panel.StreamD.GetBackendInfo(ctx, platID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("GetBackendInfo returned error: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.CapabilitiesCache[platID] = info.Capabilities
|
||||||
|
return info.Capabilities, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ui *chatUI) listUpdateItem(
|
func (ui *chatUI) listUpdateItem(
|
||||||
rowID int,
|
rowID int,
|
||||||
obj fyne.CanvasObject,
|
obj fyne.CanvasObject,
|
||||||
@@ -234,6 +260,12 @@ func (ui *chatUI) listUpdateItem(
|
|||||||
entryID := len(ui.MessagesHistory) - 1 - rowID
|
entryID := len(ui.MessagesHistory) - 1 - rowID
|
||||||
msg := ui.MessagesHistory[entryID]
|
msg := ui.MessagesHistory[entryID]
|
||||||
|
|
||||||
|
platCaps, err := ui.getPlatformCapabilities(ctx, msg.Platform)
|
||||||
|
if err != nil {
|
||||||
|
ui.Panel.ReportError(fmt.Errorf("unable to get capabilities of platform '%s': %w", msg.Platform, err))
|
||||||
|
platCaps = map[streamcontrol.Capability]struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
containerPtr := obj.(*fyne.Container)
|
containerPtr := obj.(*fyne.Container)
|
||||||
objs := containerPtr.Objects
|
objs := containerPtr.Objects
|
||||||
label := objs[0].(*widget.Label)
|
label := objs[0].(*widget.Label)
|
||||||
@@ -252,6 +284,11 @@ func (ui *chatUI) listUpdateItem(
|
|||||||
)
|
)
|
||||||
w.Show()
|
w.Show()
|
||||||
}
|
}
|
||||||
|
if _, ok := platCaps[streamcontrol.CapabilityBanUser]; !ok {
|
||||||
|
banUserButton.Disable()
|
||||||
|
} else {
|
||||||
|
banUserButton.Enable()
|
||||||
|
}
|
||||||
removeMsgButton := subContainer.Objects[1].(*widget.Button)
|
removeMsgButton := subContainer.Objects[1].(*widget.Button)
|
||||||
removeMsgButton.OnTapped = func() {
|
removeMsgButton.OnTapped = func() {
|
||||||
w := dialog.NewConfirm(
|
w := dialog.NewConfirm(
|
||||||
@@ -267,6 +304,11 @@ func (ui *chatUI) listUpdateItem(
|
|||||||
)
|
)
|
||||||
w.Show()
|
w.Show()
|
||||||
}
|
}
|
||||||
|
if _, ok := platCaps[streamcontrol.CapabilityDeleteChatMessage]; !ok {
|
||||||
|
removeMsgButton.Disable()
|
||||||
|
} else {
|
||||||
|
removeMsgButton.Enable()
|
||||||
|
}
|
||||||
label.SetText(fmt.Sprintf(
|
label.SetText(fmt.Sprintf(
|
||||||
"%s: %s: %s: %s",
|
"%s: %s: %s: %s",
|
||||||
msg.CreatedAt.Format("15:04"),
|
msg.CreatedAt.Format("15:04"),
|
||||||
|
@@ -3222,14 +3222,14 @@ func (p *Panel) profileWindow(
|
|||||||
}
|
}
|
||||||
backendEnabled[backendID] = isEnabled
|
backendEnabled[backendID] = isEnabled
|
||||||
|
|
||||||
data, err := p.StreamD.GetBackendData(ctx, backendID)
|
info, err := p.StreamD.GetBackendInfo(ctx, backendID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.Close()
|
w.Close()
|
||||||
p.DisplayError(fmt.Errorf("unable to get data of backend '%s': %w", backendID, err))
|
p.DisplayError(fmt.Errorf("unable to get data of backend '%s': %w", backendID, err))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
backendData[backendID] = data
|
backendData[backendID] = info.Data
|
||||||
}
|
}
|
||||||
_ = backendData[obs.ID].(api.BackendDataOBS)
|
_ = backendData[obs.ID].(api.BackendDataOBS)
|
||||||
dataTwitch := backendData[twitch.ID].(api.BackendDataTwitch)
|
dataTwitch := backendData[twitch.ID].(api.BackendDataTwitch)
|
||||||
|
@@ -406,6 +406,7 @@ func (p *Panel) displayIncomingServers(
|
|||||||
playButton := widget.NewButtonWithIcon("", theme.MediaPlayIcon(), func() {
|
playButton := widget.NewButtonWithIcon("", theme.MediaPlayIcon(), func() {
|
||||||
p.DisplayError(fmt.Errorf("playback is not implemented, yet"))
|
p.DisplayError(fmt.Errorf("playback is not implemented, yet"))
|
||||||
})
|
})
|
||||||
|
playButton.Hide() // TODO: unhide when it will be implemented
|
||||||
deleteButton := widget.NewButtonWithIcon("", theme.DeleteIcon(), func() {
|
deleteButton := widget.NewButtonWithIcon("", theme.DeleteIcon(), func() {
|
||||||
w := dialog.NewConfirm(
|
w := dialog.NewConfirm(
|
||||||
fmt.Sprintf("Delete incoming server %s ?", stream.StreamID),
|
fmt.Sprintf("Delete incoming server %s ?", stream.StreamID),
|
||||||
|
Reference in New Issue
Block a user