mirror of
https://codeberg.org/SafeTwitch/safetwitch-backend.git
synced 2024-12-22 05:02:58 -05:00
149 lines
3.8 KiB
Go
149 lines
3.8 KiB
Go
package twitch
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"safetwitch-backend/extractor"
|
|
"safetwitch-backend/extractor/structs"
|
|
|
|
"github.com/tidwall/gjson"
|
|
)
|
|
|
|
func GetStreamerFromVOD(vodID string) (string, error) {
|
|
payload := []TwitchPayload{
|
|
{
|
|
"operationName": "VodChannelLoginQuery",
|
|
"variables": map[string]interface{}{
|
|
"videoID": vodID,
|
|
},
|
|
"extensions": map[string]interface{}{
|
|
"persistedQuery": map[string]interface{}{
|
|
"version": 1,
|
|
"sha256Hash": "0c5feea4dad2565508828f16e53fe62614edf015159df4b3bca33423496ce78e",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
_, body, err := parseResponse(payload)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
streamerName := gjson.Get(string(body), "0.data.video.owner.login").String()
|
|
if streamerName == "" {
|
|
return "", errors.New("streamernotfound")
|
|
}
|
|
|
|
return streamerName, nil
|
|
}
|
|
|
|
func GetVODPlaylist(vodID string) ([]byte, error) {
|
|
// get streamer
|
|
streamerName, err := GetStreamerFromVOD(vodID)
|
|
if err != nil {
|
|
return []byte{}, err
|
|
}
|
|
|
|
// get playback token
|
|
tokens, err := getPlaybackAccessToken(streamerName, vodID)
|
|
if err != nil {
|
|
return []byte{}, err
|
|
}
|
|
|
|
params := fmt.Sprintf("?sig=%s&token=%s&acmb=e30=&allow_source=true&fast_bread=true&p=4189675&player_backend=mediaplayer&playlist_include_framerate=true&reassignments_supported=true&transcode_mode=cbr_v1&cdm=wv&player_version=1.20.0", tokens.Signature, tokens.Token)
|
|
req, err := http.NewRequest("GET", fmt.Sprintf("https://usher.ttvnw.net/vod/%s.m3u8%s", fmt.Sprint(vodID), params), nil)
|
|
if err != nil {
|
|
return []byte{}, err
|
|
}
|
|
|
|
// headers
|
|
req.Header.Add("Client-Id", "ue6666qo983tsx6so1t0vnawi233wa")
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return []byte{}, err
|
|
}
|
|
|
|
if resp.StatusCode == 403 {
|
|
return []byte{}, errors.New("Video is sub-only")
|
|
}
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return []byte{}, err
|
|
}
|
|
|
|
proxiedPlaylist := ProxyPlaylistFile(string(body), false, true)
|
|
|
|
return []byte(proxiedPlaylist), nil
|
|
}
|
|
|
|
func GetVodMetadata(vodID string) (structs.Video, error) {
|
|
// get streamer
|
|
streamerName, err := GetStreamerFromVOD(vodID)
|
|
if err != nil {
|
|
return structs.Video{}, err
|
|
}
|
|
|
|
payload := []TwitchPayload{
|
|
{
|
|
"operationName": "VideoMetadata",
|
|
"variables": map[string]interface{}{
|
|
"channelLogin": streamerName,
|
|
"videoID": vodID,
|
|
},
|
|
"extensions": map[string]interface{}{
|
|
"persistedQuery": map[string]interface{}{
|
|
"version": 1,
|
|
"sha256Hash": "49b5b8f268cdeb259d75b58dcb0c1a748e3b575003448a2333dc5cdafd49adad",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
"operationName": "ChannelRoot_AboutPanel",
|
|
"variables": map[string]interface{}{
|
|
"channelLogin": streamerName,
|
|
"skipSchedule": false,
|
|
},
|
|
"extensions": map[string]interface{}{
|
|
"persistedQuery": map[string]interface{}{
|
|
"version": 1,
|
|
"sha256Hash": "6089531acef6c09ece01b440c41978f4c8dc60cb4fa0124c9a9d3f896709b6c6",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
_, body, err := parseResponse(payload)
|
|
if err != nil {
|
|
return structs.Video{}, err
|
|
}
|
|
|
|
streamerData := gjson.Get(string(body), "1.data")
|
|
parsedSocials, err := ParseSocials(streamerData.String())
|
|
if err != nil {
|
|
return structs.Video{}, err
|
|
}
|
|
parsedStreamer, err := ParseStreamer(streamerData, false, parsedSocials, nil, streamerName, "")
|
|
if err != nil {
|
|
return structs.Video{}, err
|
|
}
|
|
|
|
videoData := gjson.Get(string(body), "0.data.video")
|
|
|
|
return structs.Video{
|
|
Title: videoData.Get("title").String(),
|
|
Preview: extractor.ProxyUrl(videoData.Get("previewThumbnailURL").String()),
|
|
Duration: int(videoData.Get("lengthSeconds").Int()),
|
|
Views: int(videoData.Get("viewCount").Int()),
|
|
PublishedAt: videoData.Get("publishedAt").Time(),
|
|
Game: ParseMinifiedCategory(videoData.Get("game")),
|
|
Streamer: parsedStreamer,
|
|
Id: vodID,
|
|
}, nil
|
|
|
|
}
|