mirror of
https://codeberg.org/SafeTwitch/safetwitch-backend.git
synced 2024-12-22 21:23:01 -05:00
213 lines
6.3 KiB
Go
213 lines
6.3 KiB
Go
package twitch
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"errors"
|
|
"os"
|
|
"safetwitch-backend/extractor"
|
|
"safetwitch-backend/extractor/structs"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/tidwall/gjson"
|
|
)
|
|
|
|
func ParseStreamer(streamerData gjson.Result, isLive bool, socials []structs.Social, stream *structs.Stream, login string, streamerBanner string) (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
|
|
}
|
|
|
|
var bannerUrl *string = &streamerBanner
|
|
if *bannerUrl == "" {
|
|
bannerUrl = nil
|
|
} else {
|
|
proxied := extractor.ProxyUrl(*bannerUrl)
|
|
bannerUrl = &proxied
|
|
}
|
|
|
|
parsedStreamer := structs.Streamer{
|
|
Username: streamerData.Get("user.displayName").String(),
|
|
Login: login,
|
|
About: streamerData.Get("user.description").String(),
|
|
Pfp: extractor.ProxyUrl(streamerData.Get("user.profileImageURL").String()),
|
|
Banner: bannerUrl,
|
|
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")
|
|
for _, social := range result.Array() {
|
|
parsedSocials = append(parsedSocials, structs.Social{
|
|
Name: social.Get("title").String(),
|
|
Type: social.Get("name").String(),
|
|
Url: social.Get("url").String(),
|
|
})
|
|
}
|
|
|
|
if !result.Exists() {
|
|
return parsedSocials, errors.New("error while parsing socials, path does not exist")
|
|
}
|
|
|
|
return parsedSocials, nil
|
|
}
|
|
|
|
func ParseStream(data string) (*structs.Stream, error) {
|
|
// check if live
|
|
stream := gjson.Get(data, "1.data.user.stream")
|
|
if !stream.IsObject() {
|
|
return nil, errors.New("streamer is not live")
|
|
}
|
|
|
|
var tags []string
|
|
tagArea := gjson.Get(data, "2.data.user.stream.freeformTags").Array()
|
|
for _, tag := range tagArea {
|
|
tags = append(tags, tag.Get("name").String())
|
|
}
|
|
|
|
time, err := time.Parse(time.RFC3339, stream.Get("createdAt").String())
|
|
if err != nil {
|
|
return &structs.Stream{}, err
|
|
}
|
|
|
|
parsedStream := structs.Stream{
|
|
Title: gjson.Get(data, "1.data.user.lastBroadcast.title").String(),
|
|
Topic: stream.Get("game.name").String(),
|
|
StartedAt: time,
|
|
Tags: tags,
|
|
Viewers: int(gjson.Get(data, "4.data.user.stream.viewersCount").Int()),
|
|
Preview: extractor.ProxyUrl(gjson.Get(data, "3.data.user.stream.previewImageURL").String()),
|
|
}
|
|
|
|
return &parsedStream, nil
|
|
}
|
|
|
|
// discover
|
|
func ParseCategory(data gjson.Result) (structs.CategoryPreview, error) {
|
|
tags := data.Get("node.tags").Array()
|
|
var parsedTags []string
|
|
|
|
for _, tag := range tags {
|
|
parsedTags = append(parsedTags, tag.Get("localizedName").String())
|
|
}
|
|
|
|
return structs.CategoryPreview{
|
|
Name: data.Get("node.name").String(),
|
|
DisplayName: data.Get("node.displayName").String(),
|
|
Viewers: int(data.Get("node.viewersCount").Int()),
|
|
CreatedAt: data.Get("node.originalReleaseDate").Time(),
|
|
Tags: parsedTags,
|
|
Cursor: data.Get("node.cursor").String(),
|
|
Image: extractor.ProxyUrl(data.Get("node.avatarURL").String()),
|
|
}, nil
|
|
}
|
|
|
|
func ParseMinifiedStream(data gjson.Result) (structs.CategoryMinifiedStream, error) {
|
|
var tags []string
|
|
tagArea := data.Get("node.freeformTacgs").Array()
|
|
for _, tag := range tagArea {
|
|
tags = append(tags, tag.Get("name").String())
|
|
}
|
|
|
|
// Store streamerColorHex in memory to use as pointer
|
|
var streamerColorHex *string
|
|
rawStreamerColorHex := data.Get("node.broadcaster.primaryColorHex").String()
|
|
if rawStreamerColorHex == "" {
|
|
streamerColorHex = nil
|
|
} else {
|
|
streamerColorHex = &rawStreamerColorHex
|
|
}
|
|
|
|
parsedStream := structs.CategoryMinifiedStream{
|
|
Title: data.Get("node.title").String(),
|
|
Viewers: int(data.Get("node.viewersCount").Int()),
|
|
Preview: extractor.ProxyUrl(data.Get("node.previewImageURL").String()),
|
|
Tags: tags,
|
|
Streamer: structs.CategoryMinifiedStreamer{
|
|
Name: data.Get("node.broadcaster.login").String(),
|
|
Pfp: extractor.ProxyUrl(data.Get("node.broadcaster.profileImageURL").String()),
|
|
ColorHex: streamerColorHex,
|
|
},
|
|
Cursor: data.Get("cursor").String(),
|
|
}
|
|
|
|
return parsedStream, nil
|
|
}
|
|
|
|
func ParseBadges(data gjson.Result) ([]structs.Badge, error) {
|
|
var formattedBadges = []structs.Badge{}
|
|
|
|
for _, badge := range data.Array() {
|
|
id := badge.Get("id").String()
|
|
decodedId, err := base64.StdEncoding.DecodeString(id)
|
|
if err != nil {
|
|
return []structs.Badge{}, nil
|
|
}
|
|
|
|
formattedBadges = append(formattedBadges, structs.Badge{
|
|
Id: string(decodedId),
|
|
SetId: badge.Get("setID").String(),
|
|
Title: badge.Get("title").String(),
|
|
Version: badge.Get("version").String(),
|
|
Images: map[string]string{
|
|
"image1x": extractor.ProxyUrl(badge.Get("image1x").String()),
|
|
"image2x": extractor.ProxyUrl(badge.Get("image2x").String()),
|
|
"image4x": extractor.ProxyUrl(badge.Get("image4x").String()),
|
|
},
|
|
})
|
|
}
|
|
|
|
return formattedBadges, nil
|
|
}
|
|
|
|
func StreamSubProxyUrl(url string) string {
|
|
encodedUrl := base64.StdEncoding.EncodeToString([]byte(url))
|
|
backendUrl := os.Getenv("URL")
|
|
|
|
return backendUrl + "/proxy/stream/sub/" + encodedUrl
|
|
}
|
|
|
|
func StreamSegmentProxyUrl(url string) string {
|
|
encodedUrl := base64.StdEncoding.EncodeToString([]byte(url))
|
|
backendUrl := os.Getenv("URL")
|
|
|
|
return backendUrl + "/proxy/stream/segment/" + encodedUrl
|
|
}
|
|
|
|
func ProxyPlaylistFile(playlist string, isSubPlaylist bool) string {
|
|
// Split the playlist into individual entries
|
|
entries := strings.Split(playlist, "\n")[1:] // Ignore the first line which contains the M3U header
|
|
|
|
// Loop through each entry and replace the URL
|
|
for i, entry := range entries {
|
|
if strings.HasPrefix(entry, "http") { // Only modify lines that contain URLs
|
|
var newURL string
|
|
if isSubPlaylist {
|
|
newURL = StreamSegmentProxyUrl(entry)
|
|
} else {
|
|
newURL = StreamSubProxyUrl(entry)
|
|
}
|
|
entries[i] = newURL
|
|
}
|
|
}
|
|
|
|
// Join the modified entries back into a single string separated by a newline
|
|
modifiedPlaylist := "#EXTM3U\n" + strings.Join(entries, "\n")
|
|
|
|
return modifiedPlaylist
|
|
|
|
}
|