mirror of
https://codeberg.org/SafeTwitch/safetwitch-backend.git
synced 2025-01-03 03:10:05 -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"`
|
Version string `json:"version"`
|
||||||
Images map[string]string `json:"images"`
|
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"
|
"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) {
|
func ParseSocials(data string) ([]structs.Social, error) {
|
||||||
var parsedSocials []structs.Social
|
var parsedSocials []structs.Social
|
||||||
result := gjson.Get(data, "user.channel.socialMedias")
|
result := gjson.Get(data, "user.channel.socialMedias")
|
||||||
|
|
|
@ -152,26 +152,9 @@ func GetStreamerInfo(streamerName string) (structs.Streamer, error) {
|
||||||
isLive = false
|
isLive = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store streamerColorHex in memory to use as pointer
|
parsedStreamer, err := ParseStreamer(streamerData, isLive, parsedSocials, parsedStream)
|
||||||
var streamerColorHex *string
|
if err != nil {
|
||||||
rawStreamerColorHex := streamerData.Get("user.primaryColorHex").String()
|
return structs.Streamer{}, err
|
||||||
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,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return parsedStreamer, nil
|
return parsedStreamer, nil
|
||||||
|
@ -439,3 +422,97 @@ func GetSubPlaylist(rawurl string) (string, error) {
|
||||||
proxiedPlaylist := ProxyPlaylistFile(string(playlistFile), true)
|
proxiedPlaylist := ProxyPlaylistFile(string(playlistFile), true)
|
||||||
return proxiedPlaylist, nil
|
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 (
|
import (
|
||||||
"safetwitch-backend/routes/api/badges"
|
"safetwitch-backend/routes/api/badges"
|
||||||
"safetwitch-backend/routes/api/discover"
|
"safetwitch-backend/routes/api/discover"
|
||||||
|
"safetwitch-backend/routes/api/search"
|
||||||
"safetwitch-backend/routes/api/users"
|
"safetwitch-backend/routes/api/users"
|
||||||
"safetwitch-backend/routes/proxy"
|
"safetwitch-backend/routes/proxy"
|
||||||
"safetwitch-backend/routes/root"
|
"safetwitch-backend/routes/root"
|
||||||
|
@ -14,6 +15,7 @@ func SetRoutes(router *gin.Engine) {
|
||||||
users.Routes(router)
|
users.Routes(router)
|
||||||
discover.Routes(router)
|
discover.Routes(router)
|
||||||
badges.Routes(router)
|
badges.Routes(router)
|
||||||
|
search.Routes(router)
|
||||||
|
|
||||||
proxy.Routes(router)
|
proxy.Routes(router)
|
||||||
root.Routes(router)
|
root.Routes(router)
|
||||||
|
|
Loading…
Reference in a new issue