From 865911f8ffdac7d1d9773570216c0bd35fc601d9 Mon Sep 17 00:00:00 2001 From: Tim Keller Date: Fri, 23 May 2025 21:46:20 -0500 Subject: initial commit --- main.go | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 main.go (limited to 'main.go') diff --git a/main.go b/main.go new file mode 100644 index 0000000..eb56d90 --- /dev/null +++ b/main.go @@ -0,0 +1,96 @@ +package main + +import ( + "fmt" + "html/template" + "io" + "log" + "net/http" + "os" + "strings" + "github.com/joho/godotenv" +) + +const youtubeAPI = "https://www.googleapis.com/youtube/v3/" +var tmpl = template.Must(template.ParseFiles("template.html")) + +func apiRequest(w http.ResponseWriter, r *http.Request, endpoint string, videoIdParam string, part string) { + videoID := r.URL.Query().Get("id") + if videoID == "" { + msg := "Missing ?id=VIDEO_ID parameter" + http.Error(w, msg, http.StatusBadRequest) + return + } + + apiKey := os.Getenv("API_KEY") + if apiKey == "" { + msg := "API_KEY environment variable not set" + http.Error(w, msg, http.StatusInternalServerError) + log.Println(msg) + return + } + + //url := fmt.Sprintf("%s?part=snippet&id=%s&key=%s", youtubeAPI, videoID, apiKey) + url := fmt.Sprintf("%s?part=%s&%s=%s&key=%s", youtubeAPI + endpoint, part, videoIdParam, videoID, apiKey) + resp, err := http.Get(url) + if err != nil { + msg := "Failed to fetch video info: " + err.Error() + http.Error(w, msg, http.StatusInternalServerError) + log.Println(msg) + return + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + msg := "YouTube API error: " + resp.Status + http.Error(w, msg, http.StatusBadGateway) + log.Println(msg) + return + } + + w.Header().Set("Content-Type", "application/json") + io.Copy(w, resp.Body) +} + +func videoDetailsHandler(w http.ResponseWriter, r *http.Request) { + apiRequest(w, r, "videos", "id", "snippet,statistics,topicDetails") +} + +func commentThreadsHandler(w http.ResponseWriter, r *http.Request) { + apiRequest(w, r, "commentThreads", "videoId", "snippet,replies&maxResults=100") +} + +func handler(w http.ResponseWriter, r *http.Request) { + path := strings.Trim(r.URL.Path, "/") + if path == "" { + path = "world" + } + data := struct { + Id string + }{ + Id: path, + } + err := tmpl.Execute(w, data) + if err != nil { + msg := "Template execution error" + http.Error(w, msg, http.StatusInternalServerError) + log.Println(msg) + } +} + +func main() { + // load .env file if it exists + godotenv.Load() + + // setup routes + http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static")))) + http.HandleFunc("/api/details", videoDetailsHandler) + http.HandleFunc("/api/comments", commentThreadsHandler) + + http.HandleFunc("/", handler) + log.Println("Listening on http://localhost:8080") + err := http.ListenAndServe(":8080", nil) + if err != nil { + log.Fatal(err) + } +} -- cgit v1.2.3