Implemented channel point rewards

This commit is contained in:
Luxferre
2024-09-23 21:46:21 +03:00
parent 0f638e7d43
commit 33d8a54cd8
4 changed files with 48 additions and 5 deletions
+1 -1
View File
@@ -195,7 +195,7 @@ Example `config.json` file:
The following procedure needs to be only done once per ~2 months: The following procedure needs to be only done once per ~2 months:
1. Go to the [Twitch Chat OAuth Password Generator](https://twitchapps.com/tmi/) website. 1. Go to the Twitch Chat OAuth Password Generator website using [this link](https://id.twitch.tv/oauth2/authorize?response_type=token&client_id=q6batx0epp608isickayubi39itsckt&redirect_uri=https://twitchapps.com/tmi/&scope=chat:read+chat:edit+channel:read:redemptions+channel:moderate+whispers:read+whispers:edit+channel_editor).
2. Login with your own Twitch account and give it the access. 2. Login with your own Twitch account and give it the access.
3. Copy the token string that starts with `oauth:` and paste it into the `twitch-token.txt` file in the `auth` subdirectory in the application directory (note that it is different from `twitch-cid.txt` that already is present in this subdirectory). 3. Copy the token string that starts with `oauth:` and paste it into the `twitch-token.txt` file in the `auth` subdirectory in the application directory (note that it is different from `twitch-cid.txt` that already is present in this subdirectory).
4. Save the file. The Twitch connection should now work. 4. Save the file. The Twitch connection should now work.
+10
View File
@@ -2,15 +2,25 @@ module streamgoose
go 1.23.1 go 1.23.1
replace github.com/pajlada/go-twitch-pubsub => github.com/plugnburn/go-twitch-pubsub v0.0.0-20240922200010-4bf88de12fae
require ( require (
centrifuge.hectabit.org/HectaBit/webview_go v0.0.0-20240502074857-17ae24882d16 centrifuge.hectabit.org/HectaBit/webview_go v0.0.0-20240502074857-17ae24882d16
github.com/DaRealFreak/cloudflare-bp-go v1.0.4 github.com/DaRealFreak/cloudflare-bp-go v1.0.4
github.com/plugnburn/go-twitch-pubsub v0.0.0-20240922200010-4bf88de12fae
) )
require ( require (
github.com/BurntSushi/toml v1.4.0 // indirect
github.com/EDDYCJY/fake-useragent v0.2.0 // indirect github.com/EDDYCJY/fake-useragent v0.2.0 // indirect
github.com/PuerkitoBio/goquery v1.7.1 // indirect github.com/PuerkitoBio/goquery v1.7.1 // indirect
github.com/andybalholm/cascadia v1.3.1 // indirect github.com/andybalholm/cascadia v1.3.1 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/stretchr/testify v1.9.0 // indirect github.com/stretchr/testify v1.9.0 // indirect
golang.org/x/exp/typeparams v0.0.0-20240613232115-7f521ea00fb8 // indirect
golang.org/x/mod v0.18.0 // indirect
golang.org/x/net v0.29.0 // indirect golang.org/x/net v0.29.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/tools v0.22.0 // indirect
honnef.co/go/tools v0.4.7 // indirect
) )
+26
View File
@@ -1,5 +1,7 @@
centrifuge.hectabit.org/HectaBit/webview_go v0.0.0-20240502074857-17ae24882d16 h1:gOFnYZ+G9R7Prc3Mn7z/v+LkPf/kQ2oUh5NCQd6n39k= centrifuge.hectabit.org/HectaBit/webview_go v0.0.0-20240502074857-17ae24882d16 h1:gOFnYZ+G9R7Prc3Mn7z/v+LkPf/kQ2oUh5NCQd6n39k=
centrifuge.hectabit.org/HectaBit/webview_go v0.0.0-20240502074857-17ae24882d16/go.mod h1:cAr/pT090G1kcy9uuCEUbZyGhUQRGOo4KVnkocx8BMA= centrifuge.hectabit.org/HectaBit/webview_go v0.0.0-20240502074857-17ae24882d16/go.mod h1:cAr/pT090G1kcy9uuCEUbZyGhUQRGOo4KVnkocx8BMA=
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/DaRealFreak/cloudflare-bp-go v1.0.4 h1:33X8Z0YMV1DEVvL/kYLku+rjb4wF712+VIh3xBoifQ0= github.com/DaRealFreak/cloudflare-bp-go v1.0.4 h1:33X8Z0YMV1DEVvL/kYLku+rjb4wF712+VIh3xBoifQ0=
github.com/DaRealFreak/cloudflare-bp-go v1.0.4/go.mod h1:oBI9KAKb9FqdoB42uUqHU6pdP+YDWlKjpZRSk8JTuwk= github.com/DaRealFreak/cloudflare-bp-go v1.0.4/go.mod h1:oBI9KAKb9FqdoB42uUqHU6pdP+YDWlKjpZRSk8JTuwk=
github.com/EDDYCJY/fake-useragent v0.2.0 h1:Jcnkk2bgXmDpX0z+ELlUErTkoLb/mxFBNd2YdcpvJBs= github.com/EDDYCJY/fake-useragent v0.2.0 h1:Jcnkk2bgXmDpX0z+ELlUErTkoLb/mxFBNd2YdcpvJBs=
@@ -11,19 +13,43 @@ github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x0
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/plugnburn/go-twitch-pubsub v0.0.0-20240922200010-4bf88de12fae h1:SAOjVB7aO1Ez9YRsGaMzH2NVwBTA09kyHFGnLNUYUvU=
github.com/plugnburn/go-twitch-pubsub v0.0.0-20240922200010-4bf88de12fae/go.mod h1:jdM6kjYNIz29klHhXERCjFHGwdTLVtk2RqB8W1cdhmw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
golang.org/x/exp/typeparams v0.0.0-20240613232115-7f521ea00fb8 h1:+ZJmEdDFzH5H0CnzOrwgbH3elHctfTecW9X0k2tkn5M=
golang.org/x/exp/typeparams v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.4.7 h1:9MDAWxMoSnB6QoSqiVr7P5mtkT9pOc1kSxchzPCnqJs=
honnef.co/go/tools v0.4.7/go.mod h1:+rnGS1THNh8zMwnd2oVOTL9QF6vmfyG6ZXBULae2uc0=
+11 -4
View File
@@ -26,6 +26,7 @@ var TW_BADGE_CACHE map[string]string
/* Twitch OAuth global cache */ /* Twitch OAuth global cache */
var TW_OAUTH_TOKEN string var TW_OAUTH_TOKEN string
var TW_CLIENT_ID string var TW_CLIENT_ID string
var TW_BROADCASTER_ID string
/* helper function to write a string to the socket */ /* helper function to write a string to the socket */
func tcpwritestr(conn net.Conn, str string) int { func tcpwritestr(conn net.Conn, str string) int {
@@ -55,6 +56,9 @@ func tw_api_req(url string, data string) []byte {
req, err := http.NewRequest(method, "https://api.twitch.tv/helix" + url, bytes.NewReader([]byte(data))) req, err := http.NewRequest(method, "https://api.twitch.tv/helix" + url, bytes.NewReader([]byte(data)))
req.Header.Set("Authorization", "Bearer " + TW_OAUTH_TOKEN) req.Header.Set("Authorization", "Bearer " + TW_OAUTH_TOKEN)
req.Header.Set("Client-Id", TW_CLIENT_ID) req.Header.Set("Client-Id", TW_CLIENT_ID)
if len(data) > 0 {
req.Header.Set("Content-Type", "application/json")
}
client := &http.Client{} client := &http.Client{}
resp, err := client.Do(req) resp, err := client.Do(req)
@@ -69,7 +73,6 @@ func tw_api_req(url string, data string) []byte {
/* badge cache population function */ /* badge cache population function */
func tw_fetch_badge_cache(channelname string) map[string]string { func tw_fetch_badge_cache(channelname string) map[string]string {
readycache := make(map[string]string) readycache := make(map[string]string)
broadcaster_id := ""
var ustruct map[string]interface{} var ustruct map[string]interface{}
/* get broadcaster ID from the channel name */ /* get broadcaster ID from the channel name */
body := tw_api_req("/users?login=" + channelname, "") body := tw_api_req("/users?login=" + channelname, "")
@@ -78,7 +81,7 @@ func tw_fetch_badge_cache(channelname string) map[string]string {
if err == nil { if err == nil {
if _, ok := ustruct["data"]; ok && len(ustruct["data"].([]interface{})) > 0 { if _, ok := ustruct["data"]; ok && len(ustruct["data"].([]interface{})) > 0 {
bdata := ustruct["data"].([]interface{})[0].(map[string]interface{}) bdata := ustruct["data"].([]interface{})[0].(map[string]interface{})
broadcaster_id = bdata["id"].(string) TW_BROADCASTER_ID = bdata["id"].(string)
} }
} }
} }
@@ -99,8 +102,8 @@ func tw_fetch_badge_cache(channelname string) map[string]string {
} }
} }
} }
if broadcaster_id != "" { /* also get the channel-specific badges */ if TW_BROADCASTER_ID != "" { /* also get the channel-specific badges */
body = tw_api_req(fmt.Sprintf("/chat/badges?broadcaster_id=%s", broadcaster_id), "") body = tw_api_req(fmt.Sprintf("/chat/badges?broadcaster_id=%s", TW_BROADCASTER_ID), "")
if len(body) > 0 { if len(body) > 0 {
err := json.Unmarshal(body, &ustruct) err := json.Unmarshal(body, &ustruct)
if err == nil { if err == nil {
@@ -284,6 +287,7 @@ func twitch_run(config map[string]interface{}) {
chname, _ := strings.CutPrefix(config["tw_channel"].(string), "#") chname, _ := strings.CutPrefix(config["tw_channel"].(string), "#")
TW_BADGE_CACHE = tw_fetch_badge_cache(chname) TW_BADGE_CACHE = tw_fetch_badge_cache(chname)
/* Connect to the Twitch IRC server */ /* Connect to the Twitch IRC server */
conn, err := net.Dial("tcp", "irc.chat.twitch.tv:6667") conn, err := net.Dial("tcp", "irc.chat.twitch.tv:6667")
if err != nil { if err != nil {
@@ -296,6 +300,9 @@ func twitch_run(config map[string]interface{}) {
/* request advanced chat message capabilities */ /* request advanced chat message capabilities */
tcpwritestr(conn, "CAP REQ :twitch.tv/membership twitch.tv/tags twitch.tv/commands\n") tcpwritestr(conn, "CAP REQ :twitch.tv/membership twitch.tv/tags twitch.tv/commands\n")
/* set up subscriptions and start the WebSocket event loop goroutine */
tw_ws_pubsub_readloop()
log.Println("StreamGoose Twitch Go backend connected") log.Println("StreamGoose Twitch Go backend connected")
var rawmsg string var rawmsg string