#!/usr/bin/env node /** 尝试不需 cookie 的 TikHub douyin endpoints + TikTok */ const fs = require('fs'); const path = require('path'); const os = require('os'); const https = require('https'); const TOKEN = JSON.parse(fs.readFileSync(path.join(os.homedir(), '.openclaw', 'skills', 'xiaohongshu-search-notes', 'api-config.json'), 'utf-8')).endpoint.headers.Authorization.replace(/^Bearer\s+/, ''); function req(opts) { return new Promise((resolve) => { const r = https.request(opts, (res) => { const chunks = []; res.on('data', (c) => chunks.push(c)); res.on('end', () => resolve({ status: res.statusCode, body: Buffer.concat(chunks).toString('utf-8') })); }); r.on('error', (e) => resolve({ status: 0, body: e.message })); r.setTimeout(30000, () => { r.destroy(); resolve({ status: 0, body: 'timeout' }); }); r.end(); }); } const kw = '乳酸菌素片'; const kwE = encodeURIComponent(kw); // 尝试各种可能不要 cookie 的 endpoints const tries = [ // Douyin web search variations `/thapi/v1/douyin/web/fetch_general_search_result?keyword=${kwE}&offset=0&count=20&sort_type=0&publish_time=0&search_channel=aweme_general`, // Specific challenge / hashtag search (不要 cookie) `/thapi/v1/douyin/web/fetch_challenge_search?keyword=${kwE}&offset=0&count=20`, `/thapi/v1/douyin/app/v1/fetch_challenge_search?keyword=${kwE}&offset=0&count=20`, // Hot video / hot search `/thapi/v1/douyin/web/fetch_hot_search_list`, `/thapi/v1/douyin/app/v3/fetch_hot_search_list`, // Video by ID (如果我们已知 aweme_id) `/thapi/v1/douyin/web/fetch_one_video?aweme_id=7358400000000000000`, // Live search `/thapi/v1/douyin/web/fetch_live_search?keyword=${kwE}&offset=0&count=20`, // User search `/thapi/v1/douyin/web/fetch_user_search_result?keyword=${kwE}&offset=0&count=20`, // TikTok (海外版) `/thapi/v1/tiktok/app/v3/fetch_general_search_result?keyword=${kwE}&offset=0&count=20`, `/thapi/v1/tiktok/web/fetch_general_search?keyword=${kwE}&offset=0&count=20`, ]; (async () => { for (const p of tries) { const r = await req({ hostname: 'server.fmode.cn', path: p, method: 'GET', headers: { Authorization: `Bearer ${TOKEN}`, Accept: 'application/json' }, }); let summary = ''; try { const j = JSON.parse(r.body); if (Array.isArray(j.data)) { const first = j.data[0]; summary = `data=Array(${j.data.length}), status_msg=${first?.status_msg || '(none)'}`; } else if (j.data) { const k = Object.keys(j.data); summary = `data=Object{${k.slice(0, 5).join(',')}}`; if (j.data.data && Array.isArray(j.data.data)) summary += `, data.data=Array(${j.data.data.length})`; if (j.data.aweme_list) summary += `, aweme_list=${j.data.aweme_list.length}`; if (j.data.user_list) summary += `, user_list=${j.data.user_list.length}`; if (j.data.challenge_list) summary += `, challenge_list=${j.data.challenge_list.length}`; } else if (j.detail) { summary = `detail=${JSON.stringify(j.detail).slice(0, 80)}`; } } catch (e) { summary = r.body.slice(0, 80); } console.log(`[${r.status}] ${p.slice(0, 85)}`); console.log(` → ${summary}`); await new Promise((r) => setTimeout(r, 700)); } })();