0
Fork 0
mirror of https://codeberg.org/SafeTwitch/safetwitch-backend.git synced 2024-12-22 05:02:58 -05:00

VOD support

This commit is contained in:
dragongoose 2023-07-19 20:27:36 -04:00
parent e54c610848
commit a9fe2eaaf3
No known key found for this signature in database
GPG key ID: 01397EEC371CDAA5
7 changed files with 119 additions and 3 deletions

View file

@ -113,3 +113,21 @@ type Shelve struct {
Title string `json:"title"`
Videos []Video `json:"videos"`
}
type VodMessager struct {
Name string `json:"name"`
Login string `json:"login"`
}
type VodCommentBadge struct {
Version string `json:"version"`
SetID string `json:"setId"`
}
type VodComment struct {
Message string `json:"message"`
Messager MinifiedStreamer `json:"messager"`
Offset int `json:"offset"`
Cursor string `json:"cursor"`
Badges []VodCommentBadge `json:"badges"`
}

View file

@ -0,0 +1,36 @@
package twitch
import (
"safetwitch-backend/extractor/structs"
"github.com/tidwall/gjson"
)
func GetVODChat(vodID string, second int) ([]structs.VodComment, error) {
payload := []TwitchPayload{
{
"operationName": "VideoCommentsByOffsetOrCursor",
"variables": map[string]interface{}{
"videoID": vodID,
"contentOffsetSeconds": second,
},
"extensions": map[string]interface{}{
"persistedQuery": map[string]interface{}{
"version": 1,
"sha256Hash": "b70a3591ff0f4e0313d126c6a1502d79a1c02baebb288227c582044aa76adf6a",
},
},
},
}
_, body, err := parseResponse(payload)
if err != nil {
return []structs.VodComment{}, err
}
comments := gjson.Get(string(body), "0.data.video.comments.edges").Array()
parsedComments := []structs.VodComment{}
for _, comment := range comments {
parsedComments = append(parsedComments, ParseVODMessage(comment))
}
return parsedComments, nil
}

View file

@ -285,3 +285,34 @@ func ParseShelve(data gjson.Result, streamer structs.Streamer) structs.Shelve {
Videos: parsedVideos,
}
}
func ParseVODMessage(data gjson.Result) structs.VodComment {
messager := structs.MinifiedStreamer{
Login: data.Get("node.commenter.login").String(),
Name: data.Get("node.commenter.displayName").String(),
ColorHex: data.Get("node.message.userColor").String(),
}
parsedBadges := []structs.VodCommentBadge{}
for _, badge := range data.Get("node.message.userBadges").Array() {
setID := badge.Get("setID").String()
version := badge.Get("version").String()
if version != "" && setID != "" {
b := structs.VodCommentBadge{
SetID: setID,
Version: version,
}
parsedBadges = append(parsedBadges, b)
}
}
return structs.VodComment{
Message: data.Get("node.message.fragments.0.text").String(),
Offset: int(data.Get("node.contentOffsetSeconds").Int()),
Cursor: data.Get("cursor").String(),
Messager: messager,
Badges: parsedBadges,
}
}

View file

@ -24,6 +24,7 @@ func Routes(route *gin.Engine) {
data, err := twitch.GetDiscoveryItem(context.Param("categoryName"), 50, "")
if err != nil {
context.Error(err)
return
}
context.JSON(200, extractor.FormatMessage(data, true))

View file

@ -20,6 +20,7 @@ func Routes(route *gin.Engine) {
})
} else {
context.Error(err)
return
}
return
}

View file

@ -3,14 +3,15 @@ package vods
import (
"safetwitch-backend/extractor"
"safetwitch-backend/extractor/twitch"
"strconv"
"github.com/gin-gonic/gin"
)
func Routes(route *gin.Engine) {
auth := route.Group("/api/vods")
vods := route.Group("/api/vods")
auth.GET("/shelve/:streamerName", func(context *gin.Context) {
vods.GET("/shelve/:streamerName", func(context *gin.Context) {
data, err := twitch.GetStreamerVideoShelves(context.Param("streamerName"))
if err != nil {
context.Error(err)
@ -19,7 +20,7 @@ func Routes(route *gin.Engine) {
context.JSON(200, extractor.FormatMessage(data, true))
})
auth.GET("/:streamerName", func(context *gin.Context) {
vods.GET("/:streamerName", func(context *gin.Context) {
data, err := twitch.GetVodMetadata(context.Param("streamerName"))
if err != nil {
context.Error(err)
@ -27,4 +28,20 @@ func Routes(route *gin.Engine) {
}
context.JSON(200, extractor.FormatMessage(data, true))
})
vods.GET("/comments/:vodID/:offset", func(context *gin.Context) {
offset := context.Param("offset")
o, err := strconv.Atoi(offset)
if err != nil {
context.Error(err)
return
}
data, err := twitch.GetVODChat(context.Param("vodID"), o)
if err != nil {
context.Error(err)
return
}
context.JSON(200, extractor.FormatMessage(data, true))
})
}

View file

@ -17,15 +17,18 @@ func Routes(route *gin.Engine) {
decodedUrl, err := b64.StdEncoding.DecodeString(context.Param("url"))
if err != nil {
context.Error(err)
return
}
imageResp, err := http.Get(string(decodedUrl))
if err != nil {
context.Error(err)
return
}
body, err := io.ReadAll(imageResp.Body)
if err != nil {
context.Error(err)
return
}
contentType := imageResp.Header.Get("Content-Type")
@ -39,6 +42,7 @@ func Routes(route *gin.Engine) {
playlistFile, err := twitch.GetStream(streamer)
if err != nil {
context.Error(err)
return
}
context.Data(200, "application/vnd.apple.mpegurl", []byte(playlistFile))
@ -48,11 +52,13 @@ func Routes(route *gin.Engine) {
decodedUrl, err := b64.StdEncoding.DecodeString(context.Param("encodedUrl"))
if err != nil {
context.Error(err)
return
}
playlistFile, err := twitch.GetSubPlaylist(string(decodedUrl), false)
if err != nil {
context.Error(err)
return
}
context.Data(200, "application/vnd.apple.mpegurl", []byte(playlistFile))
@ -62,6 +68,7 @@ func Routes(route *gin.Engine) {
decodedUrl, err := b64.StdEncoding.DecodeString(context.Param("encodedUrl"))
if err != nil {
context.Error(err)
return
}
segmentData, err := http.Get(string(decodedUrl))
@ -73,6 +80,7 @@ func Routes(route *gin.Engine) {
segment, err := io.ReadAll(segmentData.Body)
if err != nil {
context.Error(err)
return
}
context.Data(200, "application/text", segment)
@ -93,11 +101,13 @@ func Routes(route *gin.Engine) {
decodedUrl, err := b64.StdEncoding.DecodeString(context.Param("encodedUrl"))
if err != nil {
context.Error(err)
return
}
playlistFile, err := twitch.GetSubPlaylist(string(decodedUrl), true)
if err != nil {
context.Error(err)
return
}
context.Data(200, "application/vnd.apple.mpegurl", []byte(playlistFile))
@ -107,6 +117,7 @@ func Routes(route *gin.Engine) {
decodedUrl, err := b64.StdEncoding.DecodeString(context.Param("encodedUrl"))
if err != nil {
context.Error(err)
return
}
// remove the last path of url and replace with segment
@ -122,6 +133,7 @@ func Routes(route *gin.Engine) {
segment, err := io.ReadAll(segmentData.Body)
if err != nil {
context.Error(err)
return
}
context.Data(200, "application/text", segment)