add twitch message handler

This commit is contained in:
Simon Vieille 2025-08-27 16:24:20 +02:00
commit 1e064ab5e4
Signed by: deblan
GPG key ID: 579388D585F70417
14 changed files with 109 additions and 15 deletions

View file

@ -37,8 +37,13 @@ func (ctrl *Controller) Messages(c echo.Context) error {
Map(store.GetMessageStore().All(), func(message store.MessageInterface) Node {
var containerStyle Node
var userStyle Node
var originIcon Node
if message.Origin() == store.MessageOriginOwncast {
}
switch message.Origin() {
case store.MessageOriginOwncast:
msg := message.(store.OwncastMessage)
containerStyle = StyleAttr(fmt.Sprintf(
@ -50,6 +55,10 @@ func (ctrl *Controller) Messages(c echo.Context) error {
"color: var(--theme-color-users-%d)",
msg.WebhookMessage.User.DisplayColor,
))
originIcon = Img(Src(view.Asset("static/img/owncast.png")), Class("message-origin"))
case store.MessageOriginTwitch:
originIcon = Img(Src(view.Asset("static/img/twitch.png")), Class("message-origin"))
}
return Div(
@ -59,7 +68,7 @@ func (ctrl *Controller) Messages(c echo.Context) error {
Div(
Class("message-user"),
userStyle,
Text(message.Author()),
Group([]Node{originIcon, Text(message.Author())}),
),
Div(
Class("message-body"),

View file

@ -1,11 +1,13 @@
package owncast
import (
"fmt"
"net/http"
"github.com/labstack/echo/v4"
"gitnet.fr/deblan/owncast-webhook/backend/store"
"gitnet.fr/deblan/owncast-webhook/backend/webhook"
webhook "gitnet.fr/deblan/owncast-webhook/backend/webhook/owncast"
"gitnet.fr/deblan/owncast-webhook/config"
)
type Controller struct {
@ -14,7 +16,7 @@ type Controller struct {
func New(e *echo.Echo) *Controller {
c := Controller{}
e.POST("/webhook/owncast/chat_message", c.ChatMessage)
e.POST(fmt.Sprintf("/webhook/%s/owncast/chat_message", config.Get().Server.WebhookSecret), c.ChatMessage)
return &c
}

View file

@ -4,7 +4,7 @@ import (
"fmt"
"strings"
"gitnet.fr/deblan/owncast-webhook/backend/webhook"
webhook "gitnet.fr/deblan/owncast-webhook/backend/webhook/owncast"
"gitnet.fr/deblan/owncast-webhook/config"
)

View file

@ -0,0 +1,27 @@
package store
import "github.com/gempir/go-twitch-irc/v4"
type TwitchMessage struct {
Message twitch.PrivateMessage
}
func (o TwitchMessage) ID() string {
return o.Message.ID
}
func (o TwitchMessage) Visible() bool {
return true
}
func (o TwitchMessage) Origin() MessageOrigin {
return MessageOriginTwitch
}
func (o TwitchMessage) Author() string {
return o.Message.User.DisplayName
}
func (o TwitchMessage) Content() string {
return o.Message.Message
}

View file

@ -14,6 +14,7 @@ import (
"github.com/labstack/echo/v4/middleware"
"gitnet.fr/deblan/owncast-webhook/backend/router"
"gitnet.fr/deblan/owncast-webhook/config"
"gitnet.fr/deblan/owncast-webhook/twitch"
)
type TemplateRenderer struct {
@ -42,6 +43,10 @@ func main() {
e.Use(middleware.Logger())
router.RegisterControllers(e)
if conf.Twitch.Enable {
twitch.IrcClient()
}
if err := e.Start(fmt.Sprintf("%s:%d", conf.Server.Address, conf.Server.Port)); err != nil && !errors.Is(err, http.ErrServerClosed) {
log.Fatal(err)
}

12
config.ini.example Normal file
View file

@ -0,0 +1,12 @@
[server]
port = 1926
address = "0.0.0.0"
base_url = "https://api.example.com"
webhook_secret = "86f9ac485ffaf1c24f03e3fd441f65d9"
[owncast]
base_url = "https://live.example.com"
[twitch]
enable = false
channel = "username"

View file

@ -8,18 +8,17 @@ import (
type Config struct {
Server struct {
BaseUrl string
Address string
Port int
BaseUrl string
Address string
WebhookSecret string
Port int
}
Owncast struct {
BaseUrl string
}
Twitch struct {
ClientId string
ClientSecret string
WebhookUrl string
WebhookSecret string
Enable bool
Channel string
}
}
@ -43,11 +42,10 @@ func (c *Config) Load(file string) {
config.Server.Address = cfg.Section("server").Key("address").String()
config.Server.Port, _ = cfg.Section("server").Key("port").Int()
config.Server.BaseUrl = cfg.Section("server").Key("base_url").String()
config.Server.WebhookSecret = cfg.Section("server").Key("webhook_secret").String()
config.Owncast.BaseUrl = cfg.Section("owncast").Key("base_url").String()
config.Twitch.ClientId = cfg.Section("twitch").Key("client_id").String()
config.Twitch.ClientSecret = cfg.Section("twitch").Key("client_secret").String()
config.Twitch.WebhookSecret = cfg.Section("twitch").Key("webhook_secret").String()
config.Twitch.WebhookUrl = cfg.Section("twitch").Key("webhook_url").String()
config.Twitch.Enable = cfg.Section("twitch").Key("enable").MustBool(false)
config.Twitch.Channel = cfg.Section("twitch").Key("channel").String()
}

BIN
frontend/img/owncast.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
frontend/img/twitch.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 B

View file

@ -36,6 +36,12 @@
border-radius: 5px;
border: 2px solid #00ced1;
padding: 10px;
.message-origin {
height: 15px;
vertical-align: middle;
margin-right: 4px;
}
.message-user {
color: #58d63c;

2
go.mod
View file

@ -5,6 +5,7 @@ go 1.23.0
require (
github.com/GeertJohan/go.rice v1.0.3
github.com/a-h/templ v0.2.778
github.com/gempir/go-twitch-irc/v4 v4.2.0
github.com/go-playground/validator v9.31.0+incompatible
github.com/labstack/echo/v4 v4.12.0
gopkg.in/ini.v1 v1.67.0
@ -23,6 +24,7 @@ require (
github.com/stretchr/testify v1.9.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
github.com/yassinebenaid/godump v0.11.1 // indirect
golang.org/x/crypto v0.27.0 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/sys v0.25.0 // indirect

4
go.sum
View file

@ -8,6 +8,8 @@ github.com/daaku/go.zipexe v1.0.2 h1:Zg55YLYTr7M9wjKn8SY/WcpuuEi+kR2u4E8RhvpyXmk
github.com/daaku/go.zipexe v1.0.2/go.mod h1:5xWogtqlYnfBXkSB1o9xysukNP9GTvaNkqzUZbt3Bw8=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gempir/go-twitch-irc/v4 v4.2.0 h1:OCeff+1aH4CZIOxgKOJ8dQjh+1ppC6sLWrXOcpGZyq4=
github.com/gempir/go-twitch-irc/v4 v4.2.0/go.mod h1:QsOMMAk470uxQ7EYD9GJBGAVqM/jDrXBNbuePfTauzg=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
@ -40,6 +42,8 @@ github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyC
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/yassinebenaid/godump v0.11.1 h1:SPujx/XaYqGDfmNh7JI3dOyCUVrG0bG2duhO3Eh2EhI=
github.com/yassinebenaid/godump v0.11.1/go.mod h1:dc/0w8wmg6kVIvNGAzbKH1Oa54dXQx8SNKh4dPRyW44=
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=

29
twitch/irc_client.go Normal file
View file

@ -0,0 +1,29 @@
package twitch
import (
"log"
tw "github.com/gempir/go-twitch-irc/v4"
"gitnet.fr/deblan/owncast-webhook/backend/store"
"gitnet.fr/deblan/owncast-webhook/config"
)
func IrcClient() {
client := tw.NewAnonymousClient()
client.OnPrivateMessage(func(message tw.PrivateMessage) {
store.GetMessageStore().Add(store.TwitchMessage{
Message: message,
})
})
client.Join(config.Get().Twitch.Channel)
go func() {
err := client.Connect()
if err != nil {
log.Fatal(err.Error())
}
}()
}