ao3-api/main.go
2026-06-05 23:22:37 -04:00

107 lines
2.4 KiB
Go

package main
import (
"encoding/json"
"log"
"net/http"
"os"
"strconv"
"ao3scraper/ao3"
)
var client *ao3.Client
func main() {
client = ao3.NewClient()
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
mux := http.NewServeMux()
mux.HandleFunc("GET /autocomplete", handleAutocomplete)
mux.HandleFunc("GET /search", handleSearch)
mux.HandleFunc("GET /tags/{tag}/works", handleTagWorks)
mux.HandleFunc("GET /works/{id}", handleWork)
log.Printf("listening on :%s", port)
log.Fatal(http.ListenAndServe(":"+port, mux))
}
func handleAutocomplete(w http.ResponseWriter, r *http.Request) {
term := r.URL.Query().Get("term")
tagType := r.URL.Query().Get("type")
if term == "" {
jsonError(w, "term required", http.StatusBadRequest)
return
}
tags, err := client.AutocompleteTags(r.Context(), term, tagType)
if err != nil {
jsonError(w, err.Error(), http.StatusInternalServerError)
return
}
jsonOK(w, tags)
}
func handleSearch(w http.ResponseWriter, r *http.Request) {
q := r.URL.Query()
page, _ := strconv.Atoi(q.Get("page"))
minWords, _ := strconv.Atoi(q.Get("min_words"))
maxWords, _ := strconv.Atoi(q.Get("max_words"))
result, err := client.SearchWorks(r.Context(), ao3.SearchParams{
Query: q.Get("query"),
Fandom: q.Get("fandom"),
Tag: q.Get("tag"),
Rating: q.Get("rating"),
MinWords: minWords,
MaxWords: maxWords,
Page: page,
})
if err != nil {
jsonError(w, err.Error(), http.StatusInternalServerError)
return
}
jsonOK(w, result)
}
func handleTagWorks(w http.ResponseWriter, r *http.Request) {
tag := r.PathValue("tag")
page, _ := strconv.Atoi(r.URL.Query().Get("page"))
result, err := client.WorksByTag(r.Context(), tag, page)
if err != nil {
jsonError(w, err.Error(), http.StatusInternalServerError)
return
}
jsonOK(w, result)
}
func handleWork(w http.ResponseWriter, r *http.Request) {
id, err := strconv.Atoi(r.PathValue("id"))
if err != nil {
jsonError(w, "invalid id", http.StatusBadRequest)
return
}
work, err := client.GetWork(r.Context(), id)
if err != nil {
jsonError(w, err.Error(), http.StatusInternalServerError)
return
}
jsonOK(w, work)
}
func jsonOK(w http.ResponseWriter, v any) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(v)
}
func jsonError(w http.ResponseWriter, msg string, code int) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(code)
json.NewEncoder(w).Encode(map[string]string{"error": msg})
}