← back to Dear Bubbe Nextjs
archived/social-posters/instagram-auto-poster.js
262 lines
#!/usr/bin/env node
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
const fs = require('fs').promises;
const path = require('path');
const { exec } = require('child_process');
const util = require('util');
const execPromise = util.promisify(exec);
const { generateInstagramImage, generateCaption } = require('./instagram-image-generator');
// Use stealth plugin to avoid detection
puppeteer.use(StealthPlugin());
// Configuration
const CONFIG = {
USERNAME: 'dearBubbe',
PASSWORD: '*Instaaccess911*',
COOKIES_FILE: '/root/Projects/dear-bubbe-nextjs/lib/insta-cookies.json',
STATE_FILE: '/root/Projects/dear-bubbe-admin/logs/insta-auto-state.json',
POSTS_PER_DAY: 3,
USER_AGENT: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36'
};
// Helper function to wait
async function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// Get random user message
async function getRandomMessage() {
try {
const { stdout } = await execPromise(
`pm2 logs bubbe-ai --lines 1000 --nostream | grep -E "message:" | grep -v "__" | grep -v "test" | head -30`
);
const messages = [];
const lines = stdout.split('\n').filter(line => line.trim());
for (const line of lines) {
const match = line.match(/message:\s*["'](.+?)["']/);
if (match && match[1] && match[1].length > 20) {
messages.push(match[1].trim());
}
}
if (messages.length > 0) {
return messages[Math.floor(Math.random() * messages.length)];
}
} catch (error) {
console.error('Error getting messages:', error);
}
// Fallback messages
const fallbacks = [
"Should I quit my job without another lined up?",
"My mother-in-law criticizes everything I do",
"I haven't called my parents in months",
"My husband forgot our anniversary again"
];
return fallbacks[Math.floor(Math.random() * fallbacks.length)];
}
// Load cookies
async function loadCookies(page) {
try {
const cookies = JSON.parse(await fs.readFile(CONFIG.COOKIES_FILE, 'utf8'));
await page.setCookie(...cookies);
console.log('✅ Cookies loaded');
return true;
} catch {
console.log('📝 No saved cookies');
return false;
}
}
// Save cookies
async function saveCookies(page) {
try {
const cookies = await page.cookies();
await fs.writeFile(CONFIG.COOKIES_FILE, JSON.stringify(cookies, null, 2));
console.log('💾 Cookies saved');
} catch (error) {
console.error('Error saving cookies:', error);
}
}
// Post to Instagram
async function postToInstagram() {
console.log('🤖 Automated Instagram Poster');
console.log('=' .repeat(40));
// Get message and generate content
const message = await getRandomMessage();
console.log(`📝 Message: "${message}"`);
// Generate image
const timestamp = Date.now();
const imagePath = `/tmp/instagram-${timestamp}.png`;
await generateInstagramImage(message, imagePath);
console.log('🎨 Image generated');
// Generate caption
const caption = generateCaption(message);
console.log('📝 Caption ready');
// Launch browser
const browser = await puppeteer.launch({
headless: 'new',
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-blink-features=AutomationControlled',
'--disable-features=IsolateOrigins,site-per-process',
'--window-size=1280,720'
],
defaultViewport: { width: 1280, height: 720 }
});
const page = await browser.newPage();
// Set user agent
await page.setUserAgent(CONFIG.USER_AGENT);
// Extra headers to look more real
await page.setExtraHTTPHeaders({
'Accept-Language': 'en-US,en;q=0.9'
});
try {
// Load cookies if available
const hasCookies = await loadCookies(page);
// Go to Instagram
console.log('📱 Opening Instagram...');
await page.goto('https://www.instagram.com', {
waitUntil: 'networkidle2',
timeout: 30000
});
await wait(3000);
// Check if we need to login
const needsLogin = await page.$('input[name="username"]') !== null;
if (needsLogin && !hasCookies) {
console.log('🔐 Logging in...');
// Type username
await page.type('input[name="username"]', CONFIG.USERNAME, { delay: 100 });
await wait(1000);
// Type password
await page.type('input[name="password"]', CONFIG.PASSWORD, { delay: 100 });
await wait(1000);
// Click login
await page.click('button[type="submit"]');
console.log('⏳ Waiting for login...');
await wait(5000);
// Handle popups
try {
const notNowButton = await page.$x("//button[contains(., 'Not Now')]");
if (notNowButton.length > 0) {
await notNowButton[0].click();
console.log('📝 Skipped save login');
}
} catch {}
await wait(2000);
// Handle notifications
try {
const notNowButton2 = await page.$x("//button[contains(., 'Not Now')]");
if (notNowButton2.length > 0) {
await notNowButton2[0].click();
console.log('🔕 Skipped notifications');
}
} catch {}
// Save cookies
await saveCookies(page);
}
console.log('✅ Ready to post');
await wait(2000);
// Since Instagram upload is complex, let's save for manual posting
const publicPath = `/root/Projects/dear-bubbe-admin/public/instagram-${timestamp}.png`;
await fs.copyFile(imagePath, publicPath);
// Save caption
const captionPath = `/root/Projects/dear-bubbe-admin/public/instagram-caption.txt`;
await fs.writeFile(captionPath, caption);
console.log('\n✅ Instagram post prepared!');
console.log('\n📸 Image saved:');
console.log(` http://45.61.58.125:7902/instagram-${timestamp}.png`);
console.log('\n📝 Caption saved:');
console.log(` http://45.61.58.125:7902/instagram-caption.txt`);
console.log('\n📱 To post:');
console.log('1. Go to https://instagram.com');
console.log('2. Click + (New Post)');
console.log('3. Upload the image');
console.log('4. Paste the caption');
console.log('5. Share!');
console.log('\n📋 CAPTION:');
console.log('=' .repeat(40));
console.log(caption);
console.log('=' .repeat(40));
// Alternative: Try using Instagram's web post API
console.log('\n🔄 Attempting web post method...');
// Navigate to create page
await page.goto('https://www.instagram.com/accounts/login/?next=/create/select/', {
waitUntil: 'networkidle2'
});
await wait(3000);
// Check if create dialog opened
const createDialog = await page.$('[role="dialog"]');
if (createDialog) {
console.log('📸 Create dialog found');
// Look for file input
const fileInput = await page.$('input[type="file"]');
if (fileInput) {
await fileInput.uploadFile(imagePath);
console.log('✅ Image uploaded via dialog');
await wait(3000);
}
}
} catch (error) {
console.error('❌ Error:', error.message);
// Take screenshot for debugging
try {
await page.screenshot({ path: '/tmp/instagram-error.png' });
console.log('📸 Screenshot: /tmp/instagram-error.png');
} catch {}
} finally {
await browser.close();
// Clean up temp file
try {
await fs.unlink(imagePath);
} catch {}
}
}
// Run if called directly
if (require.main === module) {
postToInstagram().catch(console.error);
}
module.exports = { postToInstagram };