Cari Link Preset Di Video Tiktok

JavaScriptPublic
by zx-apiOct 3, 2026, 09:03 AMExpires: Never294 views
Cari Link Preset Di Video Tiktok
Raw
1/**
2 * AM Preset Finder Scraper
3 * Source: https://amfinder.web.id
4 * 
5 * Scans TikTok video description, bio, comments, and bio-link
6 * to extract Alight Motion preset links.
7 */
8
9
10/**
11 * Credit By Zx
12 * Sumber Kode: https://whatsapp.com/channel/0029VbDLqe7EquiSF4STU13o
13 * Note: Kalau Mau Di sher Lagi Minimal Credit atau sumber jangan di hapus dong
14 * Website React WhatsApp Gratis:
15 * https://react.v1.zfile.web.id/
16 */
17 
18/**
19
20Yang Mau Beli Akun Netflix, Top-Up game, Sunt1k S0Smed
21Bisa Ke Zix Store.
22
23 https://zixstore.kiospremium.site/
24
25Terimakasih ๐Ÿ˜๐Ÿ‘€
26*/
27const BASE_URL = 'https://amfinder.web.id';
28
29function isValidTikTokUrl(url) {
30  const trimmed = (url || '').trim();
31  return /tiktok\.com/i.test(trimmed) || /^\d{15,}$/.test(trimmed);
32}
33
34async function parseSSEStream(response) {
35  const reader = response.body.getReader();
36  const decoder = new TextDecoder();
37  let buffer = '';
38
39  while (true) {
40    const { done, value } = await reader.read();
41    if (done) break;
42
43    buffer += decoder.decode(value, { stream: true });
44
45    const lines = buffer.split('\n');
46    buffer = lines.pop() || ''; // simpan baris terakhir yang belum lengkap
47
48    let currentEvent = null;
49
50    for (const line of lines) {
51      if (line.startsWith('event:')) {
52        currentEvent = line.slice(6).trim();
53      } else if (line.startsWith('data:')) {
54        const data = line.slice(5).trim();
55
56        if (currentEvent === 'result') {
57          try {
58            return JSON.parse(data);
59          } catch {
60            throw new Error('Unreadable response from server');
61          }
62        }
63
64        if (currentEvent === 'error') {
65          try {
66            const err = JSON.parse(data);
67            throw new Error(err.message || 'Something went wrong');
68          } catch (e) {
69            if (e instanceof SyntaxError) {
70              throw new Error('Something went wrong, try again');
71            }
72            throw e;
73          }
74        }
75      }
76    }
77  }
78
79  throw new Error('Connection closed before it finished, try again');
80}
81
82/**
83 * Cari preset Alight Motion dari link video TikTok
84 * @param {string} link_tiktok - URL video TikTok (mis. https://vt.tiktok.com/xxx)
85 * @returns {Promise<object>} Hasil berisi preset links, info video, dan author
86 */
87async function get_preset_links(link_tiktok) {
88  const url = (link_tiktok || '').trim();
89
90  if (!url) {
91    throw new Error('TikTok video link is required');
92  }
93  if (!isValidTikTokUrl(url)) {
94    throw new Error('That link is not from TikTok. Paste a TikTok video link first.');
95  }
96
97  const apiUrl = `${BASE_URL}/api/find?url=${encodeURIComponent(url)}`;
98
99  const controller = new AbortController();
100  const timeout = setTimeout(() => controller.abort(), 60_000); // timeout 60 detik
101
102  try {
103    const response = await fetch(apiUrl, {
104      method: 'GET',
105      headers: {
106        'Accept': 'text/event-stream',
107        'User-Agent': 'Mozilla/5.0 (compatible; AMFinderScraper/1.0)',
108      },
109      signal: controller.signal,
110    });
111
112    if (!response.ok) {
113      throw new Error(`Server responded with status ${response.status}`);
114    }
115
116    const contentType = response.headers.get('content-type') || '';
117    if (!contentType.includes('text/event-stream')) {
118      throw new Error('Unexpected response format from server');
119    }
120
121    const result = await parseSSEStream(response);
122
123    if (result.ok === false) {
124      throw new Error(result.error || 'The scraper could not process this link');
125    }
126
127    return {
128      ok: true,
129      author: result.author || null,
130      avatar: result.authorDetail?.avatar || null,
131      video: {
132        description: result.video?.description?.trim() || '',
133        cover: result.video?.cover || null,
134        playUrl: result.video?.playUrlNoWm || result.video?.playUrl || null,
135        width: result.video?.width || null,
136        height: result.video?.height || null,
137        stats: {
138          views: result.video?.stats?.views ?? null,
139          likes: result.video?.stats?.likes ?? null,
140          comments: result.video?.stats?.comments ?? null,
141        },
142      },
143      presetLinks: (result.presetLinks || []).map((p) => ({
144        title: p.title || (p.type === '5mb' ? '5MB preset' : 'XML file'),
145        url: p.url,
146        type: p.type,          // "5mb" | "xml"
147        size: p.size || null,
148        ratio: p.ratio || null,
149        thumb: p.thumb || null,
150        pinned: !!p.pinned,
151        byAuthor: !!p.byAuthor,
152        detail: p.detail || null,
153      })),
154    };
155  } catch (err) {
156    if (err.name === 'AbortError') {
157      throw new Error('Request timed out. Please try again.');
158    }
159    throw err;
160  } finally {
161    clearTimeout(timeout);
162  }
163}
164
165module.exports = { get_preset_links };
166
167(async () => {
168  try {
169    const result = await get_preset_links('https://vt.tiktok.com/ZSbmR9kCu/');
170
171    console.log('โœ… Author:', result.author);
172    console.log('๐Ÿ“Š Views:', result.video.stats.views);
173    console.log(`๐Ÿ”— Found ${result.presetLinks.length} preset(s):\n`);
174
175    for (const preset of result.presetLinks) {
176      console.log(`  ๐Ÿ“Œ ${preset.title}`);
177      console.log(`     Type: ${preset.type} | Size: ${preset.size || '-'}`);
178      console.log(`     URL: ${preset.url}`);
179      console.log(`     By Author: ${preset.byAuthor ? 'Yes' : 'No'}\n`);
180    }
181  } catch (err) {
182    console.error('โŒ Error:', err.message);
183  }
184})();
184 linesยท5,352 charsยท5.2 KB