-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcommon.go
137 lines (125 loc) · 2.8 KB
/
common.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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package ytools
import (
"bufio"
"fmt"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
)
func SaveUrls(urls []string) (err error) {
dataDir, err := GetDataDir()
if err != nil {
return
}
urlsFilename := filepath.Join(dataDir, "search_results")
urlsFile, err := os.Create(urlsFilename)
if err != nil {
return
}
defer func() {
if err != nil {
urlsFile.Close()
} else {
err = urlsFile.Close()
}
}()
for _, url := range urls {
_, err = fmt.Fprintln(urlsFile, url)
}
return
}
func GetDesiredVideoUrl() (videoUrl string, err error) {
switch len(os.Args) {
case 1:
videoUrl, err = GetLastPickedUrl()
case 2:
var selection int
selection, err = strconv.Atoi(os.Args[1])
if err != nil {
return
}
videoUrl, err = GetSearchResult(selection - 1)
default:
err = fmt.Errorf("invalid argument count; give a video number as " +
"argument, or no argument to select the last picked")
}
return
}
func GetSearchResult(i int) (searchResult string, err error) {
searchResults, err := getSearchResults()
if err == nil {
if i < 0 || i >= len(searchResults) {
err = fmt.Errorf("invalid search result index")
} else {
searchResult = searchResults[i]
}
}
return
}
func getSearchResults() (searchResults []string, err error) {
searchResults = make([]string, 0)
dataDir, err := GetDataDir()
if err != nil {
return
}
urlsFile := filepath.Join(dataDir, "search_results")
file, err := os.Open(urlsFile)
if err != nil {
return
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
searchResults = append(searchResults, scanner.Text())
}
if err := scanner.Err(); err != nil {
panic(err)
}
return
}
func GetLastPickedUrl() (lastPickedUrl string, err error) {
dataDir, err := GetDataDir()
if err != nil {
return
}
lastPickedFilename := filepath.Join(dataDir, "last_picked")
fileContent, err := ioutil.ReadFile(lastPickedFilename)
if err != nil {
return
}
lastPickedUrl = strings.TrimSpace(string(fileContent))
return
}
func GetDataDir() (dataDir string, err error) {
dataDirBase := os.Getenv("XDG_DATA_HOME")
if dataDirBase == "" {
dataDirBase = filepath.Join(os.Getenv("HOME"), ".local/share/")
}
dataDir = filepath.Join(dataDirBase, "ytools/")
err = os.MkdirAll(dataDir, 0755)
return
}
// ExtractJson returns the ytInitialData JSON from the HTML at the
// given URL.
func ExtractJson(url string) (mainJson []byte, err error) {
resp, err := http.Get(url)
if err != nil {
return
}
defer resp.Body.Close()
bytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return
}
re := regexp.MustCompile(`(?m)ytInitialData.{1,3}= *(.*?);(</script>|$)`)
matches := re.FindSubmatch(bytes)
if matches == nil {
err = fmt.Errorf("retrieved HTML does not contain the expected JSON")
return
}
return matches[1], nil
}