Files
RandomVideoMaker/src/generate_pinterest_keywords.ts
2025-09-22 17:11:25 +02:00

705 lines
33 KiB
TypeScript

import puppeteer from 'puppeteer';
import type { Page } from 'puppeteer';
import dotenv from 'dotenv';
import * as fs from 'fs/promises';
import path from 'path';
import { spawn } from 'child_process';
dotenv.config();
/**
* Script: generate_pinterest_keywords.ts
*
* For each genre/subgenre pair (provided below) this script:
* - searches Pinterest for "genre subgenre"
* - scrolls the results page several times
* - collects up to 20 unique pin IDs from the page
* - outputs a JSON array to the console:
* [{ genre: "...", subGenre: "...", pinIds: ["id1","id2", ...] }, ...]
*
* Usage:
* - npx ts-node src/generate_pinterest_keywords.ts
* - or compile with tsc and run with node
*
* Notes:
* - Puppeteer will run headless by default. If you need to debug visually set headless: false.
* - Adjust SCROLL_ITERATIONS and MAX_PIN_IDS_PER_TERM if you want different behavior.
*/
const SCROLL_ITERATIONS = 8; // number of times to scroll (adjust if you want more)
const MAX_PIN_IDS_PER_TERM = 20; // target number of pin ids per genre/subgenre
const SCROLL_DELAY_MS = 900; // delay between scrolls
const searchList: { genre: string; subGenre: string }[] = [
/* { genre: "abstract", subGenre: "3D Renderings" },
{ genre: "abstract", subGenre: "Abstract Portraits" },
{ genre: "abstract", subGenre: "Collage" },
{ genre: "abstract", subGenre: "Color Explosions" },
{ genre: "abstract", subGenre: "cubic" },
{ genre: "abstract", subGenre: "Cubism" },
{ genre: "abstract", subGenre: "Digital Glitch" },
{ genre: "abstract", subGenre: "Fluid Paints" },
{ genre: "abstract", subGenre: "Fractals" },
{ genre: "abstract", subGenre: "Geometric Shapes" },
{ genre: "abstract", subGenre: "Graffiti" },
{ genre: "abstract", subGenre: "Impressionism" },
{ genre: "abstract", subGenre: "Kaleidoscopes" },
{ genre: "abstract", subGenre: "Light Art" },
{ genre: "abstract", subGenre: "Mandalas" },
{ genre: "abstract", subGenre: "Minimalism" },
{ genre: "abstract", subGenre: "Optical Illusions" },
{ genre: "abstract", subGenre: "particle" },
{ genre: "abstract", subGenre: "Pop Art" },
{ genre: "abstract", subGenre: "science" },
{ genre: "abstract", subGenre: "space" },
{ genre: "abstract", subGenre: "sphere" },
{ genre: "abstract", subGenre: "Street Art" },
{ genre: "abstract", subGenre: "Surrealism" },
{ genre: "abstract", subGenre: "Typography Art" },
{ genre: "abstruct", subGenre: "art" },
{ genre: "abstruct", subGenre: "colors" },
{ genre: "abstruct", subGenre: "particle" },
{ genre: "animals", subGenre: "Bats" },
{ genre: "animals", subGenre: "Bears" },
{ genre: "animals", subGenre: "Butterflies" },
{ genre: "animals", subGenre: "Camels" },
{ genre: "animals", subGenre: "Crocodiles" },
{ genre: "animals", subGenre: "Dolphins" },
{ genre: "animals", subGenre: "Eagles" },
{ genre: "animals", subGenre: "Elephants" },
{ genre: "animals", subGenre: "Foxes" },
{ genre: "animals", subGenre: "Giraffes" },
{ genre: "animals", subGenre: "Horses" },
{ genre: "animals", subGenre: "Lions" },
{ genre: "animals", subGenre: "Owls" },
{ genre: "animals", subGenre: "Pandas" },
{ genre: "animals", subGenre: "Penguins" },
{ genre: "animals", subGenre: "Seals" },
{ genre: "animals", subGenre: "Sharks" },
{ genre: "animals", subGenre: "Tigers" },
{ genre: "animals", subGenre: "Whales" },
{ genre: "animals", subGenre: "Wolves" },
{ genre: "architecture", subGenre: "luxury room" },
{ genre: "childhood", subGenre: "Adoption" },
{ genre: "childhood", subGenre: "Babies" },
{ genre: "childhood", subGenre: "Bedtime Stories" },
{ genre: "childhood", subGenre: "Birthday Parties" },
{ genre: "childhood", subGenre: "Children Playing" },
{ genre: "childhood", subGenre: "Family Dinners" },
{ genre: "childhood", subGenre: "Family Portraits" },
{ genre: "childhood", subGenre: "Graduations" },
{ genre: "childhood", subGenre: "Grandparents" },
{ genre: "childhood", subGenre: "Holiday Celebrations" },
{ genre: "childhood", subGenre: "Learning to Walk" },
{ genre: "childhood", subGenre: "Nursery" },
{ genre: "childhood", subGenre: "Parent-Teacher Meetings" },
{ genre: "childhood", subGenre: "Picnics" },
{ genre: "childhood", subGenre: "Pregnancy" },
{ genre: "childhood", subGenre: "School Activities" },
{ genre: "childhood", subGenre: "Siblings" },
{ genre: "childhood", subGenre: "Sports with Kids" },
{ genre: "childhood", subGenre: "Toys" },
{ genre: "childhood", subGenre: "Vacations" },
{ genre: "cinematic", subGenre: "Action Movies" },
{ genre: "cinematic", subGenre: "Animations" },
{ genre: "cinematic", subGenre: "Documentaries" },
{ genre: "cinematic", subGenre: "Experimental Cinema" },
{ genre: "cinematic", subGenre: "Fantasy Epics" },
{ genre: "cinematic", subGenre: "Historical Dramas" },
{ genre: "cinematic", subGenre: "Hollywood Blockbusters" },
{ genre: "cinematic", subGenre: "Horror Films" },
{ genre: "cinematic", subGenre: "Indie Films" },
{ genre: "cinematic", subGenre: "Mockumentaries" },
{ genre: "cinematic", subGenre: "Musicals" },
{ genre: "cinematic", subGenre: "Nature Documentaries" },
{ genre: "cinematic", subGenre: "Noir" },
{ genre: "cinematic", subGenre: "Romantic Comedies" },
{ genre: "cinematic", subGenre: "Sci-Fi Thrillers" },
{ genre: "cinematic", subGenre: "Short Films" },
{ genre: "cinematic", subGenre: "Silent Films" },
{ genre: "cinematic", subGenre: "Stop Motion" },
{ genre: "cinematic", subGenre: "Superhero Films" },
{ genre: "cinematic", subGenre: "Westerns" },
{ genre: "city", subGenre: "Bridges" },
{ genre: "city", subGenre: "Castles" },
{ genre: "city", subGenre: "Cathedrals" },
{ genre: "city", subGenre: "Factories" },
{ genre: "city", subGenre: "Futuristic Cities" },
{ genre: "city", subGenre: "Historic Towns" },
{ genre: "city", subGenre: "Libraries" },
{ genre: "city", subGenre: "Markets" },
{ genre: "city", subGenre: "Modern Plazas" },
{ genre: "city", subGenre: "Museums" },
{ genre: "city", subGenre: "Palaces" },
{ genre: "city", subGenre: "Residential Blocks" },
{ genre: "city", subGenre: "Skylines" },
{ genre: "city", subGenre: "Skyscrapers" },
{ genre: "city", subGenre: "Slums" },
{ genre: "city", subGenre: "Stadiums" },
{ genre: "city", subGenre: "Street Cafes" },
{ genre: "city", subGenre: "Urban Parks" },
{ genre: "fantasy", subGenre: "academia" },
{ genre: "fantasy", subGenre: "aesthetic" },
{ genre: "fantasy", subGenre: "art" },
{ genre: "fantasy", subGenre: "Crystal Caves" },
{ genre: "fantasy", subGenre: "Dark Castles" },
{ genre: "fantasy", subGenre: "dark ethereal" },
{ genre: "fantasy", subGenre: "darkacademia" },
{ genre: "fantasy", subGenre: "ddreamy room" },
{ genre: "fantasy", subGenre: "Dragon Realms" },
{ genre: "fantasy", subGenre: "dreamy room" },
{ genre: "fantasy", subGenre: "Elven Cities" },
{ genre: "fantasy", subGenre: "Enchanted Rivers" },
{ genre: "fantasy", subGenre: "Epic Battles" },
{ genre: "fantasy", subGenre: "ethereal" },
{ genre: "fantasy", subGenre: "Fairy Villages" },
{ genre: "fantasy", subGenre: "Floating Islands" },
{ genre: "fantasy", subGenre: "Ghostly Spirits" },
{ genre: "fantasy", subGenre: "illumication" },
{ genre: "fantasy", subGenre: "Knights" },
{ genre: "fantasy", subGenre: "landscape" },
{ genre: "fantasy", subGenre: "Magic Forests" },
{ genre: "fantasy", subGenre: "Magical Beasts" },
{ genre: "fantasy", subGenre: "Mystic Portals" },
{ genre: "fantasy", subGenre: "Mythical Weapons" },
{ genre: "fantasy", subGenre: "Queens and Kings" },
{ genre: "fantasy", subGenre: "Runes and Symbols" },
{ genre: "fantasy", subGenre: "Sacred Temples" },
{ genre: "fantasy", subGenre: "Shape-shifters" },
{ genre: "fantasy", subGenre: "Talking Animals" },
{ genre: "fantasy", subGenre: "Wizards" },
{ genre: "fashion", subGenre: "Accessories" },
{ genre: "fashion", subGenre: "Boho Style" },
{ genre: "fashion", subGenre: "Bridal Wear" },
{ genre: "fashion", subGenre: "Business Suits" },
{ genre: "fashion", subGenre: "Casual Wear" },
{ genre: "fashion", subGenre: "Cocktail Dresses" },
{ genre: "fashion", subGenre: "Cosplay" },
{ genre: "fashion", subGenre: "Evening Gowns" },
{ genre: "fashion", subGenre: "Hair Styling" },
{ genre: "fashion", subGenre: "Haute Couture" },
{ genre: "fashion", subGenre: "Makeup Styles" },
{ genre: "fashion", subGenre: "Pajamas" },
{ genre: "fashion", subGenre: "Runway Shows" },
{ genre: "fashion", subGenre: "School Uniforms" },
{ genre: "fashion", subGenre: "Shoes" },
{ genre: "fashion", subGenre: "Sportswear" },
{ genre: "fashion", subGenre: "Streetwear" },
{ genre: "fashion", subGenre: "Swimwear" },
{ genre: "fashion", subGenre: "Traditional Costumes" },
{ genre: "fashion", subGenre: "Vintage Outfits" },
{ genre: "food", subGenre: "Bakeries" },
{ genre: "food", subGenre: "BBQ" },
{ genre: "food", subGenre: "Breakfasts" },
{ genre: "food", subGenre: "Chocolate Making" },
{ genre: "food", subGenre: "Cocktails" },
{ genre: "food", subGenre: "Coffee Culture" },
{ genre: "food", subGenre: "Desserts" },
{ genre: "food", subGenre: "Farmers Market" },
{ genre: "food", subGenre: "Fine Dining" },
{ genre: "food", subGenre: "Food Trucks" },
{ genre: "food", subGenre: "Fruit Platters" },
{ genre: "food", subGenre: "Pasta Dishes" },
{ genre: "food", subGenre: "Pizza" },
{ genre: "food", subGenre: "Seafood" },
{ genre: "food", subGenre: "Spices and Herbs" },
{ genre: "food", subGenre: "Street Food" },
{ genre: "food", subGenre: "Sushi" },
{ genre: "food", subGenre: "Tea Ceremonies" },
{ genre: "food", subGenre: "Vegetarian Meals" },
{ genre: "food", subGenre: "Wine Tasting" },
{ genre: "history", subGenre: "African Tribes" },
{ genre: "history", subGenre: "Ancient Egypt" },
{ genre: "history", subGenre: "Celtic Legends" },
{ genre: "history", subGenre: "Chinese Dynasties" },
{ genre: "history", subGenre: "Greek Temples" },
{ genre: "history", subGenre: "Indian Kingdoms" },
{ genre: "history", subGenre: "Industrial Revolution" },
{ genre: "history", subGenre: "Mayan Ruins" },
{ genre: "history", subGenre: "Medieval Europe" },
{ genre: "history", subGenre: "Native American" },
{ genre: "history", subGenre: "Nomadic Life" },
{ genre: "history", subGenre: "Ottoman Empire" },
{ genre: "history", subGenre: "Renaissance" },
{ genre: "history", subGenre: "Samurai Japan" },
{ genre: "history", subGenre: "Traditional Festivals" },
{ genre: "history", subGenre: "Victorian Era" },
{ genre: "history", subGenre: "Viking Culture" },
{ genre: "history", subGenre: "World War Eras" },
{ genre: "horror", subGenre: "Abandoned Hospitals" },
{ genre: "horror", subGenre: "Ancient Tombs" },
{ genre: "horror", subGenre: "Blood Moons" },
{ genre: "horror", subGenre: "Creepy Dolls" },
{ genre: "horror", subGenre: "Curses" },
{ genre: "horror", subGenre: "Dark Alleys" },
{ genre: "horror", subGenre: "Demons" },
{ genre: "horror", subGenre: "Foggy Forests" },
{ genre: "horror", subGenre: "Ghosts" },
{ genre: "horror", subGenre: "Graveyards" },
{ genre: "horror", subGenre: "Haunted Houses" },
{ genre: "horror", subGenre: "Monsters" },
{ genre: "horror", subGenre: "Occult Rituals" },
{ genre: "horror", subGenre: "Possessions" },
{ genre: "horror", subGenre: "Scary Clowns" },
{ genre: "horror", subGenre: "Shadows" },
{ genre: "horror", subGenre: "Silent Villages" },
{ genre: "horror", subGenre: "Vampires" },
{ genre: "horror", subGenre: "Werewolves" },
{ genre: "horror", subGenre: "Witches" },
{ genre: "music", subGenre: "Ballet" },
{ genre: "music", subGenre: "Breakdance" },
{ genre: "music", subGenre: "Choirs" },
{ genre: "music", subGenre: "Classical Concerts" },
{ genre: "music", subGenre: "Dance Battles" },
{ genre: "music", subGenre: "DJ Performances" },
{ genre: "music", subGenre: "Drumming" },
{ genre: "music", subGenre: "Electronic Music" },
{ genre: "music", subGenre: "Flamenco" },
{ genre: "music", subGenre: "Folk Dance" },
{ genre: "music", subGenre: "Hip-Hop Dance" },
{ genre: "music", subGenre: "Jazz Clubs" },
{ genre: "music", subGenre: "K-Pop" },
{ genre: "music", subGenre: "Opera" },
{ genre: "music", subGenre: "Orchestras" },
{ genre: "music", subGenre: "Rock Bands" },
{ genre: "music", subGenre: "Salsa" },
{ genre: "music", subGenre: "Singing Solo" },
{ genre: "music", subGenre: "Street Dance" },
{ genre: "music", subGenre: "Tap Dance" },
{ genre: "nature", subGenre: "Aurora Skies" },
{ genre: "nature", subGenre: "Canyons" },
{ genre: "nature", subGenre: "Caves" },
{ genre: "nature", subGenre: "Cliffs" },
{ genre: "nature", subGenre: "Coral Reefs" },
{ genre: "nature", subGenre: "Deserts" },
{ genre: "nature", subGenre: "Forests" },
{ genre: "nature", subGenre: "Glaciers" },
{ genre: "nature", subGenre: "Lakes" },
{ genre: "nature", subGenre: "Meadows" },
{ genre: "nature", subGenre: "Mountains" },
{ genre: "nature", subGenre: "night sky" },
{ genre: "nature", subGenre: "Oceans" },
{ genre: "nature", subGenre: "Rainforest" },
{ genre: "nature", subGenre: "Rivers" },
{ genre: "nature", subGenre: "Savannah" },
{ genre: "nature", subGenre: "Storms" },
{ genre: "nature", subGenre: "Sunsets" },
{ genre: "nature", subGenre: "Volcanoes" },
{ genre: "nature", subGenre: "Waterfalls" },
{ genre: "nature", subGenre: "Wetlands" },
{ genre: "people", subGenre: "Artists" },
{ genre: "people", subGenre: "Celebrations" },
{ genre: "people", subGenre: "Children" },
{ genre: "people", subGenre: "Commuting" },
{ genre: "people", subGenre: "Craftsmen" },
{ genre: "people", subGenre: "Daily Life" },
{ genre: "people", subGenre: "Elderly" },
{ genre: "people", subGenre: "Family Moments" },
{ genre: "people", subGenre: "Farm Life" },
{ genre: "people", subGenre: "Festivals" },
{ genre: "people", subGenre: "Fishing Villages" },
{ genre: "people", subGenre: "Friendship" },
{ genre: "people", subGenre: "Markets" },
{ genre: "people", subGenre: "Relaxing" },
{ genre: "people", subGenre: "Romantic Dates" },
{ genre: "people", subGenre: "School Days" },
{ genre: "people", subGenre: "Shopping" },
{ genre: "people", subGenre: "Street Life" },
{ genre: "people", subGenre: "Travelers" },
{ genre: "people", subGenre: "Workplaces" },
{ genre: "romance", subGenre: "Anger" },
{ genre: "romance", subGenre: "Anniversaries" },
{ genre: "romance", subGenre: "Arguments" },
{ genre: "romance", subGenre: "Comforting" },
{ genre: "romance", subGenre: "Confessions" },
{ genre: "romance", subGenre: "Family Love" },
{ genre: "romance", subGenre: "Farewells" },
{ genre: "romance", subGenre: "First Dates" },
{ genre: "romance", subGenre: "Friendship" },
{ genre: "romance", subGenre: "Heartbreak" },
{ genre: "romance", subGenre: "Hugs" },
{ genre: "romance", subGenre: "Joy" },
{ genre: "romance", subGenre: "Kisses" },
{ genre: "romance", subGenre: "Laughter" },
{ genre: "romance", subGenre: "Loneliness" },
{ genre: "romance", subGenre: "Reunions" },
{ genre: "romance", subGenre: "Sadness" },
{ genre: "romance", subGenre: "Surprise" },
{ genre: "romance", subGenre: "wedding" },
{ genre: "romance", subGenre: "Weddings" },
{ genre: "sci-fi", subGenre: "AI Entities" },
{ genre: "sci-fi", subGenre: "Aliens" },
{ genre: "sci-fi", subGenre: "Androids" },
{ genre: "sci-fi", subGenre: "Clones" },
{ genre: "sci-fi", subGenre: "Colonies on Mars" },
{ genre: "sci-fi", subGenre: "Cyberpunk Cities" },
{ genre: "sci-fi", subGenre: "Exosuits" },
{ genre: "sci-fi", subGenre: "Futuristic Weapons" },
{ genre: "sci-fi", subGenre: "Galactic Battles" },
{ genre: "sci-fi", subGenre: "Genetic Labs" },
{ genre: "sci-fi", subGenre: "Holograms" },
{ genre: "sci-fi", subGenre: "Hover Cars" },
{ genre: "sci-fi", subGenre: "Nanotechnology" },
{ genre: "sci-fi", subGenre: "Post-Apocalypse" },
{ genre: "sci-fi", subGenre: "Robots" },
{ genre: "sci-fi", subGenre: "Space Stations" },
{ genre: "sci-fi", subGenre: "Time Travel" },
{ genre: "sci-fi", subGenre: "Virtual Reality" },
{ genre: "sci-fi", subGenre: "Wormholes" },
{ genre: "space", subGenre: "Asteroids" },
{ genre: "space", subGenre: "Aurora" },
{ genre: "space", subGenre: "Black Holes" },
{ genre: "space", subGenre: "Comets" },
{ genre: "space", subGenre: "Cosmic Dust" },
{ genre: "space", subGenre: "Deep Space" },
{ genre: "space", subGenre: "Eclipses" },
{ genre: "space", subGenre: "Exoplanets" },
{ genre: "space", subGenre: "Galaxies" },
{ genre: "space", subGenre: "Meteor Showers" },
{ genre: "space", subGenre: "Moons" },
{ genre: "space", subGenre: "Nebulae" },
{ genre: "space", subGenre: "Observatories" },
{ genre: "space", subGenre: "Planets" },
{ genre: "space", subGenre: "Rocket Launches" },
{ genre: "space", subGenre: "Satellites" },
{ genre: "space", subGenre: "Spacewalks" },
{ genre: "space", subGenre: "Stars" },
{ genre: "space", subGenre: "Supernovas" },
{ genre: "space", subGenre: "Telescopes" },
{ genre: "sports", subGenre: "Archery" },
{ genre: "sports", subGenre: "Baseball" },
{ genre: "sports", subGenre: "Basketball" },
{ genre: "sports", subGenre: "Boxing" },
{ genre: "sports", subGenre: "Climbing" },
{ genre: "sports", subGenre: "Cycling" },
{ genre: "sports", subGenre: "Fencing" },
{ genre: "sports", subGenre: "Gymnastics" },
{ genre: "sports", subGenre: "Horse Riding" },
{ genre: "sports", subGenre: "Martial Arts" },
{ genre: "sports", subGenre: "Rowing" },
{ genre: "sports", subGenre: "Running" },
{ genre: "sports", subGenre: "Skateboarding" },
{ genre: "sports", subGenre: "Skiing" },
{ genre: "sports", subGenre: "Snowboarding" },
{ genre: "sports", subGenre: "Soccer" },
{ genre: "sports", subGenre: "Surfing" },
{ genre: "sports", subGenre: "Swimming" },
{ genre: "sports", subGenre: "Tennis" },
{ genre: "sports", subGenre: "Yoga" },
{ genre: "technology", subGenre: "3D Printing" },
{ genre: "technology", subGenre: "Artificial Intelligence" },
{ genre: "technology", subGenre: "Augmented Reality" },
{ genre: "technology", subGenre: "Autonomous Cars" },
{ genre: "technology", subGenre: "Biotech" },
{ genre: "technology", subGenre: "Cyber Security" },
{ genre: "technology", subGenre: "Data Centers" },
{ genre: "technology", subGenre: "Digital Currency" },
{ genre: "technology", subGenre: "Drones" },
{ genre: "technology", subGenre: "Futuristic Homes" },
{ genre: "technology", subGenre: "Green Tech" },
{ genre: "technology", subGenre: "Nanobots" },
{ genre: "technology", subGenre: "Quantum Computing" },
{ genre: "technology", subGenre: "Robotics" },
{ genre: "technology", subGenre: "Smart Cities" },
{ genre: "technology", subGenre: "Smart Farms" },
{ genre: "technology", subGenre: "Space Elevators" },
{ genre: "technology", subGenre: "Surveillance Systems" },
{ genre: "technology", subGenre: "VR Worlds" },
{ genre: "technology", subGenre: "Wearables" },
{ genre: "travel", subGenre: "Backpacking" },
{ genre: "travel", subGenre: "Camping" },
{ genre: "travel", subGenre: "City Tours" },
{ genre: "travel", subGenre: "Cruises" },
{ genre: "travel", subGenre: "Cultural Trips" },
{ genre: "travel", subGenre: "Desert Journeys" },
{ genre: "travel", subGenre: "Diving Trips" },
{ genre: "travel", subGenre: "Exploring Ruins" },
{ genre: "travel", subGenre: "Festivals Abroad" },
{ genre: "travel", subGenre: "Glamping" },
{ genre: "travel", subGenre: "Hiking" },
{ genre: "travel", subGenre: "Hot Air Balloons" },
{ genre: "travel", subGenre: "Island Hopping" },
{ genre: "travel", subGenre: "Jungle Treks" },
{ genre: "travel", subGenre: "Motorbike Tours" },
{ genre: "travel", subGenre: "Mountain Climbing" },
{ genre: "travel", subGenre: "Polar Expeditions" },
{ genre: "travel", subGenre: "Road Trips" },
{ genre: "travel", subGenre: "Safari" },
{ genre: "travel", subGenre: "Train Journeys" },
{ genre: "work", subGenre: "Actors" },
{ genre: "work", subGenre: "Artists" },
{ genre: "work", subGenre: "Athletes" },
{ genre: "work", subGenre: "Chefs" },
{ genre: "work", subGenre: "Craftsmen" },
{ genre: "girl", subGenre: "Casual Dresses" },
{ genre: "girl", subGenre: "Mini Skirts" },
{ genre: "girl", subGenre: "Long Skirts" },
{ genre: "girl", subGenre: "Evening Gowns" },
{ genre: "girl", subGenre: "School Uniforms" },
{ genre: "girl", subGenre: "Business Suits" },
{ genre: "girl", subGenre: "Cocktail Dresses" },
{ genre: "girl", subGenre: "Boho Outfits" },
{ genre: "girl", subGenre: "Streetwear" },
{ genre: "girl", subGenre: "Traditional Costumes" },
{ genre: "girl", subGenre: "Party Dresses" },
{ genre: "girl", subGenre: "Swimwear" },
{ genre: "girl", subGenre: "Sportswear" },
{ genre: "girl", subGenre: "Lingerie" },
{ genre: "girl", subGenre: "Pajamas" },
{ genre: "girl", subGenre: "Gothic Outfits" },
{ genre: "girl", subGenre: "Vintage Dresses" },
{ genre: "girl", subGenre: "Winter Coats" },
{ genre: "girl", subGenre: "Summer Outfits" },
{ genre: "girl", subGenre: "Festival Outfits" },
{ genre: "woman", subGenre: "Evening Gowns" },
{ genre: "woman", subGenre: "Cocktail Dresses" },
{ genre: "woman", subGenre: "Ball Gowns" },
{ genre: "woman", subGenre: "Business Attire" },
{ genre: "woman", subGenre: "Formal Suits" },
{ genre: "woman", subGenre: "Luxury Lingerie" },
{ genre: "woman", subGenre: "Opera Dresses" },
{ genre: "woman", subGenre: "Elegant Skirts" },
{ genre: "woman", subGenre: "Designer Outfits" },
{ genre: "woman", subGenre: "Classic Black Dress" },
{ genre: "woman", subGenre: "High Fashion Couture" },
{ genre: "woman", subGenre: "Vintage Elegance" },
{ genre: "woman", subGenre: "Wedding Dresses" },
{ genre: "woman", subGenre: "Chic Office Wear" },
{ genre: "woman", subGenre: "Luxury Coats" },
{ genre: "woman", subGenre: "Formal Evening Suits" },
{ genre: "woman", subGenre: "Silk Dresses" },
{ genre: "woman", subGenre: "Red Carpet Outfits" },
{ genre: "woman", subGenre: "Classic Tailored Wear" },
{ genre: "woman", subGenre: "Luxury Resort Wear" }
{ "genre": "woman", "subGenre": "Casual Dresses" },
{ "genre": "woman", "subGenre": "Jeans and Blouses" },
{ "genre": "woman", "subGenre": "Maxi Skirts" },
{ "genre": "woman", "subGenre": "Casual Office Wear" },
{ "genre": "woman", "subGenre": "Cardigans with Skirts" },
{ "genre": "woman", "subGenre": "Casual Jumpsuits" },
{ "genre": "woman", "subGenre": "Casual Knitwear" },
{ "genre": "woman", "subGenre": "Linen Outfits" },
{ "genre": "woman", "subGenre": "Weekend Outfits" },
{ "genre": "woman", "subGenre": "Street Casual" },
{ "genre": "woman", "subGenre": "Boho Casual" },
{ "genre": "woman", "subGenre": "Smart Casual" },
{ "genre": "woman", "subGenre": "Denim Skirts" },
{ "genre": "woman", "subGenre": "Casual Midi Dresses" },
{ "genre": "woman", "subGenre": "Summer Casual" },
{ "genre": "woman", "subGenre": "Casual Sweaters" },
{ "genre": "woman", "subGenre": "Casual Jackets" },
{ "genre": "woman", "subGenre": "Everyday Casual Wear" },
{ "genre": "woman", "subGenre": "Relaxed Home Wear" },
{ "genre": "woman", "subGenre": "Travel Casual" },
{ "genre": "girl", "subGenre": "Casual Mini Skirts" },
{ "genre": "girl", "subGenre": "T-Shirts and Shorts" },
{ "genre": "girl", "subGenre": "Casual Sundresses" },
{ "genre": "girl", "subGenre": "Sweaters with Skirts" },
{ "genre": "girl", "subGenre": "Casual Hoodies" },
{ "genre": "girl", "subGenre": "Casual Denim" },
{ "genre": "girl", "subGenre": "Casual Rompers" },
{ "genre": "girl", "subGenre": "School Casual" },
{ "genre": "girl", "subGenre": "Casual Tops and Skirts" },
{ "genre": "girl", "subGenre": "Leggings and Tees" },
{ "genre": "girl", "subGenre": "Casual Tank Tops" },
{ "genre": "girl", "subGenre": "Sporty Casual" },
{ "genre": "girl", "subGenre": "Casual Pajamas" },
{ "genre": "girl", "subGenre": "Casual Jackets" },
{ "genre": "girl", "subGenre": "Simple Dresses" },
{ "genre": "girl", "subGenre": "Casual Streetwear" },
{ "genre": "girl", "subGenre": "Casual Overalls" },
{ "genre": "girl", "subGenre": "Casual Knit Tops" },
{ "genre": "girl", "subGenre": "Casual Party Wear" },
{ "genre": "girl", "subGenre": "Weekend Casual" },
{ "genre": "girl", "subGenre": "Anime School Uniform" },
{ "genre": "girl", "subGenre": "Magical Girl Costume" },
{ "genre": "girl", "subGenre": "Catgirl Outfit" },
{ "genre": "girl", "subGenre": "Maid Outfit" },
{ "genre": "girl", "subGenre": "Nurse Uniform" },
{ "genre": "girl", "subGenre": "Sailor Suit" },
{ "genre": "girl", "subGenre": "Fantasy Elf Costume" },
{ "genre": "girl", "subGenre": "Vampire Girl Outfit" },
{ "genre": "girl", "subGenre": "Gothic Lolita Dress" },
{ "genre": "girl", "subGenre": "Princess Dress" },
{ "genre": "girl", "subGenre": "Warrior Girl Armor" },
{ "genre": "girl", "subGenre": "Cyberpunk Outfit" },
{ "genre": "girl", "subGenre": "Steampunk Girl Costume" },
{ "genre": "girl", "subGenre": "Fairy Wings Costume" },
{ "genre": "girl", "subGenre": "Idol Singer Outfit" },
{ "genre": "girl", "subGenre": "Bunny Girl Costume" },
{ "genre": "girl", "subGenre": "Magical Witch Outfit" },
{ "genre": "girl", "subGenre": "Samurai Girl Costume" },
{ "genre": "girl", "subGenre": "Succubus Outfit" },
{ "genre": "girl", "subGenre": "Video Game Heroine Cosplay" }
{ "genre": "epic", "subGenre": "woman" },
{ "genre": "epic", "subGenre": "girl" },
{ "genre": "epic", "subGenre": "human" },
{ "genre": "epic", "subGenre": "man" },
{ "genre": "epic", "subGenre": "architecture" },
{ "genre": "epic", "subGenre": "animals" },
{ "genre": "epic", "subGenre": "ethereal" },
{ "genre": "epic", "subGenre": "gothic" },
{ "genre": "epic", "subGenre": "dark" },
{ "genre": "epic", "subGenre": "space" },
{ "genre": "epic", "subGenre": "scene" },
{ "genre": "epic", "subGenre": "black" },
{ "genre": "epic", "subGenre": "colorful" },
{ "genre": "epic", "subGenre": "bright" },
{ "genre": "epic", "subGenre": "abstract" },
{ "genre": "epic", "subGenre": "abstract color" },
{ "genre": "epic", "subGenre": "room" },
{ "genre": "epic", "subGenre": "building" },
{ "genre": "epic", "subGenre": "wizard" },
{ "genre": "epic", "subGenre": "future" },
{ "genre": "epic", "subGenre": "landscape" },
{ "genre": "epic", "subGenre": "stars" },
*/
{ "genre": "dance", "subGenre": "hiphop horizontal" },
{ "genre": "dance", "subGenre": "hiphop group horizontal" },
{ "genre": "dance", "subGenre": "tiktok horizontal" },
{ "genre": "dance", "subGenre": "female street horizontal" },
{ "genre": "dance", "subGenre": "male street horizontal" },
{ "genre": "dance", "subGenre": "idol horizontal" },
];
function extractPinIdFromHref(href: string): string | null {
// hrefs look like https://www.pinterest.com/pin/123456789012345678/...
const m = href.match(/\/pin\/([^\/\?]+)/);
return m ? m[1] : null;
}
async function collectPinIdsForSearch(page: Page, query: string): Promise<string[]> {
const pinIds = new Set<string>();
const searchUrl = `https://www.pinterest.com/search/pins/?q=${encodeURIComponent(query)}`;
await page.goto(searchUrl, { waitUntil: 'networkidle2', timeout: 60000 });
// initial collect
const collect = async () => {
const hrefs = await page.$$eval('a', anchors => (anchors as any[]).map(a => (a as any).href)) as string[];
for (const href of hrefs) {
if (!href) continue;
if (href.includes('/pin/')) {
const id = href.match(/\/pin\/([^\/\?]+)/);
if (id && id[1]) pinIds.add(id[1]);
if (pinIds.size >= MAX_PIN_IDS_PER_TERM) break;
}
}
};
await collect();
// Scroll a few times to load more results
for (let i = 0; i < SCROLL_ITERATIONS && pinIds.size < MAX_PIN_IDS_PER_TERM; i++) {
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
await new Promise(resolve => setTimeout(resolve, SCROLL_DELAY_MS + Math.floor(Math.random() * 800)));
await collect();
}
return Array.from(pinIds).slice(0, MAX_PIN_IDS_PER_TERM);
}
(async () => {
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 800 });
await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36');
const results: { genre: string; subGenre: string; pinIds: string[] }[] = [];
for (const item of searchList) {
const term = `${item.genre} ${item.subGenre}`;
try {
console.log(`Searching Pinterest for: "${term}"`);
const pinIds = await collectPinIdsForSearch(page, term);
console.log(` -> Found ${pinIds.length} pinIds for "${term}"`);
results.push({ genre: item.genre, subGenre: item.subGenre, pinIds });
// small delay between queries to avoid being throttled
await new Promise(resolve => setTimeout(resolve, 600 + Math.floor(Math.random() * 1000)));
} catch (err) {
console.error(`Error collecting pins for "${term}":`, err);
results.push({ genre: item.genre, subGenre: item.subGenre, pinIds: [] });
}
}
await browser.close();
// Merge results with existing src/pinterest_keywords.json (if present),
// then write merged data to both src/pinterest_keywords.json and generated/pinterest_keywords.json
const srcPath = path.join(process.cwd(), 'src', 'pinterest_keywords.json');
const outDir = path.join(process.cwd(), 'generated');
try {
await fs.mkdir(outDir, { recursive: true });
// load existing entries from src/pinterest_keywords.json (if available)
let existing: { genre: string; subGenre: string; pinIds: string[] }[] = [];
try {
const raw = await fs.readFile(srcPath, 'utf-8');
const parsed = JSON.parse(raw);
if (Array.isArray(parsed)) existing = parsed;
} catch (e) {
// file missing or invalid JSON -> start with empty existing array
existing = [];
}
// Build map keyed by genre||subGenre to merge pinIds (dedupe)
const map = new Map<string, { genre: string; subGenre: string; pinIds: string[] }>();
for (const e of existing) {
const key = `${e.genre}||${e.subGenre}`;
map.set(key, { genre: e.genre, subGenre: e.subGenre, pinIds: Array.from(new Set(e.pinIds || [])) });
}
for (const r of results) {
const key = `${r.genre}||${r.subGenre}`;
const existingEntry = map.get(key);
if (existingEntry) {
// preserve existing order, then append any new ids from r
const set = new Set(existingEntry.pinIds);
for (const id of r.pinIds || []) set.add(id);
existingEntry.pinIds = Array.from(set);
} else {
map.set(key, { genre: r.genre, subGenre: r.subGenre, pinIds: Array.from(new Set(r.pinIds || [])) });
}
}
const merged = Array.from(map.values());
// Write merged JSON to src and generated folder
const writePromises = [
fs.writeFile(srcPath, JSON.stringify(merged, null, 2), 'utf-8'),
fs.writeFile(path.join(outDir, 'pinterest_keywords.json'), JSON.stringify(merged, null, 2), 'utf-8')
];
await Promise.all(writePromises);
console.log(`Saved ${merged.length} entries to ${srcPath} and ${path.join(outDir, 'pinterest_keywords.json')}`);
} catch (err) {
console.error('Failed to write output file:', err);
// Fallback to printing JSON to stdout
console.log(JSON.stringify(results, null, 2));
}
})();