all repos — gopipe @ 6eff4ae6fb13714b5c8a946da03292c0f530ac4e

Embed YouTube videos on Telegram, Discord and more!

src/app/handlers.go (view raw)

  1package app
  2
  3import (
  4	"fmt"
  5	"html/template"
  6	"log"
  7	"net/http"
  8	"regexp"
  9
 10	g "github.com/birabittoh/gopipe/src/globals"
 11	"golang.org/x/time/rate"
 12)
 13
 14const (
 15	fmtYouTubeURL = "https://www.youtube.com/watch?v=%s"
 16	err404        = "Not Found"
 17	err500        = "Internal Server Error"
 18	heading       = `<!--
 19 .d8888b.       88888888888       888              
 20d88P  Y88b          888           888              
 21888    888          888           888              
 22888         .d88b.  888  888  888 88888b.   .d88b. 
 23888  88888 d88""88b 888  888  888 888 "88b d8P  Y8b
 24888    888 888  888 888  888  888 888  888 88888888
 25Y88b  d88P Y88..88P 888  Y88b 888 888 d88P Y8b.    
 26 "Y8888P88  "Y88P"  888   "Y88888 88888P"   "Y8888 
 27
 28A better way to embed YouTube videos on Telegram.
 29-->`
 30)
 31
 32var (
 33	userAgentRegex = regexp.MustCompile(`(?i)bot|facebook|embed|got|firefox\/92|firefox\/38|curl|wget|go-http|yahoo|generator|whatsapp|preview|link|proxy|vkshare|images|analyzer|index|crawl|spider|python|cfnetwork|node`)
 34	videoRegex     = regexp.MustCompile(`(?i)^[a-z0-9_-]{11}$`)
 35)
 36
 37func limit(limiter *rate.Limiter, next http.Handler) http.Handler {
 38	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 39		if !limiter.Allow() {
 40			status := http.StatusTooManyRequests
 41			http.Error(w, http.StatusText(status), status)
 42			return
 43		}
 44		next.ServeHTTP(w, r)
 45	})
 46}
 47
 48func indexHandler(w http.ResponseWriter, r *http.Request) {
 49	err := g.XT.ExecuteTemplate(w, "index.tmpl", nil)
 50	if err != nil {
 51		log.Println("indexHandler ERROR: ", err)
 52		http.Error(w, err500, http.StatusInternalServerError)
 53		return
 54	}
 55}
 56
 57func videoHandler(w http.ResponseWriter, r *http.Request) {
 58	videoID := r.URL.Query().Get("v")
 59	if videoID == "" {
 60		videoID = r.PathValue("videoID")
 61		if videoID == "" {
 62			http.Error(w, "Missing video ID", http.StatusBadRequest)
 63			return
 64		}
 65	}
 66
 67	if !userAgentRegex.MatchString(r.UserAgent()) {
 68		log.Println("Regex did not match. UA: ", r.UserAgent())
 69		if !g.Debug {
 70			log.Println("Redirecting.")
 71			http.Redirect(w, r, getURL(videoID), http.StatusFound)
 72			return
 73		}
 74	}
 75
 76	if !videoRegex.MatchString(videoID) {
 77		log.Println("Invalid video ID: ", videoID)
 78		http.Error(w, "Invalid video ID.", http.StatusBadRequest)
 79		return
 80	}
 81
 82	formatID := getFormatID(r.PathValue("formatID"))
 83
 84	video, format, err := getVideo(videoID, formatID)
 85	if err != nil {
 86		http.Error(w, err500, http.StatusInternalServerError)
 87		return
 88	}
 89
 90	if video == nil || format == nil {
 91		http.Error(w, err500, http.StatusInternalServerError)
 92		return
 93	}
 94
 95	var thumbnail string
 96	if len(video.Thumbnails) > 0 {
 97		thumbnail = video.Thumbnails[len(video.Thumbnails)-1].URL
 98	}
 99
100	videoURL := format.URL
101	if g.Proxy {
102		videoURL = fmt.Sprintf("/proxy/%s/%d", videoID, formatID)
103	}
104
105	data := map[string]interface{}{
106		"VideoID":     videoID,
107		"VideoURL":    videoURL,
108		"Author":      video.Author,
109		"Title":       video.Title,
110		"Description": video.Description,
111		"Thumbnail":   thumbnail,
112		"Duration":    video.Duration,
113		"Captions":    getCaptions(*video),
114		"Debug":       g.Debug,
115		"Heading":     template.HTML(heading),
116	}
117
118	err = g.XT.ExecuteTemplate(w, "video.tmpl", data)
119	if err != nil {
120		log.Println("indexHandler ERROR: ", err)
121		http.Error(w, err500, http.StatusInternalServerError)
122		return
123	}
124}