functions/comics/main.go

108 lines
2.8 KiB
Go
Raw Normal View History

2025-01-17 10:30:27 +01:00
package main
import (
"encoding/json"
"fmt"
"log/slog"
"math/rand/v2"
"net/http"
"github.com/PuerkitoBio/goquery"
spinhttp "github.com/fermyon/spin/sdk/go/v2/http"
"github.com/julienschmidt/httprouter"
)
const (
contentTypeHeader = "Content-Type"
)
type MonkeyUserEntry struct {
Title string `json:"title"`
URL string `json:"url"`
}
type ImageReference struct {
URL string `json:"url"`
}
func init() {
router := spinhttp.NewRouter()
2025-01-17 12:07:23 +01:00
router.GET("/comics/random", randomComic)
router.GET("/comics/monkeyuser", monkeyUserComic)
2025-01-17 10:30:27 +01:00
spinhttp.Handle(router.ServeHTTP)
}
2025-01-17 12:07:23 +01:00
func randomComic(w http.ResponseWriter, re *http.Request, params httprouter.Params) {
monkeyUserComic(w, re, params)
}
2025-01-17 10:30:27 +01:00
func monkeyUserComic(w http.ResponseWriter, re *http.Request, _ httprouter.Params) {
indexResponse, err := spinhttp.Get("https://www.monkeyuser.com/index.json")
if err != nil {
slog.Error("failed to fetch MonkeyUser index", slog.String("err", err.Error()))
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
slog.Info("Fetched MonkeyUser index")
defer indexResponse.Body.Close()
if indexResponse.StatusCode != http.StatusOK {
w.WriteHeader(indexResponse.StatusCode)
return
}
var entries []MonkeyUserEntry
if err := json.NewDecoder(indexResponse.Body).Decode(&entries); err != nil {
slog.Error("failed to decode MonkeyUser index", slog.String("err", err.Error()))
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
slog.Info("Decoded MonkeyUser index")
entry := entries[rand.IntN(len(entries))]
pageResponse, err := spinhttp.Get(fmt.Sprintf("https://www.monkeyuser.com%s", entry.URL))
if err != nil {
slog.Error("failed to fetch monkeyuser comic page", slog.String("err", err.Error()))
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer pageResponse.Body.Close()
if pageResponse.StatusCode != http.StatusOK {
w.WriteHeader(pageResponse.StatusCode)
return
}
comicDoc, err := goquery.NewDocumentFromReader(pageResponse.Body)
if err != nil {
slog.Error("failed to parse comic page", slog.String("err", err.Error()))
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
var ref ImageReference
comicDoc.Find("div.content > p > img").Each(func(_ int, s *goquery.Selection) {
for _, node := range s.Nodes {
for _, attr := range node.Attr {
if attr.Key == "src" {
ref.URL = fmt.Sprintf("https://www.monkeyuser.com%s", attr.Val)
break
}
}
slog.Info("found URL", slog.String("url", ref.URL))
}
})
w.Header().Add(contentTypeHeader, "application/json")
w.WriteHeader(http.StatusOK)
if err := json.NewEncoder(w).Encode(ref); err != nil {
slog.Error("failed to encode image ref", slog.String("err", err.Error()))
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}