all repos — fixyoutube-go @ 558f876a7938e8fde5bbf84dfe77dde6b7669634

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"))
 21
 22func indexHandler(w http.ResponseWriter, r *http.Request) {
 23	buf := &bytes.Buffer{}
 24	err := indexTemplate.Execute(buf, nil)
 25	if err != nil {
 26		http.Error(w, err.Error(), http.StatusInternalServerError)
 27		return
 28	}
 29
 30	buf.WriteTo(w)
 31}
 32
 33func watchHandler(newsapi *invidious.Client) http.HandlerFunc {
 34	return func(w http.ResponseWriter, r *http.Request) {
 35		u, err := url.Parse(r.URL.String())
 36		if err != nil {
 37			http.Error(w, err.Error(), http.StatusInternalServerError)
 38			return
 39		}
 40
 41		params := u.Query()
 42		videoId := params.Get("v")
 43
 44		video, err := newsapi.FetchEverything(videoId)
 45		if err != nil {
 46			http.Error(w, err.Error(), http.StatusInternalServerError)
 47			return
 48		}
 49
 50		buf := &bytes.Buffer{}
 51		err = videoTemplate.Execute(buf, video)
 52		if err != nil {
 53			http.Error(w, err.Error(), http.StatusInternalServerError)
 54			return
 55		}
 56
 57		buf.WriteTo(w)
 58	}
 59}
 60
 61var blacklist = []string{"favicon.ico", "robots.txt"}
 62
 63func shortHandler(newsapi *invidious.Client) http.HandlerFunc {
 64	return func(w http.ResponseWriter, r *http.Request) {
 65		videoId := mux.Vars(r)["videoId"]
 66
 67		if slices.Contains(blacklist, videoId) {
 68			http.Error(w, "Not a valid ID.", http.StatusBadRequest)
 69			return
 70		}
 71
 72		video, err := newsapi.FetchEverything(videoId)
 73		if err != nil {
 74			http.Error(w, err.Error(), http.StatusBadRequest)
 75			return
 76		}
 77
 78		buf := &bytes.Buffer{}
 79		err = videoTemplate.Execute(buf, video)
 80		if err != nil {
 81			http.Error(w, err.Error(), http.StatusInternalServerError)
 82			return
 83		}
 84
 85		buf.WriteTo(w)
 86	}
 87}
 88
 89func main() {
 90	err := godotenv.Load()
 91	if err != nil {
 92		log.Println("Error loading .env file")
 93	}
 94
 95	port := os.Getenv("PORT")
 96	if port == "" {
 97		port = "3000"
 98	}
 99
100	myClient := &http.Client{Timeout: 10 * time.Second}
101	videoapi := invidious.NewClient(myClient, "y.birabittoh.duckdns.org")
102
103	r := mux.NewRouter()
104	r.HandleFunc("/", indexHandler)
105	r.HandleFunc("/watch", watchHandler(videoapi))
106	r.HandleFunc("/{videoId}", shortHandler(videoapi))
107	//r.HandleFunc("/proxy/{videoId}", proxyHandler)
108
109	/*
110		// native go implementation (useless until february 2024)
111		r := http.NewServeMux()
112		r.HandleFunc("/watch", watchHandler(videoapi))
113		r.HandleFunc("/{videoId}/", shortHandler(videoapi))
114		r.HandleFunc("/", indexHandler)
115	*/
116	println("Serving on port", port)
117	http.ListenAndServe(":"+port, r)
118}