diff --git a/extractor/structs/parsed.go b/extractor/structs/parsed.go index 165da1c..79d5408 100644 --- a/extractor/structs/parsed.go +++ b/extractor/structs/parsed.go @@ -132,3 +132,15 @@ type VodComment struct { Cursor string `json:"cursor"` Badges []VodCommentBadge `json:"badges"` } + +type StreamMessageBadge struct { + Version string `json:"version"` + SetID string `json:"setId"` +} + +type StreamMessage struct { + Message string `json:"message"` + Username string `json:"username"` + Color string `json:"color"` + Badges []StreamMessageBadge `json:"badges"` +} diff --git a/extractor/twitch/Chat.go b/extractor/twitch/Chat.go new file mode 100644 index 0000000..b995f76 --- /dev/null +++ b/extractor/twitch/Chat.go @@ -0,0 +1,71 @@ +package twitch + +import ( + "encoding/base64" + "safetwitch-backend/extractor/structs" + "strings" + + "github.com/tidwall/gjson" +) + +func GetChatHistory(streamerName string) ([]structs.StreamMessage, error) { + id, err := GetStreamerId(streamerName) + if err != nil { + return []structs.StreamMessage{}, err + } + + payload := []TwitchPayload{ + { + "operationName": "MessageBufferChatHistory", + "variables": map[string]interface{}{ + "channelLogin": streamerName, + "channelID": id, + }, + "extensions": map[string]interface{}{ + "persistedQuery": map[string]interface{}{ + "version": 1, + "sha256Hash": "432ef3ec504a750d797297630052ec7c775f571f6634fdbda255af9ad84325ae", + }, + }, + }, + } + + _, body, err := parseResponse(payload) + if err != nil { + return []structs.StreamMessage{}, err + } + + messages := gjson.Get(string(body), "0.data.channel.recentChatMessages").Array() + parsedMessages := []structs.StreamMessage{} + for _, message := range messages { + badges := []structs.StreamMessageBadge{} + + for _, badge := range message.Get("senderBadges").Array() { + id := badge.Get("id").String() + decodedId, err := base64.StdEncoding.DecodeString(id) + if err != nil { + return []structs.StreamMessage{}, err + } + + splitId := strings.Split(string(decodedId), ";") + + parsedBadge := structs.StreamMessageBadge{ + Version: badge.Get("version").String(), + SetID: splitId[0], + } + + badges = append(badges, parsedBadge) + } + + parsedMessage := structs.StreamMessage{ + Message: message.Get("content.text").String(), + Username: message.Get("sender.displayName").String(), + Color: message.Get("sender.chatColor").String(), + Badges: badges, + } + + parsedMessages = append(parsedMessages, parsedMessage) + } + + return parsedMessages, nil +} diff --git a/routes/api/chat/chat.go b/routes/api/chat/chat.go new file mode 100644 index 0000000..1b11824 --- /dev/null +++ b/routes/api/chat/chat.go @@ -0,0 +1,22 @@ +package chat + +import ( + "github.com/gin-gonic/gin" + + "safetwitch-backend/extractor" + "safetwitch-backend/extractor/twitch" +) + +func Routes(route *gin.Engine) { + auth := route.Group("/api/chat") + + auth.GET(":streamerName/history", func(context *gin.Context) { + data, err := twitch.GetChatHistory(context.Param("streamerName")) + if err != nil { + context.Error(err) + return + } + + context.JSON(200, extractor.FormatMessage(data, true)) + }) +} diff --git a/routes/routes.go b/routes/routes.go index 4f4e5b2..7837342 100644 --- a/routes/routes.go +++ b/routes/routes.go @@ -2,6 +2,7 @@ package routes import ( "safetwitch-backend/routes/api/badges" + "safetwitch-backend/routes/api/chat" "safetwitch-backend/routes/api/discover" "safetwitch-backend/routes/api/search" "safetwitch-backend/routes/api/users" @@ -18,6 +19,7 @@ func SetRoutes(router *gin.Engine) { badges.Routes(router) search.Routes(router) vods.Routes(router) + chat.Routes(router) proxy.Routes(router) root.Routes(router)