| 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 | |
| }; |