Add the boilerplate code for Kick

This commit is contained in:
Dmitrii Okunev
2024-10-20 22:00:02 +01:00
parent e11665c11d
commit 35a1bec9c3
19 changed files with 348 additions and 7 deletions

View File

@@ -16,6 +16,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/xaionaro-go/streamctl/pkg/observability" "github.com/xaionaro-go/streamctl/pkg/observability"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol" "github.com/xaionaro-go/streamctl/pkg/streamcontrol"
kick "github.com/xaionaro-go/streamctl/pkg/streamcontrol/kick/types"
obs "github.com/xaionaro-go/streamctl/pkg/streamcontrol/obs/types" obs "github.com/xaionaro-go/streamctl/pkg/streamcontrol/obs/types"
twitch "github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch/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"
@@ -216,7 +217,7 @@ func streamStatus(cmd *cobra.Command, args []string) {
result := map[streamcontrol.PlatformName]*streamcontrol.StreamStatus{} result := map[streamcontrol.PlatformName]*streamcontrol.StreamStatus{}
for _, platID := range []streamcontrol.PlatformName{ for _, platID := range []streamcontrol.PlatformName{
obs.ID, twitch.ID, youtube.ID, obs.ID, twitch.ID, youtube.ID, kick.ID,
} { } {
isEnabled, err := streamD.IsBackendEnabled(ctx, platID) isEnabled, err := streamD.IsBackendEnabled(ctx, platID)
assertNoError(ctx, err) assertNoError(ctx, err)

View File

@@ -12,6 +12,7 @@ import (
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol" "github.com/xaionaro-go/streamctl/pkg/streamcontrol"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/kick"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch" "github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/youtube" "github.com/xaionaro-go/streamctl/pkg/streamcontrol/youtube"
"github.com/xaionaro-go/streamctl/pkg/xsync" "github.com/xaionaro-go/streamctl/pkg/xsync"
@@ -138,12 +139,14 @@ func expandPath(rawPath string) string {
const ( const (
idTwitch = twitch.ID idTwitch = twitch.ID
idKick = kick.ID
idYoutube = youtube.ID idYoutube = youtube.ID
) )
func newConfig() streamcontrol.Config { func newConfig() streamcontrol.Config {
cfg := streamcontrol.Config{} cfg := streamcontrol.Config{}
twitch.InitConfig(cfg) twitch.InitConfig(cfg)
kick.InitConfig(cfg)
youtube.InitConfig(cfg) youtube.InitConfig(cfg)
return cfg return cfg
} }
@@ -157,6 +160,9 @@ func generateConfig(cmd *cobra.Command, args []string) {
cfg[idTwitch].StreamProfiles = map[streamcontrol.ProfileName]streamcontrol.AbstractStreamProfile{ cfg[idTwitch].StreamProfiles = map[streamcontrol.ProfileName]streamcontrol.AbstractStreamProfile{
"some_profile": twitch.StreamProfile{}, "some_profile": twitch.StreamProfile{},
} }
cfg[idKick].StreamProfiles = map[streamcontrol.ProfileName]streamcontrol.AbstractStreamProfile{
"some_profile": kick.StreamProfile{},
}
cfg[idYoutube].StreamProfiles = map[streamcontrol.ProfileName]streamcontrol.AbstractStreamProfile{ cfg[idYoutube].StreamProfiles = map[streamcontrol.ProfileName]streamcontrol.AbstractStreamProfile{
"some_profile": youtube.StreamProfile{}, "some_profile": youtube.StreamProfile{},
} }
@@ -218,13 +224,24 @@ func readConfigFromPath(
logger.Debugf(ctx, "final stream profiles of twitch: %#+v", (*cfg)[idTwitch].StreamProfiles) logger.Debugf(ctx, "final stream profiles of twitch: %#+v", (*cfg)[idTwitch].StreamProfiles)
} }
if (*cfg)[idKick] != nil {
err = streamcontrol.ConvertStreamProfiles[kick.StreamProfile](
ctx,
(*cfg)[idKick].StreamProfiles,
)
if err != nil {
return fmt.Errorf("unable to convert stream profiles of kick: %w: <%s>", err, b)
}
logger.Debugf(ctx, "final stream profiles of kick: %#+v", (*cfg)[idKick].StreamProfiles)
}
if (*cfg)[idYoutube] != nil { if (*cfg)[idYoutube] != nil {
err = streamcontrol.ConvertStreamProfiles[youtube.StreamProfile]( err = streamcontrol.ConvertStreamProfiles[youtube.StreamProfile](
ctx, ctx,
(*cfg)[idYoutube].StreamProfiles, (*cfg)[idYoutube].StreamProfiles,
) )
if err != nil { if err != nil {
return fmt.Errorf("unable to convert stream profiles of twitch: %w: <%s>", err, b) return fmt.Errorf("unable to convert stream profiles of youtube: %w: <%s>", err, b)
} }
logger.Debugf( logger.Debugf(
ctx, ctx,
@@ -283,6 +300,34 @@ func getTwitchStreamController(
) )
} }
func getKickStreamController(
ctx context.Context,
cfg streamcontrol.Config,
) (*kick.Kick, error) {
platCfg := streamcontrol.GetPlatformConfig[kick.PlatformSpecificConfig, kick.StreamProfile](
ctx,
cfg,
idKick,
)
if platCfg == nil {
logger.Infof(ctx, "kick config was not found")
return nil, nil
}
logger.Debugf(ctx, "kick config: %#+v", platCfg)
return kick.New(ctx, *platCfg,
func(c kick.Config) error {
return xsync.DoR1(ctx, &saveConfigLock, func() error {
cfg[idKick] = &streamcontrol.AbstractPlatformConfig{
Config: c.Config,
StreamProfiles: streamcontrol.ToAbstractStreamProfiles(c.StreamProfiles),
}
return saveConfig(ctx, cfg)
})
},
)
}
func getYouTubeStreamController( func getYouTubeStreamController(
ctx context.Context, ctx context.Context,
cfg streamcontrol.Config, cfg streamcontrol.Config,
@@ -325,6 +370,14 @@ func getStreamControllers(
result = append(result, streamcontrol.ToAbstract(twitch)) result = append(result, streamcontrol.ToAbstract(twitch))
} }
kick, err := getKickStreamController(ctx, cfg)
if err != nil {
logger.Panic(ctx, err)
}
if kick != nil {
result = append(result, streamcontrol.ToAbstract(kick))
}
youtube, err := getYouTubeStreamController(ctx, cfg) youtube, err := getYouTubeStreamController(ctx, cfg)
if err != nil { if err != nil {
logger.Panic(ctx, err) logger.Panic(ctx, err)

View File

@@ -23,6 +23,7 @@ import (
"github.com/xaionaro-go/streamctl/cmd/streamd/ui" "github.com/xaionaro-go/streamctl/cmd/streamd/ui"
"github.com/xaionaro-go/streamctl/pkg/observability" "github.com/xaionaro-go/streamctl/pkg/observability"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol" "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/obs"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch" "github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/youtube" "github.com/xaionaro-go/streamctl/pkg/streamcontrol/youtube"
@@ -265,6 +266,9 @@ func main() {
func(ctx context.Context, cfg *streamcontrol.PlatformConfig[twitch.PlatformSpecificConfig, twitch.StreamProfile]) (bool, error) { func(ctx context.Context, cfg *streamcontrol.PlatformConfig[twitch.PlatformSpecificConfig, twitch.StreamProfile]) (bool, error) {
return false, streamd.ErrSkipBackend return false, streamd.ErrSkipBackend
}, },
func(ctx context.Context, cfg *streamcontrol.PlatformConfig[kick.PlatformSpecificConfig, kick.StreamProfile]) (bool, error) {
return false, streamd.ErrSkipBackend
},
func(ctx context.Context, cfg *streamcontrol.PlatformConfig[youtube.PlatformSpecificConfig, youtube.StreamProfile]) (bool, error) { func(ctx context.Context, cfg *streamcontrol.PlatformConfig[youtube.PlatformSpecificConfig, youtube.StreamProfile]) (bool, error) {
return false, streamd.ErrSkipBackend return false, streamd.ErrSkipBackend
}, },

View File

@@ -9,6 +9,7 @@ import (
"github.com/facebookincubator/go-belt/tool/logger" "github.com/facebookincubator/go-belt/tool/logger"
"github.com/xaionaro-go/streamctl/pkg/oauthhandler" "github.com/xaionaro-go/streamctl/pkg/oauthhandler"
"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" obs "github.com/xaionaro-go/streamctl/pkg/streamcontrol/obs/types"
twitch "github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch/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"
@@ -28,6 +29,10 @@ type UI struct {
ctx context.Context, ctx context.Context,
cfg *streamcontrol.PlatformConfig[twitch.PlatformSpecificConfig, twitch.StreamProfile], cfg *streamcontrol.PlatformConfig[twitch.PlatformSpecificConfig, twitch.StreamProfile],
) (bool, error) ) (bool, error)
InputKickUserInfoFn func(
ctx context.Context,
cfg *streamcontrol.PlatformConfig[kick.PlatformSpecificConfig, kick.StreamProfile],
) (bool, error)
InputYouTubeUserInfoFn func( InputYouTubeUserInfoFn func(
ctx context.Context, ctx context.Context,
cfg *streamcontrol.PlatformConfig[youtube.PlatformSpecificConfig, youtube.StreamProfile], cfg *streamcontrol.PlatformConfig[youtube.PlatformSpecificConfig, youtube.StreamProfile],
@@ -50,6 +55,10 @@ func NewUI(
ctx context.Context, ctx context.Context,
cfg *streamcontrol.PlatformConfig[twitch.PlatformSpecificConfig, twitch.StreamProfile], cfg *streamcontrol.PlatformConfig[twitch.PlatformSpecificConfig, twitch.StreamProfile],
) (bool, error), ) (bool, error),
inputKickUserInfoFn func(
ctx context.Context,
cfg *streamcontrol.PlatformConfig[kick.PlatformSpecificConfig, kick.StreamProfile],
) (bool, error),
inputYouTubeUserInfoFn func( inputYouTubeUserInfoFn func(
ctx context.Context, ctx context.Context,
cfg *streamcontrol.PlatformConfig[youtube.PlatformSpecificConfig, youtube.StreamProfile], cfg *streamcontrol.PlatformConfig[youtube.PlatformSpecificConfig, youtube.StreamProfile],
@@ -68,6 +77,7 @@ func NewUI(
CodeChMapLocker: xsync.RWMutex{}, CodeChMapLocker: xsync.RWMutex{},
SetLoggingLevelFn: setLoggingLevel, SetLoggingLevelFn: setLoggingLevel,
InputTwitchUserInfoFn: inputTwitchUserInfoFn, InputTwitchUserInfoFn: inputTwitchUserInfoFn,
InputKickUserInfoFn: inputKickUserInfoFn,
InputYouTubeUserInfoFn: inputYouTubeUserInfoFn, InputYouTubeUserInfoFn: inputYouTubeUserInfoFn,
InputOBSConnectInfoFn: inputOBSConnectInfoFn, InputOBSConnectInfoFn: inputOBSConnectInfoFn,
} }
@@ -220,6 +230,13 @@ func (ui *UI) OAuthHandlerTwitch(
return ui.oauth2Handler(ctx, twitch.ID, arg) return ui.oauth2Handler(ctx, twitch.ID, arg)
} }
func (ui *UI) OAuthHandlerKick(
ctx context.Context,
arg oauthhandler.OAuthHandlerArgument,
) error {
return ui.oauth2Handler(ctx, kick.ID, arg)
}
func (ui *UI) OAuthHandlerYouTube( func (ui *UI) OAuthHandlerYouTube(
ctx context.Context, ctx context.Context,
arg oauthhandler.OAuthHandlerArgument, arg oauthhandler.OAuthHandlerArgument,
@@ -234,6 +251,13 @@ func (ui *UI) InputTwitchUserInfo(
return ui.InputTwitchUserInfoFn(ctx, cfg) return ui.InputTwitchUserInfoFn(ctx, cfg)
} }
func (ui *UI) InputKickUserInfo(
ctx context.Context,
cfg *streamcontrol.PlatformConfig[kick.PlatformSpecificConfig, kick.StreamProfile],
) (bool, error) {
return ui.InputKickUserInfoFn(ctx, cfg)
}
func (ui *UI) InputYouTubeUserInfo( func (ui *UI) InputYouTubeUserInfo(
ctx context.Context, ctx context.Context,
cfg *streamcontrol.PlatformConfig[youtube.PlatformSpecificConfig, youtube.StreamProfile], cfg *streamcontrol.PlatformConfig[youtube.PlatformSpecificConfig, youtube.StreamProfile],

View File

@@ -19,6 +19,7 @@ import (
"github.com/xaionaro-go/streamctl/pkg/mainprocess" "github.com/xaionaro-go/streamctl/pkg/mainprocess"
"github.com/xaionaro-go/streamctl/pkg/observability" "github.com/xaionaro-go/streamctl/pkg/observability"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol" "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/obs"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch" "github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/youtube" "github.com/xaionaro-go/streamctl/pkg/streamcontrol/youtube"
@@ -147,6 +148,12 @@ func runStreamd(
) (bool, error) { ) (bool, error) {
return false, streamd.ErrSkipBackend return false, streamd.ErrSkipBackend
}, },
func(
ctx context.Context,
cfg *streamcontrol.PlatformConfig[kick.PlatformSpecificConfig, kick.StreamProfile],
) (bool, error) {
return false, streamd.ErrSkipBackend
},
func( func(
ctx context.Context, ctx context.Context,
cfg *streamcontrol.PlatformConfig[youtube.PlatformSpecificConfig, youtube.StreamProfile], cfg *streamcontrol.PlatformConfig[youtube.PlatformSpecificConfig, youtube.StreamProfile],

View File

@@ -19,19 +19,27 @@ type Kick struct {
Channel *kickcom.ChannelV1 Channel *kickcom.ChannelV1
Client Client Client Client
ChatHandler *ChatHandler ChatHandler *ChatHandler
SaveCfgFn func(Config) error
} }
var _ streamcontrol.StreamController[StreamProfile] = (*Kick)(nil) var _ streamcontrol.StreamController[StreamProfile] = (*Kick)(nil)
func New(channelSlug string) (*Kick, error) { func New(
ctx := context.TODO() ctx context.Context,
cfg Config,
saveCfgFn func(Config) error,
) (*Kick, error) {
if cfg.Config.Channel == "" {
return nil, fmt.Errorf("channel is not set")
}
client, err := kickcom.New() client, err := kickcom.New()
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to initialize a client to Kick: %w", err) return nil, fmt.Errorf("unable to initialize a client to Kick: %w", err)
} }
channel, err := client.GetChannelV1(ctx, channelSlug) channel, err := client.GetChannelV1(ctx, cfg.Config.Channel)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to obtain channel info: %w", err) return nil, fmt.Errorf("unable to obtain channel info: %w", err)
} }
@@ -39,6 +47,7 @@ func New(channelSlug string) (*Kick, error) {
k := &Kick{ k := &Kick{
Client: client, Client: client,
Channel: channel, Channel: channel,
SaveCfgFn: saveCfgFn,
} }
chatHandler, err := k.newChatHandler(ctx, channel.ID) chatHandler, err := k.newChatHandler(ctx, channel.ID)

View File

@@ -298,6 +298,9 @@ type BackendDataTwitch struct {
Cache cache.Twitch Cache cache.Twitch
} }
type BackendDataKick struct {
}
type BackendDataYouTube struct { type BackendDataYouTube struct {
Cache cache.YouTube Cache cache.YouTube
} }

View File

@@ -23,6 +23,7 @@ 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" obs "github.com/xaionaro-go/streamctl/pkg/streamcontrol/obs/types"
twitch "github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch/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"
@@ -802,6 +803,13 @@ func (c *Client) GetBackendData(
&_data, &_data,
) )
data = _data data = _data
case kick.ID:
_data := api.BackendDataKick{}
err = json.Unmarshal(
[]byte(reply.GetData()),
&_data,
)
data = _data
case youtube.ID: case youtube.ID:
_data := api.BackendDataYouTube{} _data := api.BackendDataYouTube{}
err = json.Unmarshal( err = json.Unmarshal(

View File

@@ -7,6 +7,7 @@ import (
"github.com/facebookincubator/go-belt/tool/logger" "github.com/facebookincubator/go-belt/tool/logger"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol" "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/obs"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch" "github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/youtube" "github.com/xaionaro-go/streamctl/pkg/streamcontrol/youtube"
@@ -35,6 +36,7 @@ func NewConfig() Config {
cfg := streamcontrol.Config{} cfg := streamcontrol.Config{}
obs.InitConfig(cfg) obs.InitConfig(cfg)
twitch.InitConfig(cfg) twitch.InitConfig(cfg)
kick.InitConfig(cfg)
youtube.InitConfig(cfg) youtube.InitConfig(cfg)
return Config{ return Config{
Backends: cfg, Backends: cfg,
@@ -54,6 +56,9 @@ func NewSampleConfig() Config {
cfg.Backends[twitch.ID].StreamProfiles = map[streamcontrol.ProfileName]streamcontrol.AbstractStreamProfile{ cfg.Backends[twitch.ID].StreamProfiles = map[streamcontrol.ProfileName]streamcontrol.AbstractStreamProfile{
"some_profile": twitch.StreamProfile{}, "some_profile": twitch.StreamProfile{},
} }
cfg.Backends[kick.ID].StreamProfiles = map[streamcontrol.ProfileName]streamcontrol.AbstractStreamProfile{
"some_profile": kick.StreamProfile{},
}
cfg.Backends[youtube.ID].StreamProfiles = map[streamcontrol.ProfileName]streamcontrol.AbstractStreamProfile{ cfg.Backends[youtube.ID].StreamProfiles = map[streamcontrol.ProfileName]streamcontrol.AbstractStreamProfile{
"some_profile": youtube.StreamProfile{}, "some_profile": youtube.StreamProfile{},
} }

View File

@@ -11,6 +11,7 @@ import (
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/xaionaro-go/streamctl/pkg/observability" "github.com/xaionaro-go/streamctl/pkg/observability"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol" "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/obs"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch" "github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/youtube" "github.com/xaionaro-go/streamctl/pkg/streamcontrol/youtube"
@@ -89,6 +90,16 @@ func (cfg *Config) UnmarshalYAML(b []byte) (_err error) {
} }
} }
if cfg.Backends[kick.ID] != nil {
err = streamcontrol.ConvertStreamProfiles[kick.StreamProfile](
context.Background(),
cfg.Backends[kick.ID].StreamProfiles,
)
if err != nil {
return fmt.Errorf("unable to convert stream profiles of kick: %w", err)
}
}
if cfg.Backends[youtube.ID] != nil { if cfg.Backends[youtube.ID] != nil {
err = streamcontrol.ConvertStreamProfiles[youtube.StreamProfile]( err = streamcontrol.ConvertStreamProfiles[youtube.StreamProfile](
context.Background(), context.Background(),

View File

@@ -6,6 +6,7 @@ import (
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol" "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/obs"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch" "github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/youtube" "github.com/xaionaro-go/streamctl/pkg/streamcontrol/youtube"
@@ -22,6 +23,8 @@ func ProfileGRPC2Go(
profile = &obs.StreamProfile{} profile = &obs.StreamProfile{}
case twitch.ID: case twitch.ID:
profile = &twitch.StreamProfile{} profile = &twitch.StreamProfile{}
case kick.ID:
profile = &kick.StreamProfile{}
case youtube.ID: case youtube.ID:
profile = &youtube.StreamProfile{} profile = &youtube.StreamProfile{}
default: default:

View File

@@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol" "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/obs"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch" "github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/youtube" "github.com/xaionaro-go/streamctl/pkg/streamcontrol/youtube"
@@ -15,6 +16,8 @@ func NewStreamProfile(
switch platID { switch platID {
case twitch.ID: case twitch.ID:
return &twitch.StreamProfile{}, nil return &twitch.StreamProfile{}, nil
case kick.ID:
return &kick.StreamProfile{}, nil
case youtube.ID: case youtube.ID:
return &youtube.StreamProfile{}, nil return &youtube.StreamProfile{}, nil
case obs.ID: case obs.ID:

View File

@@ -14,6 +14,7 @@ import (
"github.com/facebookincubator/go-belt/tool/logger" "github.com/facebookincubator/go-belt/tool/logger"
"github.com/hashicorp/go-multierror" "github.com/hashicorp/go-multierror"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol" "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/obs"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch" "github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/youtube" "github.com/xaionaro-go/streamctl/pkg/streamcontrol/youtube"
@@ -37,6 +38,8 @@ func (d *StreamD) EXPERIMENTAL_ReinitStreamControllers(ctx context.Context) erro
err = d.initOBSBackend(ctx) err = d.initOBSBackend(ctx)
case strings.ToLower(string(twitch.ID)): case strings.ToLower(string(twitch.ID)):
err = d.initTwitchBackend(ctx) err = d.initTwitchBackend(ctx)
case strings.ToLower(string(kick.ID)):
err = d.initKickBackend(ctx)
case strings.ToLower(string(youtube.ID)): case strings.ToLower(string(youtube.ID)):
err = d.initYouTubeBackend(ctx) err = d.initYouTubeBackend(ctx)
} }
@@ -196,6 +199,47 @@ func newTwitch(
return twitch, nil return twitch, nil
} }
func newKick(
ctx context.Context,
cfg *streamcontrol.AbstractPlatformConfig,
setUserData func(context.Context, *streamcontrol.PlatformConfig[kick.PlatformSpecificConfig, kick.StreamProfile]) (bool, error),
saveCfgFunc func(*streamcontrol.AbstractPlatformConfig) error,
customOAuthHandler kick.OAuthHandler,
getOAuthListenPorts func() []uint16,
) (
*kick.Kick,
error,
) {
platCfg := streamcontrol.ConvertPlatformConfig[kick.PlatformSpecificConfig, kick.StreamProfile](
ctx,
cfg,
)
if platCfg == nil {
return nil, fmt.Errorf("kick config was not found")
}
if cfg.Enable != nil && !*cfg.Enable {
return nil, ErrSkipBackend
}
logger.Debugf(ctx, "kick config: %#+v", platCfg)
cfg = streamcontrol.ToAbstractPlatformConfig(ctx, platCfg)
kick, err := kick.New(ctx, *platCfg,
func(c kick.Config) error {
return saveCfgFunc(&streamcontrol.AbstractPlatformConfig{
Enable: c.Enable,
Config: c.Config,
StreamProfiles: streamcontrol.ToAbstractStreamProfiles(c.StreamProfiles),
Custom: c.Custom,
})
},
)
if err != nil {
return nil, fmt.Errorf("unable to initialize Kick client: %w", err)
}
return kick, nil
}
func newYouTube( func newYouTube(
ctx context.Context, ctx context.Context,
cfg *streamcontrol.AbstractPlatformConfig, cfg *streamcontrol.AbstractPlatformConfig,
@@ -365,6 +409,24 @@ func (d *StreamD) initTwitchBackend(ctx context.Context) error {
return nil return nil
} }
func (d *StreamD) initKickBackend(ctx context.Context) error {
kick, err := newKick(
ctx,
d.Config.Backends[kick.ID],
d.UI.InputKickUserInfo,
func(cfg *streamcontrol.AbstractPlatformConfig) error {
return d.setPlatformConfig(ctx, kick.ID, cfg)
},
d.UI.OAuthHandlerKick,
d.GetOAuthListenPorts,
)
if err != nil {
return err
}
d.StreamControllers.Kick = kick
return nil
}
func (d *StreamD) initYouTubeBackend(ctx context.Context) error { func (d *StreamD) initYouTubeBackend(ctx context.Context) error {
youTube, err := newYouTube( youTube, err := newYouTube(
ctx, ctx,

View File

@@ -8,6 +8,7 @@ import (
"github.com/facebookincubator/go-belt/tool/logger" "github.com/facebookincubator/go-belt/tool/logger"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol" "github.com/xaionaro-go/streamctl/pkg/streamcontrol"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/kick"
twitch "github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch/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"
@@ -35,6 +36,8 @@ func (a *platformsControllerAdapter) CheckStreamStartedByURL(
platID = youtube.ID platID = youtube.ID
case strings.Contains(destination.Hostname(), "twitch"): case strings.Contains(destination.Hostname(), "twitch"):
platID = twitch.ID platID = twitch.ID
case strings.Contains(destination.Hostname(), "global-contribute.live-video.net"):
platID = kick.ID
default: default:
return false, fmt.Errorf( return false, fmt.Errorf(
"do not know how to check if the stream started for '%s'", "do not know how to check if the stream started for '%s'",

View File

@@ -19,6 +19,7 @@ import (
"github.com/xaionaro-go/streamctl/pkg/player" "github.com/xaionaro-go/streamctl/pkg/player"
"github.com/xaionaro-go/streamctl/pkg/repository" "github.com/xaionaro-go/streamctl/pkg/repository"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol" "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/obs"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch" "github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/youtube" "github.com/xaionaro-go/streamctl/pkg/streamcontrol/youtube"
@@ -42,6 +43,7 @@ import (
type StreamControllers struct { type StreamControllers struct {
OBS *obs.OBS OBS *obs.OBS
Twitch *twitch.Twitch Twitch *twitch.Twitch
Kick *kick.Kick
YouTube *youtube.YouTube YouTube *youtube.YouTube
} }
@@ -450,6 +452,8 @@ func (d *StreamD) IsBackendEnabled(
return d.StreamControllers.OBS != nil, nil return d.StreamControllers.OBS != nil, nil
case twitch.ID: case twitch.ID:
return d.StreamControllers.Twitch != nil, nil return d.StreamControllers.Twitch != nil, nil
case kick.ID:
return d.StreamControllers.Kick != nil, nil
case youtube.ID: case youtube.ID:
return d.StreamControllers.YouTube != nil, nil return d.StreamControllers.YouTube != nil, nil
default: default:
@@ -518,6 +522,21 @@ func (d *StreamD) StartStream(
return fmt.Errorf("unable to start the stream on Twitch: %w", err) return fmt.Errorf("unable to start the stream on Twitch: %w", err)
} }
return nil return nil
case kick.ID:
profile, err := streamcontrol.GetStreamProfile[kick.StreamProfile](ctx, profile)
if err != nil {
return fmt.Errorf("unable to convert the profile into Twitch profile: %w", err)
}
err = d.StreamControllers.Kick.StartStream(
d.ctxForController(ctx),
title,
description,
*profile,
customArgs...)
if err != nil {
return fmt.Errorf("unable to start the stream on Twitch: %w", err)
}
return nil
case youtube.ID: case youtube.ID:
profile, err := streamcontrol.GetStreamProfile[youtube.StreamProfile](ctx, profile) profile, err := streamcontrol.GetStreamProfile[youtube.StreamProfile](ctx, profile)
if err != nil { if err != nil {
@@ -617,6 +636,8 @@ func (d *StreamD) GetBackendData(
return api.BackendDataOBS{}, nil return api.BackendDataOBS{}, nil
case twitch.ID: case twitch.ID:
return api.BackendDataTwitch{Cache: d.Cache.Twitch}, nil return api.BackendDataTwitch{Cache: d.Cache.Twitch}, nil
case kick.ID:
return api.BackendDataKick{}, nil
case youtube.ID: case youtube.ID:
return api.BackendDataYouTube{Cache: d.Cache.Youtube}, nil return api.BackendDataYouTube{Cache: d.Cache.Youtube}, nil
default: default:
@@ -644,6 +665,21 @@ func (d *StreamD) tryConnectTwitch(
errmon.ObserveErrorCtx(ctx, err) errmon.ObserveErrorCtx(ctx, err)
} }
func (d *StreamD) tryConnectKick(
ctx context.Context,
) {
if d.StreamControllers.Kick != nil {
return
}
if _, ok := d.Config.Backends[kick.ID]; !ok {
return
}
err := d.initKickBackend(ctx)
errmon.ObserveErrorCtx(ctx, err)
}
func (d *StreamD) tryConnectYouTube( func (d *StreamD) tryConnectYouTube(
ctx context.Context, ctx context.Context,
) { ) {
@@ -676,6 +712,13 @@ func (d *StreamD) streamController(
if d.StreamControllers.Twitch != nil { if d.StreamControllers.Twitch != nil {
result = streamcontrol.ToAbstract(d.StreamControllers.Twitch) result = streamcontrol.ToAbstract(d.StreamControllers.Twitch)
} }
case kick.ID:
if d.StreamControllers.Kick == nil {
d.tryConnectKick(ctx)
}
if d.StreamControllers.Kick != nil {
result = streamcontrol.ToAbstract(d.StreamControllers.Kick)
}
case youtube.ID: case youtube.ID:
if d.StreamControllers.YouTube == nil { if d.StreamControllers.YouTube == nil {
d.tryConnectYouTube(ctx) d.tryConnectYouTube(ctx)

View File

@@ -6,6 +6,7 @@ import (
"github.com/facebookincubator/go-belt/tool/logger" "github.com/facebookincubator/go-belt/tool/logger"
"github.com/xaionaro-go/streamctl/pkg/oauthhandler" "github.com/xaionaro-go/streamctl/pkg/oauthhandler"
"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" obs "github.com/xaionaro-go/streamctl/pkg/streamcontrol/obs/types"
twitch "github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch/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"
@@ -19,12 +20,17 @@ type UI interface {
ctx context.Context, ctx context.Context,
) (bool, string, []byte, error) ) (bool, string, []byte, error)
OAuthHandlerTwitch(ctx context.Context, arg oauthhandler.OAuthHandlerArgument) error OAuthHandlerTwitch(ctx context.Context, arg oauthhandler.OAuthHandlerArgument) error
OAuthHandlerKick(ctx context.Context, arg oauthhandler.OAuthHandlerArgument) error
OAuthHandlerYouTube(ctx context.Context, arg oauthhandler.OAuthHandlerArgument) error OAuthHandlerYouTube(ctx context.Context, arg oauthhandler.OAuthHandlerArgument) error
OpenBrowser(ctx context.Context, url string) error OpenBrowser(ctx context.Context, url string) error
InputTwitchUserInfo( InputTwitchUserInfo(
ctx context.Context, ctx context.Context,
cfg *streamcontrol.PlatformConfig[twitch.PlatformSpecificConfig, twitch.StreamProfile], cfg *streamcontrol.PlatformConfig[twitch.PlatformSpecificConfig, twitch.StreamProfile],
) (bool, error) ) (bool, error)
InputKickUserInfo(
ctx context.Context,
cfg *streamcontrol.PlatformConfig[kick.PlatformSpecificConfig, kick.StreamProfile],
) (bool, error)
InputYouTubeUserInfo( InputYouTubeUserInfo(
ctx context.Context, ctx context.Context,
cfg *streamcontrol.PlatformConfig[youtube.PlatformSpecificConfig, youtube.StreamProfile], cfg *streamcontrol.PlatformConfig[youtube.PlatformSpecificConfig, youtube.StreamProfile],

View File

@@ -26,6 +26,7 @@ import (
"github.com/xaionaro-go/streamctl/pkg/colorx" "github.com/xaionaro-go/streamctl/pkg/colorx"
"github.com/xaionaro-go/streamctl/pkg/observability" "github.com/xaionaro-go/streamctl/pkg/observability"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol" "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/obs"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch" "github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/youtube" "github.com/xaionaro-go/streamctl/pkg/streamcontrol/youtube"
@@ -278,6 +279,7 @@ func (p *Panel) updateMonitorPageStreamStatus(
obs.ID, obs.ID,
youtube.ID, youtube.ID,
twitch.ID, twitch.ID,
kick.ID,
} { } {
wg.Add(1) wg.Add(1)
observability.Go(ctx, func() { observability.Go(ctx, func() {

View File

@@ -35,6 +35,7 @@ import (
"github.com/xaionaro-go/streamctl/pkg/screenshot" "github.com/xaionaro-go/streamctl/pkg/screenshot"
"github.com/xaionaro-go/streamctl/pkg/screenshoter" "github.com/xaionaro-go/streamctl/pkg/screenshoter"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol" "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/obs"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch" "github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch"
"github.com/xaionaro-go/streamctl/pkg/streamcontrol/youtube" "github.com/xaionaro-go/streamctl/pkg/streamcontrol/youtube"
@@ -107,6 +108,7 @@ type Panel struct {
youtubeCheck *widget.Check youtubeCheck *widget.Check
twitchCheck *widget.Check twitchCheck *widget.Check
kickCheck *widget.Check
configPath string configPath string
configCache *streamdconfig.Config configCache *streamdconfig.Config
@@ -662,6 +664,15 @@ func (p *Panel) OAuthHandlerTwitch(
return p.oauthHandler(ctx, twitch.ID, arg) return p.oauthHandler(ctx, twitch.ID, arg)
} }
func (p *Panel) OAuthHandlerKick(
ctx context.Context,
arg oauthhandler.OAuthHandlerArgument,
) error {
logger.Infof(ctx, "OAuthHandlerKick: %#+v", arg)
defer logger.Infof(ctx, "/OAuthHandlerKick")
return p.oauthHandler(ctx, kick.ID, arg)
}
func (p *Panel) OAuthHandlerYouTube( func (p *Panel) OAuthHandlerYouTube(
ctx context.Context, ctx context.Context,
arg oauthhandler.OAuthHandlerArgument, arg oauthhandler.OAuthHandlerArgument,
@@ -857,6 +868,13 @@ func (p *Panel) InputTwitchUserInfo(
return true, nil return true, nil
} }
func (p *Panel) InputKickUserInfo(
ctx context.Context,
cfg *streamcontrol.PlatformConfig[kick.PlatformSpecificConfig, kick.StreamProfile],
) (bool, error) {
return false, fmt.Errorf("not implemented, yet")
}
var youtubeCredentialsCreateLink, _ = url.Parse( var youtubeCredentialsCreateLink, _ = url.Parse(
"https://console.cloud.google.com/apis/credentials/oauthclient", "https://console.cloud.google.com/apis/credentials/oauthclient",
) )
@@ -1105,6 +1123,7 @@ func (p *Panel) refilterProfiles(ctx context.Context) {
subValueMatch = true subValueMatch = true
break break
} }
case kick.StreamProfile:
case youtube.StreamProfile: case youtube.StreamProfile:
if containTagSubstringCI(prof.Tags, filterValue) { if containTagSubstringCI(prof.Tags, filterValue) {
subValueMatch = true subValueMatch = true
@@ -1214,6 +1233,7 @@ func (p *Panel) openSettingsWindow(ctx context.Context) error {
for _, backendID := range []streamcontrol.PlatformName{ for _, backendID := range []streamcontrol.PlatformName{
obs.ID, obs.ID,
twitch.ID, twitch.ID,
kick.ID,
youtube.ID, youtube.ID,
} { } {
isEnabled, err := p.StreamD.IsBackendEnabled(ctx, backendID) isEnabled, err := p.StreamD.IsBackendEnabled(ctx, backendID)
@@ -1319,6 +1339,13 @@ func (p *Panel) openSettingsWindow(ctx context.Context) error {
twitchAlreadyLoggedIn.SetText("(already logged in)") twitchAlreadyLoggedIn.SetText("(already logged in)")
} }
kickAlreadyLoggedIn := widget.NewLabel("")
if !backendEnabled[kick.ID] {
kickAlreadyLoggedIn.SetText("(not logged in)")
} else {
kickAlreadyLoggedIn.SetText("(already logged in)")
}
youtubeAlreadyLoggedIn := widget.NewLabel("") youtubeAlreadyLoggedIn := widget.NewLabel("")
if !backendEnabled[youtube.ID] { if !backendEnabled[youtube.ID] {
youtubeAlreadyLoggedIn.SetText("(not logged in)") youtubeAlreadyLoggedIn.SetText("(not logged in)")
@@ -1432,6 +1459,27 @@ func (p *Panel) openSettingsWindow(ctx context.Context) error {
}), }),
twitchAlreadyLoggedIn, twitchAlreadyLoggedIn,
), ),
container.NewHBox(
widget.NewButtonWithIcon("(Re-)login in Kick", theme.LoginIcon(), func() {
if cfg.Backends[kick.ID] == nil {
kick.InitConfig(cfg.Backends)
}
cfg.Backends[kick.ID].Enable = nil
cfg.Backends[kick.ID].Config = kick.PlatformSpecificConfig{}
if err := p.StreamD.SetConfig(ctx, cfg); err != nil {
p.DisplayError(err)
return
}
if err := p.StreamD.EXPERIMENTAL_ReinitStreamControllers(ctx); err != nil {
p.DisplayError(err)
return
}
}),
kickAlreadyLoggedIn,
),
container.NewHBox( container.NewHBox(
widget.NewButtonWithIcon("(Re-)login in YouTube", theme.LoginIcon(), func() { widget.NewButtonWithIcon("(Re-)login in YouTube", theme.LoginIcon(), func() {
if cfg.Backends[youtube.ID] == nil { if cfg.Backends[youtube.ID] == nil {
@@ -1603,6 +1651,7 @@ func (p *Panel) getUpdatedStatus_backends_noLock(ctx context.Context) {
for _, backendID := range []streamcontrol.PlatformName{ for _, backendID := range []streamcontrol.PlatformName{
obs.ID, obs.ID,
twitch.ID, twitch.ID,
kick.ID,
youtube.ID, youtube.ID,
} { } {
isEnabled, err := p.StreamD.IsBackendEnabled(ctx, backendID) isEnabled, err := p.StreamD.IsBackendEnabled(ctx, backendID)
@@ -1616,6 +1665,9 @@ func (p *Panel) getUpdatedStatus_backends_noLock(ctx context.Context) {
if backendEnabled[twitch.ID] { if backendEnabled[twitch.ID] {
p.twitchCheck.Enable() p.twitchCheck.Enable()
} }
if backendEnabled[kick.ID] {
p.kickCheck.Enable()
}
if backendEnabled[youtube.ID] { if backendEnabled[youtube.ID] {
p.youtubeCheck.Enable() p.youtubeCheck.Enable()
} }
@@ -1856,6 +1908,10 @@ func (p *Panel) initMainWindow(
p.twitchCheck.SetChecked(true) p.twitchCheck.SetChecked(true)
p.twitchCheck.Disable() p.twitchCheck.Disable()
p.kickCheck = widget.NewCheck("Kick", nil)
p.kickCheck.SetChecked(true)
p.kickCheck.Disable()
p.youtubeCheck = widget.NewCheck("YouTube", nil) p.youtubeCheck = widget.NewCheck("YouTube", nil)
p.youtubeCheck.SetChecked(true) p.youtubeCheck.SetChecked(true)
p.youtubeCheck.Disable() p.youtubeCheck.Disable()
@@ -1892,6 +1948,9 @@ func (p *Panel) initMainWindow(
twLabel := widget.NewLabel("TW:") twLabel := widget.NewLabel("TW:")
twLabel.Importance = widget.HighImportance twLabel.Importance = widget.HighImportance
p.streamStatus[twitch.ID] = widget.NewLabel("") p.streamStatus[twitch.ID] = widget.NewLabel("")
kcLabel := widget.NewLabel("Kc:")
kcLabel.Importance = widget.HighImportance
p.streamStatus[kick.ID] = widget.NewLabel("")
ytLabel := widget.NewLabel("YT:") ytLabel := widget.NewLabel("YT:")
ytLabel.Importance = widget.HighImportance ytLabel.Importance = widget.HighImportance
p.streamStatus[youtube.ID] = widget.NewLabel("") p.streamStatus[youtube.ID] = widget.NewLabel("")
@@ -1903,6 +1962,7 @@ func (p *Panel) initMainWindow(
} }
streamInfoItems.Add(container.NewHBox(layout.NewSpacer(), obsLabel, p.streamStatus[obs.ID])) streamInfoItems.Add(container.NewHBox(layout.NewSpacer(), obsLabel, p.streamStatus[obs.ID]))
streamInfoItems.Add(container.NewHBox(layout.NewSpacer(), twLabel, p.streamStatus[twitch.ID])) streamInfoItems.Add(container.NewHBox(layout.NewSpacer(), twLabel, p.streamStatus[twitch.ID]))
streamInfoItems.Add(container.NewHBox(layout.NewSpacer(), kcLabel, p.streamStatus[kick.ID]))
streamInfoItems.Add(container.NewHBox(layout.NewSpacer(), ytLabel, p.streamStatus[youtube.ID])) streamInfoItems.Add(container.NewHBox(layout.NewSpacer(), ytLabel, p.streamStatus[youtube.ID]))
streamInfoContainer := container.NewBorder( streamInfoContainer := container.NewBorder(
nil, nil,
@@ -2243,6 +2303,7 @@ func (p *Panel) setupStreamNoLock(ctx context.Context) {
for _, backendID := range []streamcontrol.PlatformName{ for _, backendID := range []streamcontrol.PlatformName{
obs.ID, obs.ID,
twitch.ID, twitch.ID,
kick.ID,
youtube.ID, youtube.ID,
} { } {
isEnabled, err := p.StreamD.IsBackendEnabled(ctx, backendID) isEnabled, err := p.StreamD.IsBackendEnabled(ctx, backendID)
@@ -2278,6 +2339,19 @@ func (p *Panel) setupStreamNoLock(ctx context.Context) {
} }
} }
if p.kickCheck.Checked && backendEnabled[kick.ID] {
err := p.StreamD.StartStream(
ctx,
kick.ID,
p.streamTitleField.Text,
p.streamDescriptionField.Text,
profile.PerPlatform[kick.ID],
)
if err != nil {
p.DisplayError(fmt.Errorf("unable to setup the stream on Twitch: %w", err))
}
}
if p.youtubeCheck.Checked && backendEnabled[youtube.ID] { if p.youtubeCheck.Checked && backendEnabled[youtube.ID] {
if p.streamIsRunning(ctx, youtube.ID) { if p.streamIsRunning(ctx, youtube.ID) {
logger.Debugf(ctx, "updating the stream info at YouTube") logger.Debugf(ctx, "updating the stream info at YouTube")
@@ -2435,6 +2509,9 @@ func (p *Panel) stopStreamNoLock(ctx context.Context) {
if backendEnabled[twitch.ID] { if backendEnabled[twitch.ID] {
p.twitchCheck.Enable() p.twitchCheck.Enable()
} }
if backendEnabled[kick.ID] {
p.kickCheck.Enable()
}
if backendEnabled[youtube.ID] { if backendEnabled[youtube.ID] {
p.youtubeCheck.Enable() p.youtubeCheck.Enable()
} }
@@ -2845,6 +2922,7 @@ func (p *Panel) profileWindow(
var ( var (
obsProfile *obs.StreamProfile obsProfile *obs.StreamProfile
twitchProfile *twitch.StreamProfile twitchProfile *twitch.StreamProfile
kickProfile *kick.StreamProfile
youtubeProfile *youtube.StreamProfile youtubeProfile *youtube.StreamProfile
) )
@@ -2870,6 +2948,7 @@ func (p *Panel) profileWindow(
for _, backendID := range []streamcontrol.PlatformName{ for _, backendID := range []streamcontrol.PlatformName{
obs.ID, obs.ID,
twitch.ID, twitch.ID,
kick.ID,
youtube.ID, youtube.ID,
} { } {
isEnabled, err := p.StreamD.IsBackendEnabled(ctx, backendID) isEnabled, err := p.StreamD.IsBackendEnabled(ctx, backendID)
@@ -2893,6 +2972,8 @@ func (p *Panel) profileWindow(
} }
_ = backendData[obs.ID].(api.BackendDataOBS) _ = backendData[obs.ID].(api.BackendDataOBS)
dataTwitch := backendData[twitch.ID].(api.BackendDataTwitch) dataTwitch := backendData[twitch.ID].(api.BackendDataTwitch)
dataKick := backendData[kick.ID].(api.BackendDataKick)
_ = dataKick // TODO: delete me!
dataYouTube := backendData[youtube.ID].(api.BackendDataYouTube) dataYouTube := backendData[youtube.ID].(api.BackendDataYouTube)
var bottomContent []fyne.CanvasObject var bottomContent []fyne.CanvasObject
@@ -3026,6 +3107,14 @@ func (p *Panel) profileWindow(
bottomContent = append(bottomContent, widget.NewLabel("Twitch is disabled")) bottomContent = append(bottomContent, widget.NewLabel("Twitch is disabled"))
} }
bottomContent = append(bottomContent, widget.NewSeparator())
bottomContent = append(bottomContent, widget.NewRichTextFromMarkdown("# Kick:"))
if backendEnabled[kick.ID] {
bottomContent = append(bottomContent, widget.NewLabel("Kick configuration is not implemented, yet"))
} else {
bottomContent = append(bottomContent, widget.NewLabel("Kick is disabled"))
}
var getYoutubeTags func() []string var getYoutubeTags func() []string
bottomContent = append(bottomContent, widget.NewSeparator()) bottomContent = append(bottomContent, widget.NewSeparator())
bottomContent = append(bottomContent, widget.NewRichTextFromMarkdown("# YouTube:")) bottomContent = append(bottomContent, widget.NewRichTextFromMarkdown("# YouTube:"))
@@ -3228,6 +3317,9 @@ func (p *Panel) profileWindow(
} }
profile.PerPlatform[twitch.ID] = twitchProfile profile.PerPlatform[twitch.ID] = twitchProfile
} }
if kickProfile != nil {
profile.PerPlatform[kick.ID] = kickProfile
}
if youtubeProfile != nil { if youtubeProfile != nil {
if getYoutubeTags != nil { if getYoutubeTags != nil {
youtubeProfile.Tags = sanitizeTags(getYoutubeTags()) youtubeProfile.Tags = sanitizeTags(getYoutubeTags())

View File

@@ -15,6 +15,7 @@ import (
"github.com/hashicorp/go-multierror" "github.com/hashicorp/go-multierror"
"github.com/xaionaro-go/streamctl/pkg/observability" "github.com/xaionaro-go/streamctl/pkg/observability"
"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" obs "github.com/xaionaro-go/streamctl/pkg/streamcontrol/obs/types"
twitch "github.com/xaionaro-go/streamctl/pkg/streamcontrol/twitch/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"
@@ -250,6 +251,7 @@ func (ui *timersUI) kickOffRemotely(
for _, platID := range []streamcontrol.PlatformName{ for _, platID := range []streamcontrol.PlatformName{
youtube.ID, youtube.ID,
twitch.ID, twitch.ID,
kick.ID,
obs.ID, obs.ID,
} { } {
_, err := streamD.AddTimer(ctx, deadline, &action.EndStream{ _, err := streamD.AddTimer(ctx, deadline, &action.EndStream{