Skip to content

Commit 9b34f59

Browse files
committed
Dedupe feed items. Add playlist artwork.
Feed endpoint ignores the client limit for now, hardcoded to 40 per request. Currently time span is hardcoded to last 30 days. Client can either specify a time cursor, or we could try to expand the time range based on offset param. There are a few tricky details when expanding the time range with the de-dupe logic... Will have to think about that a bit.
1 parent 8ca53de commit 9b34f59

4 files changed

Lines changed: 39 additions & 34 deletions

File tree

api/dbv1/full_playlists.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ type FullPlaylist struct {
1919
FolloweeReposts []*FolloweeRepost `json:"followee_reposts"`
2020
FolloweeFavorites []*FolloweeFavorite `json:"followee_favorites"`
2121
PlaylistContents []FullPlaylistContentsItem `json:"playlist_contents"`
22+
AddedTimestamps []FullPlaylistContentsItem `json:"added_timestamps"`
2223
}
2324

2425
type FullPlaylistContentsItem struct {
@@ -84,15 +85,16 @@ func (q *Queries) FullPlaylistsKeyed(ctx context.Context, arg GetPlaylistsParams
8485
}
8586

8687
playlistMap[playlist.PlaylistID] = FullPlaylist{
87-
GetPlaylistsRow: playlist,
88-
ID: id,
89-
// Artwork: squareImageStruct(track.CoverArtSizes, track.CoverArt),
88+
GetPlaylistsRow: playlist,
89+
ID: id,
90+
Artwork: squareImageStruct(playlist.Artwork),
9091
User: user,
9192
UserID: user.ID,
9293
Tracks: tracks,
9394
FolloweeFavorites: fullFolloweeFavorites(playlist.FolloweeFavorites),
9495
FolloweeReposts: fullFolloweeReposts(playlist.FolloweeReposts),
9596
PlaylistContents: fullPlaylistContents,
97+
AddedTimestamps: fullPlaylistContents,
9698
}
9799
}
98100

api/dbv1/get_playlists.sql.go

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

api/dbv1/queries/get_playlists.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ SELECT
1212
p.is_stream_gated,
1313
-- is_streamable,
1414

15+
coalesce(playlist_image_sizes_multihash, playlist_image_multihash) as artwork,
16+
1517
p.playlist_name,
1618

1719
p.playlist_id,

api/v1_users_feed.go

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,9 @@ func (app *ApiServer) v1UsersFeed(c *fiber.Ctx) error {
2424
2525
(
2626
SELECT
27-
user_id as actor_id,
28-
'repost' as verb,
29-
repost_type as obj_type,
30-
repost_item_id as obj_id,
31-
reposts.created_at
27+
repost_type as entity_type,
28+
repost_item_id as entity_id,
29+
min(reposts.created_at) as created_at
3230
FROM reposts
3331
JOIN follow_set using (user_id)
3432
LEFT JOIN tracks
@@ -47,16 +45,15 @@ func (app *ApiServer) v1UsersFeed(c *fiber.Ctx) error {
4745
AND reposts.created_at >= @before - INTERVAL '30 DAYS'
4846
AND reposts.is_delete = false
4947
AND (tracks.track_id IS NOT NULL OR playlists.playlist_id IS NOT NULL)
48+
GROUP BY entity_type, entity_id
5049
)
5150
5251
UNION ALL
5352
5453
(
5554
SELECT
56-
user_id as actor_id,
57-
'post' as verb,
58-
'track' as obj_type,
59-
track_id as obj_id,
55+
'track' as entity_type,
56+
track_id as entity_id,
6057
created_at
6158
from tracks
6259
join follow_set on owner_id = user_id
@@ -71,42 +68,44 @@ func (app *ApiServer) v1UsersFeed(c *fiber.Ctx) error {
7168
7269
(
7370
SELECT
74-
user_id as actor_id,
75-
'post' as verb,
76-
'playlist' as obj_type,
77-
playlist_id as obj_id,
71+
'playlist' as entity_type,
72+
playlist_id as entity_id,
7873
created_at
7974
from playlists
8075
join follow_set on playlist_owner_id = user_id
8176
where created_at < @before
82-
and created_at >= @before::timestamp - INTERVAL '30 DAYS'
77+
and created_at >= @before - INTERVAL '30 DAYS'
8378
and is_delete = false
8479
AND is_private = false
8580
)
8681
8782
)
88-
SELECT * FROM history
89-
ORDER BY created_at asc
83+
SELECT
84+
entity_type,
85+
entity_id,
86+
max(created_at) as created_at
87+
FROM history
88+
GROUP BY entity_type, entity_id
89+
ORDER BY created_at DESC
9090
LIMIT @limit
9191
OFFSET @offset
9292
`
9393

9494
rows, err := app.pool.Query(c.Context(), sql, pgx.NamedArgs{
9595
"userId": c.Locals("userId"),
9696
"before": time.Now(),
97-
"limit": c.Query("limit", "50"),
97+
// "limit": c.Query("limit", "50"),
98+
"limit": 40,
9899
"offset": c.Query("offset", "0"),
99100
})
100101
if err != nil {
101102
return err
102103
}
103104

104105
type FeedItem struct {
105-
ActorID int
106-
Verb string
107-
ObjType string `json:"type"`
108-
ObjID int32
109-
CreatedAt time.Time
106+
EntityType string `json:"type"`
107+
EntityId int32 `json:"-"`
108+
CreatedAt time.Time `json:"timestamp"`
110109

111110
Item any `db:"-" json:"item"`
112111
}
@@ -116,17 +115,15 @@ func (app *ApiServer) v1UsersFeed(c *fiber.Ctx) error {
116115
return err
117116
}
118117

119-
// todo: remove duplicates
120-
// something like:
121-
// https://github.com/stereosteve/Elemental/blob/master/server/db/query-feed.ts#L77-L85
118+
// todo: remove loose tracks that appear in playlist?
122119

123120
trackIds := []int32{}
124121
playlistIds := []int32{}
125122
for _, stub := range stubs {
126-
if stub.ObjType == "track" {
127-
trackIds = append(trackIds, stub.ObjID)
123+
if stub.EntityType == "track" {
124+
trackIds = append(trackIds, stub.EntityId)
128125
} else {
129-
playlistIds = append(playlistIds, stub.ObjID)
126+
playlistIds = append(playlistIds, stub.EntityId)
130127
}
131128
}
132129

@@ -140,10 +137,10 @@ func (app *ApiServer) v1UsersFeed(c *fiber.Ctx) error {
140137
}
141138

142139
for idx, stub := range stubs {
143-
if stub.ObjType == "track" {
144-
stub.Item = loaded.TrackMap[stub.ObjID]
140+
if stub.EntityType == "track" {
141+
stub.Item = loaded.TrackMap[stub.EntityId]
145142
} else {
146-
stub.Item = loaded.PlaylistMap[stub.ObjID]
143+
stub.Item = loaded.PlaylistMap[stub.EntityId]
147144
}
148145
stubs[idx] = stub
149146
}

0 commit comments

Comments
 (0)