const axios = require('axios'); const cheerio = require('cheerio'); const { shannz: cf } = require('bycf'); async function getTurnstileToken() { try { const token = await cf.turnstileMin( "https://claptools.com/tiktok-profile-viewer/", "0x4AAAAAAA0aU62HwPRV0j1U" ); return token; } catch (error) { throw new Error("Gagal mendapatkan Turnstile token: " + error.message); } } async function getNonce() { const response = await axios.get('https://claptools.com/tiktok-profile-viewer/', { headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' } }); const $ = cheerio.load(response.data); const nonce = $('input[name="tt_nonce"]').val(); return nonce; } async function tiktokStalk(username) { const token = await getTurnstileToken(); const nonce = await getNonce(); const formData = new URLSearchParams(); formData.append('username', username); formData.append('tt_nonce', nonce); formData.append('cf-turnstile-response', token); const response = await axios.post('https://claptools.com/tiktok-profile-viewer/', formData, { headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', 'Referer': 'https://claptools.com/tiktok-profile-viewer/', 'Origin': 'https://claptools.com' } }); const $ = cheerio.load(response.data); const avatar = $('.profile img').attr('src'); const fullText = $('.profile-details h2').text().trim(); const bio = $('.profile-details p').text().trim(); const nameMatch = fullText.match(/^(.+?)\s*\(@(.+?)\)$/); const nickname = nameMatch ? nameMatch[1].trim() : ''; const usernameFromPage = nameMatch ? nameMatch[2].trim() : username; const followers = $('.stats .box').eq(0).find('.number').text().trim(); const likes = $('.stats .box').eq(1).find('.number').text().trim(); const videos = $('.stats .box').eq(2).find('.number').text().trim(); const videoList = []; $('.thumb').each((i, elem) => { const thumbnail = $(elem).find('img').attr('src'); if (thumbnail) { videoList.push({ thumbnail: thumbnail }); } }); return { username: usernameFromPage, nickname: nickname, bio: bio, avatar: avatar, stats: { followers: followers, likes: likes, videos: videos }, videoList: videoList }; } 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,24}$/; if (!usernameRegex.test(username)) { return res.status(400).json({ success: false, error: 'Invalid username format' }); } const result = await tiktokStalk(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: 'TikTok Stalk', description: 'Get TikTok user profile information including stats and avatar', type: 'GET', routes: ['api/stalk/tiktok'], tags: ['social', 'tiktok', 'stalk', 'profile'], parameters: ['username', 'key'], enabled: true, main: ['Stalk'], handler };