hashtag.js
1 import { cli, Strategy } from '@jackwener/opencli/registry'; 2 import { browserFetch } from './_shared/browser-fetch.js'; 3 import { ArgumentError } from '@jackwener/opencli/errors'; 4 cli({ 5 site: 'douyin', 6 name: 'hashtag', 7 description: '话题搜索 / AI推荐 / 热点词', 8 domain: 'creator.douyin.com', 9 strategy: Strategy.COOKIE, 10 args: [ 11 { name: 'action', required: true, positional: true, choices: ['search', 'suggest', 'hot'], help: 'search=关键词搜索 suggest=AI推荐 hot=热点词' }, 12 { name: 'keyword', default: '', help: '搜索关键词(search/hot 使用)' }, 13 { name: 'cover', default: '', help: '封面 URI(suggest 使用)' }, 14 { name: 'limit', type: 'int', default: 10 }, 15 ], 16 columns: ['name', 'id', 'view_count'], 17 func: async (page, kwargs) => { 18 const action = kwargs.action; 19 if (action === 'search') { 20 const url = `https://creator.douyin.com/aweme/v1/challenge/search/?keyword=${encodeURIComponent(kwargs.keyword)}&count=${kwargs.limit}&aid=1128`; 21 const res = await browserFetch(page, 'GET', url); 22 return (res.challenge_list ?? []).map(c => ({ 23 name: c.challenge_info.cha_name, 24 id: c.challenge_info.cid, 25 view_count: c.challenge_info.view_count, 26 })); 27 } 28 if (action === 'suggest') { 29 const url = `https://creator.douyin.com/web/api/media/hashtag/rec/?cover_uri=${encodeURIComponent(kwargs.cover)}&aid=1128`; 30 const res = await browserFetch(page, 'GET', url); 31 return (res.hashtag_list ?? []).map(h => ({ name: h.name, id: h.id, view_count: h.view_count })); 32 } 33 if (action === 'hot') { 34 const kw = kwargs.keyword; 35 const url = `https://creator.douyin.com/aweme/v1/hotspot/recommend/?${kw ? `keyword=${encodeURIComponent(kw)}&` : ''}aid=1128`; 36 const res = await browserFetch(page, 'GET', url); 37 const items = res.hotspot_list 38 ?? res.all_sentences?.map(h => ({ 39 sentence: h.word ?? '', 40 hot_value: h.hot_value, 41 sentence_id: h.sentence_id ?? '', 42 })) 43 ?? []; 44 return items.slice(0, kwargs.limit).map(h => ({ 45 name: h.sentence, 46 id: 'sentence_id' in h ? h.sentence_id : '', 47 view_count: h.hot_value, 48 })); 49 } 50 throw new ArgumentError(`未知的 action: ${action}`); 51 }, 52 });