fix: add les 11
This commit is contained in:
258
Les11-AI-SDK/seed-polderfest.ts
Normal file
258
Les11-AI-SDK/seed-polderfest.ts
Normal file
@@ -0,0 +1,258 @@
|
||||
/**
|
||||
* Polderfest 2027 — seed script
|
||||
* ----------------------------------------------------------
|
||||
* Genereert 500 fictieve bands en zet ze in je Supabase `bands` tabel.
|
||||
* Run:
|
||||
* 1. Zorg dat `bands` tabel bestaat (zie schema.sql)
|
||||
* 2. Vul .env.local met:
|
||||
* SUPABASE_URL=https://<project>.supabase.co
|
||||
* SUPABASE_SERVICE_ROLE_KEY=<service role key>
|
||||
* 3. npm i @supabase/supabase-js dotenv tsx --save-dev
|
||||
* 4. npx tsx seed-polderfest.ts
|
||||
*
|
||||
* Service role key is bewust nodig — alleen voor lokaal seeden.
|
||||
* NIET committen, NIET in client gebruiken.
|
||||
*/
|
||||
|
||||
import { createClient } from "@supabase/supabase-js";
|
||||
import "dotenv/config";
|
||||
|
||||
const supabase = createClient(
|
||||
process.env.SUPABASE_URL!,
|
||||
process.env.SUPABASE_SERVICE_ROLE_KEY!,
|
||||
{ auth: { persistSession: false } }
|
||||
);
|
||||
|
||||
// ────────────────────────────────────────────────────────────
|
||||
// Deterministische random (zodat seed reproduceerbaar is)
|
||||
// ────────────────────────────────────────────────────────────
|
||||
let seed = 42;
|
||||
function rand() {
|
||||
seed = (seed * 9301 + 49297) % 233280;
|
||||
return seed / 233280;
|
||||
}
|
||||
function pick<T>(arr: readonly T[]): T {
|
||||
return arr[Math.floor(rand() * arr.length)];
|
||||
}
|
||||
function pickN<T>(arr: readonly T[], n: number): T[] {
|
||||
const copy = [...arr];
|
||||
const out: T[] = [];
|
||||
for (let i = 0; i < n && copy.length; i++) {
|
||||
out.push(copy.splice(Math.floor(rand() * copy.length), 1)[0]);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
function range(min: number, max: number): number {
|
||||
return Math.floor(rand() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
// ────────────────────────────────────────────────────────────
|
||||
// Bouwstenen voor band-namen
|
||||
// ────────────────────────────────────────────────────────────
|
||||
const adjectives = [
|
||||
"Lost", "Velvet", "Iron", "Neon", "Silent", "Wild", "Glass", "Paper", "Sleeping",
|
||||
"Honest", "Crooked", "Bitter", "Sweet", "Drowsy", "Drowning", "Restless", "Sober",
|
||||
"Midnight", "Morning", "Yellow", "Crimson", "Hollow", "Heavy", "Floating", "Slow",
|
||||
"Burning", "Frozen", "Cardboard", "Plastic", "Analog", "Digital", "Forgotten",
|
||||
] as const;
|
||||
|
||||
const nouns = [
|
||||
"Tigers", "Wolves", "Horses", "Rabbits", "Mirrors", "Clouds", "Echoes", "Ghosts",
|
||||
"Lights", "Roots", "Stones", "Foxes", "Riders", "Ships", "Tides", "Anchors",
|
||||
"Maps", "Letters", "Postcards", "Radios", "Telegrams", "Diaries", "Highways",
|
||||
"Cassettes", "Polaroids", "Cathedrals", "Stations", "Lanterns", "Compasses",
|
||||
"Saturdays", "Tuesdays", "Mondays",
|
||||
] as const;
|
||||
|
||||
const dutchPrefixes = [
|
||||
"De", "Het", "Van der", "Polder", "Noord", "Zuid",
|
||||
] as const;
|
||||
|
||||
const soloNamesFirst = [
|
||||
"Sanne", "Joost", "Yara", "Lex", "Mila", "Tess", "Bram", "Lotte", "Ravi", "Imani",
|
||||
"Marit", "Stijn", "Liva", "Noor", "Casper", "Anouk", "Mees", "Pien", "Daan", "Olivia",
|
||||
"Niels", "Fenna", "Tygo", "Saar", "Cas", "Maud", "Roos", "Vince", "Lieke", "Floris",
|
||||
] as const;
|
||||
|
||||
const soloNamesLast = [
|
||||
"Van Dijk", "De Boer", "Visser", "Jansen", "Bakker", "Hendriks", "Mulder", "Smit",
|
||||
"Peters", "De Vries", "Kuipers", "Brouwer", "Postma", "Hofman", "Van Loon",
|
||||
] as const;
|
||||
|
||||
// ────────────────────────────────────────────────────────────
|
||||
// Fest-velden
|
||||
// ────────────────────────────────────────────────────────────
|
||||
const genres = [
|
||||
"Indie Rock", "Electronic", "Hip-Hop", "Jazz Fusion", "Folk", "Punk", "Soul",
|
||||
"Ambient", "Disco-House", "Experimental", "Singer-Songwriter", "Synth-Pop",
|
||||
"Garage Rock", "Neo-Soul", "Drum & Bass", "Afrobeat", "Dream Pop", "Post-Rock",
|
||||
] as const;
|
||||
|
||||
const subGenresByGenre: Record<string, string[]> = {
|
||||
"Indie Rock": ["Shoegaze", "Lo-Fi", "Math Rock", "Slowcore"],
|
||||
"Electronic": ["Techno", "House", "IDM", "Glitch", "Trance"],
|
||||
"Hip-Hop": ["Boom Bap", "Trap", "Lo-Fi", "Conscious"],
|
||||
"Jazz Fusion": ["Funk Jazz", "Cosmic Jazz", "Nu-Jazz"],
|
||||
"Folk": ["Anti-Folk", "Sea Shanty", "Modern Folk"],
|
||||
"Punk": ["Post-Punk", "Hardcore", "Surf Punk"],
|
||||
"Soul": ["Neo-Soul", "Northern Soul", "Funk"],
|
||||
"Ambient": ["Drone", "New Age", "Field Recording"],
|
||||
"Disco-House": ["Italo Disco", "Nu-Disco", "French House"],
|
||||
"Experimental": ["Noise", "Sound Art", "Avantgarde"],
|
||||
"Singer-Songwriter": ["Confessional", "Storytelling"],
|
||||
"Synth-Pop": ["Vaporwave", "Italo", "Darkwave"],
|
||||
"Garage Rock": ["Surf", "Power Pop"],
|
||||
"Neo-Soul": ["Alt R&B", "Jazz-influenced"],
|
||||
"Drum & Bass": ["Liquid", "Jungle", "Neurofunk"],
|
||||
"Afrobeat": ["Afro-Fusion", "Highlife"],
|
||||
"Dream Pop": ["Bedroom Pop", "Ethereal"],
|
||||
"Post-Rock": ["Cinematic", "Math-influenced"],
|
||||
};
|
||||
|
||||
const stages = [
|
||||
"Main Stage", "Tent Stage", "Beach Stage", "Acoustic Bar", "Late Night Tent",
|
||||
] as const;
|
||||
|
||||
const days = ["Vrijdag", "Zaterdag", "Zondag"] as const;
|
||||
|
||||
const timeSlots = [
|
||||
"14:00", "15:30", "17:00", "18:30", "20:00", "21:30", "23:00", "00:30",
|
||||
] as const;
|
||||
|
||||
const cities = [
|
||||
"Amsterdam", "Rotterdam", "Utrecht", "Groningen", "Eindhoven", "Den Haag",
|
||||
"Tilburg", "Maastricht", "Nijmegen", "Leeuwarden", "Arnhem", "Breda", "Haarlem",
|
||||
"Zwolle", "Enschede", "Delft", "Den Bosch", "Apeldoorn",
|
||||
] as const;
|
||||
|
||||
const tiers = ["headliner", "mid", "opener"] as const;
|
||||
|
||||
// ────────────────────────────────────────────────────────────
|
||||
// Bio-fragmenten — combinatorisch zodat 500 bios uniek voelen
|
||||
// ────────────────────────────────────────────────────────────
|
||||
const bioOpenings = [
|
||||
"Begonnen in een garage in",
|
||||
"Ontstaan tijdens een blackout in",
|
||||
"Een vriendengroep uit",
|
||||
"Doorgebroken op het kleine podium van",
|
||||
"Geboren uit een jam-sessie in",
|
||||
"Een collectief van producers uit",
|
||||
];
|
||||
const bioMiddle = [
|
||||
"experimenteert met analoge synths en gefluisterde lyrics",
|
||||
"balanceert tussen melancholie en dansvloer-euforie",
|
||||
"mixt traditionele samples met breakbeats",
|
||||
"gebruikt veldopnames als ritmesectie",
|
||||
"schrijft songs in Nederlands en Engels door elkaar",
|
||||
"speelt instrumenten die ze grotendeels zelf hebben gebouwd",
|
||||
"draait alleen optredens op locaties zonder Wi-Fi",
|
||||
];
|
||||
const bioEnding = [
|
||||
"Debuut-EP verschijnt eind 2027.",
|
||||
"Hun laatste album werd genomineerd voor de fictieve Edison Polder Award.",
|
||||
"Polderfest is hun grootste festival tot nu toe.",
|
||||
"Vorig jaar speelden ze nog in cafés, dit jaar op Stage B.",
|
||||
"Spelen voor het eerst op een buitenpodium.",
|
||||
"Beruchte live-show met 12 backing vocalists.",
|
||||
];
|
||||
|
||||
// ────────────────────────────────────────────────────────────
|
||||
// Namen genereren
|
||||
// ────────────────────────────────────────────────────────────
|
||||
function generateBandName(seedIdx: number): string {
|
||||
const pattern = seedIdx % 4;
|
||||
if (pattern === 0) {
|
||||
return `${pick(adjectives)} ${pick(nouns)}`;
|
||||
}
|
||||
if (pattern === 1) {
|
||||
return `${pick(dutchPrefixes)} ${pick(nouns)}`;
|
||||
}
|
||||
if (pattern === 2) {
|
||||
return `${pick(soloNamesFirst)} ${pick(soloNamesLast)}`;
|
||||
}
|
||||
return `${pick(soloNamesFirst)} & The ${pick(nouns)}`;
|
||||
}
|
||||
|
||||
function generateMembers(): string[] {
|
||||
const count = range(1, 5);
|
||||
const out: string[] = [];
|
||||
for (let i = 0; i < count; i++) {
|
||||
out.push(`${pick(soloNamesFirst)} ${pick(soloNamesLast)}`);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function generateBio(name: string): string {
|
||||
return `${pick(bioOpenings)} ${pick(cities)}, ${name} ${pick(bioMiddle)}. ${pick(bioEnding)}`;
|
||||
}
|
||||
|
||||
// ────────────────────────────────────────────────────────────
|
||||
// Hoofdfunctie
|
||||
// ────────────────────────────────────────────────────────────
|
||||
async function seed() {
|
||||
console.log("Genereren van 500 Polderfest bands...");
|
||||
|
||||
// Wipe bestaande data (optioneel)
|
||||
await supabase.from("bands").delete().neq("id", 0);
|
||||
|
||||
const bands = [];
|
||||
const usedNames = new Set<string>();
|
||||
|
||||
for (let i = 0; i < 500; i++) {
|
||||
let name = generateBandName(i);
|
||||
let attempts = 0;
|
||||
while (usedNames.has(name) && attempts < 10) {
|
||||
name = generateBandName(i + attempts * 7);
|
||||
attempts++;
|
||||
}
|
||||
usedNames.add(name);
|
||||
|
||||
const genre = pick(genres);
|
||||
const sub_genre = pick(subGenresByGenre[genre]);
|
||||
const tier = pick(tiers);
|
||||
const popularity = tier === "headliner" ? range(80, 100)
|
||||
: tier === "mid" ? range(40, 79)
|
||||
: range(10, 39);
|
||||
const ticket_impact = tier === "headliner" ? range(25, 60)
|
||||
: tier === "mid" ? range(5, 25)
|
||||
: 0;
|
||||
|
||||
bands.push({
|
||||
name,
|
||||
genre,
|
||||
sub_genre,
|
||||
stage: pick(stages),
|
||||
day: pick(days),
|
||||
start_time: pick(timeSlots),
|
||||
duration_min: tier === "headliner" ? range(75, 120)
|
||||
: tier === "mid" ? range(45, 75)
|
||||
: range(30, 45),
|
||||
origin_city: pick(cities),
|
||||
members: generateMembers(),
|
||||
bio: generateBio(name),
|
||||
tier,
|
||||
popularity,
|
||||
ticket_impact,
|
||||
});
|
||||
}
|
||||
|
||||
console.log("Schrijven naar Supabase in batches van 100...");
|
||||
|
||||
// Supabase insert in batches (single call van 500 kan timeouten)
|
||||
for (let i = 0; i < bands.length; i += 100) {
|
||||
const batch = bands.slice(i, i + 100);
|
||||
const { error } = await supabase.from("bands").insert(batch);
|
||||
if (error) {
|
||||
console.error("Insert error op batch", i / 100, ":", error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
console.log(` ✓ ${i + batch.length}/${bands.length}`);
|
||||
}
|
||||
|
||||
console.log("Klaar! 500 Polderfest bands staan in Supabase.");
|
||||
}
|
||||
|
||||
seed().catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user