Compare commits

...

10 commits

Author SHA1 Message Date
tyler f35ec00a16 Migrated from github 2024-06-14 13:29:24 -04:00
tyler 6bcc437bc0 Updated chat info scraper to match rumble website update 2024-05-31 11:26:07 -04:00
tyler a4125e8de8 Added raid and sub fields to chat view 2024-05-27 16:07:44 -04:00
tyler 3818644bb0 LoggedIn returns response 2024-05-24 11:41:51 -04:00
tyler ea9955c164 Added fields to logged-in response 2024-05-24 11:36:04 -04:00
tyler 563d9f9413 Added badge constants 2024-05-21 15:43:04 -04:00
tyler 9c32f33d9f Added rumble chat type constants 2024-05-18 13:08:42 -04:00
tyler ba26735378 Added message time to chat view 2024-05-18 12:41:13 -04:00
tyler a779afcaba Trimmed quotes from RumbleChat args 2024-05-16 17:03:28 -04:00
tyler 5b3593ec1e Trimmed whitespace in RumbleChat arguments 2024-05-16 16:56:35 -04:00
7 changed files with 76 additions and 43 deletions

87
chat.go
View file

@ -13,9 +13,23 @@ import (
"time"
"github.com/r3labs/sse/v2"
"github.com/tylertravisty/go-utils/random"
"golang.org/x/net/html"
"gopkg.in/cenkalti/backoff.v1"
"travisty.io/tyler/go-utils/random"
)
const (
ChatBadgeRecurringSubscription = "recurring_subscription"
ChatBadgeLocalsSupporter = "locals_supporter"
ChatTypeInit = "init"
ChatTypeMessages = "messages"
ChatTypeMuteUsers = "mute_users"
ChatTypeDeleteMessages = "delete_messages"
ChatTypeSubscriber = "locals_supporter"
ChatTypeRaiding = "raid_confirmed"
ChatTypePinMessage = "pin_message"
ChatTypeUnpinMessage = "unpin_message"
)
type ChatInfo struct {
@ -65,24 +79,6 @@ func (c *Client) getChatInfo() (*ChatInfo, error) {
lineS, err := r.ReadString('\n')
for err == nil {
if strings.Contains(lineS, "RumbleChat(") {
//start := strings.Index(lineS, "RumbleChat(") + len("RumbleChat(")
//if start == -1 {
// return nil, fmt.Errorf("error finding chat function in webpage")
//}
//end := strings.Index(lineS[start:], ");")
//if end == -1 {
// return nil, fmt.Errorf("error finding end of chat function in webpage")
//}
//argsS := strings.ReplaceAll(lineS[start:start+end], ", ", ",")
//argsS = strings.Replace(argsS, "[", "\"[", 1)
//n := strings.LastIndex(argsS, "]")
//argsS = argsS[:n] + "]\"" + argsS[n+1:]
//c := csv.NewReader(strings.NewReader(argsS))
//args, err := c.ReadAll()
//if err != nil {
// return nil, fmt.Errorf("error parsing csv: %v", err)
//}
//info := args[0]
start := strings.Index(lineS, "RumbleChat(") + len("RumbleChat(")
if start == -1 {
return nil, fmt.Errorf("error finding chat function in webpage")
@ -92,11 +88,11 @@ func (c *Client) getChatInfo() (*ChatInfo, error) {
return nil, fmt.Errorf("error finding end of chat function in webpage")
}
args := parseRumbleChatArgs(lineS[start : start+end])
channelID, err := strconv.Atoi(args[5])
channelID, err := strconv.Atoi(args[6])
if err != nil {
return nil, fmt.Errorf("error converting channel ID argument string to int: %v", err)
}
chatInfo = &ChatInfo{ChannelID: channelID, ChatID: args[1], UrlPrefix: args[0]}
chatInfo = &ChatInfo{ChannelID: channelID, ChatID: args[2], UrlPrefix: args[0]}
} else if strings.Contains(lineS, "media-by--a") && strings.Contains(lineS, "author") {
r := strings.NewReader(lineS)
node, err := html.Parse(r)
@ -132,7 +128,7 @@ func parseRumbleChatArgs(argsS string) []string {
arg := []rune{}
for _, c := range argsS {
if c == ',' && open == 0 {
args = append(args, string(arg))
args = append(args, trimRumbleChatArg(string(arg)))
arg = []rune{}
} else {
if c == '[' {
@ -146,12 +142,16 @@ func parseRumbleChatArgs(argsS string) []string {
}
}
if len(arg) > 0 {
args = append(args, string(arg))
args = append(args, trimRumbleChatArg(string(arg)))
}
return args
}
func trimRumbleChatArg(arg string) string {
return strings.Trim(strings.TrimSpace(arg), "\"")
}
type ChatMessage struct {
Text string `json:"text"`
}
@ -258,6 +258,15 @@ type ChatEventBlock struct {
Type string `json:"type"`
}
type ChatEventNotification struct {
Badge string `json:"badge"`
Text string `json:"text"`
}
type ChatEventRaidNotification struct {
StartTs int64 `json:"start_ts"`
}
type ChatEventRant struct {
Duration int `json:"duration"`
ExpiresOn string `json:"expires_on"`
@ -265,13 +274,15 @@ type ChatEventRant struct {
}
type ChatEventMessage struct {
Blocks []ChatEventBlock `json:"blocks"`
ChannelID *int64 `json:"channel_id"`
ID string `json:"id"`
Rant *ChatEventRant `json:"rant"`
Text string `json:"text"`
Time string `json:"time"`
UserID string `json:"user_id"`
Blocks []ChatEventBlock `json:"blocks"`
ChannelID *int64 `json:"channel_id"`
ID string `json:"id"`
Notification *ChatEventNotification `json:"notification"`
RaidNotification *ChatEventRaidNotification `json:"raid_notification"`
Rant *ChatEventRant `json:"rant"`
Text string `json:"text"`
Time string `json:"time"`
UserID string `json:"user_id"`
}
type ChatEventUser struct {
@ -392,8 +403,11 @@ type ChatView struct {
ImageUrl string
Init bool
IsFollower bool
Raid bool
Rant int
Sub bool
Text string
Time time.Time
Type string
Username string
}
@ -455,10 +469,23 @@ func parseMessages(eventType string, messages []ChatEventMessage, users map[stri
view.Color = user.Color
view.ImageUrl = user.Image1
view.IsFollower = user.IsFollower
if message.RaidNotification != nil {
view.Raid = true
}
if message.Rant != nil {
view.Rant = message.Rant.PriceCents
}
if message.Notification != nil {
if message.Notification.Badge == ChatBadgeRecurringSubscription {
view.Sub = true
}
}
view.Text = message.Text
t, err := time.Parse(time.RFC3339, message.Time)
if err != nil {
return nil, fmt.Errorf("error parsing message time: %v", err)
}
view.Time = t
view.Type = eventType
view.Username = user.Username

View file

@ -273,31 +273,37 @@ func (c *Client) userLogout() error {
return nil
}
type LoggedInResponseData struct {
Username string `json:"username"`
}
type LoggedInResponseUser struct {
LoggedIn bool `json:"logged_in"`
ID string `json:"id"`
LoggedIn bool `json:"logged_in"`
}
type LoggedInResponse struct {
Data LoggedInResponseData `json:"data"`
User LoggedInResponseUser `json:"user"`
}
func (c *Client) LoggedIn() (bool, error) {
func (c *Client) LoggedIn() (*LoggedInResponse, error) {
resp, err := c.httpClient.Get(urlUserLogin)
if err != nil {
return false, pkgErr("error getting login service", err)
return nil, pkgErr("error getting login service", err)
}
defer resp.Body.Close()
bodyB, err := io.ReadAll(resp.Body)
if err != nil {
return false, pkgErr("error reading body bytes", err)
return nil, pkgErr("error reading body bytes", err)
}
var lir LoggedInResponse
err = json.NewDecoder(strings.NewReader(string(bodyB))).Decode(&lir)
if err != nil {
return false, pkgErr("error un-marshaling response body", err)
return nil, pkgErr("error un-marshaling response body", err)
}
return lir.User.LoggedIn, nil
return &lir, nil
}

4
go.mod
View file

@ -1,13 +1,13 @@
module github.com/tylertravisty/rumble-livestream-lib-go
module travisty.io/tyler/rumble-livestream-lib-go
go 1.19
require (
github.com/r3labs/sse/v2 v2.10.0
github.com/robertkrimen/otto v0.2.1
github.com/tylertravisty/go-utils v0.0.0-20230524204414-6893ae548909
golang.org/x/net v0.24.0
gopkg.in/cenkalti/backoff.v1 v1.1.0
travisty.io/tyler/go-utils v0.0.0-20240614172648-00b0b1a557b4
)
require (

4
go.sum
View file

@ -9,8 +9,6 @@ github.com/robertkrimen/otto v0.2.1/go.mod h1:UPwtJ1Xu7JrLcZjNWN8orJaM5n5YEtqL//
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/tylertravisty/go-utils v0.0.0-20230524204414-6893ae548909 h1:xrjIFqzGQXlCrCdMPpW6+SodGFSlrQ3ZNUCr3f5tF1g=
github.com/tylertravisty/go-utils v0.0.0-20230524204414-6893ae548909/go.mod h1:2W31Jhs9YSy7y500wsCOW0bcamGi9foQV1CKrfvfTxk=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20191116160921-f9c825593386/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
@ -26,3 +24,5 @@ gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=
gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
travisty.io/tyler/go-utils v0.0.0-20240614172648-00b0b1a557b4 h1:/InkkmR3O6lh63ckLJe14k1DRB6RuOZJv5TpfxGVRKQ=
travisty.io/tyler/go-utils v0.0.0-20240614172648-00b0b1a557b4/go.mod h1:2inG89XtlVnppctG2WnKir4mWWN0zbF/PB9m1HXdTYI=

6
vendor/modules.txt vendored
View file

@ -10,9 +10,6 @@ github.com/robertkrimen/otto/file
github.com/robertkrimen/otto/parser
github.com/robertkrimen/otto/registry
github.com/robertkrimen/otto/token
# github.com/tylertravisty/go-utils v0.0.0-20230524204414-6893ae548909
## explicit; go 1.16
github.com/tylertravisty/go-utils/random
# golang.org/x/net v0.24.0
## explicit; go 1.18
golang.org/x/net/context
@ -40,3 +37,6 @@ gopkg.in/cenkalti/backoff.v1
## explicit
gopkg.in/sourcemap.v1
gopkg.in/sourcemap.v1/base64vlq
# travisty.io/tyler/go-utils v0.0.0-20240614172648-00b0b1a557b4
## explicit; go 1.16
travisty.io/tyler/go-utils/random