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