Create a server (go) and webapp (vue) development tool to explore OPDS-PS capable servers. This tool is intended for development purposes only, it should allow to navigate the server, view raw requests and responses and interact with the API in a general way. I think it's best if we provide a columns layout to navigate the OPDS-PS server much like the macos finder does, with a panel with details to the far right for technical information. Here's the SPEC: https://specs.opds.io/
65 lines
1.8 KiB
Go
65 lines
1.8 KiB
Go
package main
|
|
|
|
import (
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"opds-explorer/internal/handlers"
|
|
"opds-explorer/internal/proxy"
|
|
)
|
|
|
|
func main() {
|
|
proxyClient := proxy.NewClient()
|
|
h := handlers.New(proxyClient)
|
|
|
|
mux := http.NewServeMux()
|
|
|
|
// API: fetch OPDS feed (proxies request, returns parsed + raw)
|
|
mux.HandleFunc("GET /api/fetch", h.FetchFeed)
|
|
mux.HandleFunc("POST /api/fetch", h.FetchFeed)
|
|
// API: stream a URL through the server (e.g. for images to avoid CORS)
|
|
mux.HandleFunc("GET /api/proxy", h.ProxyResource)
|
|
|
|
// Serve Vue SPA from dist (or embedded)
|
|
dist := os.Getenv("OPDS_DIST")
|
|
if dist == "" {
|
|
dist = filepath.Join(".", "dist")
|
|
}
|
|
if info, err := os.Stat(dist); err == nil && info.IsDir() {
|
|
mux.Handle("/", http.FileServer(http.Dir(dist)))
|
|
} else {
|
|
// Dev: serve a simple message if dist missing
|
|
mux.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/" {
|
|
http.NotFound(w, r)
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
|
w.Write([]byte(`<h1>OPDS-PS Explorer</h1><p>Build the Vue app: <code>cd webapp && bun run build</code>, then run the server from repo root.</p>`))
|
|
})
|
|
}
|
|
|
|
addr := ":8080"
|
|
if p := os.Getenv("PORT"); p != "" {
|
|
addr = ":" + p
|
|
}
|
|
log.Printf("OPDS-PS Explorer server listening on %s", addr)
|
|
if err := http.ListenAndServe(addr, cors(mux)); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func cors(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
|
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
|
|
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
|
|
if r.Method == "OPTIONS" {
|
|
w.WriteHeader(http.StatusNoContent)
|
|
return
|
|
}
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|