src/app/video.go (view raw)
1package app
2
3import (
4 "errors"
5 "fmt"
6 "log"
7 "regexp"
8 "strconv"
9 "time"
10
11 g "github.com/birabittoh/gopipe/src/globals"
12 "github.com/kkdai/youtube/v2"
13)
14
15const (
16 maxMB = 20
17 maxContentLength = maxMB * 1048576
18 defaultCacheDuration = 6 * time.Hour
19)
20
21var (
22 emptyVideo = youtube.Video{}
23 expireRegex = regexp.MustCompile(`(?i)expire=(\d+)`)
24)
25
26func parseExpiration(url string) (time.Duration, error) {
27 expireString := expireRegex.FindStringSubmatch(url)
28 expireTimestamp, err := strconv.ParseInt(expireString[1], 10, 64)
29 if err != nil {
30 log.Println("parseExpiration ERROR: ", err)
31 return time.Duration(0), err
32 }
33
34 return time.Until(time.Unix(expireTimestamp, 0)), nil
35}
36
37func formatsSelectFn(f youtube.Format) bool {
38 return f.AudioChannels > 1 && f.ContentLength < maxContentLength
39}
40
41func getURL(videoID string) string {
42 return fmt.Sprintf(fmtYouTubeURL, videoID)
43}
44
45func getFromCache(videoID string) (video *youtube.Video, format youtube.Format, err error) {
46 video, err = g.KS.Get(videoID)
47 if err != nil {
48 return
49 }
50
51 if video == nil {
52 err = errors.New("video should not be nil")
53 return
54 }
55
56 if video.ID == emptyVideo.ID {
57 err = errors.New("no formats for this video")
58 return
59 }
60
61 formats := video.Formats.Select(formatsSelectFn)
62 if len(formats) == 0 {
63 err = errors.New("no formats for this video")
64 return
65 }
66
67 format = formats[0]
68 return
69}
70
71func getFromYT(videoID string) (video *youtube.Video, format youtube.Format, err error) {
72 video, err = g.YT.GetVideo(getURL(videoID))
73 if err != nil {
74 return
75 }
76
77 formats := video.Formats.Select(formatsSelectFn)
78 if len(formats) == 0 {
79 g.KS.Set(videoID, emptyVideo, defaultCacheDuration)
80 return
81 }
82
83 format = formats[0]
84 expiration, err := parseExpiration(format.URL)
85 if err != nil {
86 expiration = defaultCacheDuration
87 }
88
89 g.KS.Set(videoID, *video, expiration)
90 return
91}
92
93func getVideo(videoID string) (video *youtube.Video, format youtube.Format, err error) {
94 video, format, err = getFromCache(videoID)
95 if err != nil {
96 video, format, err = getFromYT(videoID)
97 }
98 return
99}