-
Notifications
You must be signed in to change notification settings - Fork 101
/
ytcfg.go
101 lines (86 loc) · 2.53 KB
/
ytcfg.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package main
import (
"bytes"
"encoding/json"
"fmt"
"golang.org/x/net/html"
)
var ytcfgStart = []byte("ytcfg.set(")
// TODO: If necessary, grab dataSyncIds as well
// Will be needed if SessionIndex is not available
type YTCFG struct {
DelegatedSessionId string `json:"DELEGATED_SESSION_ID"`
IdToken string `json:"ID_TOKEN"`
Hl string `json:"HL"`
InnertubeApiKey string `json:"INNERTUBE_API_KEY"`
InnertubeClientName string `json:"INNERTUBE_CLIENT_NAME"`
InnertubeClientVersion string `json:"INNERTUBE_CLIENT_VERSION"`
InnertubeCtxClientName int `json:"INNERTUBE_CONTEXT_CLIENT_NAME"`
InnertubeCtxClientVersion string `json:"INNERTUBE_CONTEXT_CLIENT_VERSION"`
SessionIndex string `json:"SESSION_INDEX"`
VisitorData string `json:"VISITOR_DATA"`
}
// Search the given HTML for the ytcfg object
func GetYTCFGFromHtml(data []byte) []byte {
var objData []byte
reader := bytes.NewReader(data)
tokenizer := html.NewTokenizer(reader)
isScript := false
for {
tt := tokenizer.Next()
switch tt {
case html.ErrorToken:
return objData
case html.TextToken:
if isScript {
data := tokenizer.Text()
setStart := bytes.Index(data, ytcfgStart)
if setStart < 0 {
continue
}
// Maybe add a LogTrace in the future for stuff like this
//LogDebug("Found script element with ytcfg data in watch page.")
objStart := bytes.Index(data[setStart:], []byte("{")) + setStart
objEnd := bytes.Index(data[objStart:], []byte("});")) + 1 + objStart
if objEnd > objStart {
objData = data[objStart:objEnd]
}
if len(objData) > 0 {
return objData
}
}
case html.StartTagToken:
tn, _ := tokenizer.TagName()
if string(tn) == "script" {
isScript = true
} else {
isScript = false
}
}
}
}
func GetDefaultYTCFG() *YTCFG {
return &YTCFG{
InnertubeApiKey: "AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8",
InnertubeClientName: "WEB",
InnertubeClientVersion: "2.20241119.01.01",
InnertubeCtxClientName: 1,
InnertubeCtxClientVersion: "2.20241119.01.01",
}
}
func (di *DownloadInfo) GetYTCFG(videoHtml []byte) error {
ytcfg := GetDefaultYTCFG()
di.Ytcfg = ytcfg
if len(videoHtml) == 0 {
return fmt.Errorf("unable to retrieve data from video page")
}
prData := GetYTCFGFromHtml(videoHtml)
if len(prData) == 0 {
return fmt.Errorf("unable to retrieve ytcfg data from watch page")
}
err := json.Unmarshal(prData, di.Ytcfg)
if err != nil {
return err
}
return nil
}