@streamapp/stream 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -0
- package/bin/stream.mjs +89 -0
- package/package.json +34 -0
- package/resources/app/dist-panel/panel-boards.js +6 -0
- package/resources/app/dist-panel/panel-detail.css +1 -0
- package/resources/app/dist-panel/panel-detail.js +2141 -0
- package/resources/app/dist-panel/panel-manage.css +1 -0
- package/resources/app/dist-panel/panel-manage.js +2246 -0
- package/resources/app/dist-panel/panel-movie.css +1 -0
- package/resources/app/dist-panel/panel-movie.js +2268 -0
- package/resources/app/dist-panel/panel-research.css +1 -0
- package/resources/app/dist-panel/panel-research.js +316 -0
- package/resources/app/dist-panel/panel.css +1 -0
- package/resources/app/dist-panel/panel.js +463 -0
- package/resources/dsh-engine-lock/package-lock.json +9032 -0
- package/resources/extension/.output/chrome-mv3/assets/popup-C2NUZZQW.css +2 -0
- package/resources/extension/.output/chrome-mv3/background.js +1 -0
- package/resources/extension/.output/chrome-mv3/chunks/popup-BeBts9v2.js +50 -0
- package/resources/extension/.output/chrome-mv3/icon/128.png +0 -0
- package/resources/extension/.output/chrome-mv3/icon/16.png +0 -0
- package/resources/extension/.output/chrome-mv3/icon/32.png +0 -0
- package/resources/extension/.output/chrome-mv3/icon/48.png +0 -0
- package/resources/extension/.output/chrome-mv3/icon/96.png +0 -0
- package/resources/extension/.output/chrome-mv3/manifest.json +1 -0
- package/resources/extension/.output/chrome-mv3/popup.html +21 -0
- package/resources/packages/1lou/1lou-search.recipe.json +102 -0
- package/resources/packages/1lou/README.md +7 -0
- package/resources/packages/1lou/package.json +15 -0
- package/resources/packages/Douyin_TikTok_Download_API/README.md +23 -0
- package/resources/packages/Douyin_TikTok_Download_API/activate.ts +14 -0
- package/resources/packages/Douyin_TikTok_Download_API/adapter/adapter.ts +321 -0
- package/resources/packages/Douyin_TikTok_Download_API/adapter/danmaku.ts +21 -0
- package/resources/packages/Douyin_TikTok_Download_API/adapter/executor.ts +75 -0
- package/resources/packages/Douyin_TikTok_Download_API/adapter/normalize.ts +20 -0
- package/resources/packages/Douyin_TikTok_Download_API/manifests.yaml +521 -0
- package/resources/packages/Douyin_TikTok_Download_API/package.json +32 -0
- package/resources/packages/alist/README.md +14 -0
- package/resources/packages/alist/activate.ts +12 -0
- package/resources/packages/alist/adapter.ts +74 -0
- package/resources/packages/alist/manifests.yaml +76 -0
- package/resources/packages/alist/mounts.ts +120 -0
- package/resources/packages/alist/package.json +24 -0
- package/resources/packages/alist/presets.ts +53 -0
- package/resources/packages/alist/provision.ts +84 -0
- package/resources/packages/baidu/baidu-share.recipe.json +93 -0
- package/resources/packages/baidu/package.json +16 -0
- package/resources/packages/baidu-search/baidu-search.recipe.json +129 -0
- package/resources/packages/baidu-search/package.json +25 -0
- package/resources/packages/brave/brave-search.recipe.json +129 -0
- package/resources/packages/brave/package.json +25 -0
- package/resources/packages/browser/README.md +3 -0
- package/resources/packages/browser/adapter.ts +44 -0
- package/resources/packages/browser/manifests.yaml +20 -0
- package/resources/packages/browser/package.json +13 -0
- package/resources/packages/bt0/README.md +7 -0
- package/resources/packages/bt0/bt0-search.recipe.json +69 -0
- package/resources/packages/bt0/bt0-tlist.recipe.json +74 -0
- package/resources/packages/bt0/package.json +15 -0
- package/resources/packages/btbtla/README.md +6 -0
- package/resources/packages/btbtla/btbtla-detail.recipe.json +76 -0
- package/resources/packages/btbtla/btbtla-search.recipe.json +74 -0
- package/resources/packages/btbtla/package.json +15 -0
- package/resources/packages/builtin/README.md +8 -0
- package/resources/packages/builtin/manifests.yaml +487 -0
- package/resources/packages/builtin/package.json +14 -0
- package/resources/packages/douyin/README.md +39 -0
- package/resources/packages/douyin/douyin-collection.recipe.json +127 -0
- package/resources/packages/douyin/douyin-search.recipe.json +163 -0
- package/resources/packages/douyin/package.json +16 -0
- package/resources/packages/firecrawl/firecrawl-create-key.recipe.json +81 -0
- package/resources/packages/firecrawl/firecrawl-read-key.recipe.json +56 -0
- package/resources/packages/firecrawl/package.json +16 -0
- package/resources/packages/google/google-search.recipe.json +127 -0
- package/resources/packages/google/package.json +24 -0
- package/resources/packages/groq/groq-create-key.recipe.json +67 -0
- package/resources/packages/groq/package.json +16 -0
- package/resources/packages/huggingface/README.md +7 -0
- package/resources/packages/huggingface/huggingface-spaces.recipe.json +73 -0
- package/resources/packages/huggingface/package.json +15 -0
- package/resources/packages/imdb/imdb-chart.recipe.json +75 -0
- package/resources/packages/imdb/package.json +15 -0
- package/resources/packages/index.ts +15 -0
- package/resources/packages/iqiyi/README.md +10 -0
- package/resources/packages/iqiyi/iqiyi-cn-album.recipe.json +80 -0
- package/resources/packages/iqiyi/iqiyi-cn-search.recipe.json +71 -0
- package/resources/packages/iqiyi/package.json +15 -0
- package/resources/packages/lizhi/README.md +35 -0
- package/resources/packages/lizhi/lizhi-user.recipe.json +80 -0
- package/resources/packages/lizhi/package.json +15 -0
- package/resources/packages/manmanbuy/README.md +16 -0
- package/resources/packages/manmanbuy/manmanbuy-search.recipe.json +115 -0
- package/resources/packages/manmanbuy/package.json +15 -0
- package/resources/packages/mineru/README.md +38 -0
- package/resources/packages/mineru/package.json +28 -0
- package/resources/packages/pansou/README.md +14 -0
- package/resources/packages/pansou/activate.ts +11 -0
- package/resources/packages/pansou/adapter.ts +94 -0
- package/resources/packages/pansou/manifests.yaml +50 -0
- package/resources/packages/pansou/package.json +27 -0
- package/resources/packages/qq/package.json +15 -0
- package/resources/packages/qq/qq-send.recipe.json +104 -0
- package/resources/packages/quark/package.json +16 -0
- package/resources/packages/quark/quark-share.recipe.json +40 -0
- package/resources/packages/reddit/package.json +15 -0
- package/resources/packages/reddit/reddit-sub.recipe.json +77 -0
- package/resources/packages/replay/README.md +7 -0
- package/resources/packages/replay/package.json +13 -0
- package/resources/packages/rsshub/README.md +16 -0
- package/resources/packages/rsshub/manifests.yaml +107 -0
- package/resources/packages/rsshub/package.json +21 -0
- package/resources/packages/telegram/package.json +15 -0
- package/resources/packages/telegram/telegram-search.recipe.json +125 -0
- package/resources/packages/tencent/README.md +11 -0
- package/resources/packages/tencent/package.json +15 -0
- package/resources/packages/tencent/tencent-cn-episode.recipe.json +98 -0
- package/resources/packages/toubiec/README.md +38 -0
- package/resources/packages/toubiec/package.json +15 -0
- package/resources/packages/toubiec/toubiec-download.recipe.json +58 -0
- package/resources/packages/toubiec/toubiec-playlist.recipe.json +49 -0
- package/resources/packages/toubiec/toubiec-search.recipe.json +80 -0
- package/resources/packages/voiceprint/README.md +31 -0
- package/resources/packages/voiceprint/package.json +36 -0
- package/resources/packages/wikipedia/package.json +15 -0
- package/resources/packages/wikipedia/wikipedia-award-list.recipe.json +102 -0
- package/resources/packages/xhs/README.md +32 -0
- package/resources/packages/xhs/package.json +21 -0
- package/resources/packages/xhs/xhs-detail.recipe.json +129 -0
- package/resources/packages/xhs/xhs-home.recipe.json +144 -0
- package/resources/packages/xhs/xhs-like.recipe.json +96 -0
- package/resources/packages/xhs/xhs-search.recipe.json +138 -0
- package/resources/packages/xueqiu/README.md +9 -0
- package/resources/packages/xueqiu/package.json +16 -0
- package/resources/packages/xueqiu/xueqiu-detail.recipe.json +92 -0
- package/resources/packages/xueqiu/xueqiu-user.recipe.json +75 -0
- package/resources/packages/zhipu/package.json +16 -0
- package/resources/packages/zhipu/zhipu-create-key.recipe.json +74 -0
- package/resources/packages/zuna/README.md +31 -0
- package/resources/packages/zuna/package.json +15 -0
- package/resources/packages/zuna/zuna-album.recipe.json +46 -0
- package/resources/packages/zuna/zuna-download.recipe.json +53 -0
- package/resources/packages/zuna/zuna-playlist.recipe.json +46 -0
- package/resources/packages/zuna/zuna-search.recipe.json +96 -0
- package/resources/server.mjs +238876 -0
- package/resources/sidequest.jobs.js +1 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"kind": "http",
|
|
4
|
+
"sourceId": "toubiec-playlist",
|
|
5
|
+
"request": {
|
|
6
|
+
"url": "https://nextmusic.toubiec.cn/api/playlist_trackall",
|
|
7
|
+
"method": "POST",
|
|
8
|
+
"headers": { "content-type": "application/json" }
|
|
9
|
+
},
|
|
10
|
+
"compute": {
|
|
11
|
+
"capabilities": [],
|
|
12
|
+
"prefetch": [
|
|
13
|
+
{ "as": "ipResp", "request": { "url": "https://nextmusic.toubiec.cn/api/ip", "method": "GET" } }
|
|
14
|
+
],
|
|
15
|
+
"sign": "(() => { const ip = (input.pre.ipResp && input.pre.ipResp.data && input.pre.ipResp.data.ip) || '0.0.0.0'; return { body: JSON.stringify({ id: String(input.params.id), limit: 1000, offset: 0, ip }) }; })()"
|
|
16
|
+
},
|
|
17
|
+
"pagination": { "mode": "increment", "param": "page", "start": 1, "step": 1, "itemsAt": "data.songs", "maxPages": 1 },
|
|
18
|
+
"assert": [{ "path": "data.songs", "desc": "toubiec playlist_trackall returned data.songs[] (one request, full list)" }],
|
|
19
|
+
"mapping": {
|
|
20
|
+
"guid": "id",
|
|
21
|
+
"title": "name",
|
|
22
|
+
"author": "singer",
|
|
23
|
+
"link": "https://music.163.com/song?id={id}",
|
|
24
|
+
"description": "album",
|
|
25
|
+
"image": "picimg",
|
|
26
|
+
"pubDate": "time"
|
|
27
|
+
},
|
|
28
|
+
"meta": {
|
|
29
|
+
"normalizer": "rsshub",
|
|
30
|
+
"type": "post",
|
|
31
|
+
"title": "歌单曲目",
|
|
32
|
+
"description": "toubiec 网易云解析 — 歌单曲目(整份名单一次取回;每首歌的文件地址在播放/下载时由 netease-track 现解)",
|
|
33
|
+
"topics": ["toubiec", "网易云", "音乐", "歌单", "music", "netease"],
|
|
34
|
+
"categories": ["music"],
|
|
35
|
+
"facility": { "key": "toubiec", "label": "toubiec" },
|
|
36
|
+
"capabilities": ["timeline"],
|
|
37
|
+
"mode": "collection",
|
|
38
|
+
"key_param": "id",
|
|
39
|
+
"priority": 80,
|
|
40
|
+
"discoverable": true,
|
|
41
|
+
"cadence_hint_seconds": 86400,
|
|
42
|
+
"auth": { "type": "none" },
|
|
43
|
+
"homepage": "wyapi.toubiec.cn",
|
|
44
|
+
"params_schema": {
|
|
45
|
+
"id": { "type": "string", "required": true, "description": "网易云歌单 ID(取自 music.163.com/playlist?id=…)" }
|
|
46
|
+
},
|
|
47
|
+
"radar": ["music.163.com/playlist"]
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"kind": "http",
|
|
4
|
+
"sourceId": "toubiec-search",
|
|
5
|
+
"request": {
|
|
6
|
+
"url": "https://nextmusic.toubiec.cn/api/search",
|
|
7
|
+
"method": "POST",
|
|
8
|
+
"headers": {
|
|
9
|
+
"content-type": "application/json"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"compute": {
|
|
13
|
+
"capabilities": [],
|
|
14
|
+
"prefetch": [
|
|
15
|
+
{ "as": "ipResp", "request": { "url": "https://nextmusic.toubiec.cn/api/ip", "method": "GET" } }
|
|
16
|
+
],
|
|
17
|
+
"sign": "(() => { const ip = (input.pre.ipResp && input.pre.ipResp.data && input.pre.ipResp.data.ip) || '0.0.0.0'; return { body: JSON.stringify({ keyword: input.params.keyword, limit: 100, offset: 0, ip }) }; })()"
|
|
18
|
+
},
|
|
19
|
+
"pagination": {
|
|
20
|
+
"mode": "increment",
|
|
21
|
+
"param": "page",
|
|
22
|
+
"start": 1,
|
|
23
|
+
"step": 1,
|
|
24
|
+
"itemsAt": "data.songs",
|
|
25
|
+
"maxPages": 1
|
|
26
|
+
},
|
|
27
|
+
"assert": [
|
|
28
|
+
{
|
|
29
|
+
"path": "data.songs",
|
|
30
|
+
"desc": "toubiec search returned data.songs[]"
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"mapping": {
|
|
34
|
+
"guid": "id",
|
|
35
|
+
"title": "name",
|
|
36
|
+
"author": "singer",
|
|
37
|
+
"link": "https://music.163.com/song?id={id}",
|
|
38
|
+
"description": "album",
|
|
39
|
+
"image": "picimg",
|
|
40
|
+
"pubDate": "time"
|
|
41
|
+
},
|
|
42
|
+
"meta": {
|
|
43
|
+
"normalizer": "rsshub",
|
|
44
|
+
"type": "post",
|
|
45
|
+
"description": "toubiec 网易云解析 — 搜索",
|
|
46
|
+
"topics": [
|
|
47
|
+
"toubiec",
|
|
48
|
+
"网易云",
|
|
49
|
+
"音乐",
|
|
50
|
+
"搜索",
|
|
51
|
+
"music",
|
|
52
|
+
"netease"
|
|
53
|
+
],
|
|
54
|
+
"categories": [
|
|
55
|
+
"music"
|
|
56
|
+
],
|
|
57
|
+
"facility": {
|
|
58
|
+
"key": "toubiec",
|
|
59
|
+
"label": "toubiec"
|
|
60
|
+
},
|
|
61
|
+
"capabilities": [
|
|
62
|
+
"search"
|
|
63
|
+
],
|
|
64
|
+
"key_param": "keyword",
|
|
65
|
+
"priority": 80,
|
|
66
|
+
"discoverable": true,
|
|
67
|
+
"cadence_hint_seconds": 3600,
|
|
68
|
+
"auth": {
|
|
69
|
+
"type": "none"
|
|
70
|
+
},
|
|
71
|
+
"homepage": "wyapi.toubiec.cn",
|
|
72
|
+
"params_schema": {
|
|
73
|
+
"keyword": {
|
|
74
|
+
"type": "string",
|
|
75
|
+
"required": true,
|
|
76
|
+
"description": "搜索关键词(歌名/歌手/专辑)"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Voiceprint
|
|
2
|
+
|
|
3
|
+
sherpa-onnx diarization + speaker embedding backend (no credentials, no source).
|
|
4
|
+
Service-only plugin: contributes a backend container reached via the gateway at `/_p/voiceprint`.
|
|
5
|
+
Registers no source adapter.
|
|
6
|
+
|
|
7
|
+
GPU-ONLY(用户拍板 2026-07-23):CPU 上 diarization ~0.9x 实时,2 小时综艺要跑近 2 小时,功能本身
|
|
8
|
+
失去意义——不做 CPU/GPU 双变体,镜像只出 CUDA 版(`containers/voiceprint/Dockerfile`,轻量 slim +
|
|
9
|
+
pip cu11 轮子方案,同 whisper-asr)。代价:无 GPU 的主机起不了这个服务(compose 的 nvidia 预留硬性
|
|
10
|
+
要求 nvidia container toolkit)。
|
|
11
|
+
|
|
12
|
+
## backend
|
|
13
|
+
|
|
14
|
+
- `gpu: true` —— GPU-only 镜像 ⇒ 让 compose 发 nvidia 设备预留(容器里 libcuda 来自宿主驱动)。
|
|
15
|
+
- `env.VOICEPRINT_HINT_DEFAULT` —— sherpa-onnx model bundle (segmentation + speaker embedding) baked
|
|
16
|
+
into the image.
|
|
17
|
+
- `env.VOICEPRINT_USE_CUDA` —— GPU-only 镜像显式要 cuda provider。`app.py` 仍留 cuda→cpu 兜底(宿主
|
|
18
|
+
GPU 抽风时降级慢跑,不至于整个能力挂掉),`/health` 的 provider 字段报的是实际生效的那个——盯它验真。
|
|
19
|
+
- `env.VOICEPRINT_MODEL_VERSION` —— Vector-comparability key: pinned to the baked
|
|
20
|
+
segmentation+embedding model pair (3D-Speaker ERes2NetV2, Chinese zh-cn common, 16k, 192-dim).
|
|
21
|
+
Bump only if the baked models change — old voiceprints of a different version are treated as
|
|
22
|
+
incomparable.
|
|
23
|
+
- `env.VOICEPRINT_DFN` —— DFN 前置清洗试用开关(2026-07-27 证伪缺省关;用户手动开做端到端体验,
|
|
24
|
+
随时可撤此项恢复)。
|
|
25
|
+
- `dev` —— 源码 bind-mount + `uvicorn --reload`,改 `app.py` 不用重建镜像(产出时仍走 baked image)。
|
|
26
|
+
两处不能想当然:
|
|
27
|
+
1. **base image 就复用烤好的那个** —— 依赖(sherpa-onnx +cuda 轮子、cudnn)和模型(`/app/models`,
|
|
28
|
+
几百 MB)都在里面,换个干净 python 镜像等于要重装一遍。
|
|
29
|
+
2. **挂到 `/src` 而不是 `/app`** —— `app.py` 在 `/app`、模型也在 `/app/models`;把源码挂到 `/app`
|
|
30
|
+
会把模型目录整个盖掉。代码里模型是绝对路径(`/app/models/...`),所以工作目录换到 `/src`
|
|
31
|
+
照样解析得到。
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@streamapp/voiceprint",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"stream": {
|
|
7
|
+
"id": "voiceprint",
|
|
8
|
+
"name": "Diarization",
|
|
9
|
+
"tagline": "分离说话人 + 认出是谁",
|
|
10
|
+
"description": "把一段音频切成「谁在什么时候说话」,再把每个人的嗓音转成一串数字存进声纹库——认过一次,以后在别的节目里再遇到同一个人也能认出来。用来做「只听某个人说的部分」。只出 GPU 版:没有显卡的机器起不了它(CPU 上跑两小时的综艺要花近两小时,功能本身就没意义了)。",
|
|
11
|
+
"backend": {
|
|
12
|
+
"image": "ghcr.io/jaggerh/voiceprint-server:latest",
|
|
13
|
+
"service": "voiceprint",
|
|
14
|
+
"port": 80,
|
|
15
|
+
"health": "/health",
|
|
16
|
+
"gpu": true,
|
|
17
|
+
"env": {
|
|
18
|
+
"VOICEPRINT_HINT_DEFAULT": "accuracy",
|
|
19
|
+
"VOICEPRINT_USE_CUDA": "1",
|
|
20
|
+
"VOICEPRINT_MODEL_VERSION": "sherpa-eres2netv2-zhcn-192-v1",
|
|
21
|
+
"VOICEPRINT_DFN": "1"
|
|
22
|
+
},
|
|
23
|
+
"volumes": ["voiceprint-cache:/root/.cache"],
|
|
24
|
+
"dev": {
|
|
25
|
+
"image": "ghcr.io/jaggerh/voiceprint-server:latest",
|
|
26
|
+
"mount": "./containers/voiceprint",
|
|
27
|
+
"workdir": "/src",
|
|
28
|
+
"command": "uvicorn app:app --host 0.0.0.0 --port 80 --reload"
|
|
29
|
+
},
|
|
30
|
+
"mem": "4G",
|
|
31
|
+
"standby": {
|
|
32
|
+
"idleMinutes": 10
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@streamapp/wikipedia",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"author": "stream",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"stream-recipe"
|
|
7
|
+
],
|
|
8
|
+
"stream": {
|
|
9
|
+
"type": "recipe",
|
|
10
|
+
"name": "Wikipedia",
|
|
11
|
+
"tagline": "某个奖项的历年获奖名单",
|
|
12
|
+
"facility": "wikipedia",
|
|
13
|
+
"schemaVersion": 1
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"kind": "html",
|
|
4
|
+
"sourceId": "wikipedia-award-list",
|
|
5
|
+
"request": {
|
|
6
|
+
"url": "https://en.wikipedia.org/wiki/{page}",
|
|
7
|
+
"method": "GET",
|
|
8
|
+
"headers": {
|
|
9
|
+
"accept": "text/html",
|
|
10
|
+
"accept-language": "en"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"list": {
|
|
14
|
+
"selector": "table.wikitable tr:has(td i a)",
|
|
15
|
+
"limit": 400,
|
|
16
|
+
"fields": {
|
|
17
|
+
"title": { "selector": "td i a", "text": true },
|
|
18
|
+
"link": { "selector": "td i a", "attr": "href", "resolve": true },
|
|
19
|
+
"guid": { "selector": "td i a", "attr": "href" },
|
|
20
|
+
"description": { "text": true }
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"detail": {
|
|
24
|
+
"urlFrom": "link",
|
|
25
|
+
"fields": {
|
|
26
|
+
"imdb_id": {
|
|
27
|
+
"selector": [
|
|
28
|
+
"a[href*=\"imdb.com/title/tt\"]:not(cite *)",
|
|
29
|
+
"a[href*=\"imdb.com/title/tt\"]"
|
|
30
|
+
],
|
|
31
|
+
"attr": "href"
|
|
32
|
+
},
|
|
33
|
+
"wikidata_id": { "selector": "a[href*=\"wikidata.org/wiki/\"]", "attr": "href" },
|
|
34
|
+
"wikidata_qid": {
|
|
35
|
+
"selector": "a[href*=\"wikidata.org/wiki/\"]",
|
|
36
|
+
"attr": "href",
|
|
37
|
+
"extract": "wikidata\\.org/wiki/(?:Special:EntityPage/)?(Q\\d+)"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"hops": [
|
|
42
|
+
{
|
|
43
|
+
"url": "https://www.wikidata.org/w/api.php?action=wbgetclaims&entity={wikidata_qid}&property=P4947&format=json",
|
|
44
|
+
"parse": "json",
|
|
45
|
+
"headers": { "accept": "application/json" },
|
|
46
|
+
"fields": {
|
|
47
|
+
"tmdb_movie_id": { "path": "claims.P4947.0.mainsnak.datavalue.value", "extract": "^\\d+$" }
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"url": "https://www.wikidata.org/w/api.php?action=wbgetclaims&entity={wikidata_qid}&property=P4983&format=json",
|
|
52
|
+
"parse": "json",
|
|
53
|
+
"headers": { "accept": "application/json" },
|
|
54
|
+
"fields": {
|
|
55
|
+
"tmdb_tv_id": { "path": "claims.P4983.0.mainsnak.datavalue.value", "extract": "^\\d+$" }
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"url": "https://www.wikidata.org/w/api.php?action=wbgetclaims&entity={wikidata_qid}&property=P345&format=json",
|
|
60
|
+
"parse": "json",
|
|
61
|
+
"headers": { "accept": "application/json" },
|
|
62
|
+
"fields": {
|
|
63
|
+
"imdb_id": { "path": "claims.P345.0.mainsnak.datavalue.value", "extract": "^tt\\d+$" }
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
],
|
|
67
|
+
"pagination": {
|
|
68
|
+
"mode": "increment",
|
|
69
|
+
"param": "_unused",
|
|
70
|
+
"start": 1,
|
|
71
|
+
"step": 1,
|
|
72
|
+
"maxPages": 1
|
|
73
|
+
},
|
|
74
|
+
"assert": [
|
|
75
|
+
{
|
|
76
|
+
"selector": "table.wikitable tr:has(td i a)",
|
|
77
|
+
"desc": "Wikipedia award table with linked italic work titles"
|
|
78
|
+
}
|
|
79
|
+
],
|
|
80
|
+
"meta": {
|
|
81
|
+
"title": "Wikipedia 奖项名单",
|
|
82
|
+
"description": "Wikipedia 上某个奖项分类的历年获奖/提名名单:一行一部作品,取斜体链接的作品名 + 条目链接,再进作品自己的条目取它的 IMDb 标识。本源只交身份证据、不解析任何元数据——标题/年份/类型/海报一律由影视详情那条既有链路从 TMDb 取(凭 IMDb id 直取,不走片名年份的模糊匹配)。",
|
|
83
|
+
"topics": ["wikipedia", "奖项", "获奖", "榜单", "影视", "剧集", "动画", "award", "winners"],
|
|
84
|
+
"categories": ["video"],
|
|
85
|
+
"capabilities": ["timeline"],
|
|
86
|
+
"mode": "collection",
|
|
87
|
+
"type": "post",
|
|
88
|
+
"key_param": "page",
|
|
89
|
+
"discoverable": true,
|
|
90
|
+
"cadence_hint_seconds": 604800,
|
|
91
|
+
"auth": { "type": "none" },
|
|
92
|
+
"homepage": "en.wikipedia.org",
|
|
93
|
+
"facility": { "key": "wikipedia", "label": "Wikipedia" },
|
|
94
|
+
"params_schema": {
|
|
95
|
+
"page": {
|
|
96
|
+
"type": "string",
|
|
97
|
+
"required": true,
|
|
98
|
+
"description": "英文维基条目标题(URL 里 /wiki/ 后面那一段),如 Children%27s_and_Family_Emmy_Award_for_Outstanding_Preschool_Animated_Series"
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
|
|
2
|
+
## 说明
|
|
3
|
+
|
|
4
|
+
落到小红书上的频率闸门(一次 recipe 运行 = 一次访问:搜索 / detail / 互动各算一次)。
|
|
5
|
+
|
|
6
|
+
为什么是 6/分钟 + burst 5:2026-07-29 撞过一次登录墙,形态是几分钟内连续打了十来次
|
|
7
|
+
detail(拟人光标和 900ms 动作间隔全程开着,照样撞)。站点数的是频率,所以这里压的是
|
|
8
|
+
持续速率;burst 留 5 是因为真人本来就一阵一阵——连点五条笔记再去读十分钟,是正常节奏,
|
|
9
|
+
不该每条都罚站。
|
|
10
|
+
|
|
11
|
+
maxWaitMs 15s:前台点开一条笔记,等 3 秒是加载、等 90 秒是坏了。超过就明确告诉用户
|
|
12
|
+
"太快了,X 秒后再试",而不是转一个不会停的圈。
|
|
13
|
+
|
|
14
|
+
## 说明(迁自 manifests.yaml 注释)
|
|
15
|
+
|
|
16
|
+
小红书 — replay Tier-C DOM harvest sources(跑在用户自己的 Chrome 上)。登录态浏览器采集:
|
|
17
|
+
人性化滚动,运行期零 token。
|
|
18
|
+
|
|
19
|
+
login detect 的便宜那一半(xhs-home/xhs-search/xhs-detail/xhs-like 的 auth 块共用):这些
|
|
20
|
+
cookie(sessionCookies)一个都不在 ⇒ 一定没登录,不必开 tab;反过来不成立(cookie 在不代表
|
|
21
|
+
服务端还认),肯定判据仍是 recipe 的 loginCheck 选择器。
|
|
22
|
+
|
|
23
|
+
xhs-search 的 `provides:[search-content]` —— 加入 content-search provider 的
|
|
24
|
+
{mode:auto, provides:search-content} 扇出。
|
|
25
|
+
|
|
26
|
+
xhs-detail:单条笔记详情(图组/视频流/正文/评论)——登录态 tab 内调站点 feed 详情签名客户端。
|
|
27
|
+
on-open 懒加载 enrich 用,不进推荐/时间线,故 discoverable:false。
|
|
28
|
+
|
|
29
|
+
xhs-like:互动写入(点赞/收藏)——登录态 tab 内调站点签名接口写用户账户。knowingly 放宽 recipe
|
|
30
|
+
只读边界(Gap C,见 spec 2026-07-18 §2)。context-free——无需打开笔记,只要 noteId + action。
|
|
31
|
+
on-demand 互动,从不被调度;cadence_hint_seconds 的取值同 xhs-detail(实际不生效,schema 只是
|
|
32
|
+
要求正数)。
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@streamapp/xhs",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"author": "stream",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"stream-recipe"
|
|
7
|
+
],
|
|
8
|
+
"stream": {
|
|
9
|
+
"type": "recipe",
|
|
10
|
+
"name": "小红书",
|
|
11
|
+
"tagline": "关键词搜索,登录态浏览器采集",
|
|
12
|
+
"facility": "xhs",
|
|
13
|
+
"schemaVersion": 1,
|
|
14
|
+
"cookieDomain": "xiaohongshu.com",
|
|
15
|
+
"rateLimit": {
|
|
16
|
+
"burst": 5,
|
|
17
|
+
"perMinute": 6,
|
|
18
|
+
"maxWaitMs": 15000
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 5,
|
|
3
|
+
"kind": "browser",
|
|
4
|
+
"sourceId": "xhs-detail",
|
|
5
|
+
"cookieDomain": "xiaohongshu.com",
|
|
6
|
+
"_why_entryUrl": "这个 recipe 的工作上下文是 feed(在 feed 上找卡片、点开 overlay),不是目标笔记页——目标笔记页是 step.fallbackUrl 的活。rideCurrentPage 让入场导航整段跳过,所以 entryUrl 只是**落点的兜底**:真正的落点是骑进来时标签停在哪(今天是搜索结果页,账本就是那一批);只有那一页认不出来(冷启的 about:blank、或上一次 fallback 把标签停在笔记页上)才回到这里。曾经这里填的是和 fallbackUrl 一模一样的笔记页——那样落点确认会把「停在笔记页」当成已经回到 entry,等于没确认。",
|
|
7
|
+
"entryUrl": "https://www.xiaohongshu.com/explore",
|
|
8
|
+
"entryWait": "domcontentloaded",
|
|
9
|
+
"rideCurrentPage": true,
|
|
10
|
+
"loginCheck": {
|
|
11
|
+
"loggedIn": ".main-container .user",
|
|
12
|
+
"wall": ".login-modal.reds-modal-open"
|
|
13
|
+
},
|
|
14
|
+
"session": {
|
|
15
|
+
"facility": "xhs",
|
|
16
|
+
"lifecycle": "persistent",
|
|
17
|
+
"visibility": "unattended"
|
|
18
|
+
},
|
|
19
|
+
"_why_unattended": "后台档(unattended):**不抢屏**。用户在 Stream 里点一下,屏幕就该留在 Stream —— 浏览器蹦到面前再缩回去,比它省下的那点时间烦得多。\n\n「前台」和「能不能跑」本来就不是一回事。可信输入不是靠占前台换来的,是靠 `Emulation.setFocusEmulationEnabled`(在 `browser-ext.ts` 的 launch 一处开启,那里有对照数字)——**它给的是「页面被当成有焦点」,不是帧**,别把两件事说成一件。开了之后,隐藏标签一次可信点击 **162–185ms**,比它当活动标签时的 204–257ms 还快;不开则是 **39.8–41.6s**。\n\n本条另有一层:locate 的「滚动」实测是 0 次滚轮——卡片还在 DOM 里就直接读 docY 一步跳过去(账本第 1 条和第 40 条分别是 0 次和 1 次 jump),所以连滚动那半个理由也是虚的。",
|
|
20
|
+
"steps": [
|
|
21
|
+
{
|
|
22
|
+
"_why_selector": "两种落地形状都收:/explore/<id> 与 /search_result/<id>。账本来源换成 search feed 之后,卡片可能挂在后一种路径下——只认 /explore/ 会让视口里一张「认识的卡」都没有,locate 当场 MISS、每次 detail 都退化成整页导航(有数据、不报错,最坏的一种坏)。findCard/openTarget 用的是 href.includes(id),本来就两种都认。",
|
|
23
|
+
"kind": "locate",
|
|
24
|
+
"selector": "a[href*=\"/explore/\"], a[href*=\"/search_result/\"]",
|
|
25
|
+
"identityParam": "noteId",
|
|
26
|
+
"orderedParam": "ordered",
|
|
27
|
+
"maxSteps": 8,
|
|
28
|
+
"restore": "back",
|
|
29
|
+
"fallbackUrl": "https://www.xiaohongshu.com/explore/{noteId}?xsec_token={xsec_token}&xsec_source=pc_feed"
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
"observers": [
|
|
33
|
+
{
|
|
34
|
+
"kind": "state",
|
|
35
|
+
"statePath": "__INITIAL_STATE__.note.noteDetailMap",
|
|
36
|
+
"trigger": "after-step",
|
|
37
|
+
"collection": "values",
|
|
38
|
+
"keyField": "noteId",
|
|
39
|
+
"identityParam": "noteId",
|
|
40
|
+
"readyWhen": "comments.firstRequestFinish",
|
|
41
|
+
"maxWaitMs": 15000,
|
|
42
|
+
"pollMs": 50,
|
|
43
|
+
"input": {
|
|
44
|
+
"itemsAt": "items",
|
|
45
|
+
"dedupeBy": "noteId",
|
|
46
|
+
"targetCount": 1,
|
|
47
|
+
"mapping": {
|
|
48
|
+
"noteId": "noteId",
|
|
49
|
+
"guid": "noteId",
|
|
50
|
+
"title": "note.title",
|
|
51
|
+
"desc": "note.desc",
|
|
52
|
+
"author": "note.user.nickname",
|
|
53
|
+
"author_avatar": "note.user.avatar",
|
|
54
|
+
"note_type": "note.type",
|
|
55
|
+
"imageList": "note.imageList",
|
|
56
|
+
"video_stream": "note.video.media.stream",
|
|
57
|
+
"comments": "comments.list"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
],
|
|
62
|
+
"output": {
|
|
63
|
+
"itemsAt": "items",
|
|
64
|
+
"dedupeBy": "noteId",
|
|
65
|
+
"targetCount": 1,
|
|
66
|
+
"mapping": {
|
|
67
|
+
"noteId": "noteId",
|
|
68
|
+
"guid": "guid",
|
|
69
|
+
"title": "title",
|
|
70
|
+
"desc": "desc",
|
|
71
|
+
"imageList": "imageList",
|
|
72
|
+
"video_stream": "video_stream",
|
|
73
|
+
"comments": "comments"
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"policy": {
|
|
77
|
+
"maxTaskMs": 30000
|
|
78
|
+
},
|
|
79
|
+
"meta": {
|
|
80
|
+
"auth": {
|
|
81
|
+
"type": "session",
|
|
82
|
+
"facility": "xhs",
|
|
83
|
+
"login": "qr",
|
|
84
|
+
"loginUrl": "https://www.xiaohongshu.com/explore",
|
|
85
|
+
"qrSelector": ".login-container img.qrcode-img, .qrcode img",
|
|
86
|
+
"cookieDomain": "xiaohongshu.com",
|
|
87
|
+
"sessionCookies": [
|
|
88
|
+
"web_session"
|
|
89
|
+
]
|
|
90
|
+
},
|
|
91
|
+
"normalizer": "xhs",
|
|
92
|
+
"type": "post",
|
|
93
|
+
"title": "笔记详情(enrich)",
|
|
94
|
+
"description": "小红书单条笔记详情 · 登录态 tab 导航到笔记页读 __INITIAL_STATE__ 拉图组/视频(masterUrl)/正文/首页评论",
|
|
95
|
+
"topics": [
|
|
96
|
+
"xhs",
|
|
97
|
+
"xiaohongshu",
|
|
98
|
+
"social"
|
|
99
|
+
],
|
|
100
|
+
"categories": [
|
|
101
|
+
"social-media"
|
|
102
|
+
],
|
|
103
|
+
"facility": {
|
|
104
|
+
"key": "xhs",
|
|
105
|
+
"label": "小红书"
|
|
106
|
+
},
|
|
107
|
+
"capabilities": [
|
|
108
|
+
"anchor"
|
|
109
|
+
],
|
|
110
|
+
"priority": 80,
|
|
111
|
+
"discoverable": false,
|
|
112
|
+
"_why_pick_in": "两个选择面都不出现——打开一条笔记时由 enrich 直调",
|
|
113
|
+
"pick_in": [],
|
|
114
|
+
"cadence_hint_seconds": 1800,
|
|
115
|
+
"homepage": "xiaohongshu.com",
|
|
116
|
+
"params_schema": {
|
|
117
|
+
"noteId": {
|
|
118
|
+
"type": "string",
|
|
119
|
+
"required": true,
|
|
120
|
+
"description": "笔记 id"
|
|
121
|
+
},
|
|
122
|
+
"xsec_token": {
|
|
123
|
+
"type": "string",
|
|
124
|
+
"required": true,
|
|
125
|
+
"description": "笔记 xsec_token"
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 7,
|
|
3
|
+
"kind": "browser",
|
|
4
|
+
"sourceId": "xhs-home",
|
|
5
|
+
"cookieDomain": "xiaohongshu.com",
|
|
6
|
+
"entryUrl": "https://www.xiaohongshu.com/explore",
|
|
7
|
+
"entryWait": "load",
|
|
8
|
+
"loginCheck": {
|
|
9
|
+
"loggedIn": ".main-container .user",
|
|
10
|
+
"wall": ".login-modal.reds-modal-open"
|
|
11
|
+
},
|
|
12
|
+
"_why_browser": "跑在用户自己的 Chrome 上(后台标签,不抢焦点),不再用 cloak。三个理由,第一个是主要的:cloak 是第三方闭源二进制却持有用户全部 facility 的真实登录 profile,指纹 patch 不开源、无法审计;其次它常驻约 1218MB;第三,同 profile 之后 cookie 注入那一整类故障(前导点、凭证过期、缓存不热刷)不存在。过去认为这条路走不通,依据是文档里那句「ext-cdp 后台档的 trusted input IMPOSSIBLE」——已被推翻:hidden 的 tab 不拒绝输入,而 Emulation.setFocusEmulationEnabled(browser-ext.ts 的 launch 一处开启)让它稳定落地,动作位一帧都不用逼。本 recipe 的懒加载**也不吃帧**:2026-08-15 三臂活体,逼帧全开 / 只留 dwell 心跳 / 全摘三种下产出都是 109–113 条,所以 driver 里的逼帧已经整条摘掉(今天一帧都不逼)。注意这是本站结论——同一批对照里当时的 douyin 摘掉 dwell 心跳就少一整批。**「后台标签的懒加载要不要帧」是站点差异,别把这条推广出去**;判据与量法见 browser-harvest/references/session-runtime.md「为什么今天一帧都不逼」。",
|
|
13
|
+
"session": {
|
|
14
|
+
"facility": "xhs",
|
|
15
|
+
"lifecycle": "persistent",
|
|
16
|
+
"visibility": "unattended"
|
|
17
|
+
},
|
|
18
|
+
"steps": [
|
|
19
|
+
{
|
|
20
|
+
"kind": "scroll",
|
|
21
|
+
"dwell_s": [
|
|
22
|
+
2,
|
|
23
|
+
4
|
|
24
|
+
],
|
|
25
|
+
"maxTimes": 40,
|
|
26
|
+
"noProgressStop": 3
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
"observers": [
|
|
30
|
+
{
|
|
31
|
+
"_why": "首屏那批笔记是 SSR 进 __INITIAL_STATE__ 的,页面根本不为它们发请求——只挂 network observer 会静悄悄把它们丢掉(实测页面 75 条里有 33 条如此,账本从第 34 条才开始)。trigger=entry 让它在任何 XHR 到达之前读到,于是账本从 feed 的第 0 条起、和 DOM 顺序一致。SSR 那批字段是小驼峰、XHR 那批是 snake_case,所以两个 observer 各带 input.mapping 各自归一化。",
|
|
32
|
+
"kind": "state",
|
|
33
|
+
"statePath": "__INITIAL_STATE__.feed.feeds._value",
|
|
34
|
+
"trigger": "entry",
|
|
35
|
+
"input": {
|
|
36
|
+
"itemsAt": "items",
|
|
37
|
+
"dedupeBy": "id",
|
|
38
|
+
"targetCount": 400,
|
|
39
|
+
"mapping": {
|
|
40
|
+
"noteId": "id",
|
|
41
|
+
"guid": "id",
|
|
42
|
+
"title": "noteCard.displayTitle",
|
|
43
|
+
"author": "noteCard.user.nickName",
|
|
44
|
+
"author_avatar": "noteCard.user.avatar",
|
|
45
|
+
"likes": "noteCard.interactInfo.likedCount",
|
|
46
|
+
"cover": "noteCard.cover.urlDefault",
|
|
47
|
+
"note_type": "noteCard.type",
|
|
48
|
+
"xsec_token": "xsecToken",
|
|
49
|
+
"link": "https://www.xiaohongshu.com/explore/{id}?xsec_token={xsecToken}&xsec_source=pc_feed"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"kind": "network",
|
|
55
|
+
"urlPattern": "*/api/sns/web/v1/homefeed*",
|
|
56
|
+
"windowMs": 300000,
|
|
57
|
+
"maxBodyBytes": 8000000,
|
|
58
|
+
"input": {
|
|
59
|
+
"itemsAt": "data.items",
|
|
60
|
+
"dedupeBy": "id",
|
|
61
|
+
"targetCount": 400,
|
|
62
|
+
"mapping": {
|
|
63
|
+
"noteId": "id",
|
|
64
|
+
"guid": "id",
|
|
65
|
+
"title": "note_card.display_title",
|
|
66
|
+
"author": "note_card.user.nick_name",
|
|
67
|
+
"author_avatar": "note_card.user.avatar",
|
|
68
|
+
"likes": "note_card.interact_info.liked_count",
|
|
69
|
+
"cover": "note_card.cover.url_default",
|
|
70
|
+
"note_type": "note_card.type",
|
|
71
|
+
"xsec_token": "xsec_token",
|
|
72
|
+
"link": "https://www.xiaohongshu.com/explore/{id}?xsec_token={xsec_token}&xsec_source=pc_feed"
|
|
73
|
+
},
|
|
74
|
+
"assert": [
|
|
75
|
+
{
|
|
76
|
+
"path": "data.items",
|
|
77
|
+
"desc": "xhs homefeed items"
|
|
78
|
+
}
|
|
79
|
+
]
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
],
|
|
83
|
+
"output": {
|
|
84
|
+
"itemsAt": "items",
|
|
85
|
+
"dedupeBy": "guid",
|
|
86
|
+
"targetCount": 100,
|
|
87
|
+
"mapping": {
|
|
88
|
+
"noteId": "noteId",
|
|
89
|
+
"guid": "guid",
|
|
90
|
+
"title": "title",
|
|
91
|
+
"author": "author",
|
|
92
|
+
"author_avatar": "author_avatar",
|
|
93
|
+
"likes": "likes",
|
|
94
|
+
"cover": "cover",
|
|
95
|
+
"note_type": "note_type",
|
|
96
|
+
"xsec_token": "xsec_token",
|
|
97
|
+
"link": "link"
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
"policy": {
|
|
101
|
+
"minActionIntervalMs": 900,
|
|
102
|
+
"maxTaskMs": 300000
|
|
103
|
+
},
|
|
104
|
+
"meta": {
|
|
105
|
+
"_why_uses": "打开一条笔记要的正文/图集/评论不在这份 feed 里,是另一份共用的 recipe(xhs-detail)现取的(src/content/enrich/index.ts)。申报它,detail 漂了才有人能回答「跟着哑的还有谁」——否则本源的健康状态一路是绿的,而每一条笔记都点不开。",
|
|
106
|
+
"uses": [
|
|
107
|
+
"xhs-detail"
|
|
108
|
+
],
|
|
109
|
+
"auth": {
|
|
110
|
+
"type": "session",
|
|
111
|
+
"facility": "xhs",
|
|
112
|
+
"login": "qr",
|
|
113
|
+
"loginUrl": "https://www.xiaohongshu.com/explore",
|
|
114
|
+
"qrSelector": ".login-container img.qrcode-img, .qrcode img",
|
|
115
|
+
"cookieDomain": "xiaohongshu.com",
|
|
116
|
+
"sessionCookies": [
|
|
117
|
+
"web_session"
|
|
118
|
+
]
|
|
119
|
+
},
|
|
120
|
+
"normalizer": "xhs",
|
|
121
|
+
"type": "post",
|
|
122
|
+
"title": "HomeFeed",
|
|
123
|
+
"description": "小红书首页推荐流 · 登录态浏览器滚动触发 homefeed XHR,拦截返回体采集",
|
|
124
|
+
"topics": [
|
|
125
|
+
"xhs",
|
|
126
|
+
"xiaohongshu",
|
|
127
|
+
"social"
|
|
128
|
+
],
|
|
129
|
+
"categories": [
|
|
130
|
+
"social-media"
|
|
131
|
+
],
|
|
132
|
+
"facility": {
|
|
133
|
+
"key": "xhs",
|
|
134
|
+
"label": "小红书"
|
|
135
|
+
},
|
|
136
|
+
"capabilities": [
|
|
137
|
+
"timeline"
|
|
138
|
+
],
|
|
139
|
+
"priority": 80,
|
|
140
|
+
"discoverable": true,
|
|
141
|
+
"cadence_hint_seconds": 1800,
|
|
142
|
+
"homepage": "xiaohongshu.com"
|
|
143
|
+
}
|
|
144
|
+
}
|