Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 36 additions & 15 deletions mpd-web-proxy/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
Expand All @@ -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)
}
Expand Down Expand Up @@ -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)
}

Expand All @@ -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" {
Expand All @@ -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)
Expand All @@ -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 {
Expand Down
3 changes: 1 addition & 2 deletions mpd-web-proxy/internal/art/art_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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))
}
}
6 changes: 3 additions & 3 deletions mpd-web-proxy/internal/gpio/gpio.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package gpio

import (
"fmt"
"log/slog"
)

// PhysicalState represents the physical voltage value
Expand Down Expand Up @@ -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
}
24 changes: 5 additions & 19 deletions mpd-web-proxy/internal/mpd.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package internal
import (
"bufio"
"bytes"
"context"
"errors"
"fmt"
"io"
Expand All @@ -14,40 +13,27 @@ 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 {
return nil, err
}
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
Expand Down
Loading