← 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 };