const fs = require('fs'); const https = require('https'); const crawlTime = new Date().toISOString(); const seeds = []; function fetchJson(url) { return new Promise((resolve, reject) => { https.get(url, { headers: { 'User-Agent': 'Mozilla/5.0' } }, (res) => { let data = ''; res.on('data', chunk => data += chunk); res.on('end', () => { try { resolve(JSON.parse(data)); } catch (e) { reject(e); } }); }).on('error', reject); }); } function fetchHttp(url) { return new Promise((resolve, reject) => { https.get(url, { headers: { 'User-Agent': 'Mozilla/5.0' } }, (res) => { let data = ''; res.on('data', chunk => data += chunk); res.on('end', () => resolve(data)); }).on('error', reject); }); } async function collectHn(query, platformLabel) { const url = `https://hn.algolia.com/api/v1/search?query=${encodeURIComponent(query)}&tags=story&hitsPerPage=30`; const data = await fetchJson(url); for (const hit of data.hits || []) { seeds.push({ id: `hn-${hit.objectID}`, platform: platformLabel, trend_type: 'discussion', title: hit.title, url: hit.url || `https://news.ycombinator.com/item?id=${hit.objectID}`, metric: hit.points || 0, metric_label: 'points', comments: hit.num_comments || 0, author: hit.author, created_at: new Date(hit.created_at_i * 1000).toISOString(), description: '', source_url: url, crawl_time: crawlTime }); } } async function collectGitHub(query, platformLabel) { const url = `https://api.github.com/search/repositories?q=${encodeURIComponent(query)}&sort=updated&order=desc&per_page=30`; const data = await fetchJson(url); for (const item of data.items || []) { seeds.push({ id: `gh-${item.id}`, platform: platformLabel, trend_type: 'repo', title: item.full_name, url: item.html_url, metric: item.stargazers_count || 0, metric_label: 'stars', language: item.language || '', updated_at: item.updated_at, description: (item.description || '').slice(0, 200), source_url: url, crawl_time: crawlTime }); } } async function collectTikTokDiscover() { const url = 'https://www.tiktok.com/node/share/discover?noUser=1&userCount=50'; const data = await fetchJson(url); const list = data.body?.[0]?.exploreList || []; for (const x of list) { const ci = x.cardItem; seeds.push({ id: `tt-${ci.id}`, platform: 'tiktok', trend_type: 'hashtag', title: ci.title, url: `https://www.tiktok.com${ci.link}`, metric: ci.extraInfo?.views || 0, metric_label: 'views', cover: ci.cover || '', description: (ci.description || '').slice(0, 200), source_url: url, crawl_time: crawlTime }); } } async function collectProductHunt() { const url = 'https://www.producthunt.com/feed?category=tech'; const xml = await fetchHttp(url); const entryRegex = /([\s\S]*?)<\/entry>/g; let m; while ((m = entryRegex.exec(xml)) !== null) { const entry = m[1]; const idMatch = entry.match(/([^<]+)<\/id>/); const titleMatch = entry.match(/([^<]+)<\/title>/); const linkMatch = entry.match(/<link rel="alternate"[^>]+href="([^"]+)"/); const contentMatch = entry.match(/<content type="html"><!\[CDATA\[([\s\S]*?)\]\]>/); const publishedMatch = entry.match(/<published>([^<]+)<\/published>/); seeds.push({ id: `ph-${(idMatch?.[1] || '').replace(/.*\//, '')}`, platform: 'product_hunt', trend_type: 'product', title: titleMatch?.[1] || '', url: linkMatch?.[1] || '', metric: 0, metric_label: 'votes', description: ((contentMatch?.[1] || '').replace(/<[^>]+>/g, ' ').trim()).slice(0, 200), published_at: publishedMatch?.[1] || '', source_url: url, crawl_time: crawlTime }); } } (async () => { await collectTikTokDiscover(); await collectHn('tiktok', 'hn_tiktok'); await collectHn('youtube shorts', 'hn_youtube_shorts'); await collectHn('instagram reels', 'hn_instagram_reels'); await collectHn('twitter video', 'hn_twitter_video'); await collectGitHub('tiktok', 'github_tiktok'); await collectGitHub('youtube shorts', 'github_youtube_shorts'); await collectGitHub('instagram reels', 'github_instagram_reels'); await collectProductHunt(); const outPath = 'system/templates/trend-scout-global/train/hunt/seed_data.json'; fs.writeFileSync(outPath, JSON.stringify(seeds, null, 2)); console.log(`Wrote ${seeds.length} seeds to ${outPath}`); })();