134 lines
4.2 KiB
Go
134 lines
4.2 KiB
Go
|
|
package main
|
||
|
|
|
||
|
|
import (
|
||
|
|
"database/sql"
|
||
|
|
"fmt"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
// SeededPlaylist holds playlist data.
|
||
|
|
type SeededPlaylist struct {
|
||
|
|
ID string
|
||
|
|
UserID string
|
||
|
|
Name string
|
||
|
|
}
|
||
|
|
|
||
|
|
// SeedPlaylists creates playlists and populates playlist_tracks, playlist_follows.
|
||
|
|
func SeedPlaylists(db *sql.DB, cfg Config, users []SeededUser, tracks []SeededTrack) ([]SeededPlaylist, error) {
|
||
|
|
fmt.Println("\n═══ PLAYLISTS ═══")
|
||
|
|
|
||
|
|
allUsers := users
|
||
|
|
playlists := make([]SeededPlaylist, 0, cfg.Playlists)
|
||
|
|
|
||
|
|
// ── 1. Create playlists ──────────────────────────────────────────────────
|
||
|
|
p := NewProgress("playlists", cfg.Playlists)
|
||
|
|
playlistRows := make([][]interface{}, 0, cfg.Playlists)
|
||
|
|
|
||
|
|
for i := 0; i < cfg.Playlists; i++ {
|
||
|
|
id := newUUID()
|
||
|
|
user := allUsers[rng.Intn(len(allUsers))]
|
||
|
|
name := GenPlaylistName(i)
|
||
|
|
desc := fmt.Sprintf("Curated by %s", user.DisplayName)
|
||
|
|
createdAt := RandomTimeAfter(user.CreatedAt)
|
||
|
|
|
||
|
|
visibility := "public"
|
||
|
|
isPublic := true
|
||
|
|
if randChance(15) {
|
||
|
|
visibility = "private"
|
||
|
|
isPublic = false
|
||
|
|
}
|
||
|
|
isCollab := randChance(10)
|
||
|
|
|
||
|
|
pl := SeededPlaylist{ID: id, UserID: user.ID, Name: name}
|
||
|
|
playlists = append(playlists, pl)
|
||
|
|
|
||
|
|
playlistRows = append(playlistRows, []interface{}{
|
||
|
|
id, user.ID, name, desc, nil, // cover_url
|
||
|
|
visibility, isCollab, 0, 0, 0, // track_count, duration_seconds, follower_count
|
||
|
|
name, isPublic,
|
||
|
|
createdAt, createdAt, nil,
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
_, err := BulkInsert(db, "playlists",
|
||
|
|
"id, user_id, name, description, cover_url, visibility, is_collaborative, track_count, duration_seconds, follower_count, title, is_public, created_at, updated_at, deleted_at",
|
||
|
|
playlistRows)
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("insert playlists: %w", err)
|
||
|
|
}
|
||
|
|
p.Update(cfg.Playlists)
|
||
|
|
p.Done()
|
||
|
|
|
||
|
|
// ── 2. Populate playlist_tracks ──────────────────────────────────────────
|
||
|
|
if len(tracks) == 0 {
|
||
|
|
return playlists, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
p = NewProgress("playlist_tracks", cfg.Playlists)
|
||
|
|
ptRows := make([][]interface{}, 0, cfg.Playlists*15)
|
||
|
|
seen := make(map[string]bool) // prevent duplicate (playlist_id, track_id)
|
||
|
|
|
||
|
|
for _, pl := range playlists {
|
||
|
|
trackCount := randInt(cfg.PlaylistMinTracks, cfg.PlaylistMaxTracks)
|
||
|
|
if trackCount > len(tracks) {
|
||
|
|
trackCount = len(tracks)
|
||
|
|
}
|
||
|
|
selectedTracks := pickN(tracks, trackCount)
|
||
|
|
for pos, t := range selectedTracks {
|
||
|
|
key := pl.ID + ":" + t.ID
|
||
|
|
if seen[key] {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
seen[key] = true
|
||
|
|
ptRows = append(ptRows, []interface{}{
|
||
|
|
newUUID(), pl.ID, t.ID, pos, pl.UserID, time.Now(),
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
_, err = BulkInsert(db, "playlist_tracks",
|
||
|
|
"id, playlist_id, track_id, position, added_by, added_at",
|
||
|
|
ptRows)
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("insert playlist_tracks: %w", err)
|
||
|
|
}
|
||
|
|
p.Update(len(ptRows))
|
||
|
|
p.Done()
|
||
|
|
|
||
|
|
// ── 3. Update track_count on playlists ───────────────────────────────────
|
||
|
|
_, _ = db.Exec("UPDATE playlists SET track_count = (SELECT COUNT(*) FROM playlist_tracks WHERE playlist_tracks.playlist_id = playlists.id)")
|
||
|
|
|
||
|
|
// ── 4. Playlist follows ──────────────────────────────────────────────────
|
||
|
|
followCount := len(playlists) * 3 // ~3 follows per playlist on average
|
||
|
|
p = NewProgress("playlist_follows", followCount)
|
||
|
|
pfRows := make([][]interface{}, 0, followCount)
|
||
|
|
pfSeen := make(map[string]bool)
|
||
|
|
|
||
|
|
for i := 0; i < followCount; i++ {
|
||
|
|
pl := playlists[rng.Intn(len(playlists))]
|
||
|
|
user := allUsers[rng.Intn(len(allUsers))]
|
||
|
|
if user.ID == pl.UserID {
|
||
|
|
continue // Don't follow own playlist
|
||
|
|
}
|
||
|
|
key := pl.ID + ":" + user.ID
|
||
|
|
if pfSeen[key] {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
pfSeen[key] = true
|
||
|
|
pfRows = append(pfRows, []interface{}{
|
||
|
|
newUUID(), pl.ID, user.ID, time.Now(), time.Now(), nil,
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
_, err = BulkInsert(db, "playlist_follows",
|
||
|
|
"id, playlist_id, user_id, created_at, updated_at, deleted_at",
|
||
|
|
pfRows)
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("insert playlist_follows: %w", err)
|
||
|
|
}
|
||
|
|
p.Update(len(pfRows))
|
||
|
|
p.Done()
|
||
|
|
|
||
|
|
return playlists, nil
|
||
|
|
}
|