summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--go.mod2
-rw-r--r--go.sum2
-rw-r--r--grimtube.go2
-rw-r--r--templates/search.html2
-rw-r--r--ytparser/ytparser.go188
5 files changed, 6 insertions, 190 deletions
diff --git a/go.mod b/go.mod
index dab7b92..ee57324 100644
--- a/go.mod
+++ b/go.mod
@@ -1,3 +1,5 @@
module grimtube
go 1.15
+
+require git.sr.ht/~ark/ytparser v0.0.0-20201019100927-5f211df7cfbb
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..c84bdcb
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,2 @@
+git.sr.ht/~ark/ytparser v0.0.0-20201019100927-5f211df7cfbb h1:cl79Gq9gc7XrfYh42k7FHngRT0oh1u+GgH1DTot/cYQ=
+git.sr.ht/~ark/ytparser v0.0.0-20201019100927-5f211df7cfbb/go.mod h1:/LVNTXoOf1dnQ85TQK3Osw8KK7POmeeqBQUoXivfIPI=
diff --git a/grimtube.go b/grimtube.go
index 0ea1d50..17de1b6 100644
--- a/grimtube.go
+++ b/grimtube.go
@@ -10,7 +10,7 @@ import (
"strconv"
//"path"
- "grimtube/ytparser"
+ "git.sr.ht/~ark/ytparser"
)
func getLangs() []string {
diff --git a/templates/search.html b/templates/search.html
index 8a75962..c0cdb76 100644
--- a/templates/search.html
+++ b/templates/search.html
@@ -16,7 +16,7 @@
{{range .Items}}
<tr>
<td>
- <a href="/embed?id={{.Id}}"><img width=240 src="{{.Thumb}}"></a>
+ <a href="/embed?id={{.Id}}"><img width=240 src="{{.ThumbUrl}}"></a>
</td>
<td>
<p><a href="/embed?id={{.Id}}">{{.Title}}</a></p>
diff --git a/ytparser/ytparser.go b/ytparser/ytparser.go
deleted file mode 100644
index 1ebd783..0000000
--- a/ytparser/ytparser.go
+++ /dev/null
@@ -1,188 +0,0 @@
-package ytparser
-
-import (
- "text/template"
- "encoding/json"
- "fmt"
- "net/http"
- "bytes"
- "os"
- "io"
- "io/ioutil"
- "strings"
- "net/url"
- "regexp"
-)
-
-const windowInitDataString string = "window[\"ytInitialData\"] = "
-const initDataString string = "var ytInitialData = "
-const baseUrl string = "https://youtube.com"
-
-type Item struct {
- Id string
- Title string
- Url string
- Thumb string
- ChannelTitle string
- ChannelUrl string
- Published string
-}
-
-func (item Item) Format(t *template.Template) string {
- var b strings.Builder
- err := t.Execute(&b, item)
- if err != nil {
- panic(err)
- }
- return b.String()
-}
-
-func (item Item) String() string {
- return fmt.Sprintf("id: %s, title: %s, url: %s, thumb: %s", item.Id, item.Title, item.Url, item.Thumb)
-}
-
-func parsejson(data string) ([]Item, error) {
- dec := json.NewDecoder(strings.NewReader(data))
-
- depth := 0
- isArray := false
- isValue := false
- var items []Item
- var item Item
- var names []string
- nbItems := 0
- for {
- tok, err := dec.Token()
- if err == io.EOF {
- break
- } else if err != nil {
- return items, err
- }
-
- switch t := tok.(type) {
- case json.Delim:
- if t == '{' {
- depth++
- } else if t == '}' {
- depth--
- names = names[:depth]
- }
- isArray = t == '['
- isValue = false
- case string:
- if !isArray {
- if !isValue {
- if t == "videoRenderer" {
- if nbItems > 0 {
- items = append(items, item)
- }
- item = Item{}
- nbItems++
- }
- if depth > len(names) {
- names = append(names, t)
- } else {
- names[depth - 1] = t
- }
- //fmt.Println(t, depth, len(names), names[depth - 1])
- isValue = true
- } else {
- //fmt.Println(names[len(names) - 1])
- if names[depth-1] == "videoId" {
- item.Id = t
- item.Url = fmt.Sprintf("https://youtube.com/watch?v=%s", t)
- }
- if depth >= 3 && names[depth-3] == "title" &&
- names[depth-2] == "runs" &&
- names[depth-1] == "text" {
- item.Title = t
- }
- if depth >= 3 && names[depth-3] == "ownerText" &&
- names[depth-2] == "runs" &&
- names[depth-1] == "text" {
- item.ChannelTitle = t
- }
- if depth >= 6 &&
- names[depth-6] == "ownerText" &&
- names[depth-5] == "runs" &&
- names[depth-4] == "navigationEndpoint" &&
- names[depth-3] == "commandMetadata" &&
- names[depth-2] == "webCommandMetadata" &&
- names[depth-1] == "url" {
- item.ChannelUrl = baseUrl + t
- }
- if depth >= 4 &&
- names[depth-4] == "videoRenderer" &&
- names[depth-3] == "thumbnail" &&
- names[depth-2] == "thumbnails" &&
- names[depth-1] == "url" {
- item.Thumb = t
- }
- if depth >= 3 &&
- names[depth-3] == "videoRenderer" &&
- names[depth-2] == "publishedTimeText" &&
- names[depth-1] == "simpleText" {
- item.Published = t
- }
- isValue = false
- }
- }
- default:
- }
- }
- return items, nil
-}
-
-func PrintItems(items []Item, format string) {
- t := template.Must(template.New("items").Parse(format))
- for _, i := range items {
- fmt.Println(i.Format(t))
- }
-}
-
-func request(query string, page int, lang string) (string, error) {
- q := url.QueryEscape(query)
- url := fmt.Sprintf("https://www.youtube.com/results?search_query=%s&page=%d&hl=%s", q, page, lang)
- res, err := http.DefaultClient.Get(url)
- if err != nil {
- return "", err
- }
- body, err := ioutil.ReadAll(res.Body)
- if err != nil {
- return "", err
- }
- initString := windowInitDataString
- idx := bytes.Index(body, []byte(windowInitDataString))
- if idx == -1 {
- initString = initDataString
- idx = bytes.Index(body, []byte(initDataString))
- }
- idx += len(initString)
- startData := body[idx:]
- pattern := regexp.MustCompile(`; *\n`)
- loc := pattern.FindIndex(startData)
- startData = startData[:loc[0]]
- return string(startData), nil
-}
-
-func isValidData(data string) bool {
- return data != ""
-}
-
-func Search(query string, page int, lang string) ([]Item, error) {
- if lang == "" {
- lang = "en"
- }
- var data string = ""
- var err error
- for i := 1; i < 4 && !isValidData(data); i++ {
- if i > 1 {
- fmt.Fprintf(os.Stderr, "Yt data invalid, retrying (attempt %d)\n", i)
- }
- data, err = request(query, page, lang)
- if err != nil {
- return nil, err
- }
- }
- return parsejson(data)
-}