From bb8b868354359c1df6710b6c425d6e91196a7e20 Mon Sep 17 00:00:00 2001 From: dragongoose Date: Sat, 20 May 2023 16:30:12 -0400 Subject: [PATCH] Begin the streamer info endpoint --- extractor/structs/streamerInfoRaw.go | 64 +++++++++++++++ extractor/twitchExtractor.go | 111 +++++++++++++++++++++++++++ routes/users/users.go | 9 ++- 3 files changed, 180 insertions(+), 4 deletions(-) create mode 100644 extractor/structs/streamerInfoRaw.go create mode 100644 extractor/twitchExtractor.go diff --git a/extractor/structs/streamerInfoRaw.go b/extractor/structs/streamerInfoRaw.go new file mode 100644 index 0000000..1cd2248 --- /dev/null +++ b/extractor/structs/streamerInfoRaw.go @@ -0,0 +1,64 @@ +package structs + +import "time" + +type StreamerDataRaw struct { + Data Data `json:"data"` + Extensions Extensions `json:"extensions"` +} +type Followers struct { + TotalCount int `json:"totalCount"` +} +type SocialMedias struct { + ID string `json:"id"` + Name string `json:"name"` + Title string `json:"title"` + URL string `json:"url"` +} +type NextSegment struct { + ID string `json:"id"` + StartAt time.Time `json:"startAt"` + HasReminder bool `json:"hasReminder"` +} +type Schedule struct { + ID string `json:"id"` + NextSegment NextSegment `json:"nextSegment"` +} +type Channel struct { + ID string `json:"id"` + SocialMedias []SocialMedias `json:"socialMedias"` + Schedule Schedule `json:"schedule"` +} +type Game struct { + ID string `json:"id"` + DisplayName string `json:"displayName"` +} +type LastBroadcast struct { + ID string `json:"id"` + Game Game `json:"game"` +} +type PrimaryTeam struct { + ID string `json:"id"` + Name string `json:"name"` + DisplayName string `json:"displayName"` +} +type User struct { + ID string `json:"id"` + Description string `json:"description"` + DisplayName string `json:"displayName"` + IsPartner bool `json:"isPartner"` + PrimaryColorHex string `json:"primaryColorHex"` + ProfileImageURL string `json:"profileImageURL"` + Followers Followers `json:"followers"` + Channel Channel `json:"channel"` + LastBroadcast LastBroadcast `json:"lastBroadcast"` + PrimaryTeam PrimaryTeam `json:"primaryTeam"` +} +type Data struct { + User User `json:"user"` +} +type Extensions struct { + DurationMilliseconds int `json:"durationMilliseconds"` + OperationName string `json:"operationName"` + RequestID string `json:"requestID"` +} diff --git a/extractor/twitchExtractor.go b/extractor/twitchExtractor.go new file mode 100644 index 0000000..2dd6b3e --- /dev/null +++ b/extractor/twitchExtractor.go @@ -0,0 +1,111 @@ +package extractor + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "log" + "net/http" + "safetwitch-backend/extractor/structs" +) + +const twitchUrl = "https://gql.twitch.tv/gql" + +func call(url, method string, body io.Reader) (*http.Response, error) { + req, err := http.NewRequest(method, url, body) + if err != nil { + return req.Response, fmt.Errorf("Got error %s", err.Error()) + } + + req.Header.Add("Client-Id", "kimne78kx3ncx6brgo4mv6wki5h1ko") + resp, err := http.DefaultClient.Do(req) + return resp, err +} + +type TwitchPayload = map[string]interface{} + +func GetStreamerInfo(streamerName string) structs.StreamerDataRaw { + payload := []TwitchPayload{ + { + "operationName": "ChannelRoot_AboutPanel", + "variables": map[string]interface{}{ + "channelLogin": streamerName, + "skipSchedule": false, + }, + "extensions": map[string]interface{}{ + "persistedQuery": map[string]interface{}{ + "version": 1, + "sha256Hash": "6089531acef6c09ece01b440c41978f4c8dc60cb4fa0124c9a9d3f896709b6c6", + }, + }, + }, + { + "operationName": "StreamMetadata", + "variables": map[string]interface{}{ + "channelLogin": streamerName, + }, + "extensions": map[string]interface{}{ + "persistedQuery": map[string]interface{}{ + "version": 1, + "sha256Hash": "a647c2a13599e5991e175155f798ca7f1ecddde73f7f341f39009c14dbf59962", + }, + }, + }, + { + "operationName": "StreamTagsTrackingChannel", + "variables": map[string]interface{}{ + "channel": streamerName, + }, + "extensions": map[string]interface{}{ + "persistedQuery": map[string]interface{}{ + "version": 1, + "sha256Hash": "6aa3851aaaf88c320d514eb173563d430b28ed70fdaaf7eeef6ed4b812f48608", + }, + }, + }, + { + "operationName": "VideoPreviewOverlay", + "variables": map[string]interface{}{ + "login": streamerName, + }, + "extensions": map[string]interface{}{ + "persistedQuery": map[string]interface{}{ + "version": 1, + "sha256Hash": "9515480dee68a77e667cb19de634739d33f243572b007e98e67184b1a5d8369f", + }, + }, + }, + { + "operationName": "UseViewCount", + "variables": map[string]interface{}{ + "channelLogin": streamerName, + }, + "extensions": map[string]interface{}{ + "persistedQuery": map[string]interface{}{ + "version": 1, + "sha256Hash": "00b11c9c428f79ae228f30080a06ffd8226a1f068d6f52fbc057cbde66e994c2", + }, + }, + }, + } + + json_data, err := json.Marshal(payload) + + if err != nil { + fmt.Errorf("err") + } + resp, err := call(twitchUrl, "POST", bytes.NewBuffer(json_data)) + if err != nil { + fmt.Errorf("y") + } + body, err := io.ReadAll(resp.Body) + + var result []structs.StreamerDataRaw + err = json.Unmarshal(body, &result) + if err != nil { + log.Fatalln(err) + } + + return result[0] +} diff --git a/routes/users/users.go b/routes/users/users.go index ac26f7b..fed0043 100644 --- a/routes/users/users.go +++ b/routes/users/users.go @@ -1,15 +1,16 @@ package users import ( + "safetwitch-backend/extractor" + "github.com/gin-gonic/gin" ) func Routes(route *gin.Engine) { auth := route.Group("/users") - auth.GET("/test", func(context *gin.Context) { - context.JSON(200, gin.H{ - "message": "i'm working!", - }) + auth.GET("/:streamerName", func(context *gin.Context) { + data := extractor.GetStreamerInfo(context.Param("streamerName")) + context.JSON(200, data) }) }