@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.
Files changed (144) hide show
  1. package/README.md +24 -0
  2. package/bin/stream.mjs +89 -0
  3. package/package.json +34 -0
  4. package/resources/app/dist-panel/panel-boards.js +6 -0
  5. package/resources/app/dist-panel/panel-detail.css +1 -0
  6. package/resources/app/dist-panel/panel-detail.js +2141 -0
  7. package/resources/app/dist-panel/panel-manage.css +1 -0
  8. package/resources/app/dist-panel/panel-manage.js +2246 -0
  9. package/resources/app/dist-panel/panel-movie.css +1 -0
  10. package/resources/app/dist-panel/panel-movie.js +2268 -0
  11. package/resources/app/dist-panel/panel-research.css +1 -0
  12. package/resources/app/dist-panel/panel-research.js +316 -0
  13. package/resources/app/dist-panel/panel.css +1 -0
  14. package/resources/app/dist-panel/panel.js +463 -0
  15. package/resources/dsh-engine-lock/package-lock.json +9032 -0
  16. package/resources/extension/.output/chrome-mv3/assets/popup-C2NUZZQW.css +2 -0
  17. package/resources/extension/.output/chrome-mv3/background.js +1 -0
  18. package/resources/extension/.output/chrome-mv3/chunks/popup-BeBts9v2.js +50 -0
  19. package/resources/extension/.output/chrome-mv3/icon/128.png +0 -0
  20. package/resources/extension/.output/chrome-mv3/icon/16.png +0 -0
  21. package/resources/extension/.output/chrome-mv3/icon/32.png +0 -0
  22. package/resources/extension/.output/chrome-mv3/icon/48.png +0 -0
  23. package/resources/extension/.output/chrome-mv3/icon/96.png +0 -0
  24. package/resources/extension/.output/chrome-mv3/manifest.json +1 -0
  25. package/resources/extension/.output/chrome-mv3/popup.html +21 -0
  26. package/resources/packages/1lou/1lou-search.recipe.json +102 -0
  27. package/resources/packages/1lou/README.md +7 -0
  28. package/resources/packages/1lou/package.json +15 -0
  29. package/resources/packages/Douyin_TikTok_Download_API/README.md +23 -0
  30. package/resources/packages/Douyin_TikTok_Download_API/activate.ts +14 -0
  31. package/resources/packages/Douyin_TikTok_Download_API/adapter/adapter.ts +321 -0
  32. package/resources/packages/Douyin_TikTok_Download_API/adapter/danmaku.ts +21 -0
  33. package/resources/packages/Douyin_TikTok_Download_API/adapter/executor.ts +75 -0
  34. package/resources/packages/Douyin_TikTok_Download_API/adapter/normalize.ts +20 -0
  35. package/resources/packages/Douyin_TikTok_Download_API/manifests.yaml +521 -0
  36. package/resources/packages/Douyin_TikTok_Download_API/package.json +32 -0
  37. package/resources/packages/alist/README.md +14 -0
  38. package/resources/packages/alist/activate.ts +12 -0
  39. package/resources/packages/alist/adapter.ts +74 -0
  40. package/resources/packages/alist/manifests.yaml +76 -0
  41. package/resources/packages/alist/mounts.ts +120 -0
  42. package/resources/packages/alist/package.json +24 -0
  43. package/resources/packages/alist/presets.ts +53 -0
  44. package/resources/packages/alist/provision.ts +84 -0
  45. package/resources/packages/baidu/baidu-share.recipe.json +93 -0
  46. package/resources/packages/baidu/package.json +16 -0
  47. package/resources/packages/baidu-search/baidu-search.recipe.json +129 -0
  48. package/resources/packages/baidu-search/package.json +25 -0
  49. package/resources/packages/brave/brave-search.recipe.json +129 -0
  50. package/resources/packages/brave/package.json +25 -0
  51. package/resources/packages/browser/README.md +3 -0
  52. package/resources/packages/browser/adapter.ts +44 -0
  53. package/resources/packages/browser/manifests.yaml +20 -0
  54. package/resources/packages/browser/package.json +13 -0
  55. package/resources/packages/bt0/README.md +7 -0
  56. package/resources/packages/bt0/bt0-search.recipe.json +69 -0
  57. package/resources/packages/bt0/bt0-tlist.recipe.json +74 -0
  58. package/resources/packages/bt0/package.json +15 -0
  59. package/resources/packages/btbtla/README.md +6 -0
  60. package/resources/packages/btbtla/btbtla-detail.recipe.json +76 -0
  61. package/resources/packages/btbtla/btbtla-search.recipe.json +74 -0
  62. package/resources/packages/btbtla/package.json +15 -0
  63. package/resources/packages/builtin/README.md +8 -0
  64. package/resources/packages/builtin/manifests.yaml +487 -0
  65. package/resources/packages/builtin/package.json +14 -0
  66. package/resources/packages/douyin/README.md +39 -0
  67. package/resources/packages/douyin/douyin-collection.recipe.json +127 -0
  68. package/resources/packages/douyin/douyin-search.recipe.json +163 -0
  69. package/resources/packages/douyin/package.json +16 -0
  70. package/resources/packages/firecrawl/firecrawl-create-key.recipe.json +81 -0
  71. package/resources/packages/firecrawl/firecrawl-read-key.recipe.json +56 -0
  72. package/resources/packages/firecrawl/package.json +16 -0
  73. package/resources/packages/google/google-search.recipe.json +127 -0
  74. package/resources/packages/google/package.json +24 -0
  75. package/resources/packages/groq/groq-create-key.recipe.json +67 -0
  76. package/resources/packages/groq/package.json +16 -0
  77. package/resources/packages/huggingface/README.md +7 -0
  78. package/resources/packages/huggingface/huggingface-spaces.recipe.json +73 -0
  79. package/resources/packages/huggingface/package.json +15 -0
  80. package/resources/packages/imdb/imdb-chart.recipe.json +75 -0
  81. package/resources/packages/imdb/package.json +15 -0
  82. package/resources/packages/index.ts +15 -0
  83. package/resources/packages/iqiyi/README.md +10 -0
  84. package/resources/packages/iqiyi/iqiyi-cn-album.recipe.json +80 -0
  85. package/resources/packages/iqiyi/iqiyi-cn-search.recipe.json +71 -0
  86. package/resources/packages/iqiyi/package.json +15 -0
  87. package/resources/packages/lizhi/README.md +35 -0
  88. package/resources/packages/lizhi/lizhi-user.recipe.json +80 -0
  89. package/resources/packages/lizhi/package.json +15 -0
  90. package/resources/packages/manmanbuy/README.md +16 -0
  91. package/resources/packages/manmanbuy/manmanbuy-search.recipe.json +115 -0
  92. package/resources/packages/manmanbuy/package.json +15 -0
  93. package/resources/packages/mineru/README.md +38 -0
  94. package/resources/packages/mineru/package.json +28 -0
  95. package/resources/packages/pansou/README.md +14 -0
  96. package/resources/packages/pansou/activate.ts +11 -0
  97. package/resources/packages/pansou/adapter.ts +94 -0
  98. package/resources/packages/pansou/manifests.yaml +50 -0
  99. package/resources/packages/pansou/package.json +27 -0
  100. package/resources/packages/qq/package.json +15 -0
  101. package/resources/packages/qq/qq-send.recipe.json +104 -0
  102. package/resources/packages/quark/package.json +16 -0
  103. package/resources/packages/quark/quark-share.recipe.json +40 -0
  104. package/resources/packages/reddit/package.json +15 -0
  105. package/resources/packages/reddit/reddit-sub.recipe.json +77 -0
  106. package/resources/packages/replay/README.md +7 -0
  107. package/resources/packages/replay/package.json +13 -0
  108. package/resources/packages/rsshub/README.md +16 -0
  109. package/resources/packages/rsshub/manifests.yaml +107 -0
  110. package/resources/packages/rsshub/package.json +21 -0
  111. package/resources/packages/telegram/package.json +15 -0
  112. package/resources/packages/telegram/telegram-search.recipe.json +125 -0
  113. package/resources/packages/tencent/README.md +11 -0
  114. package/resources/packages/tencent/package.json +15 -0
  115. package/resources/packages/tencent/tencent-cn-episode.recipe.json +98 -0
  116. package/resources/packages/toubiec/README.md +38 -0
  117. package/resources/packages/toubiec/package.json +15 -0
  118. package/resources/packages/toubiec/toubiec-download.recipe.json +58 -0
  119. package/resources/packages/toubiec/toubiec-playlist.recipe.json +49 -0
  120. package/resources/packages/toubiec/toubiec-search.recipe.json +80 -0
  121. package/resources/packages/voiceprint/README.md +31 -0
  122. package/resources/packages/voiceprint/package.json +36 -0
  123. package/resources/packages/wikipedia/package.json +15 -0
  124. package/resources/packages/wikipedia/wikipedia-award-list.recipe.json +102 -0
  125. package/resources/packages/xhs/README.md +32 -0
  126. package/resources/packages/xhs/package.json +21 -0
  127. package/resources/packages/xhs/xhs-detail.recipe.json +129 -0
  128. package/resources/packages/xhs/xhs-home.recipe.json +144 -0
  129. package/resources/packages/xhs/xhs-like.recipe.json +96 -0
  130. package/resources/packages/xhs/xhs-search.recipe.json +138 -0
  131. package/resources/packages/xueqiu/README.md +9 -0
  132. package/resources/packages/xueqiu/package.json +16 -0
  133. package/resources/packages/xueqiu/xueqiu-detail.recipe.json +92 -0
  134. package/resources/packages/xueqiu/xueqiu-user.recipe.json +75 -0
  135. package/resources/packages/zhipu/package.json +16 -0
  136. package/resources/packages/zhipu/zhipu-create-key.recipe.json +74 -0
  137. package/resources/packages/zuna/README.md +31 -0
  138. package/resources/packages/zuna/package.json +15 -0
  139. package/resources/packages/zuna/zuna-album.recipe.json +46 -0
  140. package/resources/packages/zuna/zuna-download.recipe.json +53 -0
  141. package/resources/packages/zuna/zuna-playlist.recipe.json +46 -0
  142. package/resources/packages/zuna/zuna-search.recipe.json +96 -0
  143. package/resources/server.mjs +238876 -0
  144. package/resources/sidequest.jobs.js +1 -0
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "@streamapp/google",
3
+ "version": "1.0.0",
4
+ "author": "stream",
5
+ "keywords": [
6
+ "stream-recipe"
7
+ ],
8
+ "stream": {
9
+ "type": "recipe",
10
+ "name": "Google",
11
+ "tagline": "网页搜索",
12
+ "facility": "google",
13
+ "schemaVersion": 1,
14
+ "cookieDomain": "google.com",
15
+ "_why_rateLimit": "**这三个数是量出来的,别凭手感调。** 实测(2026-08-13,用户自己那个 Chrome):18 发查询挤在 13 秒内打出去(≈80 次/分钟),两次里有一次被 Google 的验证码页拦掉 6 发;同样 18 发拆成 3 轮 × 6 并发(≈35 次/分钟)两次都是零被拦。被拦是**瞬时**的——拦完紧接着单发照常有结果,不是持续封号。所以闸门按「一轮 6 发」这个已验证安全的形状定:burst 6 让 search agent 的一整轮一次过(`src/agent/search/flow.ts` 每轮 4–6 条查询并发),perMinute 30 把持续速率压在实测干净的那一档以下。maxWaitMs 10000:桶空了宁可等也别放弃——这条腿同时长在对话热路径上(`web_search`),而单发查询在桶满时压根不排队,会排队的只有 agent 那种连打。",
16
+ "_why_perHour": "**burst/perMinute 管瞬时形状,perHour 管累计量——Google 拦人数的是后者。** 实测:一小时内约一百发之后稳定回 /sorry/index,**IP 级**(换查询、单发都一样,同出口的 Brave 也跟着弹人机验证)。2026-08-15 亲历:一个 agent 15 分钟连打约 40 发就吃到拦截页,而令牌桶从头到尾一次都没拒绝过(40 发摊 15 分钟 ≈ 2.7 次/分,离 perMinute 30 的闸门差一个数量级);反过来说,完全合规地跑满 30 次/分,一小时就是 1800 发,比撞墙门槛高 18 倍。**100 正好是实测撞墙点,所以这个预算是贴着墙走、零余量的**——它挡的是「同一小时里被打爆」,不保证一定不撞(撞墙点本身还没被连续跑一小时证明过,只是一次亲历的观察)。**这个数的实测分布正在自己攒**:每次撞墙都会把「撞墙前这一小时我们发了几发」记进 `data/block-episodes.json`(`spentLastHour`),攒够几条就能拿真分布替掉这个贴墙的猜测,不必去跑那个要占着用户浏览器一小时的低速压测。**要收紧就改这一个数**,别去动 burst/perMinute:那两个是另一维、另一份实测。撞满之后的处置不是报错也不是等(等下一格要 36s、等回满要一小时),是 src/search/web-search-ladder.ts 把这条腿当作不存在:走备胎 Brave,中文查询还有百度那条并联腿。",
17
+ "rateLimit": {
18
+ "burst": 6,
19
+ "perMinute": 30,
20
+ "perHour": 100,
21
+ "maxWaitMs": 10000
22
+ }
23
+ }
24
+ }
@@ -0,0 +1,67 @@
1
+ {
2
+ "version": 1,
3
+ "kind": "browser",
4
+ "sourceId": "groq-create-key",
5
+ "cookieDomain": "groq.com",
6
+ "entryUrl": "https://console.groq.com/keys",
7
+ "entryWait": "load",
8
+ "loginCheck": {
9
+ "loggedIn": "[data-testid=keys-page-create-button]",
10
+ "wall": "a[href*='/login']"
11
+ },
12
+ "session": {
13
+ "facility": "groq",
14
+ "lifecycle": "one-shot",
15
+ "visibility": "interactive"
16
+ },
17
+ "_selectors_verified": "2026-07-26 活体重定于 console.groq.com/keys。别用 button[type=submit]:这一页第一个 type=submit 是「Sign Out」,click 点第一个匹配 —— 那会把用户签退而不是建 key。",
18
+ "steps": [
19
+ {
20
+ "kind": "click",
21
+ "selector": "[data-testid=keys-page-create-button]",
22
+ "expect": { "selector": "input[name=\"cf-turnstile-response\"]", "timeout": 10000 }
23
+ },
24
+ {
25
+ "_why_position": "widget 300x72,复选框在最左侧方块区、中间是文字。点中心=点在文字上,不生效。",
26
+ "_why_expect": "等的不是这次点击,是挑战解出来 —— 提交按钮直到拿到 token 才渲染,而挑战要多久是它说了算。",
27
+ "_why_settle": "widget 在 closed shadow root 里,DOM 连续 9.3s 一个字节不动,而这段时间它正从「空」变「转圈」变「可点」。早点下去不是白点,是把它打进失败态(实测重做 8 次全废)。所以盯这块区域的画面:变过了 + 停住了 才动手。",
28
+ "kind": "click",
29
+ "selector": ":has(> input[name=\"cf-turnstile-response\"])",
30
+ "position": { "x": 36, "y": 36 },
31
+ "settle": { "selector": ":has(> input[name=\"cf-turnstile-response\"])", "stableFrames": 3, "intervalMs": 250, "timeout": 15000 },
32
+ "expect": { "selector": "[data-testid=key-form-submit-button]", "timeout": 45000 }
33
+ },
34
+ { "kind": "type", "selector": "[data-testid=key-name-input]", "text": "{name}" },
35
+ { "kind": "click", "selector": "[data-testid=key-form-submit-button]" }
36
+ ],
37
+ "observers": [],
38
+ "output": { "itemsAt": "", "dedupeBy": "", "targetCount": 0, "mapping": {} },
39
+ "allowEmpty": true,
40
+ "extract": { "field": "apiKey", "pattern": "gsk_[A-Za-z0-9_-]{20,}", "timeout": 20000 },
41
+ "meta": {
42
+ "description": "在 console.groq.com 自助建一把 API key,并把只显示一次的明文落进 runtime_config(不产 item)",
43
+ "discoverable": false,
44
+ "_why_pick_in": "两个选择面都不出现——配置流程:用户在场自助建 key",
45
+ "pick_in": [],
46
+ "capabilities": ["anchor"],
47
+ "facility": { "key": "groq", "label": "Groq" },
48
+ "params_schema": {
49
+ "name": {
50
+ "type": "string",
51
+ "required": true,
52
+ "description": "key 名。带一段随机后缀(如 stream-auto-7f3a)——建 key 不幂等,重跑会堆出一排看不出区别的同名 key"
53
+ }
54
+ },
55
+ "runtime_config": {
56
+ "ref": "groq",
57
+ "fields": {
58
+ "apiKey": {
59
+ "type": "secret",
60
+ "label": "Groq API Key",
61
+ "description": "转写梯子的 Groq 成员用它。可以手填,也可以让本 recipe 自己去建一把填进来。",
62
+ "helpUrl": "https://console.groq.com/keys"
63
+ }
64
+ }
65
+ }
66
+ }
67
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "@streamapp/groq",
3
+ "version": "1.0.0",
4
+ "author": "stream",
5
+ "keywords": [
6
+ "stream-recipe"
7
+ ],
8
+ "stream": {
9
+ "type": "recipe",
10
+ "name": "Groq",
11
+ "tagline": "在 console.groq.com 自助建一把 API key",
12
+ "facility": "groq",
13
+ "schemaVersion": 1,
14
+ "cookieDomain": "groq.com"
15
+ }
16
+ }
@@ -0,0 +1,7 @@
1
+
2
+ ## 说明(迁自 manifests.yaml 注释)
3
+
4
+ Hugging Face Spaces 搜索 — 纯 http recipe(明文 JSON,huggingface.co/api/spaces,无签名)。
5
+ 迁自本地 RSSHub 路由 lib/routes/huggingface/spaces.ts。响应是根级数组 SpaceItem[],用 itemsAt:""
6
+ 取根(引擎空路径=identity)。只保留默认过滤(sdk/hardware/running=all,无需引擎侧过滤),search 由
7
+ 接口完成。
@@ -0,0 +1,73 @@
1
+ {
2
+ "version": 1,
3
+ "kind": "http",
4
+ "sourceId": "huggingface-spaces",
5
+ "request": {
6
+ "url": "https://huggingface.co/api/spaces?search={query}&sort=createdAt&direction=-1&limit=100&full=true",
7
+ "method": "GET"
8
+ },
9
+ "pagination": {
10
+ "mode": "increment",
11
+ "param": "page",
12
+ "start": 1,
13
+ "step": 1,
14
+ "itemsAt": "",
15
+ "maxPages": 1
16
+ },
17
+ "assert": [
18
+ {
19
+ "path": "",
20
+ "desc": "huggingface /api/spaces returned a root array"
21
+ }
22
+ ],
23
+ "mapping": {
24
+ "guid": "id",
25
+ "title": "id",
26
+ "link": "https://huggingface.co/spaces/{id}",
27
+ "description": "{shortDescription}<br>SDK: {sdk}<br>Likes: {likes}",
28
+ "author": "author",
29
+ "category": "sdk",
30
+ "pubDate": "createdAt"
31
+ },
32
+ "meta": {
33
+ "normalizer": "rsshub",
34
+ "type": "post",
35
+ "description": "Hugging Face Spaces — 搜索",
36
+ "topics": [
37
+ "huggingface",
38
+ "spaces",
39
+ "AI",
40
+ "gradio",
41
+ "搜索",
42
+ "search"
43
+ ],
44
+ "categories": [
45
+ "programming"
46
+ ],
47
+ "facility": {
48
+ "key": "huggingface",
49
+ "label": "Hugging Face"
50
+ },
51
+ "capabilities": [
52
+ "search"
53
+ ],
54
+ "key_param": "query",
55
+ "priority": 80,
56
+ "discoverable": true,
57
+ "cadence_hint_seconds": 3600,
58
+ "auth": {
59
+ "type": "none"
60
+ },
61
+ "homepage": "huggingface.co",
62
+ "params_schema": {
63
+ "query": {
64
+ "type": "string",
65
+ "required": true,
66
+ "description": "搜索关键词"
67
+ }
68
+ },
69
+ "radar": [
70
+ "huggingface.co/spaces"
71
+ ]
72
+ }
73
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "@streamapp/huggingface",
3
+ "version": "1.0.0",
4
+ "author": "stream",
5
+ "keywords": [
6
+ "stream-recipe"
7
+ ],
8
+ "stream": {
9
+ "type": "recipe",
10
+ "name": "Hugging Face",
11
+ "tagline": "Spaces 搜索",
12
+ "facility": "huggingface",
13
+ "schemaVersion": 1
14
+ }
15
+ }
@@ -0,0 +1,75 @@
1
+ {
2
+ "version": 1,
3
+ "kind": "http",
4
+ "sourceId": "imdb-chart",
5
+ "request": {
6
+ "url": "https://api.graphql.imdb.com/",
7
+ "method": "POST",
8
+ "headers": {
9
+ "content-type": "application/json",
10
+ "x-imdb-user-country": "US",
11
+ "x-imdb-user-language": "en-US"
12
+ },
13
+ "body": "{\"query\":\"query Chart($chartType: ChartTitleType!, $first: Int!) { chartTitles(chart: { chartType: $chartType }, first: $first) { edges { currentRank node { id titleText { text } originalTitleText { text } titleType { text } releaseYear { year endYear } primaryImage { url caption { plainText } } ratingsSummary { aggregateRating voteCount } certificate { rating } plot { plotText { plainText } } titleGenres { genres { genre { text } } } } } } }\",\"variables\":{\"chartType\":\"{chart}\",\"first\":250}}"
14
+ },
15
+ "pagination": {
16
+ "mode": "increment",
17
+ "param": "page",
18
+ "start": 1,
19
+ "step": 1,
20
+ "itemsAt": "data.chartTitles.edges",
21
+ "maxPages": 1
22
+ },
23
+ "assert": [
24
+ {
25
+ "path": "data.chartTitles.edges",
26
+ "desc": "GraphQL returned chartTitles.edges array"
27
+ }
28
+ ],
29
+ "mapping": {
30
+ "guid": "node.id",
31
+ "title": "{currentRank}. {node.titleText.text}",
32
+ "description": "<img src=\"{node.primaryImage.url}\" /><br/>Original title: {node.originalTitleText.text}<br/>IMDb RATING: {node.ratingsSummary.aggregateRating}/10 ({node.ratingsSummary.voteCount})<br/><br/>{node.plot.plotText.plainText}",
33
+ "link": "https://www.imdb.com/title/{node.id}"
34
+ },
35
+ "meta": {
36
+ "normalizer": "rsshub",
37
+ "type": "post",
38
+ "description": "IMDb Charts",
39
+ "topics": [
40
+ "imdb",
41
+ "charts",
42
+ "movies",
43
+ "tv"
44
+ ],
45
+ "categories": [
46
+ "multimedia"
47
+ ],
48
+ "facility": {
49
+ "key": "imdb",
50
+ "label": "IMDb"
51
+ },
52
+ "capabilities": [
53
+ "timeline"
54
+ ],
55
+ "key_param": "chart",
56
+ "priority": 90,
57
+ "discoverable": true,
58
+ "cadence_hint_seconds": 86400,
59
+ "auth": {
60
+ "type": "none"
61
+ },
62
+ "homepage": "imdb.com",
63
+ "params_schema": {
64
+ "chart": {
65
+ "type": "string",
66
+ "required": true,
67
+ "description": "The chart to display (e.g. MOST_POPULAR_MOVIES)"
68
+ }
69
+ },
70
+ "radar": [
71
+ "imdb.com/chart/:chart",
72
+ "www.imdb.com/chart/:chart"
73
+ ]
74
+ }
75
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "@streamapp/imdb",
3
+ "version": "1.0.0",
4
+ "author": "stream",
5
+ "keywords": [
6
+ "stream-recipe"
7
+ ],
8
+ "stream": {
9
+ "type": "recipe",
10
+ "name": "IMDb",
11
+ "tagline": "Charts 排行榜",
12
+ "facility": "imdb",
13
+ "schemaVersion": 1
14
+ }
15
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * 内置包代码入口的静态表。**字面量 import**——这样 esbuild 能把它们打进发行 bundle、
3
+ * tsc 也全覆盖(第三方包走的是另一条:运行时动态 import 它自带的预打包 JS,P4 才开)。
4
+ * 加一个带 code 槽位的内置包 = 这里加一行。
5
+ */
6
+ import type { ActivateFn } from '../src/packages/activate.ts'
7
+ import { activate as pansou } from './pansou/activate.ts'
8
+ import { activate as douyinTiktokDownloadApi } from './Douyin_TikTok_Download_API/activate.ts'
9
+ import { activate as alist } from './alist/activate.ts'
10
+
11
+ export const BUILTIN_ACTIVATIONS = new Map<string, ActivateFn>([
12
+ ['pansou', pansou],
13
+ ['Douyin_TikTok_Download_API', douyinTiktokDownloadApi],
14
+ ['alist', alist],
15
+ ])
@@ -0,0 +1,10 @@
1
+
2
+ ## 说明(迁自 manifests.yaml 注释)
3
+
4
+ iqiyi 国内站 — 纯 http recipe(mesh.if.iqiyi.com)。迁自本地 RSSHub 路由
5
+ lib/routes/iqiyi/{search,cn-album}.ts。
6
+
7
+ - cn/search:明文 JSON 搜索,无签名,返回专辑(albumInfo),可拿 qipuId 喂给 cn-album。
8
+ - cn/album:tvg/v2/selector 是签名端点,用 compute.sign 算 md5(sorted params + &secret_key=howcuteitis);
9
+ compute.decode 把 data.videos[].data 按年分组拍平成 items[] 并把封面 regex 升清到 720x405。
10
+ albumId 要数字 qipuId(省掉 RSSHub 从 a_*.html 抠 albumId 的 HTML 步;搜索结果里就有)。
@@ -0,0 +1,80 @@
1
+ {
2
+ "version": 1,
3
+ "kind": "http",
4
+ "sourceId": "iqiyi-cn-album",
5
+ "request": {
6
+ "url": "https://mesh.if.iqiyi.com/tvg/v2/selector",
7
+ "method": "GET"
8
+ },
9
+ "compute": {
10
+ "capabilities": [
11
+ "md5"
12
+ ],
13
+ "sign": "(() => { const p = { album_id: input.params.albumId, timestamp: input.now * 1000, src: 'lw', user_id: '', vip_status: '0', vip_type: '-1', device_id: 'aaaaaaaabbbbbbbb', app_version: '17.071.25717', scale: '100' }; const base = Object.keys(p).sort().map((k) => k + '=' + p[k]).join('&'); const sign = md5(base + '&secret_key=howcuteitis').toUpperCase(); const all = Object.assign({}, p, { sign }); const qs = Object.keys(all).map((k) => encodeURIComponent(k) + '=' + encodeURIComponent(all[k])).join('&'); return { url: 'https://mesh.if.iqiyi.com/tvg/v2/selector?' + qs }; })()",
14
+ "decode": "(() => { const up = (u) => u ? String(u).replace(/(_\\d{2,4}_\\d{2,4})?\\.(jpg|jpeg|png|webp)(\\?.*)?$/i, '_720_405.$2$3') : u; const groups = (input.body && input.body.data && input.body.data.videos) || []; const items = []; for (const g of groups) { for (const v of (g.data || [])) { if (v.page_url) { items.push(Object.assign({}, v, { image_hd: up(v.image_url) })); } } } return { items }; })()"
15
+ },
16
+ "pagination": {
17
+ "mode": "increment",
18
+ "param": "page",
19
+ "start": 1,
20
+ "step": 1,
21
+ "itemsAt": "items",
22
+ "maxPages": 1
23
+ },
24
+ "assert": [
25
+ {
26
+ "path": "items",
27
+ "desc": "iqiyi selector season videos flattened"
28
+ }
29
+ ],
30
+ "mapping": {
31
+ "guid": "page_url",
32
+ "title": "title",
33
+ "link": "page_url",
34
+ "image": "image_hd",
35
+ "description": "description",
36
+ "pubDate": "publish_date"
37
+ },
38
+ "meta": {
39
+ "normalizer": "rsshub",
40
+ "type": "post",
41
+ "description": "爱奇艺(国内站)— 剧集/综艺分集",
42
+ "topics": [
43
+ "爱奇艺",
44
+ "iqiyi",
45
+ "影视",
46
+ "综艺",
47
+ "剧集",
48
+ "分集",
49
+ "tv"
50
+ ],
51
+ "categories": [
52
+ "multimedia"
53
+ ],
54
+ "facility": {
55
+ "key": "iqiyi",
56
+ "label": "爱奇艺"
57
+ },
58
+ "capabilities": [
59
+ "timeline"
60
+ ],
61
+ "key_param": "albumId",
62
+ "priority": 80,
63
+ "discoverable": true,
64
+ "cadence_hint_seconds": 86400,
65
+ "auth": {
66
+ "type": "none"
67
+ },
68
+ "homepage": "iqiyi.com",
69
+ "params_schema": {
70
+ "albumId": {
71
+ "type": "string",
72
+ "required": true,
73
+ "description": "数字专辑 id(qipuId,来自 cn/search 结果)"
74
+ }
75
+ },
76
+ "radar": [
77
+ "iqiyi.com/a_:id.html"
78
+ ]
79
+ }
80
+ }
@@ -0,0 +1,71 @@
1
+ {
2
+ "version": 1,
3
+ "kind": "http",
4
+ "sourceId": "iqiyi-cn-search",
5
+ "request": {
6
+ "url": "https://mesh.if.iqiyi.com/portal/lw/search/homePageV3?key={keyword}&current_page=1&mode=1&source=input&pageNum=1&pageSize=20&u=aaa&scale=150&dataType=webSearch",
7
+ "method": "GET"
8
+ },
9
+ "pagination": {
10
+ "mode": "increment",
11
+ "param": "page",
12
+ "start": 1,
13
+ "step": 1,
14
+ "itemsAt": "data.templates",
15
+ "maxPages": 1
16
+ },
17
+ "assert": [
18
+ {
19
+ "path": "data.templates",
20
+ "desc": "iqiyi search returned data.templates array"
21
+ }
22
+ ],
23
+ "mapping": {
24
+ "title": "albumInfo.title",
25
+ "link": "albumInfo.pageUrl",
26
+ "guid": "iqiyi-{albumInfo.qipuId}",
27
+ "description": "<img src=\"{albumInfo.img}\"><br>频道:{albumInfo.channel}<br>albumId:{albumInfo.qipuId}(分集订阅:/iqiyi/cn/album/{albumInfo.qipuId})"
28
+ },
29
+ "meta": {
30
+ "normalizer": "rsshub",
31
+ "type": "post",
32
+ "description": "爱奇艺(国内站)— 关键词搜索",
33
+ "topics": [
34
+ "爱奇艺",
35
+ "iqiyi",
36
+ "影视",
37
+ "综艺",
38
+ "搜索",
39
+ "movie",
40
+ "search"
41
+ ],
42
+ "categories": [
43
+ "multimedia"
44
+ ],
45
+ "facility": {
46
+ "key": "iqiyi",
47
+ "label": "爱奇艺"
48
+ },
49
+ "capabilities": [
50
+ "search"
51
+ ],
52
+ "key_param": "keyword",
53
+ "priority": 80,
54
+ "discoverable": true,
55
+ "cadence_hint_seconds": 3600,
56
+ "auth": {
57
+ "type": "none"
58
+ },
59
+ "homepage": "iqiyi.com",
60
+ "params_schema": {
61
+ "keyword": {
62
+ "type": "string",
63
+ "required": true,
64
+ "description": "搜索关键词(片名)"
65
+ }
66
+ },
67
+ "radar": [
68
+ "iqiyi.com/search"
69
+ ]
70
+ }
71
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "@streamapp/iqiyi",
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": "iqiyi",
13
+ "schemaVersion": 1
14
+ }
15
+ }
@@ -0,0 +1,35 @@
1
+
2
+ ## 说明
3
+
4
+ No cookieDomain: the vodapi needs no login — a cookie-less request gets 200. Declaring a
5
+ domain anyway would ask the broker for credentials this source has no use for.
6
+
7
+ ### 关于 request.headers 里的 User-Agent
8
+
9
+ **这里的 UA 不是伪装,是「躲进人群」。** 别把它读成"必须长这样才能过"。
10
+
11
+ 荔枝的 WAF(Tencent EdgeOne)接受哪种 UA 是会变的,而且两个方向都变过——所以**任何"某站拦某类
12
+ UA"的结论都必须现测、并写上日期**,别照抄。实测同一 id、间隔 4s:
13
+
14
+ | UA | 2026-08-01 | 2026-08-05 |
15
+ |---|---|---|
16
+ | 浏览器样(Chrome Android / iPhone Safari) | 403 无 body | **200** |
17
+ | 无 UA | **200** | 567 |
18
+ | `Stream/1.0` / `okhttp/*` / App 自己的 token | 200 | 200 |
19
+
20
+ 选 `okhttp/4.12.0` 的理由只有一个:**独一份的 UA 是免费的靶子**。`Stream/1.0` 全网只有我们在发,
21
+ 站方要精确掐掉我们,加一条规则、零附带损失;`okhttp/4.12.0`(安卓 HTTP 客户端默认串)要拦就得
22
+ 连带砍掉大片正常 App 流量。
23
+
24
+ 参考——荔枝 App 自己按用途分了四个 UA(2026-08-05 手机抓明文 HTTP):诊断接口
25
+ `LizhiFM/5.21.12_build156474 NetType/WIFI Language/zh`、埋点与拉封面 `Dalvik/2.1.0 (...)`、
26
+ 测速 `LizhiFM Android cdn_test 156474`、拉音频流 `LizhiFM Android player 156474`。**别去精确
27
+ 冒充其中任何一个**:带 build 号的串会随版本作废,而且业务 API 走 HTTPS,抓包里那几个都不是它。
28
+
29
+ ## 说明(迁自 manifests.yaml 注释)
30
+
31
+ 荔枝 FM 用户音频 — kind:'http' recipe (no browser)。
32
+ Migrated from the local-only RSSHub route lib/routes/lizhi/user.ts, which is why the
33
+ radar patterns below are carried over verbatim: the `podcast-feed` Provider reaches this
34
+ source by URL match ({mode:'auto', matches:'lizhi.fm/user/:id'}), not by source id, so
35
+ dropping them would silently break that Provider while the Stream member kept working.
@@ -0,0 +1,80 @@
1
+ {
2
+ "version": 1,
3
+ "kind": "http",
4
+ "sourceId": "lizhi-user",
5
+ "request": {
6
+ "url": "https://m.lizhi.fm/vodapi/user/{id}?pageNo={page}&pageSize=30",
7
+ "method": "GET",
8
+ "headers": {
9
+ "User-Agent": "okhttp/4.12.0"
10
+ }
11
+ },
12
+ "pagination": {
13
+ "mode": "increment",
14
+ "param": "page",
15
+ "start": 1,
16
+ "step": 1,
17
+ "itemsAt": "data",
18
+ "maxPages": 40
19
+ },
20
+ "assert": [
21
+ {
22
+ "path": "data",
23
+ "desc": "vodapi/user returned a data[] array"
24
+ }
25
+ ],
26
+ "mapping": {
27
+ "guid": "voiceInfo.voiceId",
28
+ "title": "voiceInfo.name",
29
+ "description": "voiceDetailProperty.text",
30
+ "link": "https://www.lizhi.fm/vod/{voiceInfo.voiceId}",
31
+ "author": "userInfo.name",
32
+ "pubDate": "voiceInfo.createTime",
33
+ "itunes_item_image": "voiceInfo.imageUrl",
34
+ "itunes_duration": "voiceInfo.duration",
35
+ "enclosure_url": "voicePlayProperty.trackUrl",
36
+ "price": "voiceExProperty.voicePrice"
37
+ },
38
+ "meta": {
39
+ "normalizer": "rsshub",
40
+ "type": "post",
41
+ "description": "荔枝 FM — 用户音频",
42
+ "topics": [
43
+ "荔枝",
44
+ "lizhi",
45
+ "播客",
46
+ "电台",
47
+ "podcast",
48
+ "音频"
49
+ ],
50
+ "categories": [
51
+ "podcast"
52
+ ],
53
+ "facility": {
54
+ "key": "lizhi",
55
+ "label": "荔枝 FM"
56
+ },
57
+ "capabilities": [
58
+ "timeline"
59
+ ],
60
+ "key_param": "id",
61
+ "priority": 90,
62
+ "discoverable": true,
63
+ "cadence_hint_seconds": 1800,
64
+ "auth": {
65
+ "type": "none"
66
+ },
67
+ "homepage": "lizhi.fm",
68
+ "params_schema": {
69
+ "id": {
70
+ "type": "string",
71
+ "required": true,
72
+ "description": "用户 id(荔枝 FM 用户主页 URL lizhi.fm/user/<id> 中的数字)"
73
+ }
74
+ },
75
+ "radar": [
76
+ "lizhi.fm/user/:id",
77
+ "www.lizhi.fm/user/:id"
78
+ ]
79
+ }
80
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "@streamapp/lizhi",
3
+ "version": "1.0.0",
4
+ "author": "stream",
5
+ "keywords": [
6
+ "stream-recipe"
7
+ ],
8
+ "stream": {
9
+ "type": "recipe",
10
+ "name": "荔枝 FM",
11
+ "tagline": "某个用户的音频播客",
12
+ "facility": "lizhi",
13
+ "schemaVersion": 1
14
+ }
15
+ }
@@ -0,0 +1,16 @@
1
+ # @streamapp/manmanbuy
2
+
3
+ 慢慢买(manmanbuy.com)· 全网比价关键词搜索。
4
+
5
+ 搜一个商品名,返回各电商平台(京东 / 天猫 / 淘宝 / 拼多多 …)对它的报价与促销,
6
+ 一行一个平台报价 —— 即"同一商品的跨平台比价"。
7
+
8
+ - **能力**:`search`(`provides: search-content`),`key_param: keyword`
9
+ - **取数**:Tier-2 `kind:'html'` recipe,抓慢慢买优惠流页(`s.manmanbuy.com` 的 `c=discount` tab,
10
+ 服务端直出),linkedom + CSS 选择器映射。免签名、免登录、无容器。
11
+ - **为什么不是比价 tab**:站点的商品比价 tab(`c=search`)走带签名的 `prom2Extra` XHR 且要慢慢买
12
+ 登录态(否则 `7700 需登录验证`),成本高一级。优惠流每行本身就是"某平台对某商品的报价",
13
+ 已满足比价意图。要精确到同一 SKU 分组,再考虑升级到浏览器 recipe 打比价 tab。
14
+
15
+ 选择器用 `[class*="DiscountItemPC_..."]` 前缀匹配抗 CSS-module 哈希变动;站点改版导致列表抓空时,
16
+ 按 `browser-harvest` / `onboard-source` 的 html 档重新校准选择器。