package twitch import ( "encoding/base64" "errors" "safetwitch-backend/extractor" "safetwitch-backend/extractor/structs" "strings" "time" "github.com/tidwall/gjson" ) 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 ProxyPlaylistFile(playlist string) 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 newURL := extractor.ProxyUrl(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 }