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