-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhttp.go
135 lines (111 loc) · 2.59 KB
/
http.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
package main
import (
"errors"
"fmt"
"io"
"log"
"net/http"
"net/http/cookiejar"
"net/url"
"os"
"regexp"
"golang.org/x/net/publicsuffix"
"github.com/PuerkitoBio/goquery"
)
var (
lessonClass = ".lessons-list__li"
descMeta = "meta[itemprop=description]"
content = "content"
linkAttr = "link[itemprop=url]"
linkTag = "href"
)
type hunter struct {
Path string
Client *http.Client
Videos []video
}
type video struct {
Name string `json:"name"`
URL string `json:"url"`
}
var (
baseURL = "https://coursehunters.net/course"
authURL = "https://coursehunters.net/sign-in"
)
func newHunter(course, email, password string) (*hunter, error) {
jar, _ := cookiejar.New(&cookiejar.Options{
PublicSuffixList: publicsuffix.List,
})
client := &http.Client{
Jar: jar,
}
if ok := authenticateUser(email, password, client); !ok {
return nil, errors.New("Authorization failed")
}
get := baseURL + "/" + course
resp, err := client.Get(get)
if err != nil {
return nil, err
}
defer resp.Body.Close()
return &hunter{
Path: course,
Client: client,
Videos: parseCourseContent(resp.Body),
}, nil
}
func (h *hunter) download(notify chan os.Signal) {
for _, video := range h.Videos {
resp, err := h.Client.Get(video.URL)
if err != nil {
log.Fatalf("Error while Getting video: %v", err)
}
defer resp.Body.Close()
file := fmt.Sprintf("%s/%s.mp4", h.Path, video.Name)
f, err := os.Create(file)
if err != nil {
log.Fatalf("Error Creating file: %v", err)
}
defer f.Close()
go func() {
<-notify
fmt.Println("\nDownload interrupted saving state")
h.saveState()
os.Exit(1)
}()
done := make(chan int64)
go showProgress(file, resp.ContentLength, done)
done <- saveToDisk(resp.Body, f)
}
}
func authenticateUser(email, password string, client *http.Client) bool {
resp, err := client.PostForm(authURL, url.Values{
"e_mail": {email},
"password": {password},
})
if err != nil {
return false
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return false
}
return true
}
func parseCourseContent(reader io.Reader) []video {
contents := make([]video, 0)
doc, _ := goquery.NewDocumentFromReader(reader)
doc.Find(lessonClass).Each(func(i int, selector *goquery.Selection) {
title, _ := selector.Find(descMeta).Attr(content)
url, _ := selector.Find(linkAttr).Attr(linkTag)
contents = append(contents, video{
Name: renameFileName(title),
URL: url,
})
})
return contents
}
func renameFileName(fileName string) string {
reg := regexp.MustCompile(`[\\\/*:\-|?"\<\>]`)
return reg.ReplaceAllString(fileName, "")
}