src/app/video.go (view raw)
1package app
2
3import (
4 "errors"
5 "fmt"
6 "log"
7 "regexp"
8 "strconv"
9 "strings"
10 "time"
11
12 g "github.com/birabittoh/gopipe/src/globals"
13 "github.com/kkdai/youtube/v2"
14)
15
16const (
17 maxMB = 20
18 maxContentLength = maxMB * 1048576
19 defaultCacheDuration = 6 * time.Hour
20)
21
22var (
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 selectFn := formatsSelectFn
39 if formatID == 0 {
40 selectFn = formatsSelectFnBest
41 formatID = 1
42 }
43
44 f := video.Formats.Select(selectFn)
45 l := len(f)
46 if l == 0 {
47 return nil
48 }
49 return &f[(formatID-1)%l]
50}
51
52func formatsSelectFn(f youtube.Format) bool {
53 return f.AudioChannels > 1 && f.ContentLength < maxContentLength && strings.HasPrefix(f.MimeType, "video/mp4")
54}
55
56func formatsSelectFnBest(f youtube.Format) bool {
57 return f.AudioChannels > 1 && strings.HasPrefix(f.MimeType, "video/mp4")
58}
59
60func getURL(videoID string) string {
61 return fmt.Sprintf(fmtYouTubeURL, videoID)
62}
63
64func getFromCache(videoID string, formatID int) (video *youtube.Video, format *youtube.Format, err error) {
65 video, err = g.KS.Get(videoID)
66 if err != nil {
67 return
68 }
69
70 if video == nil {
71 err = errors.New("video should not be nil")
72 return
73 }
74
75 format = getFormat(*video, formatID)
76 return
77}
78
79func getFromYT(videoID string, formatID int) (video *youtube.Video, format *youtube.Format, err error) {
80 url := getURL(videoID)
81
82 log.Println("Requesting video ", url)
83 video, err = g.YT.GetVideo(url)
84 if err != nil || video == nil {
85 return
86 }
87
88 format = getFormat(*video, formatID)
89 duration := defaultCacheDuration
90 if format != nil {
91 duration = parseExpiration(format.URL)
92 }
93
94 g.KS.Set(videoID, *video, duration)
95 return
96}
97
98func getVideo(videoID string, formatID int) (video *youtube.Video, format *youtube.Format, err error) {
99 video, format, err = getFromCache(videoID, formatID)
100 if err != nil {
101 video, format, err = getFromYT(videoID, formatID)
102 }
103 return
104}