| const axios = require('axios'); |
|
|
| async function twitterStalk(username) { |
| try { |
| const profileResponse = await axios.get( |
| `https://www.archivlyx.com/api/x/user?username=${username}`, |
| { |
| headers: { |
| 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', |
| 'Accept': 'application/json' |
| } |
| } |
| ); |
|
|
| if (!profileResponse.data.success) { |
| throw new Error('Failed to fetch profile data'); |
| } |
|
|
| const profile = profileResponse.data.data; |
|
|
| const tweetsResponse = await axios.get( |
| `https://www.archivlyx.com/api/x/user-tweets?user=${profile.restId}&cursor=`, |
| { |
| headers: { |
| 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', |
| 'Accept': 'application/json' |
| } |
| } |
| ); |
|
|
| if (!tweetsResponse.data.success) { |
| throw new Error('Failed to fetch tweets data'); |
| } |
|
|
| const tweetsData = tweetsResponse.data.data; |
|
|
| return { |
| profile: { |
| display_name: profile.displayName, |
| handle: profile.handle, |
| bio: profile.bio, |
| avatar: profile.avatar, |
| banner: profile.banner || null, |
| is_verified: profile.isVerified, |
| is_protected: profile.protected, |
| rest_id: profile.restId, |
| stats: { |
| tweets: profile.tweetsCount, |
| followers: profile.followersCount, |
| following: profile.followingCount |
| }, |
| website: profile.website || null, |
| location: profile.location || null, |
| join_date: profile.joinDate |
| }, |
| tweets: tweetsData.tweets.map(tweet => ({ |
| id: tweet.id, |
| text: tweet.text, |
| created_at: tweet.createdAt, |
| author: { |
| id: tweet.author.id, |
| display_name: tweet.author.displayName, |
| handle: tweet.author.handle, |
| avatar: tweet.author.avatar, |
| banner: tweet.author.bannerProfile || null, |
| is_verified: tweet.author.isVerified |
| }, |
| stats: { |
| likes: tweet.stats.likes, |
| retweets: tweet.stats.retweets, |
| replies: tweet.stats.replies, |
| quotes: tweet.stats.quotes, |
| views: tweet.stats.views, |
| bookmarks: tweet.stats.bookmarks |
| }, |
| media: tweet.media.map(m => ({ |
| type: m.type, |
| url: m.url, |
| media_key: m.mediaKey, |
| video_url: m.videoUrl || null |
| })), |
| is_quote: tweet.isQuote, |
| is_retweet: tweet.isRetweet, |
| quoted_tweet: tweet.quotedTweet, |
| retweeted_tweet: tweet.retweetedTweet |
| })), |
| pagination: { |
| next_cursor: tweetsData.pagination.nextCursor, |
| prev_cursor: tweetsData.pagination.prevCursor, |
| has_more: tweetsData.pagination.hasMore |
| } |
| }; |
| } catch (error) { |
| if (error.response) { |
| throw new Error(`API Error: ${error.response.status} - ${error.response.statusText}`); |
| } |
| throw new Error(`Failed to fetch Twitter data: ${error.message}`); |
| } |
| } |
|
|
| const handler = async (req, res) => { |
| try { |
| const { username } = req.query; |
|
|
| if (!username) { |
| return res.status(400).json({ |
| success: false, |
| error: 'Missing required parameter: username' |
| }); |
| } |
|
|
| const usernameRegex = /^[a-zA-Z0-9_]{1,15}$/; |
| if (!usernameRegex.test(username)) { |
| return res.status(400).json({ |
| success: false, |
| error: 'Invalid username format' |
| }); |
| } |
|
|
| const result = await twitterStalk(username); |
|
|
| res.json({ |
| author: "Herza", |
| success: true, |
| data: result |
| }); |
|
|
| } catch (error) { |
| res.status(500).json({ |
| author: "Herza", |
| success: false, |
| error: error.message |
| }); |
| } |
| }; |
|
|
| module.exports = { |
| name: 'Twitter Stalk', |
| description: 'Get Twitter/X user profile information including stats, bio, and recent tweets', |
| type: 'GET', |
| routes: ['api/stalk/twitter'], |
| tags: ['social', 'twitter', 'x', 'stalk', 'profile'], |
| parameters: ['username', 'key'], |
| enabled: true, |
| main: ['Stalk'], |
| handler |
| }; |