all repos — gopipe @ 907efd7608540381e20c938f1b7e7a94963a3737

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 {
 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}