Files
pipu-music/services/api/internal/wave/friends.go
T
mrleo1nid 11a16cd023
ci / api / api (push) Canceled after 0s
ci / module boundaries / boundaries (push) Canceled after 0s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Canceled after 11m29s
ci / db / db (push) Canceled after 11m22s
ci / mobile / mobile (Metro-бандл Android) (push) Canceled after 6m43s
ci / recommender / recommender (push) Canceled after 6m47s
ci / ts / ts (packages + web) (push) Canceled after 1s
feat(social): add listening activity, shared rooms and modern chat
2026-10-23 10:45:40 +03:00

49 lines
2.0 KiB
Go

package wave
import (
"context"
"github.com/google/uuid"
"github.com/jackc/pgx/v5"
)
// Only currently visible activity is a social signal. A hidden profile never contributes
// its listening history, and self feedback/recent plays retain precedence.
func (h *Handler) friendCandidates(ctx context.Context, user uuid.UUID, exclude []string) ([]string, error) {
rows, e := h.pool.Query(ctx, `SELECT a.track_id::text FROM listening_activity a
JOIN users friend ON friend.id=a.user_id AND NOT friend.is_blocked AND friend.activity_visibility IN ('friends','everyone')
JOIN users own ON own.id=$1 AND own.friends_recommendations
JOIN friendships f ON f.low_id=LEAST($1::uuid,a.user_id) AND f.high_id=GREATEST($1::uuid,a.user_id) AND f.accepted
JOIN tracks t ON t.id=a.track_id JOIN media_files mf ON mf.id=t.primary_file_id AND mf.missing_since IS NULL
JOIN library_sources src ON src.id=mf.source_id AND src.status='mounted'
WHERE a.updated_at>now()-interval '90 seconds' AND NOT(a.track_id::text=ANY($2::text[]))
AND NOT EXISTS(SELECT 1 FROM social_blocks b WHERE (b.user_id=$1 AND b.peer_id=a.user_id) OR (b.user_id=a.user_id AND b.peer_id=$1))
AND NOT EXISTS(SELECT 1 FROM track_reactions r WHERE r.user_id=$1 AND r.track_id=a.track_id AND r.reaction='dislike')
AND NOT EXISTS(SELECT 1 FROM play_events e WHERE e.user_id=$1 AND e.track_id=a.track_id AND e.type='play_start' AND e.occurred_at>now()-interval '3 hours')
GROUP BY a.track_id ORDER BY count(DISTINCT a.user_id) DESC,max(a.updated_at) DESC LIMIT 30`, user, exclude)
if e != nil {
return nil, e
}
defer rows.Close()
return pgx.CollectRows(rows, pgx.RowTo[string])
}
func blendFriendPick(picks []Pick, ids []string) []Pick {
if len(ids) == 0 || len(picks) < 3 {
return picks
}
for _, id := range ids {
exists := false
for _, p := range picks {
if p.ID == id {
exists = true
break
}
}
if !exists {
out := append([]Pick(nil), picks...)
out[len(out)-1] = Pick{ID: id, Source: "friends", Score: 0.1}
return out
}
}
return picks
}