all repos — gopipe @ d9ab51a35a4242ee8f1f5c0760ced3905f84e872

Embed YouTube videos on Telegram, Discord and more!

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}