← back to Dear Bubbe Nextjs

archived/social-posters/twitter-v2-poster.js

91 lines

const { TwitterApi } = require('twitter-api-v2');
const fs = require('fs').promises;

// You need to get these from https://developer.twitter.com
const config = {
  appKey: 'YOUR_APP_KEY',
  appSecret: 'YOUR_APP_SECRET', 
  accessToken: 'YOUR_ACCESS_TOKEN',
  accessSecret: 'YOUR_ACCESS_SECRET',
};

async function loadConfig() {
  try {
    const configPath = '/root/Projects/dear-bubbe-nextjs/lib/twitter-api-config.json';
    const savedConfig = JSON.parse(await fs.readFile(configPath, 'utf8'));
    Object.assign(config, savedConfig);
    return true;
  } catch (e) {
    console.log('No saved Twitter API config found');
    console.log('\n⚠️  You need Twitter API v2 credentials!');
    console.log('Get them from: https://developer.twitter.com/en/portal/dashboard');
    console.log('\n1. Create an app');
    console.log('2. Get API Key, API Secret, Access Token, Access Secret');
    console.log('3. Save them in twitter-api-config.json');
    return false;
  }
}

async function postTweet(text) {
  console.log('🐦 Posting to Twitter/X via API v2...');
  
  if (!await loadConfig()) {
    return false;
  }
  
  try {
    const client = new TwitterApi({
      appKey: config.appKey,
      appSecret: config.appSecret,
      accessToken: config.accessToken,
      accessSecret: config.accessSecret,
    });
    
    const tweet = await client.v2.tweet(text);
    console.log('✅ Tweet posted!');
    console.log('Tweet ID:', tweet.data.id);
    console.log('URL: https://twitter.com/DearBubbe/status/' + tweet.data.id);
    return true;
  } catch (error) {
    console.error('❌ Error:', error.message);
    return false;
  }
}

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('Posting from queue:', toPost.text.substring(0, 50) + '...');
    const success = await postTweet(toPost.text);
    
    if (success) {
      toPost.status = 'posted';
      toPost.postedAt = new Date().toISOString();
      await fs.writeFile(queuePath, JSON.stringify(queue, null, 2));
      console.log('Queue updated');
    }
    
    return success;
  } catch (error) {
    console.error('Error:', error);
    return false;
  }
}

module.exports = { postTweet, postFromQueue };

if (require.main === module) {
  if (process.argv[2] === 'test') {
    postTweet('Testing Bubbe auto-post with API v2! #BubbeAI Visit Bubbe.AI');
  } else {
    postFromQueue();
  }
}