Skip to content

Commit b401737

Browse files
b0bbywanclaude
andcommitted
fix(mpris): decode percent-encoded file:// cover URIs
Closes #112. RFC 3986-compliant MPRIS daemons percent-encode reserved chars in mpris:artUrl; parse the URI so paths with spaces/accents resolve correctly instead of 404ing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 6c24ae6 commit b401737

2 files changed

Lines changed: 32 additions & 1 deletion

File tree

api/handlers_mpris_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,17 @@ func TestCoverHandler(t *testing.T) {
1919
t.Fatal(err)
2020
}
2121

22+
// Path containing a space — MPRIS daemons percent-encode it per RFC 3986.
23+
encodedDir := filepath.Join(tmpDir, "Transmission pirate")
24+
if err := os.Mkdir(encodedDir, 0755); err != nil {
25+
t.Fatal(err)
26+
}
27+
encodedCoverPath := filepath.Join(encodedDir, "folder.jpg")
28+
if err := os.WriteFile(encodedCoverPath, []byte("encoded-image-data"), 0644); err != nil {
29+
t.Fatal(err)
30+
}
31+
encodedArtUrl := "file://" + strings.ReplaceAll(encodedCoverPath, " ", "%20")
32+
2233
tests := []struct {
2334
name string
2435
busName string
@@ -55,6 +66,17 @@ func TestCoverHandler(t *testing.T) {
5566
wantStatusCode: http.StatusOK,
5667
wantBody: "fake-image-data",
5768
},
69+
{
70+
name: "file:// URL with percent-encoded path serves file",
71+
busName: "org.mpris.MediaPlayer2.mpd",
72+
getPlayer: func(string) (*mpris.Player, error) {
73+
return &mpris.Player{Metadata: map[string]string{
74+
"mpris:artUrl": encodedArtUrl,
75+
}}, nil
76+
},
77+
wantStatusCode: http.StatusOK,
78+
wantBody: "encoded-image-data",
79+
},
5880
{
5981
name: "http:// URL redirects",
6082
busName: "org.mpris.MediaPlayer2.spotify",

api/players.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package api
33
import (
44
"errors"
55
"net/http"
6+
"net/url"
67
"strings"
78

89
"github.com/b0bbywan/go-odio-api/backend/mpris"
@@ -147,7 +148,15 @@ func CoverHandler(getPlayer func(string) (*mpris.Player, error)) http.HandlerFun
147148
case artUrl == "":
148149
http.NotFound(w, r)
149150
case strings.HasPrefix(artUrl, "file://"):
150-
http.ServeFile(w, r, strings.TrimPrefix(artUrl, "file://"))
151+
// Standards-compliant MPRIS daemons percent-encode reserved
152+
// characters in file:// URIs (RFC 3986). Parse to recover the
153+
// decoded filesystem path.
154+
u, err := url.Parse(artUrl)
155+
if err != nil {
156+
http.NotFound(w, r)
157+
return
158+
}
159+
http.ServeFile(w, r, u.Path)
151160
case strings.HasPrefix(artUrl, "http://"), strings.HasPrefix(artUrl, "https://"):
152161
http.Redirect(w, r, artUrl, http.StatusTemporaryRedirect)
153162
default:

0 commit comments

Comments
 (0)