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}