all repos — fixyoutube-go @ 712b9c42dc774930f2aff23a028d98e3f7b993d3

A better way to embed YouTube videos everywhere (inspired by FixTweet).

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}