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
14 changes: 11 additions & 3 deletions api/dbv1/tracks.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ type TracksParams struct {
GetTracksParams
}

// IncludeID3TagsCtxKey is the request-context key used to opt in to ID3 tag
// query params on generated stream/preview URLs. The id3 middleware sets it
// from the `?id3=true` query param.
const IncludeID3TagsCtxKey = "includeID3Tags"

// Track is the standard track type containing all track data
type Track struct {
GetTracksRow
Expand Down Expand Up @@ -128,9 +133,12 @@ func (q *Queries) TracksKeyed(ctx context.Context, arg TracksParams) (map[int32]
// Get access from the bulk access map
access := accessMap[rawTrack.TrackID]

id3Tags := &Id3Tags{
Title: rawTrack.Title.String,
Artist: user.Name.String,
var id3Tags *Id3Tags
if includeID3Tags, _ := ctx.Value(IncludeID3TagsCtxKey).(bool); includeID3Tags {
id3Tags = &Id3Tags{
Title: rawTrack.Title.String,
Artist: user.Name.String,
}
}

var stream *MediaLink
Expand Down
20 changes: 20 additions & 0 deletions api/id3_middleware.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package api

import (
"api.audius.co/api/dbv1"
"github.com/gofiber/fiber/v2"
)

// id3Middleware reads the optional `?id3=true` query param and stashes the
// resulting bool on the request context so dbv1.TracksKeyed can decide
// whether to embed ID3 tag query params on generated stream/preview URLs.
//
// ID3 tags are opt-in: when omitted, validator nodes can redirect straight to
// presigned blob-storage URLs; when requested, the validator must proxy the
// bytes so it can prepend the ID3 tag.
func (app *ApiServer) id3Middleware(c *fiber.Ctx) error {
if c.QueryBool("id3") {
c.Locals(dbv1.IncludeID3TagsCtxKey, true)
}
return c.Next()
}
1 change: 1 addition & 0 deletions api/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,7 @@ func NewApiServer(config config.Config) *ApiServer {
app.Use(app.resolveMyIdMiddleware)
app.Use(app.authMiddleware)
app.Use(app.solanaWalletMiddleware)
app.Use(app.id3Middleware)

v1 := app.Group("/v1")
v1Full := app.Group("/v1/full")
Expand Down
19 changes: 18 additions & 1 deletion api/v1_track_stream_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,22 @@ func TestGetTrackStream(t *testing.T) {
req := httptest.NewRequest("GET", "/v1/tracks/eYJyn/stream", nil)
res, err := app.Test(req, -1)
assert.NoError(t, err)
assert.Contains(t, res.Header.Get("Location"), "tracks/cidstream/?id3=true&id3_artist=&id3_title=Culca+Canyon&signature=%7B%22data%22%3A%22%7B%5C%22cid%5C%22%3A%5C%22%5C%22%2C%5C%22timestamp%5C%22%3")
location := res.Header.Get("Location")
assert.Contains(t, location, "tracks/cidstream/")
assert.Contains(t, location, "signature=")
// ID3 tags are opt-in via ?id3=true; verify they are NOT present by default.
assert.NotContains(t, location, "id3=true")
assert.NotContains(t, location, "id3_artist=")
assert.NotContains(t, location, "id3_title=")
}

func TestGetTrackStreamWithID3(t *testing.T) {
app := testAppWithFixtures(t)
req := httptest.NewRequest("GET", "/v1/tracks/eYJyn/stream?id3=true", nil)
res, err := app.Test(req, -1)
assert.NoError(t, err)
location := res.Header.Get("Location")
assert.Contains(t, location, "tracks/cidstream/")
assert.Contains(t, location, "id3=true")
assert.Contains(t, location, "id3_title=Culca+Canyon")
}
Loading