all repos — gopipe @ 4f63af74cb8008676063943eb6b457c0a76bc03c

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