← back to Dear Bubbe Nextjs

archived/social-posters/alternative-poster.js

226 lines

const https = require('https');
const http = require('http');
const fs = require('fs').promises;

// Alternative posting methods that don't trigger bot detection

// Method 1: Try posting via mobile API endpoints
async function postViaMobileAPI(text) {
    console.log('📱 Trying mobile API approach...');
    
    const cookies = {
        auth_token: '29242b900adcea897a68bf3c6f5ba838bc5b90ad',
        ct0: '2162404f2a02090757d7dd75042da41274308247b3296bd5cdfe262dee726059fcf260ea7caf13c41bb8bebf6f79acff9bb8b9dc6cdca30b0846bc65ec6f30c5212f03270cb1467cefbb5e44a9a18297'
    };
    
    const cookieString = `auth_token=${cookies.auth_token}; ct0=${cookies.ct0}`;
    
    // Try the legacy endpoint
    const postData = JSON.stringify({
        status: text,
        weighted_character_count: text.length,
        possibly_sensitive: false
    });
    
    return new Promise((resolve) => {
        const options = {
            hostname: 'api.twitter.com',
            path: '/1.1/statuses/update.json',
            method: 'POST',
            headers: {
                'User-Agent': 'Twitter-iPhone/9.0 iOS/16.0',
                'Content-Type': 'application/json',
                'Content-Length': Buffer.byteLength(postData),
                'Cookie': cookieString,
                'X-Twitter-Auth-Type': 'OAuth2Session',
                'X-Csrf-Token': cookies.ct0,
                'Authorization': 'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA'
            }
        };
        
        const req = https.request(options, (res) => {
            let data = '';
            res.on('data', chunk => data += chunk);
            res.on('end', () => {
                console.log('Mobile API Status:', res.statusCode);
                if (res.statusCode === 200) {
                    console.log('✅ Posted via mobile API!');
                    resolve(true);
                } else {
                    console.log('❌ Mobile API failed:', data.substring(0, 200));
                    resolve(false);
                }
            });
        });
        
        req.on('error', (e) => {
            console.error('Error:', e.message);
            resolve(false);
        });
        
        req.write(postData);
        req.end();
    });
}

// Method 2: Try TweetDeck endpoint
async function postViaTweetDeck(text) {
    console.log('🎯 Trying TweetDeck approach...');
    
    const cookies = {
        auth_token: '29242b900adcea897a68bf3c6f5ba838bc5b90ad',
        ct0: '2162404f2a02090757d7dd75042da41274308247b3296bd5cdfe262dee726059fcf260ea7caf13c41bb8bebf6f79acff9bb8b9dc6cdca30b0846bc65ec6f30c5212f03270cb1467cefbb5e44a9a18297'
    };
    
    const postData = new URLSearchParams({
        text: text,
        media_ids: ''
    }).toString();
    
    return new Promise((resolve) => {
        const options = {
            hostname: 'tweetdeck.twitter.com',
            path: '/i/api/1.1/statuses/update.json',
            method: 'POST',
            headers: {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
                'Content-Type': 'application/x-www-form-urlencoded',
                'Content-Length': Buffer.byteLength(postData),
                'Cookie': `auth_token=${cookies.auth_token}; ct0=${cookies.ct0}`,
                'X-Csrf-Token': cookies.ct0,
                'X-Td-Auth-Token': cookies.auth_token,
                'Authorization': 'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA'
            }
        };
        
        const req = https.request(options, (res) => {
            let data = '';
            res.on('data', chunk => data += chunk);
            res.on('end', () => {
                console.log('TweetDeck Status:', res.statusCode);
                if (res.statusCode === 200) {
                    console.log('✅ Posted via TweetDeck!');
                    resolve(true);
                } else {
                    console.log('❌ TweetDeck failed');
                    resolve(false);
                }
            });
        });
        
        req.on('error', (e) => {
            console.error('Error:', e.message);
            resolve(false);
        });
        
        req.write(postData);
        req.end();
    });
}

// Method 3: Check if we can read from Nitter
async function checkNitter() {
    console.log('🔍 Checking Nitter instances...');
    
    const nitterInstances = [
        'nitter.net',
        'nitter.unixfox.eu',
        'nitter.poast.org',
        'nitter.bird.froth.zone',
        'nitter.privacydev.net'
    ];
    
    for (const instance of nitterInstances) {
        try {
            const result = await new Promise((resolve) => {
                https.get(`https://${instance}/DearBubbe`, (res) => {
                    if (res.statusCode === 200) {
                        console.log(`✅ ${instance} is working`);
                        resolve(true);
                    } else {
                        console.log(`❌ ${instance} returned ${res.statusCode}`);
                        resolve(false);
                    }
                }).on('error', () => {
                    console.log(`❌ ${instance} is down`);
                    resolve(false);
                });
            });
            
            if (result) {
                return instance;
            }
        } catch (e) {
            continue;
        }
    }
    
    return null;
}

// Try all methods
async function tryAllMethods(text) {
    console.log('\n🚀 Trying alternative posting methods...\n');
    
    // Try mobile API
    let success = await postViaMobileAPI(text);
    if (success) return true;
    
    // Try TweetDeck
    success = await postViaTweetDeck(text);
    if (success) return true;
    
    // Check Nitter (read-only, but good to know)
    const nitter = await checkNitter();
    if (nitter) {
        console.log(`\n📖 You can view posts at: https://${nitter}/DearBubbe`);
    }
    
    return false;
}

// Post from queue
async function postFromQueue() {
    try {
        const queuePath = '/root/Projects/dear-bubbe-admin/logs/twitter-queue.json';
        const queue = JSON.parse(await fs.readFile(queuePath, 'utf8'));
        
        const toPost = queue.find(t => t.status === 'queued');
        if (!toPost) {
            console.log('No posts in queue');
            return false;
        }
        
        console.log('📤 Attempting to post:', toPost.text.substring(0, 50) + '...');
        const success = await tryAllMethods(toPost.text);
        
        if (success) {
            toPost.status = 'posted';
            toPost.postedAt = new Date().toISOString();
            await fs.writeFile(queuePath, JSON.stringify(queue, null, 2));
            console.log('✅ Posted and queue updated!');
        } else {
            console.log('\n❌ All automated methods failed.');
            console.log('\n📋 Please post manually:');
            console.log('─'.repeat(50));
            console.log(toPost.text);
            console.log('─'.repeat(50));
            console.log('\nGo to: https://x.com/compose/post');
        }
        
        return success;
    } catch (error) {
        console.error('Error:', error);
        return false;
    }
}

module.exports = { tryAllMethods, postFromQueue };

if (require.main === module) {
    if (process.argv[2] === 'test') {
        tryAllMethods('Testing alternative posting methods! #BubbeAI Visit Bubbe.AI');
    } else {
        postFromQueue();
    }
}