Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import { extractAddressFromMessage } from '../../utils/text-validator';
- import { SocialPlatformRecipient } from '../../types/scraper';
- import { Scraper } from 'agent-twitter-client';
- import { env } from '@/lib/config/env';
- import { CookieJar, Cookie } from 'tough-cookie';
- export class TwitterService {
- private scraper: Scraper;
- private cookieJar: CookieJar;
- private static instance: TwitterService;
- private initializationPromise: Promise<void>;
- private initialized = false;
- private constructor() {
- this.scraper = new Scraper();
- this.cookieJar = new CookieJar();
- this.initializationPromise = this.initialize();
- }
- public static getInstance(): TwitterService {
- if (!TwitterService.instance) {
- TwitterService.instance = new TwitterService();
- }
- return TwitterService.instance;
- }
- private async initialize() {
- if (this.initialized) return;
- try {
- console.log('🔑 [Twitter Service] Signing in...');
- await this.scraper.login(env.TWITTER_USERNAME, env.TWITTER_PASSWORD);
- const cookies = await this.scraper.getCookies();
- for (const cookie of cookies) {
- if (!cookie) continue;
- try {
- const cookieString = `${cookie.key}=${cookie.value}; Domain=${
- cookie.domain
- }; Path=${cookie.path}${cookie.secure ? '; Secure' : ''}${
- cookie.httpOnly ? '; HttpOnly' : ''
- }`;
- const parsedCookie = Cookie.parse(cookieString);
- if (parsedCookie) {
- await this.cookieJar.setCookie(parsedCookie, 'https://twitter.com');
- }
- } catch (error) {
- console.error('Twitter: Failed to save cookie:', error);
- }
- }
- this.initialized = true;
- console.log('✅ [Twitter Service] Successfully signed in and saved cookies');
- } catch (error) {
- console.error('❌ [Twitter Service] Authentication failed:', error);
- throw error;
- }
- }
- private async ensureInitialized() {
- if (!this.initialized) {
- await this.initializationPromise;
- }
- }
- private async loadCookiesToScraper() {
- const cookies = await this.cookieJar.getCookies('https://twitter.com');
- const hasAuthToken = cookies.some((cookie) => cookie.key === 'auth_token');
- const hasCSRF = cookies.some((cookie) => cookie.key === 'ct0');
- if (!hasAuthToken || !hasCSRF) {
- console.log('🔄 [Twitter Service] Missing required cookies, reinitializing...');
- this.initialized = false;
- this.initializationPromise = this.initialize();
- await this.initializationPromise;
- return;
- }
- const cookieStrings = cookies.map((cookie) => cookie.toString());
- await this.scraper.setCookies(cookieStrings);
- console.log('🍪 [Twitter Service] Using existing cookies');
- }
- async extractRecipient(url: string): Promise<SocialPlatformRecipient> {
- try {
- await this.ensureInitialized();
- await this.loadCookiesToScraper();
- const tweetId = this.extractTweetId(url);
- const data = await this.scraper.getTweet(tweetId);
- if (!data?.text || !data.username) {
- throw new Error('Tweet data not found');
- }
- try {
- const address = extractAddressFromMessage(data.text, true);
- return {
- message: data.text,
- platform_user_id: data.username,
- platform: 'twitter',
- address,
- };
- } catch (error) {
- throw new Error(
- error instanceof Error ? error.message : 'Failed to extract address',
- );
- }
- } catch (error) {
- if (
- error instanceof Error &&
- (error.message.includes('csrf') ||
- error.message.includes('unauthorized'))
- ) {
- console.log('🔄 [Twitter Service] Auth error, reinitializing...');
- this.initialized = false;
- this.initializationPromise = this.initialize();
- await this.initializationPromise;
- return this.extractRecipient(url);
- }
- console.error('❌ [Twitter Service] Failed to extract data:', error);
- throw error instanceof Error
- ? error
- : new Error('Failed to extract recipient');
- }
- }
- private extractTweetId(url: string): string {
- const match = url.match(/status\/(\d+)/);
- if (!match) {
- throw new Error('Invalid tweet URL');
- }
- return match[1];
- }
- async logout(): Promise<void> {
- try {
- await this.ensureInitialized();
- await this.scraper.logout();
- await this.cookieJar.removeAllCookies();
- this.initialized = false;
- console.log('👋 [Twitter Service] Logged out');
- } catch (error) {
- console.error('❌ [Twitter Service] Logout failed:', error);
- throw error;
- }
- }
- isTwitterUrl(url: string): boolean {
- return url.includes('twitter.com') || url.includes('x.com');
- }
- }
- export const twitterService = TwitterService.getInstance();
Advertisement
Add Comment
Please, Sign In to add comment