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