/ clis / douyin / hashtag.js
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  });