all repos — gopipe @ cec307a9e07ec65951325dcc377f9c24c25ac94b

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