mirror of
https://codeberg.org/SafeTwitch/safetwitch-backend.git
synced 2024-12-22 13:13:00 -05:00
Add search endpoint
This commit is contained in:
parent
785e38ea29
commit
5c5da5404a
5 changed files with 159 additions and 20 deletions
|
@ -74,3 +74,10 @@ type Badge struct {
|
|||
Version string `json:"version"`
|
||||
Images map[string]string `json:"images"`
|
||||
}
|
||||
|
||||
type SearchResult struct {
|
||||
Channels []Streamer `json:"channels"`
|
||||
Categories []CategoryPreview `json:"categories"`
|
||||
RelatedLiveChannels []Streamer `json:"relatedChannels"`
|
||||
ChannelsWithTag []Streamer `json:"channelsWithTag"`
|
||||
}
|
||||
|
|
|
@ -12,6 +12,32 @@ import (
|
|||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
func ParseStreamer(streamerData gjson.Result, isLive bool, socials []structs.Social, stream *structs.Stream) (structs.Streamer, error) {
|
||||
// Store streamerColorHex in memory to use as pointer
|
||||
var streamerColorHex *string
|
||||
rawStreamerColorHex := streamerData.Get("user.primaryColorHex").String()
|
||||
if rawStreamerColorHex == "" {
|
||||
streamerColorHex = nil
|
||||
} else {
|
||||
streamerColorHex = &rawStreamerColorHex
|
||||
}
|
||||
|
||||
parsedStreamer := structs.Streamer{
|
||||
Username: streamerData.Get("user.displayName").String(),
|
||||
About: streamerData.Get("user.description").String(),
|
||||
Pfp: extractor.ProxyUrl(streamerData.Get("user.profileImageURL").String()),
|
||||
Followers: int(streamerData.Get("user.followers.totalCount").Int()),
|
||||
Socials: socials,
|
||||
IsLive: isLive,
|
||||
IsPartner: streamerData.Get("user.isPartner").Bool(),
|
||||
ColorHex: streamerColorHex,
|
||||
Id: streamerData.Get("user.id").String(),
|
||||
Stream: stream,
|
||||
}
|
||||
|
||||
return parsedStreamer, nil
|
||||
}
|
||||
|
||||
func ParseSocials(data string) ([]structs.Social, error) {
|
||||
var parsedSocials []structs.Social
|
||||
result := gjson.Get(data, "user.channel.socialMedias")
|
||||
|
|
|
@ -152,26 +152,9 @@ func GetStreamerInfo(streamerName string) (structs.Streamer, error) {
|
|||
isLive = false
|
||||
}
|
||||
|
||||
// Store streamerColorHex in memory to use as pointer
|
||||
var streamerColorHex *string
|
||||
rawStreamerColorHex := streamerData.Get("user.primaryColorHex").String()
|
||||
if rawStreamerColorHex == "" {
|
||||
streamerColorHex = nil
|
||||
} else {
|
||||
streamerColorHex = &rawStreamerColorHex
|
||||
}
|
||||
|
||||
parsedStreamer := structs.Streamer{
|
||||
Username: streamerData.Get("user.displayName").String(),
|
||||
About: streamerData.Get("user.description").String(),
|
||||
Pfp: extractor.ProxyUrl(streamerData.Get("user.profileImageURL").String()),
|
||||
Followers: int(streamerData.Get("user.followers.totalCount").Int()),
|
||||
Socials: parsedSocials,
|
||||
IsLive: isLive,
|
||||
IsPartner: streamerData.Get("user.isPartner").Bool(),
|
||||
ColorHex: streamerColorHex,
|
||||
Id: streamerData.Get("user.id").String(),
|
||||
Stream: parsedStream,
|
||||
parsedStreamer, err := ParseStreamer(streamerData, isLive, parsedSocials, parsedStream)
|
||||
if err != nil {
|
||||
return structs.Streamer{}, err
|
||||
}
|
||||
|
||||
return parsedStreamer, nil
|
||||
|
@ -439,3 +422,97 @@ func GetSubPlaylist(rawurl string) (string, error) {
|
|||
proxiedPlaylist := ProxyPlaylistFile(string(playlistFile), true)
|
||||
return proxiedPlaylist, nil
|
||||
}
|
||||
|
||||
func GetSearchResult(query string) (structs.SearchResult, error) {
|
||||
payload := []TwitchPayload{
|
||||
{
|
||||
"operationName": "SearchResultsPage_SearchResults",
|
||||
"variables": map[string]interface{}{
|
||||
"query": query,
|
||||
"options": nil,
|
||||
"requestID": "75948144-d051-4203-8511-57f3ee9b809a",
|
||||
},
|
||||
"extensions": map[string]interface{}{
|
||||
"persistedQuery": map[string]interface{}{
|
||||
"version": 1,
|
||||
"sha256Hash": "6ea6e6f66006485e41dbe3ebd69d5674c5b22896ce7b595d7fce6411a3790138",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
_, body, err := parseResponse(payload)
|
||||
if err != nil {
|
||||
return structs.SearchResult{}, err
|
||||
}
|
||||
|
||||
rawStreamers := gjson.Get(string(body), "0.data.searchFor.channels.edges")
|
||||
parsedStreamers := []structs.Streamer{}
|
||||
for _, streamer := range rawStreamers.Array() {
|
||||
stream := streamer.Get("item.stream").String()
|
||||
|
||||
parsedStreamers = append(parsedStreamers, structs.Streamer{
|
||||
Username: streamer.Get("item.login").String(),
|
||||
Followers: int(streamer.Get("item.followers.totalCount").Int()),
|
||||
IsLive: !(stream == ""),
|
||||
About: streamer.Get("item.description").String(),
|
||||
Pfp: extractor.ProxyUrl(streamer.Get("item.prifileImageURL").String()),
|
||||
IsPartner: false,
|
||||
ColorHex: nil,
|
||||
Id: streamer.Get("item.channel.id").String(),
|
||||
})
|
||||
}
|
||||
|
||||
parsedCategories := []structs.CategoryPreview{}
|
||||
rawCategories := gjson.Get(string(body), "0.data.searchFor.games.edges")
|
||||
|
||||
for _, category := range rawCategories.Array() {
|
||||
var tags []string
|
||||
for _, tag := range category.Get("item.tags").Array() {
|
||||
tags = append(tags, tag.Get("tagName").String())
|
||||
}
|
||||
|
||||
parsedCategories = append(parsedCategories, structs.CategoryPreview{
|
||||
Name: category.Get("item.name").String(),
|
||||
DisplayName: category.Get("item.displayName").String(),
|
||||
Viewers: int(category.Get("item.viewersCount").Int()),
|
||||
Image: category.Get("item.boxArtURL").String(),
|
||||
Tags: tags,
|
||||
})
|
||||
}
|
||||
|
||||
foundRelatedLiveChannels := []structs.Streamer{}
|
||||
streams := gjson.Get(string(body), "0.data.searchFor.relatedLiveChannels.edges")
|
||||
for _, channel := range streams.Array() {
|
||||
name := channel.Get("item.stream.broadcaster.login").String()
|
||||
channel, err := GetStreamerInfo(name)
|
||||
if err != nil {
|
||||
return structs.SearchResult{}, nil
|
||||
}
|
||||
foundRelatedLiveChannels = append(foundRelatedLiveChannels, channel)
|
||||
}
|
||||
|
||||
foundChannelsWithTag := []structs.Streamer{}
|
||||
streams = gjson.Get(string(body), "0.data.searchFor.channelsWithTag.edges")
|
||||
for _, stream := range streams.Array() {
|
||||
foundChannelsWithTag = append(foundChannelsWithTag, structs.Streamer{
|
||||
Username: stream.Get("item.login").String(),
|
||||
Followers: int(stream.Get("item.followers.totalCount").Int()),
|
||||
IsLive: !(stream.Get("stream").String() != ""),
|
||||
About: stream.Get("item.description").String(),
|
||||
Pfp: extractor.ProxyUrl(stream.Get("item.profileImageURL").String()),
|
||||
IsPartner: false,
|
||||
ColorHex: nil,
|
||||
Id: stream.Get("item.channel.id").String(),
|
||||
})
|
||||
}
|
||||
|
||||
final := structs.SearchResult{
|
||||
Channels: parsedStreamers,
|
||||
Categories: parsedCategories,
|
||||
RelatedLiveChannels: foundRelatedLiveChannels,
|
||||
ChannelsWithTag: foundChannelsWithTag,
|
||||
}
|
||||
|
||||
return final, nil
|
||||
}
|
||||
|
|
27
routes/api/search/search.go
Normal file
27
routes/api/search/search.go
Normal file
|
@ -0,0 +1,27 @@
|
|||
package search
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"safetwitch-backend/extractor"
|
||||
"safetwitch-backend/extractor/twitch"
|
||||
)
|
||||
|
||||
func Routes(route *gin.Engine) {
|
||||
auth := route.Group("/api/search")
|
||||
|
||||
auth.GET("/", func(context *gin.Context) {
|
||||
query := context.Query("query")
|
||||
if query == "" {
|
||||
context.JSON(400, extractor.FormatMessage("Missing query", false))
|
||||
}
|
||||
|
||||
data, err := twitch.GetSearchResult(query)
|
||||
if err != nil {
|
||||
context.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
context.JSON(200, extractor.FormatMessage(data, true))
|
||||
})
|
||||
}
|
|
@ -3,6 +3,7 @@ package routes
|
|||
import (
|
||||
"safetwitch-backend/routes/api/badges"
|
||||
"safetwitch-backend/routes/api/discover"
|
||||
"safetwitch-backend/routes/api/search"
|
||||
"safetwitch-backend/routes/api/users"
|
||||
"safetwitch-backend/routes/proxy"
|
||||
"safetwitch-backend/routes/root"
|
||||
|
@ -14,6 +15,7 @@ func SetRoutes(router *gin.Engine) {
|
|||
users.Routes(router)
|
||||
discover.Routes(router)
|
||||
badges.Routes(router)
|
||||
search.Routes(router)
|
||||
|
||||
proxy.Routes(router)
|
||||
root.Routes(router)
|
||||
|
|
Loading…
Reference in a new issue