Skip to content

Commit 47852ac

Browse files
authored
Add new collections endpoint (#771)
1 parent b823679 commit 47852ac

File tree

4 files changed

+204
-0
lines changed

4 files changed

+204
-0
lines changed

api/server.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,7 @@ func NewApiServer(config config.Config) *ApiServer {
535535
g.Get("/playlists/unclaimed-id", app.v1PlaylistsUnclaimedId)
536536
g.Get("/playlists/trending", app.v1PlaylistsTrending)
537537
g.Get("/playlists/top", app.v1PlaylistsTop)
538+
g.Get("/playlists/new-releases", app.v1PlaylistsNewReleases)
538539
g.Get("/playlists/by_permalink/:handle/:slug", app.v1PlaylistByPermalink)
539540
g.Get("/playlists/by-permalink/:handle/:slug", app.v1PlaylistByPermalink)
540541

api/swagger/swagger-v1.yaml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1483,6 +1483,51 @@ paths:
14831483
"500":
14841484
description: Server error
14851485
content: {}
1486+
/playlists/new-releases:
1487+
get:
1488+
tags:
1489+
- playlists
1490+
description: Returns recently released playlists or albums
1491+
operationId: Get Playlists New Releases
1492+
security:
1493+
- {}
1494+
- OAuth2:
1495+
- read
1496+
parameters:
1497+
- name: offset
1498+
in: query
1499+
description:
1500+
The number of items to skip. Useful for pagination (page number
1501+
* limit)
1502+
schema:
1503+
type: integer
1504+
- name: limit
1505+
in: query
1506+
description: The number of items to fetch
1507+
schema:
1508+
type: integer
1509+
- name: type
1510+
in: query
1511+
description: The type of content to filter by
1512+
schema:
1513+
type: string
1514+
default: playlist
1515+
enum:
1516+
- playlist
1517+
- album
1518+
responses:
1519+
"200":
1520+
description: Success
1521+
content:
1522+
application/json:
1523+
schema:
1524+
$ref: "#/components/schemas/trending_playlists_response"
1525+
"400":
1526+
description: Bad request
1527+
content: {}
1528+
"500":
1529+
description: Server error
1530+
content: {}
14861531
/playlists/trending:
14871532
get:
14881533
tags:

api/v1_playlists_new_releases.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package api
2+
3+
import (
4+
"api.audius.co/api/dbv1"
5+
"github.com/gofiber/fiber/v2"
6+
"github.com/jackc/pgx/v5"
7+
)
8+
9+
type GetPlaylistsNewReleasesParams struct {
10+
Limit int `query:"limit" default:"10" validate:"min=1,max=100"`
11+
Offset int `query:"offset" default:"0" validate:"min=0"`
12+
Type string `query:"type" default:"playlist" validate:"oneof=playlist album"`
13+
}
14+
15+
func (app *ApiServer) v1PlaylistsNewReleases(c *fiber.Ctx) error {
16+
params := GetPlaylistsNewReleasesParams{}
17+
if err := app.ParseAndValidateQueryParams(c, &params); err != nil {
18+
return err
19+
}
20+
21+
isAlbum := params.Type == "album"
22+
23+
sql := `
24+
SELECT playlist_id
25+
FROM playlists
26+
WHERE is_delete = false
27+
AND is_current = true
28+
AND is_private = false
29+
AND is_album = @is_album
30+
AND COALESCE(release_date, created_at) <= NOW()
31+
AND COALESCE(release_date, created_at) > NOW() - INTERVAL '90 days'
32+
ORDER BY COALESCE(release_date, created_at) DESC, playlist_id DESC
33+
LIMIT @limit
34+
OFFSET @offset
35+
`
36+
37+
rows, err := app.pool.Query(c.Context(), sql, pgx.NamedArgs{
38+
"is_album": isAlbum,
39+
"limit": params.Limit,
40+
"offset": params.Offset,
41+
})
42+
if err != nil {
43+
return err
44+
}
45+
46+
ids, err := pgx.CollectRows(rows, pgx.RowTo[int32])
47+
if err != nil {
48+
return err
49+
}
50+
51+
playlists, err := app.queries.Playlists(c.Context(), dbv1.PlaylistsParams{
52+
GetPlaylistsParams: dbv1.GetPlaylistsParams{
53+
Ids: ids,
54+
MyID: app.getMyId(c),
55+
},
56+
OmitTracks: true,
57+
AuthedWallet: app.tryGetAuthedWallet(c),
58+
})
59+
if err != nil {
60+
return err
61+
}
62+
63+
return v1PlaylistsResponse(c, playlists)
64+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package api
2+
3+
import (
4+
"testing"
5+
"time"
6+
7+
"api.audius.co/api/dbv1"
8+
"api.audius.co/database"
9+
"api.audius.co/trashid"
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func TestGetPlaylistsNewReleases_Albums(t *testing.T) {
14+
app := emptyTestApp(t)
15+
now := time.Now()
16+
fixtures := database.FixtureMap{
17+
"users": {{"user_id": 1, "handle_lc": "one"}},
18+
"playlists": {
19+
// newest album
20+
{
21+
"playlist_id": 1,
22+
"playlist_owner_id": 1,
23+
"is_album": true,
24+
"is_private": false,
25+
"release_date": now.AddDate(0, 0, -1),
26+
"created_at": now.AddDate(0, 0, -1),
27+
"playlist_name": "one",
28+
},
29+
// older album
30+
{
31+
"playlist_id": 2,
32+
"playlist_owner_id": 1,
33+
"is_album": true,
34+
"is_private": false,
35+
"release_date": now.AddDate(0, 0, -10),
36+
"created_at": now.AddDate(0, 0, -10),
37+
"playlist_name": "two",
38+
},
39+
// non-album playlist (excluded when type=album)
40+
{
41+
"playlist_id": 3,
42+
"playlist_owner_id": 1,
43+
"is_album": false,
44+
"is_private": false,
45+
"release_date": now,
46+
"created_at": now,
47+
"playlist_name": "three",
48+
},
49+
// private album (excluded)
50+
{
51+
"playlist_id": 4,
52+
"playlist_owner_id": 1,
53+
"is_album": true,
54+
"is_private": true,
55+
"release_date": now,
56+
"created_at": now,
57+
"playlist_name": "four",
58+
},
59+
// outside of 90-day window (excluded)
60+
{
61+
"playlist_id": 5,
62+
"playlist_owner_id": 1,
63+
"is_album": true,
64+
"is_private": false,
65+
"release_date": now.AddDate(0, 0, -120),
66+
"created_at": now.AddDate(0, 0, -120),
67+
"playlist_name": "five",
68+
},
69+
// future release (excluded until release_date has passed)
70+
{
71+
"playlist_id": 6,
72+
"playlist_owner_id": 1,
73+
"is_album": true,
74+
"is_private": false,
75+
"release_date": now.AddDate(0, 0, 10),
76+
"created_at": now,
77+
"playlist_name": "six",
78+
},
79+
},
80+
}
81+
database.Seed(app.pool.Replicas[0], fixtures)
82+
83+
var resp struct {
84+
Data []dbv1.Playlist
85+
}
86+
87+
status, body := testGet(t, app, "/v1/playlists/new-releases?type=album", &resp)
88+
assert.Equal(t, 200, status)
89+
jsonAssert(t, body, map[string]any{
90+
"data.0.id": trashid.MustEncodeHashID(1),
91+
"data.1.id": trashid.MustEncodeHashID(2),
92+
})
93+
assert.Len(t, resp.Data, 2)
94+
}

0 commit comments

Comments
 (0)