← back to Dear Bubbe Nextjs

archived/social-posters/recipe-poster.js

267 lines

#!/usr/bin/env node

/**
 * Recipe Poster - Posts Bubbe's recipes 3x daily
 * Automatically posts Jewish recipes with Bubbe's commentary
 */

const fs = require('fs').promises;
const path = require('path');

// Jewish recipes with Bubbe's commentary
const RECIPES = [
  {
    name: "Bubbe's Matzo Ball Soup",
    ingredients: [
      "4 eggs", "1/4 cup schmaltz (or oil)", 
      "1 cup matzo meal", "1/4 cup seltzer",
      "2 tsp salt", "Chicken broth"
    ],
    instructions: "Mix eggs with schmaltz, add matzo meal and seltzer. Refrigerate 30 min. Roll into balls, boil in salted water 30 min.",
    bubbeComment: "If your matzo balls are hard as rocks, you're a disappointment to your ancestors! Light and fluffy, that's the secret!"
  },
  {
    name: "Classic Challah Bread", 
    ingredients: [
      "4 cups flour", "1/4 cup sugar",
      "2 tsp yeast", "3 eggs", 
      "1/3 cup oil", "1 tsp salt"
    ],
    instructions: "Mix dry ingredients, add wet. Knead 10 min. Rise 2 hours. Braid. Egg wash. Bake 350°F for 30 min.",
    bubbeComment: "Store-bought challah? What are you, too lazy to braid? Your grandmother is rolling in her grave!"
  },
  {
    name: "Bubbe's Brisket",
    ingredients: [
      "5 lb brisket", "4 onions sliced",
      "1 cup ketchup", "1/2 cup brown sugar",
      "Paprika", "Salt & pepper"
    ],
    instructions: "Season brisket. Layer onions. Mix ketchup & sugar, pour over. Cover tight. 325°F for 3 hours.",
    bubbeComment: "Dry brisket? That's what happens when you rush! Low and slow, just like your dating life should be!"
  },
  {
    name: "Latkes (Potato Pancakes)",
    ingredients: [
      "6 potatoes grated", "1 onion grated",
      "2 eggs", "1/4 cup flour",
      "Salt & pepper", "Oil for frying"
    ],
    instructions: "Squeeze water from potatoes. Mix all. Fry spoonfuls in hot oil until crispy. Drain on paper towels.",
    bubbeComment: "Not crispy enough? What, you're afraid of a little oil? This is why you're still single!"
  },
  {
    name: "Rugelach",
    ingredients: [
      "8oz cream cheese", "1 cup butter",
      "2 cups flour", "Jam & nuts for filling",
      "Cinnamon sugar"
    ],
    instructions: "Mix dough, chill. Roll thin, spread filling, roll up, slice. Bake 350°F for 20 min.",
    bubbeComment: "Buying rugelach from the store? For shame! Even your cousin's kids can make these!"
  },
  {
    name: "Gefilte Fish",
    ingredients: [
      "2 lb whitefish", "1 lb pike",
      "2 onions", "3 eggs",
      "1/4 cup matzo meal", "Carrots"
    ],
    instructions: "Grind fish with onions. Mix with eggs and matzo meal. Form ovals. Simmer in fish stock 1 hour.",
    bubbeComment: "From a jar? OY VEY! Your great-grandmother made this by hand every Friday!"
  },
  {
    name: "Kugel (Noodle Pudding)",
    ingredients: [
      "1 lb egg noodles", "6 eggs",
      "1 cup sour cream", "1 cup cottage cheese",
      "1/2 cup sugar", "Cinnamon"
    ],
    instructions: "Cook noodles. Mix with beaten eggs and cheeses. Add sugar. Bake 350°F for 45 min until golden.",
    bubbeComment: "Too sweet? Too bad! This is how we've made it for generations. Don't like it? Make your own!"
  },
  {
    name: "Hamantaschen",
    ingredients: [
      "3 cups flour", "1/2 cup sugar",
      "3 eggs", "1/2 cup oil",
      "Jam or poppy filling"
    ],
    instructions: "Make dough, roll out. Cut circles. Add filling, pinch into triangles. Bake 350°F for 15 min.",
    bubbeComment: "Can't make a proper triangle? What kind of Jewish education did you get? Practice on paper first!"
  },
  {
    name: "Chopped Liver",
    ingredients: [
      "1 lb chicken livers", "4 hard-boiled eggs",
      "2 onions caramelized", "Schmaltz",
      "Salt & pepper"
    ],
    instructions: "Sauté livers. Grind with eggs and onions. Add schmaltz to bind. Season well.",
    bubbeComment: "You don't eat liver? What are you, too fancy? This is what made your grandfather strong!"
  },
  {
    name: "Babka",
    ingredients: [
      "4 cups flour", "1/2 cup sugar",
      "2 tsp yeast", "3 eggs",
      "Chocolate filling", "Butter"
    ],
    instructions: "Make dough, let rise. Roll out, spread chocolate, roll up, twist. Bake 350°F for 45 min.",
    bubbeComment: "Buying babka from that fancy bakery? $30 for what? I can make three for that price!"
  }
];

// Track posted recipes
const POSTED_FILE = path.join(__dirname, '../data/posted-recipes.json');

async function getPostedRecipes() {
  try {
    const data = await fs.readFile(POSTED_FILE, 'utf-8');
    return JSON.parse(data);
  } catch {
    return [];
  }
}

async function savePostedRecipe(recipe) {
  const posted = await getPostedRecipes();
  posted.push({
    recipe: recipe.name,
    timestamp: new Date().toISOString()
  });
  
  // Keep only last 30 posts
  const recent = posted.slice(-30);
  await fs.writeFile(POSTED_FILE, JSON.stringify(recent, null, 2));
}

async function getUnpostedRecipe() {
  const posted = await getPostedRecipes();
  const postedNames = posted.map(p => p.recipe);
  
  // Find recipes not posted recently
  const available = RECIPES.filter(r => !postedNames.includes(r.name));
  
  // If all posted, reset and use any
  if (available.length === 0) {
    await fs.writeFile(POSTED_FILE, JSON.stringify([]));
    return RECIPES[Math.floor(Math.random() * RECIPES.length)];
  }
  
  return available[Math.floor(Math.random() * available.length)];
}

function formatRecipePost(recipe) {
  const post = `🥯 ${recipe.name}

INGREDIENTS:
${recipe.ingredients.map(i => `• ${i}`).join('\\n')}

INSTRUCTIONS:
${recipe.instructions}

💭 BUBBE SAYS: "${recipe.bubbeComment}"

Want more of Bubbe's recipes & wisdom? Visit Bubbe.AI

#JewishCooking #BubbeRecipes #JewishFood #Kosher #Recipe #BubbeAI #TraditionalCooking`;

  return post;
}

async function postRecipeToTwitter(recipe) {
  const content = formatRecipePost(recipe);
  
  try {
    // Send to Twitter poster
    const response = await fetch('http://45.61.58.125:5013/api/post-recipe-twitter', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        content,
        recipeName: recipe.name,
        timestamp: new Date().toISOString()
      })
    });
    
    if (response.ok) {
      console.log(`✅ Posted recipe to Twitter: ${recipe.name}`);
      await savePostedRecipe(recipe);
      return true;
    }
  } catch (error) {
    console.error(`❌ Error posting recipe:`, error.message);
  }
  return false;
}

async function postRecipeToBluesky(recipe) {
  const content = formatRecipePost(recipe).substring(0, 300); // Bluesky limit
  
  try {
    const response = await fetch('http://45.61.58.125:5013/api/post-recipe-bluesky', {
      method: 'POST', 
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        content,
        recipeName: recipe.name,
        timestamp: new Date().toISOString()
      })
    });
    
    if (response.ok) {
      console.log(`✅ Posted recipe to Bluesky: ${recipe.name}`);
      return true;
    }
  } catch (error) {
    console.error(`❌ Error posting to Bluesky:`, error.message);
  }
  return false;
}

async function postRecipe() {
  console.log('\\n🍽️ RECIPE POSTER - Starting');
  console.log('=' .repeat(40));
  
  const recipe = await getUnpostedRecipe();
  console.log(`📖 Selected Recipe: ${recipe.name}`);
  
  // Post to both platforms
  const twitterResult = await postRecipeToTwitter(recipe);
  const blueskyResult = await postRecipeToBluesky(recipe);
  
  if (twitterResult || blueskyResult) {
    console.log(`✅ Recipe posted successfully!`);
    
    // Log to admin dashboard
    const logData = {
      type: 'recipe_posted',
      recipe: recipe.name,
      platforms: {
        twitter: twitterResult,
        bluesky: blueskyResult
      },
      timestamp: new Date().toISOString()
    };
    
    try {
      await fs.appendFile(
        '/root/Projects/dear-bubbe-admin/logs/recipes.log',
        JSON.stringify(logData) + '\\n'
      );
    } catch (e) {
      // Ignore log errors
    }
  }
  
  console.log('=' .repeat(40));
  console.log('Recipe posting complete\\n');
}

// Run immediately if called directly
if (require.main === module) {
  postRecipe().catch(console.error);
}

module.exports = { postRecipe, RECIPES };