package main import ( "database/sql" "fmt" "time" ) // SeedContent creates files, user_storage_quotas, courses, lessons, gear_items, groups. func SeedContent(db *sql.DB, cfg Config, users []SeededUser, tracks []SeededTrack) error { fmt.Println("\n═══ CONTENT ═══") artists := GetArtists(users) // ── 1. Files (simulated entries for tracks and avatars) ────────────────── p := NewProgress("files", cfg.FileEntries) fileRows := make([][]interface{}, 0, cfg.FileEntries) // Audio files for tracks for i, t := range tracks { if i >= cfg.FileEntries*2/3 { break } fileSize := int64(t.Duration) * int64(randInt(16000, 32000)) storagePath := fmt.Sprintf("audio/%s.mp3", t.ID) url := fmt.Sprintf("https://cdn.veza.music/%s", storagePath) fileRows = append(fileRows, []interface{}{ newUUID(), t.CreatorID, fmt.Sprintf("%s.mp3", t.ID), fmt.Sprintf("%s.mp3", t.Title), "audio/mpeg", fileSize, storagePath, "s3", "veza-audio", url, nil, // thumbnail_url fmt.Sprintf("%x", rng.Int63()), nil, // file_hash, metadata true, time.Now(), nil, // is_processed, processed_at, processing_error true, "clean", time.Now(), // virus_scanned, virus_scan_result, virus_scanned_at false, // is_public time.Now(), time.Now(), nil, }) } // Avatar files for users avatarCount := cfg.FileEntries / 3 for i := 0; i < avatarCount && i < len(users); i++ { u := users[i] fileSize := int64(randInt(50000, 500000)) // 50KB - 500KB storagePath := fmt.Sprintf("avatars/%s.jpg", u.ID) url := fmt.Sprintf("https://cdn.veza.music/%s", storagePath) fileRows = append(fileRows, []interface{}{ newUUID(), u.ID, fmt.Sprintf("%s.jpg", u.ID), "avatar.jpg", "image/jpeg", fileSize, storagePath, "s3", "veza-avatars", url, nil, fmt.Sprintf("%x", rng.Int63()), nil, true, time.Now(), nil, true, "clean", time.Now(), true, u.CreatedAt, u.CreatedAt, nil, }) } _, err := BulkInsert(db, "files", "id, user_id, filename, original_filename, mime_type, file_size, storage_path, storage_provider, bucket_name, url, thumbnail_url, file_hash, metadata, is_processed, processed_at, processing_error, virus_scanned, virus_scan_result, virus_scanned_at, is_public, created_at, updated_at, deleted_at", fileRows) if err != nil { return fmt.Errorf("insert files: %w", err) } p.Update(len(fileRows)) p.Done() // ── 2. User storage quotas ─────────────────────────────────────────────── p = NewProgress("user_storage_quotas", len(artists)) quotaRows := make([][]interface{}, 0, len(artists)) for _, a := range artists { usedBytes := int64(randInt(100, 5000)) * 1024 * 1024 // 100MB - 5GB maxBytes := int64(10) * 1024 * 1024 * 1024 // 10GB quotaRows = append(quotaRows, []interface{}{ newUUID(), a.ID, usedBytes, maxBytes, time.Now(), time.Now(), }) } _, _ = BulkInsert(db, "user_storage_quotas", "id, user_id, used_bytes, max_bytes, created_at, updated_at", quotaRows) p.Update(len(quotaRows)) p.Done() // ── 3. Courses & Lessons ───────────────────────────────────────────────── p = NewProgress("courses", cfg.Courses) courseRows := make([][]interface{}, 0, cfg.Courses) type courseInfo struct { id string lessonCount int } courses := make([]courseInfo, 0, cfg.Courses) courseCategories := []string{"production", "mixing", "sound-design", "songwriting", "djing", "mastering"} levels := []string{"beginner", "intermediate", "advanced"} lessonTitles := []string{ "Getting Started", "Setting Up Your DAW", "Understanding Audio Basics", "Your First Beat", "Melody and Harmony", "Sound Design Fundamentals", "Arrangement Techniques", "Mixing Basics", "EQ and Compression", "Effects and Processing", "Mastering Your Track", "Final Project", "Advanced Techniques", "Creative Workflows", "Industry Standards", } for i := 0; i < cfg.Courses && i < len(artists); i++ { id := newUUID() artist := artists[i%len(artists)] title := fmt.Sprintf("%s Masterclass — %s", GenreForArtist(i)[0].Name, pick([]string{"From Zero to Pro", "Complete Guide", "Deep Dive", "Essentials", "Workshop"})) slug := fmt.Sprintf("course-%d", i) category := pick(courseCategories) level := pick(levels) price := randInt(0, 9999) // 0 = free lessonCount := randInt(5, 15) createdAt := RandomTimeAfter(artist.CreatedAt) var publishedAt interface{} = createdAt status := "published" if randChance(10) { status = "draft" publishedAt = nil } c := courseInfo{id: id, lessonCount: lessonCount} courses = append(courses, c) courseRows = append(courseRows, []interface{}{ id, artist.ID, title, slug, fmt.Sprintf("Learn %s with %s. Comprehensive course covering everything from basics to advanced techniques.", category, artist.DisplayName), category, fmt.Sprintf("{music,production,%s}", category), price, "EUR", "fixed", status, level, "fr", lessonCount, publishedAt, createdAt, createdAt, }) } _, err = BulkInsert(db, "courses", "id, creator_id, title, slug, description, category, tags, price_cents, currency, pricing_model, status, level, language, lesson_count, published_at, created_at, updated_at", courseRows) if err != nil { return fmt.Errorf("insert courses: %w", err) } p.Update(len(courseRows)) p.Done() // Lessons totalLessons := 0 for _, c := range courses { totalLessons += c.lessonCount } p = NewProgress("lessons", totalLessons) lessonRows := make([][]interface{}, 0, totalLessons) for _, c := range courses { for li := 0; li < c.lessonCount; li++ { title := lessonTitles[li%len(lessonTitles)] lessonRows = append(lessonRows, []interface{}{ newUUID(), c.id, li, title, fmt.Sprintf("Lesson %d: %s", li+1, title), randInt(300, 1800), // duration 5-30min li < 2, // first 2 lessons free preview "completed", }) } } _, _ = BulkInsert(db, "lessons", "id, course_id, order_index, title, description, duration_seconds, is_preview_free, transcoding_status", lessonRows) p.Update(totalLessons) p.Done() // Course enrollments enrollCount := cfg.Courses * 5 p = NewProgress("course_enrollments", enrollCount) enrollRows := make([][]interface{}, 0, enrollCount) enrollSeen := make(map[string]bool) for i := 0; i < enrollCount*2 && len(enrollRows) < enrollCount; i++ { c := courses[rng.Intn(len(courses))] u := users[rng.Intn(len(users))] key := c.id + ":" + u.ID if enrollSeen[key] { continue } enrollSeen[key] = true enrollRows = append(enrollRows, []interface{}{ newUUID(), u.ID, c.id, "active", time.Now(), }) } _, _ = BulkInsert(db, "course_enrollments", "id, user_id, course_id, status, purchased_at", enrollRows) p.Update(len(enrollRows)) p.Done() // ── 4. Gear items ──────────────────────────────────────────────────────── p = NewProgress("gear_items", cfg.GearItems) gearRows := make([][]interface{}, 0, cfg.GearItems) conditions := []string{"Excellent", "Good", "Fair"} for i := 0; i < cfg.GearItems; i++ { artist := artists[rng.Intn(len(artists))] gear := pick(gearTemplates) purchaseDate := RandomTimeAfter(artist.CreatedAt).Format("2006-01-02") gearRows = append(gearRows, []interface{}{ newUUID(), artist.ID, gear.Name, gear.Category, gear.Brand, gear.Model, "Active", pick(conditions), gear.Price, "EUR", purchaseDate, true, time.Now(), time.Now(), }) } _, _ = BulkInsert(db, "gear_items", "id, user_id, name, category, brand, model, status, condition, purchase_price, currency, purchase_date, is_public, created_at, updated_at", gearRows) p.Update(cfg.GearItems) p.Done() // ── 5. Groups ──────────────────────────────────────────────────────────── p = NewProgress("groups", cfg.Groups) groupRows := make([][]interface{}, 0, cfg.Groups) type groupInfo struct { id string creatorID string } groups := make([]groupInfo, 0, cfg.Groups) groupNames := []string{ "Electronic Producers", "Hip-Hop Collective", "Ambient Sound Lab", "Jazz Fusion Circle", "Indie Artists Network", "Vinyl Enthusiasts", "Sound Design Guild", "Remix Community", "Songwriters Hub", "Studio Gear Talk", "Music Theory Nerds", "Live Performance Group", "Lo-Fi Producers", "Techno Underground", "Acoustic Sessions", } for i := 0; i < cfg.Groups; i++ { id := newUUID() creator := users[rng.Intn(len(users))] name := groupNames[i%len(groupNames)] if i >= len(groupNames) { name = fmt.Sprintf("%s #%d", pick(groupNames), i) } createdAt := RandomTimeAfter(creator.CreatedAt) g := groupInfo{id: id, creatorID: creator.ID} groups = append(groups, g) groupRows = append(groupRows, []interface{}{ id, name, fmt.Sprintf("A community for %s enthusiasts", name), creator.ID, nil, true, 1, createdAt, createdAt, nil, }) } _, _ = BulkInsert(db, "groups", "id, name, description, creator_id, avatar_url, is_public, member_count, created_at, updated_at, deleted_at", groupRows) p.Update(cfg.Groups) p.Done() // Group members memberCount := cfg.Groups * 15 p = NewProgress("group_members", memberCount) gmRows := make([][]interface{}, 0, memberCount) gmSeen := make(map[string]bool) for _, g := range groups { // Add creator key := g.id + ":" + g.creatorID gmSeen[key] = true gmRows = append(gmRows, []interface{}{ newUUID(), g.id, g.creatorID, "admin", time.Now(), time.Now(), }) // Add random members count := randInt(5, 30) for j := 0; j < count; j++ { u := users[rng.Intn(len(users))] key = g.id + ":" + u.ID if gmSeen[key] { continue } gmSeen[key] = true gmRows = append(gmRows, []interface{}{ newUUID(), g.id, u.ID, "member", time.Now(), time.Now(), }) } } _, _ = BulkInsert(db, "group_members", "id, group_id, user_id, role, joined_at, created_at", gmRows) // Update member counts _, _ = db.Exec("UPDATE groups SET member_count = (SELECT COUNT(*) FROM group_members WHERE group_members.group_id = groups.id)") p.Update(len(gmRows)) p.Done() return nil }