diff --git a/mpd-web-proxy/cmd/main.go b/mpd-web-proxy/cmd/main.go index eff949f..1c08e22 100644 --- a/mpd-web-proxy/cmd/main.go +++ b/mpd-web-proxy/cmd/main.go @@ -53,7 +53,7 @@ func (s *Server) PutChannel(rw http.ResponseWriter, req *http.Request) error { defer req.Body.Close() err := json.NewDecoder(req.Body).Decode(&envelope) if err != nil { - WriteBadRequest(rw, fmt.Sprintf("bad json: %s", err.Error())) + WriteMPDErrorResponse(rw, fmt.Sprintf("bad json: %s", err.Error())) return err } if envelope.Action == nil { @@ -76,7 +76,7 @@ func (s *Server) PutChannel(rw http.ResponseWriter, req *http.Request) error { } err = action(envelope.Pin) if err != nil { - WriteBadRequest(rw, err.Error()) + WriteMPDErrorResponse(rw, err.Error()) return err } return nil @@ -92,7 +92,7 @@ func (s *Server) Channels(rw http.ResponseWriter, req *http.Request) { s.WriteResponse(rw) } -func WriteBadRequest(rw http.ResponseWriter, msg string) { +func WriteMPDErrorResponse(rw http.ResponseWriter, msg string) { rw.WriteHeader(http.StatusBadRequest) fmt.Fprintf(rw, "ACK: %s\n", msg) } @@ -138,11 +138,11 @@ func (s *Server) MpdEvents(rw http.ResponseWriter, req *http.Request) { func MpdCommand(rw http.ResponseWriter, req *http.Request) { qs, ok := req.URL.Query()["q"] if !ok { - WriteBadRequest(rw, "query parameter `q` not defined") + WriteMPDErrorResponse(rw, "query parameter `q` not defined") return } q := qs[0] - data := Must(internal.MpdQuery(q, MpdAuthority)) + data := Must(internal.MpdQuery(MpdAuthority, q)) rw.Write(data) } @@ -161,11 +161,13 @@ func MpdVersion(rw http.ResponseWriter, req *http.Request) { json.NewEncoder(rw).Encode(&payload) } +var AlbumNotFound = errors.New("no results for provided album ID") + func chooseAFile(sc *bufio.Scanner) (string, error) { for sc.Scan() { line := strings.TrimSpace(sc.Text()) if line == "OK" { - return "", errors.New("no file label. how???") + return "", AlbumNotFound } parts := strings.Split(line, ": ") if len(parts) == 2 && parts[0] == "file" { @@ -186,11 +188,15 @@ func AlbumArt(rw http.ResponseWriter, req *http.Request) { if sc.Err() != nil { panic(sc.Err()) } - Must(fmt.Fprintf(conn, "search albumartist \"%s\" album \"%s\"\n", req.PathValue("albumartist"), req.PathValue("album"))) + albumArtist := req.PathValue("albumartist") + album := req.PathValue("album") + Must(fmt.Fprintf(conn, "search albumartist \"%s\" album \"%s\"\n", albumArtist, album)) fname, err := chooseAFile(sc) - if err != nil { + if errors.Is(err, AlbumNotFound) { rw.WriteHeader(404) return + } else if err != nil { + panic(err) } fullPath := path.Join(MusicDir, fname) fullDir, _ := path.Split(fullPath) @@ -199,24 +205,39 @@ func AlbumArt(rw http.ResponseWriter, req *http.Request) { panic(err) } if img != "" { - fmt.Println("found file:", img) + slog.Info( + "send folder image", + slog.String("albumartist", albumArtist), + slog.String("album", album), + slog.String("path", img), + ) rw.Header().Set("Content-Type", "image/jpeg") f := Must(os.Open(img)) io.Copy(rw, f) return } - f, err := os.Open(fullPath) - if err != nil { - rw.WriteHeader(500) - return - } + f := Must(os.Open(fullPath)) defer f.Close() mime, size, err := art.FindAPICInMP3(f) - fmt.Printf("%d\n", size) if err != nil { + slog.Error( + "could not extract album art", + slog.String("albumartist", albumArtist), + slog.String("album", album), + slog.String("file", fullPath), + slog.String("message", err.Error()), + ) rw.WriteHeader(404) return } + slog.Info( + "send embedded album art", + slog.String("albumartist", albumArtist), + slog.String("album", album), + slog.String("type", mime), + slog.Int64("size", int64(size)), + slog.String("file", fullPath), + ) rw.Header().Set("Content-Type", mime) _, err = io.CopyN(rw, f, int64(size)) if err != nil { diff --git a/mpd-web-proxy/internal/art/art_test.go b/mpd-web-proxy/internal/art/art_test.go index 46d8130..db39fa8 100644 --- a/mpd-web-proxy/internal/art/art_test.go +++ b/mpd-web-proxy/internal/art/art_test.go @@ -28,7 +28,6 @@ func BenchmarkFindAPICInMP3(b *testing.B) { if err != nil { panic(err) } - nul, err := os.Open("/dev/null") defer f.Close() for range b.N { _, err := f.Seek(0, io.SeekStart) @@ -39,6 +38,6 @@ func BenchmarkFindAPICInMP3(b *testing.B) { if err != nil { panic(err) } - io.CopyN(nul, f, int64(sz)) + io.CopyN(io.Discard, f, int64(sz)) } } diff --git a/mpd-web-proxy/internal/gpio/gpio.go b/mpd-web-proxy/internal/gpio/gpio.go index 3c7b31b..54b948c 100644 --- a/mpd-web-proxy/internal/gpio/gpio.go +++ b/mpd-web-proxy/internal/gpio/gpio.go @@ -1,7 +1,7 @@ package gpio import ( - "fmt" + "log/slog" ) // PhysicalState represents the physical voltage value @@ -35,11 +35,11 @@ func (n *NopBackend) Set(pin int, state PhysicalState) error { if state { newState = "HIGH" } - fmt.Printf("\u001b[32mSet pin %d to %s\u001b[0m\n", pin, newState) + slog.Info("set gpio pin state", slog.Int("pin", pin), slog.String("state", newState)) return nil } func (n *NopBackend) Close() error { - fmt.Println("GPIO Close called") + slog.Info("gpio close called") return nil } diff --git a/mpd-web-proxy/internal/mpd.go b/mpd-web-proxy/internal/mpd.go index 3de42bc..8f42f9f 100644 --- a/mpd-web-proxy/internal/mpd.go +++ b/mpd-web-proxy/internal/mpd.go @@ -3,7 +3,6 @@ package internal import ( "bufio" "bytes" - "context" "errors" "fmt" "io" @@ -14,32 +13,19 @@ import ( // MpdQuery connects and queries the MPD server // with the given command. Returns the response body // or any connection error. -func MpdQuery(cmd string, authority string) ([]byte, error) { +func MpdQuery(authority string, cmd string, args ...any) ([]byte, error) { mpd, err := net.Dial("tcp", authority) if err != nil { return nil, err } defer mpd.Close() - return mpdQuery(cmd, mpd) -} - -// A cancellable MPD Query. -func MpdQueryContext(cmd string, authority string, ctx context.Context) ([]byte, error) { - mpd, err := net.Dial("tcp", authority) - if err != nil { - return nil, err - } - go func() { - <-ctx.Done() - fmt.Println("client gone. closing mpd") - mpd.Close() - }() - return mpdQuery(cmd, mpd) + return mpdQuery(mpd, cmd, args...) } // mpdQuery reads and parses a response stream // to verify that the response is valid. -func mpdQuery(cmd string, mpd io.ReadWriter) ([]byte, error) { +func mpdQuery(mpd io.ReadWriter, cmd string, args ...any) ([]byte, error) { + q := fmt.Sprintf(cmd, args...) scanner := bufio.NewScanner(mpd) if !scanner.Scan() { if err := scanner.Err(); err != nil { @@ -47,7 +33,7 @@ func mpdQuery(cmd string, mpd io.ReadWriter) ([]byte, error) { } return nil, errors.New("unexpected EOF") } - if _, err := io.WriteString(mpd, strings.TrimSpace(cmd)+"\n"); err != nil { + if _, err := io.WriteString(mpd, strings.TrimSpace(q)+"\n"); err != nil { return nil, err } var ret bytes.Buffer