diff options
author | Tim Keller <tjkeller.xyz> | 2025-05-23 21:46:20 -0500 |
---|---|---|
committer | Tim Keller <tjkeller.xyz> | 2025-05-23 21:46:20 -0500 |
commit | 865911f8ffdac7d1d9773570216c0bd35fc601d9 (patch) | |
tree | 2c29ff9cfe78d95e095a39163ade4e83e4d56b92 /main.go | |
download | mintube-865911f8ffdac7d1d9773570216c0bd35fc601d9.tar.xz mintube-865911f8ffdac7d1d9773570216c0bd35fc601d9.zip |
initial commit
Diffstat (limited to 'main.go')
-rw-r--r-- | main.go | 96 |
1 files changed, 96 insertions, 0 deletions
@@ -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) + } +} |