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 {
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 defaultCacheDuration
32 }
33
34 return time.Until(time.Unix(expireTimestamp, 0))
35}
36
37func getFormat(video youtube.Video) *youtube.Format {
38 formats := video.Formats.Select(formatsSelectFn)
39 if len(formats) == 0 {
40 return nil
41 }
42
43 return &formats[0]
44}
45
46func formatsSelectFn(f youtube.Format) bool {
47 return f.AudioChannels > 1 && f.ContentLength < maxContentLength
48}
49
50func getURL(videoID string) string {
51 return fmt.Sprintf(fmtYouTubeURL, videoID)
52}
53
54func getFromCache(videoID string) (video *youtube.Video, format *youtube.Format, err error) {
55 video, err = g.KS.Get(videoID)
56 if err != nil {
57 return
58 }
59
60 if video == nil {
61 err = errors.New("video should not be nil")
62 return
63 }
64
65 if video.ID == emptyVideo.ID {
66 err = errors.New("no formats for this video")
67 return
68 }
69
70 format = getFormat(*video)
71 return
72}
73
74func getFromYT(videoID string) (video *youtube.Video, format *youtube.Format, err error) {
75 url := getURL(videoID)
76
77 log.Println("Requesting video ", url)
78 video, err = g.YT.GetVideo(url)
79 if err != nil {
80 return
81 }
82
83 format = getFormat(*video)
84 duration := defaultCacheDuration
85 v := emptyVideo
86 if format != nil {
87 v = *video
88 duration = parseExpiration(format.URL)
89 }
90
91 g.KS.Set(videoID, v, duration)
92 return
93}
94
95func getVideo(videoID string) (video *youtube.Video, format *youtube.Format, err error) {
96 video, format, err = getFromCache(videoID)
97 if err != nil {
98 video, format, err = getFromYT(videoID)
99 }
100 return
101}