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(`

OPDS-PS Explorer

Build the Vue app: cd webapp && bun run build, then run the server from repo root.

`)) }) } 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) }) }