Files
jukebox_maker/internal/api/server.go
Michael Chus 29f3ad9576 Add jukebox_maker web app v1.0
Go web application for filling USB drives with media files.
Runs in Docker on Unraid with /media, /mnt/usb, /config volumes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 21:33:43 +03:00

101 lines
2.7 KiB
Go

package api
import (
"encoding/json"
"html/template"
"net/http"
webui "jukebox_maker/web"
"jukebox_maker/internal/config"
"jukebox_maker/internal/copier"
"jukebox_maker/internal/task"
"jukebox_maker/internal/watcher"
)
type Deps struct {
Config *config.Config
ConfigPath string
Watcher *watcher.Watcher
Copier *copier.Copier
Tasks *task.Store
MediaPath string
MountPath string
}
type Server struct {
deps Deps
dashboard *template.Template
settings *template.Template
mux *http.ServeMux
}
func New(deps Deps) (*Server, error) {
dash, err := template.ParseFS(webui.FS, "templates/layout.html", "templates/dashboard.html")
if err != nil {
return nil, err
}
sett, err := template.ParseFS(webui.FS, "templates/layout.html", "templates/settings.html")
if err != nil {
return nil, err
}
s := &Server{deps: deps, dashboard: dash, settings: sett, mux: http.NewServeMux()}
s.routes()
return s, nil
}
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
s.mux.ServeHTTP(w, r)
}
func (s *Server) routes() {
s.mux.Handle("GET /static/", http.FileServerFS(webui.FS))
s.mux.HandleFunc("GET /", s.handleDashboard)
s.mux.HandleFunc("GET /settings", s.handleSettings)
s.mux.HandleFunc("GET /health", s.handleHealth)
s.mux.HandleFunc("GET /api/disk", s.handleDiskStatus)
s.mux.HandleFunc("GET /api/sources", s.handleSources)
s.mux.HandleFunc("GET /api/config", s.handleGetConfig)
s.mux.HandleFunc("PUT /api/config", s.handlePutConfig)
s.mux.HandleFunc("POST /api/copy/start", s.handleCopyStart)
s.mux.HandleFunc("POST /api/copy/cancel", s.handleCopyCancel)
s.mux.HandleFunc("GET /api/tasks/{id}", s.handleTaskGet)
}
func (s *Server) handleDashboard(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
s.render(w, s.dashboard, map[string]any{"Title": "Dashboard", "Page": "dashboard"})
}
func (s *Server) handleSettings(w http.ResponseWriter, r *http.Request) {
s.render(w, s.settings, map[string]any{"Title": "Настройки", "Page": "settings"})
}
func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) {
jsonOK(w, map[string]string{"status": "ok"})
}
func (s *Server) render(w http.ResponseWriter, tmpl *template.Template, data any) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
if err := tmpl.ExecuteTemplate(w, "layout", data); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func jsonOK(w http.ResponseWriter, v any) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(v)
}
func jsonErr(w http.ResponseWriter, code int, msg string) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(code)
json.NewEncoder(w).Encode(map[string]string{"error": msg})
}