diff --git a/api.go b/api.go index dd530e7..d107dc6 100644 --- a/api.go +++ b/api.go @@ -10,6 +10,8 @@ import ( "io" "net" "net/http" + "net/http/httputil" + "net/url" "os" "strings" "time" @@ -159,7 +161,28 @@ func (s *Server) handleConfigReload(w http.ResponseWriter, r *http.Request) { jsonResponse(w, http.StatusOK, APIResponse{Success: true, Data: "reloaded"}) } -// handleStream proxies MJPEG streams from go2rtc to avoid cross-origin issues. +// handleCameraProxy forwards requests to a camera's web interface. +// GET /camera/{cam_id}/... → http://{camera_ip}/... +func (s *Server) handleCameraProxy(w http.ResponseWriter, r *http.Request) { + path := strings.TrimPrefix(r.URL.Path, "/camera/") + parts := strings.SplitN(path, "/", 2) + camID := parts[0] + + cam, _ := s.findCamera(camID) + if cam == nil { + http.Error(w, "camera not found", http.StatusNotFound) + return + } + + remaining := "/" + if len(parts) > 1 { + remaining += parts[1] + } + + target, _ := url.Parse("http://" + cam.IP + remaining) + proxy := httputil.NewSingleHostReverseProxy(target) + proxy.ServeHTTP(w, r) +} // GET /stream/{cam_id}?type=sub (default: sub stream via go2rtc) func (s *Server) handleStream(w http.ResponseWriter, r *http.Request) { camID := strings.TrimPrefix(r.URL.Path, "/stream/") diff --git a/public/app.js b/public/app.js index 004d8b4..1514ec9 100644 --- a/public/app.js +++ b/public/app.js @@ -291,6 +291,7 @@ async function renderCameraCards() {

📷 ${c.name || 'Camera_' + c.ip.split('.').pop()} ${c.ip} + ⚙️

diff --git a/server.go b/server.go index 87a69bc..fd39bc8 100644 --- a/server.go +++ b/server.go @@ -141,6 +141,9 @@ func (s *Server) registerRoutes() { s.mux.Handle("/go2rtc/", http.StripPrefix("/go2rtc", s.go2rtcProxy())) + // Camera web interface proxy — access cameras remotely through NextNVR. + s.mux.HandleFunc("/camera/", s.handleCameraProxy) + // Static file server for recordings (actual video files on disk). s.mux.Handle("/recordings/", http.StripPrefix("/recordings/", http.FileServer(http.Dir(s.config.Storage.RecordingsPath))))