Skip to content

Commit 9ebe441

Browse files
committed
Fix creating a playlist with description
The description was completely ignored by accident.
1 parent 215743a commit 9ebe441

File tree

8 files changed

+86
-40
lines changed

8 files changed

+86
-40
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Change Log
22

3+
## v1.6.1 - 2025-08-10
4+
5+
Fixes a bug where the description was ignored when set in the API request for creating a brand new playlist.
6+
37
## v1.6.0 - 2025-06-07
48

59
This one of the biggest improvements of Euterpe so far. As always, it retains API backwards compatibility with older Euterpe versions.

src/playlists/manager.go

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -201,20 +201,19 @@ func (m *manager) List(ctx context.Context, args ListArgs) ([]Playlist, error) {
201201
// Create implements Playlister.
202202
func (m *manager) Create(
203203
ctx context.Context,
204-
name string,
205-
tracks []int64,
204+
args CreateArgs,
206205
) (int64, error) {
207-
if name == "" {
206+
if args.Name == "" {
208207
return 0, fmt.Errorf("name cannot be empty")
209208
}
210209

211210
var lastInsertID int64
212211

213212
insertPlaylistQuery := `
214213
INSERT INTO
215-
playlists (name, public, created_at, updated_at)
214+
playlists (name, description, public, created_at, updated_at)
216215
VALUES
217-
(@name, 1, @current_time, @current_time)
216+
(@name, @description, 1, @current_time, @current_time)
218217
`
219218

220219
insertSongsQuery := `
@@ -238,9 +237,15 @@ func (m *manager) Create(
238237
}
239238
}()
240239

240+
descVal := sql.Named("description", nil)
241+
if args.Description != "" {
242+
descVal = sql.Named("description", args.Description)
243+
}
244+
241245
res, err := tx.ExecContext(ctx, insertPlaylistQuery,
242-
sql.Named("name", name),
246+
sql.Named("name", args.Name),
243247
sql.Named("current_time", time.Now().Unix()),
248+
descVal,
244249
)
245250
if err != nil {
246251
return fmt.Errorf("failed to insert playlist: %w", err)
@@ -252,18 +257,18 @@ func (m *manager) Create(
252257
}
253258

254259
lastInsertID = id
255-
if len(tracks) == 0 {
260+
if len(args.Tracks) == 0 {
256261
return nil
257262
}
258263

259264
insertSongsQuery += strings.TrimSuffix(strings.Repeat(
260-
"(@playlist_id, ?, ?),", len(tracks),
265+
"(@playlist_id, ?, ?),", len(args.Tracks),
261266
), ",")
262267

263268
queryVals := []any{
264269
sql.Named("playlist_id", lastInsertID),
265270
}
266-
for index, trackID := range tracks {
271+
for index, trackID := range args.Tracks {
267272
queryVals = append(queryVals, trackID, index)
268273
}
269274

src/playlists/playlists.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,10 @@ type Playlister interface {
2323
// Count returns the count of all playlists available.
2424
Count(ctx context.Context) (int64, error)
2525

26-
// Create creates a new playlist with the given name. `songs` is an list
27-
// of track IDs to be added in the playlist.
26+
// Create creates a new playlist with the given create arguments.
2827
//
2928
// Returns the unique ID of the newly created playlist.
30-
Create(ctx context.Context, name string, tracks []int64) (int64, error)
29+
Create(ctx context.Context, args CreateArgs) (int64, error)
3130

3231
// Update updates the playlist with ID `id` with the values
3332
// given in `args`. Note that everything in args is optional
@@ -59,6 +58,18 @@ type Playlist struct {
5958
Tracks []library.TrackInfo
6059
}
6160

61+
// CreateArgs are the arguments needed for creating a playlist.
62+
type CreateArgs struct {
63+
Name string // Name is the short name of the playlist. Required.
64+
65+
// Description is an optional short text which explains more about the playlist.
66+
Description string
67+
68+
// Tracks is an list of track IDs to be added in the playlist. May be left
69+
// empty.
70+
Tracks []int64
71+
}
72+
6273
// UpdateArgs is all the possible arguments which could be updated
6374
// for a given playlist.
6475
type UpdateArgs struct {

src/playlists/playlists_test.go

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func TestPlaylistsManagerCRUD(t *testing.T) {
4040
const playlistName = "empty playlist"
4141

4242
now := time.Now()
43-
id, err := manager.Create(ctx, playlistName, []int64{})
43+
id, err := manager.Create(ctx, playlists.CreateArgs{Name: playlistName})
4444
assert.NilErr(t, err, "creating empty playlist")
4545

4646
expected := playlists.Playlist{
@@ -98,6 +98,27 @@ func TestPlaylistsManagerCRUD(t *testing.T) {
9898

9999
_, err = manager.Get(ctx, playlist.ID)
100100
assert.NotNilErr(t, err, "expected 'not found' error for deleted playlist")
101+
102+
const listDescription = "some playlist description"
103+
now = time.Now()
104+
id, err = manager.Create(ctx, playlists.CreateArgs{
105+
Name: playlistName,
106+
Description: listDescription,
107+
})
108+
assert.NilErr(t, err, "creating empty playlist with description")
109+
110+
expected = playlists.Playlist{
111+
Name: playlistName,
112+
Desc: listDescription,
113+
ID: id,
114+
Public: true,
115+
CreatedAt: time.Unix(now.Unix(), 0), // seconds precision in the db
116+
UpdatedAt: time.Unix(now.Unix(), 0), // seconds precision in the db
117+
}
118+
119+
playlist, err = manager.Get(ctx, id)
120+
assert.NilErr(t, err, "getting a single playlist with description")
121+
assertPlaylist(t, expected, playlist)
101122
}
102123

103124
// TestPlaylistsManagerNotFoundErrors makes sure that the playlists manager returns
@@ -165,7 +186,8 @@ func TestPlaylistsManagerSongOperations(t *testing.T) {
165186
t.Fatalf("not enough tracks found in the library for working with playlists")
166187
}
167188

168-
playlistID, err := manager.Create(ctx, "Testing Playlist", trackIDs)
189+
createArgs := playlists.CreateArgs{Name: "Testing Playlist", Tracks: trackIDs}
190+
playlistID, err := manager.Create(ctx, createArgs)
169191
assert.NilErr(t, err, "failed while creating a playlist with all tracks")
170192

171193
playlist, err := manager.Get(ctx, playlistID)
@@ -268,7 +290,7 @@ func TestPlaylistsManagerErrors(t *testing.T) {
268290
}()
269291
manager := playlists.NewManager(lib.ExecuteDBJobAndWait)
270292

271-
_, err := manager.Create(ctx, "", []int64{})
293+
_, err := manager.Create(ctx, playlists.CreateArgs{})
272294
assert.NotNilErr(t, err,
273295
"creating a playlist with empty name should have been an error",
274296
)

src/playlists/playlistsfakes/fake_playlister.go

Lines changed: 10 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/webserver/handler_playlists.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ func (plh playlistsHandler) ServeHTTP(w http.ResponseWriter, req *http.Request)
3838
}
3939

4040
func (plh playlistsHandler) create(w http.ResponseWriter, req *http.Request) {
41-
listReq := playlistRequest{}
41+
createReq := playlistRequest{}
4242
dec := json.NewDecoder(req.Body)
43-
if err := dec.Decode(&listReq); err != nil {
43+
if err := dec.Decode(&createReq); err != nil {
4444
webutils.JSONError(
4545
w,
4646
fmt.Sprintf("Cannot decode playlist JSON: %s", err),
@@ -49,7 +49,11 @@ func (plh playlistsHandler) create(w http.ResponseWriter, req *http.Request) {
4949
return
5050
}
5151

52-
newID, err := plh.playlists.Create(req.Context(), listReq.Name, listReq.AddTracksByID)
52+
newID, err := plh.playlists.Create(req.Context(), playlists.CreateArgs{
53+
Name: createReq.Name,
54+
Description: createReq.Desc,
55+
Tracks: createReq.AddTracksByID,
56+
})
5357
if err != nil {
5458
webutils.JSONError(
5559
w,

src/webserver/handler_playlists_test.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ func TestPlaylistsCreation(t *testing.T) {
2424
const (
2525
expectedID = 10
2626
expectedName = "new playlist"
27+
expectedDesc = "some description"
2728
)
2829
var expectedTracks = []int64{4, 8}
2930

@@ -36,6 +37,7 @@ func TestPlaylistsCreation(t *testing.T) {
3637

3738
body := bytes.NewBufferString(`{
3839
"name": "new playlist",
40+
"description": "some description",
3941
"add_tracks_by_id": [4, 8]
4042
}`)
4143
req := httptest.NewRequest(http.MethodPost, "/v1/playlists", body)
@@ -47,11 +49,12 @@ func TestPlaylistsCreation(t *testing.T) {
4749
assertJSONContentType(t, result)
4850

4951
assert.Equal(t, 1, fakeplay.CreateCallCount(), "unexpected number of Create calls")
50-
_, actualName, actualTracks := fakeplay.CreateArgsForCall(0)
51-
assert.Equal(t, expectedName, actualName, "wrong name during creation")
52-
assert.Equal(t, len(expectedTracks), len(actualTracks), "wrong number of tracks")
52+
_, actualArgs := fakeplay.CreateArgsForCall(0)
53+
assert.Equal(t, expectedName, actualArgs.Name, "wrong name during creation")
54+
assert.Equal(t, expectedDesc, actualArgs.Description, "wrong description")
55+
assert.Equal(t, len(expectedTracks), len(actualArgs.Tracks), "wrong number of tracks")
5356
for ind, trackID := range expectedTracks {
54-
assert.Equal(t, trackID, actualTracks[ind], "track at index %s mismatch", ind)
57+
assert.Equal(t, trackID, actualArgs.Tracks[ind], "track at index %s mismatch", ind)
5558
}
5659

5760
respJSON := struct {

src/webserver/subsonic/create_playlist.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ func (s *subsonic) createNewPlaylist(w http.ResponseWriter, req *http.Request) {
3131
return
3232
}
3333

34-
id, err := s.playlists.Create(req.Context(), name, trackIDs)
34+
createArgs := playlists.CreateArgs{
35+
Name: name,
36+
Tracks: trackIDs,
37+
}
38+
id, err := s.playlists.Create(req.Context(), createArgs)
3539
if err != nil {
3640
resp := responseError(
3741
errCodeGeneric,

0 commit comments

Comments
 (0)