fixyoutube.go (view raw)
1package main
2
3import (
4 "bytes"
5 "html/template"
6 "log"
7 "net/http"
8 "net/url"
9 "os"
10 "slices"
11 "time"
12
13 "github.com/BiRabittoh/fixyoutube-go/invidious"
14 "github.com/gorilla/mux"
15 "github.com/joho/godotenv"
16)
17
18var templatesDirectory = "templates/"
19var indexTemplate = template.Must(template.ParseFiles(templatesDirectory + "index.html"))
20var videoTemplate = template.Must(template.ParseFiles(templatesDirectory + "video.html"))
21var blacklist = []string{"favicon.ico", "robots.txt"}
22
23func indexHandler(w http.ResponseWriter, r *http.Request) {
24 buf := &bytes.Buffer{}
25 err := indexTemplate.Execute(buf, nil)
26 if err != nil {
27 http.Error(w, err.Error(), http.StatusInternalServerError)
28 return
29 }
30
31 buf.WriteTo(w)
32}
33
34func clearHandler(w http.ResponseWriter, r *http.Request) {
35 //TODO: check with some secret API key before clearing cache.
36 invidious.ClearDB()
37 //TODO: return a message
38}
39
40func watchHandler(invidiousClient *invidious.Client) http.HandlerFunc {
41 return func(w http.ResponseWriter, r *http.Request) {
42 u, err := url.Parse(r.URL.String())
43 if err != nil {
44 http.Error(w, err.Error(), http.StatusInternalServerError)
45 return
46 }
47
48 params := u.Query()
49 videoId := params.Get("v")
50
51 video, err := invidiousClient.GetVideo(videoId)
52 if err != nil {
53 http.Error(w, err.Error(), http.StatusInternalServerError)
54 return
55 }
56
57 buf := &bytes.Buffer{}
58 err = videoTemplate.Execute(buf, video)
59 if err != nil {
60 http.Error(w, err.Error(), http.StatusInternalServerError)
61 return
62 }
63
64 buf.WriteTo(w)
65 }
66}
67
68func shortHandler(invidiousClient *invidious.Client) http.HandlerFunc {
69 return func(w http.ResponseWriter, r *http.Request) {
70 videoId := mux.Vars(r)["videoId"]
71
72 if slices.Contains(blacklist, videoId) {
73 http.Error(w, "Not a valid ID.", http.StatusBadRequest)
74 return
75 }
76
77 video, err := invidiousClient.GetVideo(videoId)
78 if err != nil {
79 http.Error(w, err.Error(), http.StatusBadRequest)
80 return
81 }
82
83 buf := &bytes.Buffer{}
84 err = videoTemplate.Execute(buf, video)
85 if err != nil {
86 http.Error(w, err.Error(), http.StatusInternalServerError)
87 return
88 }
89
90 buf.WriteTo(w)
91 }
92}
93
94func main() {
95 err := godotenv.Load()
96 if err != nil {
97 log.Println("Error loading .env file")
98 }
99
100 port := os.Getenv("PORT")
101 if port == "" {
102 port = "3000"
103 }
104
105 myClient := &http.Client{Timeout: 10 * time.Second}
106 videoapi := invidious.NewClient(myClient)
107
108 r := mux.NewRouter()
109 r.HandleFunc("/", indexHandler)
110 r.HandleFunc("/clear", clearHandler)
111 r.HandleFunc("/watch", watchHandler(videoapi))
112 r.HandleFunc("/{videoId}", shortHandler(videoapi))
113 //TODO: r.HandleFunc("/proxy/{videoId}", proxyHandler)
114
115 /*
116 // native go implementation (useless until february 2024)
117 r := http.NewServeMux()
118 r.HandleFunc("/watch", watchHandler(videoapi))
119 r.HandleFunc("/{videoId}/", shortHandler(videoapi))
120 r.HandleFunc("/", indexHandler)
121 */
122 println("Serving on port", port)
123 http.ListenAndServe(":"+port, r)
124}