@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,521 @@
1
+ # ------------------------------------------------------------------ douyin (handlers)
2
+ # douyin-collection 已迁到 recipes/douyin/(登录态浏览器:进收藏页拦第一发 listcollection,
3
+ # 其余批次在页内调站点自己的签名客户端)。这里的 HTTP 端点是死路:
4
+ # `/aweme/v1/web/aweme/listcollection/` 恒 403 `Blocked by ArgusSecurityPlugin`——它挪到 Argus
5
+ # 那套签名头(X-Argus/X-Gorgon/X-Ladon)后面了,和 bogus 无关(X-Bogus 与 a_bogus × GET/POST
6
+ # 四种组合实测同样的 403),上游 video-service 至今没有任何 Argus 实现。
7
+ - id: douyin-follow
8
+ adapter: Douyin_TikTok_Download_API
9
+ title: 我的关注
10
+ description: 获取已关注创作者的最新作品聚合时间线。
11
+ topics: [douyin, 抖音, 关注, 时间线, 作品, social-media, video]
12
+ categories: [social-media, video]
13
+ example_queries:
14
+ - 我在抖音关注的人最近发了什么
15
+ - douyin 关注时间线
16
+ capabilities: [timeline]
17
+ normalizer: douyin
18
+ auth:
19
+ type: cookie
20
+ domain: douyin.com
21
+ inject: { kind: env, name: DOUYIN_COOKIE }
22
+ cadence_hint_seconds: 1800
23
+ api: { handler: douyin-follow } # 注入 cookie 作 query
24
+ params_schema:
25
+ count: { type: number, required: false }
26
+ # douyin-search 已迁到 recipes/douyin/(登录态浏览器拦 XHR)。这里的 HTTP 搜索端点是死路:
27
+ # 无 cookie → 内层 status_code 2483「请先登录」(外层还是 200,静默空列表);带 cookie →
28
+ # CookieCloud 的 douyin cookie 有 7KB+,塞进 query 会被上游 h11 判为 Invalid HTTP request。
29
+ - id: douyin-user
30
+ adapter: Douyin_TikTok_Download_API
31
+ title: 指定用户作品
32
+ description: 获取指定创作者个人主页发布的所有视频(支持个人主页链接或 sec_user_id 解析)。
33
+ topics: [douyin, 抖音, 用户, 作品, 视频, 博主, social-media, video]
34
+ categories: [social-media, video]
35
+ example_queries:
36
+ - 某个抖音博主的最新视频
37
+ - douyin user videos
38
+ capabilities: [timeline]
39
+ normalizer: douyin
40
+ auth:
41
+ type: none
42
+ cadence_hint_seconds: 3600
43
+ api: { handler: douyin-user } # url → sec_user_id 预解析 (get_sec_user_id)
44
+ params_schema:
45
+ url: { type: string, required: false, description: "个人主页链接" }
46
+ sec_user_id: { type: string, required: false, description: "直接指定 sec_user_id" }
47
+ count: { type: number, required: false }
48
+ radar:
49
+ - source: ["www.douyin.com/user/:sec_user_id"]
50
+ # ------------------------------------------------------------------ bilibili
51
+ - id: bilibili-video
52
+ adapter: Douyin_TikTok_Download_API
53
+ title: 视频详情
54
+ description: 获取特定 BV 号视频的详细元数据,包含标题、封面、播放时长以及 UP 主信息。
55
+ topics: [bilibili, 哔哩哔哩, b站, 视频, video, social-media]
56
+ categories: [social-media, video]
57
+ example_queries:
58
+ - 查一下这个B站视频
59
+ - bilibili video detail
60
+ capabilities: [anchor]
61
+ normalizer: bilibili-web
62
+ auth: { type: none }
63
+ cadence_hint_seconds: 3600
64
+ api:
65
+ endpoint: /api/bilibili/web/fetch_one_video
66
+ query:
67
+ bv_id: { from: bv_id, required: true }
68
+ unwrap: data.data # video-service 透传 bilibili 官方 envelope → 内容在 data.data
69
+ params_schema:
70
+ bv_id: { type: string, required: true, description: "the video's BV id" }
71
+ - id: bilibili-user-profile
72
+ adapter: Douyin_TikTok_Download_API
73
+ title: 用户信息
74
+ description: 查询指定 UID 创作者的个人主页名片,包括昵称、头像、个性签名等。
75
+ topics: [bilibili, 哔哩哔哩, b站, 用户, 主页, social-media]
76
+ categories: [social-media]
77
+ example_queries:
78
+ - 查一下这个B站用户
79
+ - bilibili user profile
80
+ capabilities: [anchor]
81
+ normalizer: bilibili-web
82
+ auth: { type: none }
83
+ cadence_hint_seconds: 86400
84
+ api:
85
+ endpoint: /api/bilibili/web/fetch_user_profile
86
+ query:
87
+ uid: { from: uid, required: true }
88
+ unwrap: data.data
89
+ params_schema:
90
+ uid: { type: string, required: true, description: "bilibili numeric user id" }
91
+ - id: bilibili-user-videos
92
+ adapter: Douyin_TikTok_Download_API
93
+ title: 用户投稿视频
94
+ description: 拉取特定创作者在 B 站公开发布的投稿视频列表。
95
+ topics: [bilibili, 哔哩哔哩, b站, up主, 投稿, 视频, video, social-media]
96
+ categories: [social-media, video]
97
+ example_queries:
98
+ - 某个B站up主的最新视频
99
+ - bilibili user videos
100
+ capabilities: [timeline]
101
+ normalizer: bilibili-web
102
+ auth: { type: none }
103
+ cadence_hint_seconds: 3600
104
+ api:
105
+ endpoint: /api/bilibili/web/fetch_user_post_videos
106
+ query:
107
+ uid: { from: uid, required: true }
108
+ pn: { from: pn, default: 1 }
109
+ unwrap: data.data.list.vlist
110
+ params_schema:
111
+ uid: { type: string, required: true, description: "bilibili numeric user id" }
112
+ pn: { type: number, required: false, description: "page number, default 1" }
113
+ radar:
114
+ - source: ["space.bilibili.com/:uid"]
115
+ - id: bilibili-collection
116
+ adapter: Douyin_TikTok_Download_API
117
+ title: 收藏夹视频
118
+ description: 获取指定公开收藏夹(folder_id)内收录的视频列表。
119
+ topics: [bilibili, 哔哩哔哩, b站, 收藏夹, 视频, video, social-media]
120
+ categories: [social-media, video]
121
+ example_queries:
122
+ - B站收藏夹里的视频
123
+ - bilibili favorites folder videos
124
+ capabilities: [timeline]
125
+ normalizer: bilibili-web
126
+ auth: { type: none }
127
+ cadence_hint_seconds: 3600
128
+ api:
129
+ endpoint: /api/bilibili/web/fetch_user_collection_videos
130
+ query:
131
+ folder_id: { from: folder_id, required: true }
132
+ pn: { from: pn, default: 1 }
133
+ unwrap: data.data.medias
134
+ params_schema:
135
+ folder_id: { type: string, required: true, description: "collection folder id" }
136
+ pn: { type: number, required: false, description: "page number, default 1" }
137
+ - id: bilibili-popular
138
+ adapter: Douyin_TikTok_Download_API
139
+ title: 综合热门视频榜
140
+ description: 获取当前全站最热的视频榜单及推荐流。
141
+ topics: [bilibili, 哔哩哔哩, b站, 热门, 榜单, 发现, video, social-media]
142
+ categories: [social-media, video]
143
+ example_queries:
144
+ - B站热门视频
145
+ - bilibili popular videos
146
+ capabilities: [timeline]
147
+ normalizer: bilibili-web
148
+ auth: { type: none }
149
+ cadence_hint_seconds: 3600
150
+ api:
151
+ endpoint: /api/bilibili/web/fetch_com_popular
152
+ query:
153
+ pn: { from: pn, default: 1 }
154
+ unwrap: data.data.list
155
+ params_schema:
156
+ pn: { type: number, required: false, description: "page number, default 1" }
157
+ - id: bilibili-comments
158
+ adapter: Douyin_TikTok_Download_API
159
+ title: 视频评论
160
+ description: 获取视频下方的用户评论列表,支持按 rpid 获取子回复。
161
+ topics: [bilibili, 哔哩哔哩, b站, 评论, 视频, social-media]
162
+ categories: [social-media]
163
+ example_queries:
164
+ - 看看这个B站视频的评论
165
+ - bilibili video comments
166
+ capabilities: [timeline]
167
+ normalizer: bilibili-web
168
+ auth: { type: none }
169
+ cadence_hint_seconds: 1800
170
+ api: { handler: bilibili-comments } # rpid 有无 → 回复端点/评论端点
171
+ params_schema:
172
+ bv_id: { type: string, required: true, description: "the video's BV id" }
173
+ pn: { type: number, required: false, description: "page number, default 1" }
174
+ rpid: { type: string, required: false, description: "reply id — when set, fetches replies to this comment" }
175
+ - id: bilibili-user-dynamic
176
+ adapter: Douyin_TikTok_Download_API
177
+ title: 用户动态
178
+ description: 追踪指定创作者的最新图文或转发动态流。
179
+ topics: [bilibili, 哔哩哔哩, b站, 动态, 用户, social-media]
180
+ categories: [social-media]
181
+ example_queries:
182
+ - 这个B站用户发了什么动态
183
+ - bilibili user dynamic feed
184
+ capabilities: [timeline]
185
+ normalizer: bilibili-web
186
+ auth: { type: none }
187
+ cadence_hint_seconds: 1800
188
+ api:
189
+ endpoint: /api/bilibili/web/fetch_user_dynamic
190
+ query:
191
+ uid: { from: uid, required: true }
192
+ offset: { from: offset }
193
+ unwrap: data.data.items
194
+ params_schema:
195
+ uid: { type: string, required: true, description: "bilibili numeric user id" }
196
+ offset: { type: string, required: false, description: "pagination offset from a previous page" }
197
+ radar:
198
+ - source: ["space.bilibili.com/:uid"]
199
+ - id: bilibili-danmaku
200
+ adapter: Douyin_TikTok_Download_API
201
+ title: 视频弹幕
202
+ description: 获取指定视频最新的实时弹幕数据流。
203
+ topics: [bilibili, 哔哩哔哩, b站, 弹幕, 视频, social-media]
204
+ categories: [social-media]
205
+ example_queries:
206
+ - 这个B站视频的弹幕
207
+ - bilibili video danmaku
208
+ capabilities: [timeline]
209
+ normalizer: bilibili-web
210
+ auth: { type: none }
211
+ cadence_hint_seconds: 1800
212
+ api: { handler: bilibili-danmaku } # 两步: fetch_one_video 取 cid → fetch_video_danmaku 取 XML
213
+ params_schema:
214
+ bv_id: { type: string, required: true, description: "the video's BV id" }
215
+ - id: bilibili-live-room
216
+ adapter: Douyin_TikTok_Download_API
217
+ title: 直播间信息
218
+ description: 查询直播间当前的播放状态、标题、分区及主播信息。
219
+ topics: [bilibili, 哔哩哔哩, b站, 直播, 直播间, social-media]
220
+ categories: [social-media]
221
+ example_queries:
222
+ - 查一下这个B站直播间
223
+ - bilibili live room detail
224
+ capabilities: [anchor]
225
+ normalizer: bilibili-web
226
+ auth: { type: none }
227
+ cadence_hint_seconds: 600
228
+ api:
229
+ endpoint: /api/bilibili/web/fetch_live_room_detail
230
+ query:
231
+ room_id: { from: room_id, required: true }
232
+ unwrap: data.data
233
+ params_schema:
234
+ room_id: { type: string, required: true, description: "live room id" }
235
+ - id: bilibili-live-videos
236
+ adapter: Douyin_TikTok_Download_API
237
+ title: 直播视频流
238
+ description: 获取指定直播间当前的视频流播放地址。
239
+ topics: [bilibili, 哔哩哔哩, b站, 直播, 视频流, social-media]
240
+ categories: [social-media]
241
+ example_queries:
242
+ - 这个B站直播间的直播流
243
+ - bilibili live stream url
244
+ capabilities: [anchor]
245
+ normalizer: bilibili-web
246
+ auth: { type: none }
247
+ cadence_hint_seconds: 600
248
+ api:
249
+ endpoint: /api/bilibili/web/fetch_live_videos
250
+ query:
251
+ room_id: { from: room_id, required: true }
252
+ unwrap: data.data
253
+ params_schema:
254
+ room_id: { type: string, required: true, description: "live room id" }
255
+ - id: bilibili-live-streamers
256
+ adapter: Douyin_TikTok_Download_API
257
+ title: 直播分区主播
258
+ description: 获取特定直播分区内正在进行直播的主播列表。
259
+ topics: [bilibili, 哔哩哔哩, b站, 直播, 分区, 主播, social-media]
260
+ categories: [social-media]
261
+ example_queries:
262
+ - 这个B站直播分区谁在播
263
+ - bilibili live area streamers
264
+ capabilities: [timeline]
265
+ normalizer: bilibili-web
266
+ auth: { type: none }
267
+ cadence_hint_seconds: 600
268
+ api:
269
+ endpoint: /api/bilibili/web/fetch_live_streamers
270
+ query:
271
+ area_id: { from: area_id, required: true }
272
+ pn: { from: pn, default: 1 }
273
+ unwrap: data.data.list
274
+ params_schema:
275
+ area_id: { type: string, required: true, description: "live area id" }
276
+ pn: { type: number, required: false, description: "page number, default 1" }
277
+ # ------------------------------------------------------------------ tiktok
278
+ # ⚠️ UNWRAP UNVERIFIED (except tiktok-user-profile): tiktok endpoints need a real
279
+ # sec_uid / item_id (and likely a login cookie) to curl-verify against the live backend.
280
+ # The unwrap paths below are the old-adapter values; treat them as PROVISIONAL and
281
+ # re-verify with real data — video-service may wrap tiktok's official envelope like it
282
+ # does bilibili (data.data.*). Tracked as a follow-up task.
283
+ - id: tiktok-video
284
+ adapter: Douyin_TikTok_Download_API
285
+ title: 视频详情
286
+ description: 根据作品 ID 获取 TikTok 视频的详细数据(基于 Web 端接口)。
287
+ topics: [tiktok, video, social-media]
288
+ categories: [social-media, video]
289
+ example_queries:
290
+ - look up this tiktok video
291
+ - tiktok video detail
292
+ capabilities: [anchor]
293
+ normalizer: tiktok
294
+ auth: { type: none }
295
+ cadence_hint_seconds: 3600
296
+ api:
297
+ endpoint: /api/tiktok/web/fetch_one_video
298
+ query:
299
+ itemId: { from: item_id, required: true }
300
+ unwrap: data.itemStruct
301
+ params_schema:
302
+ item_id: { type: string, required: true, description: "the video's item id" }
303
+ - id: tiktok-app-video
304
+ adapter: Douyin_TikTok_Download_API
305
+ title: 视频详情(App)
306
+ description: 根据作品 ID 获取 TikTok 视频的详细数据(基于 App 端接口,签名机制不同)。
307
+ topics: [tiktok, video, social-media]
308
+ categories: [social-media, video]
309
+ example_queries:
310
+ - look up this tiktok video via the app api
311
+ capabilities: [anchor]
312
+ normalizer: tiktok
313
+ auth: { type: none }
314
+ cadence_hint_seconds: 3600
315
+ api:
316
+ endpoint: /api/tiktok/app/fetch_one_video
317
+ query:
318
+ aweme_id: { from: aweme_id, required: true }
319
+ unwrap: data.aweme_detail
320
+ params_schema:
321
+ aweme_id: { type: string, required: true, description: "the video's aweme id" }
322
+ - id: tiktok-user-profile
323
+ adapter: Douyin_TikTok_Download_API
324
+ title: 用户信息
325
+ description: 查询指定创作者的资料卡,支持 uniqueId(用户名)或 secUid。
326
+ topics: [tiktok, 用户, 主页, social-media]
327
+ categories: [social-media]
328
+ example_queries:
329
+ - look up this tiktok user
330
+ capabilities: [anchor]
331
+ normalizer: tiktok
332
+ auth: { type: none }
333
+ cadence_hint_seconds: 86400
334
+ api:
335
+ endpoint: /api/tiktok/web/fetch_user_profile
336
+ query:
337
+ uniqueId: { from: unique_id }
338
+ secUid: { from: sec_uid }
339
+ unwrap: data.userInfo.user # ✅ curl 确证
340
+ params_schema:
341
+ unique_id: { type: string, required: false, description: "the username in the profile url" }
342
+ sec_uid: { type: string, required: false, description: "TikTok's internal secUid, alternative to unique_id" }
343
+ - id: tiktok-user-post
344
+ adapter: Douyin_TikTok_Download_API
345
+ title: 用户投稿视频
346
+ description: 获取指定用户主页公开发布的视频作品列表。
347
+ topics: [tiktok, 用户, 作品, video, social-media]
348
+ categories: [social-media, video]
349
+ example_queries:
350
+ - this tiktok user's latest videos
351
+ capabilities: [timeline]
352
+ normalizer: tiktok
353
+ auth: { type: none }
354
+ cadence_hint_seconds: 3600
355
+ api:
356
+ endpoint: /api/tiktok/web/fetch_user_post
357
+ query:
358
+ secUid: { from: sec_uid, required: true }
359
+ cursor: { from: cursor, default: 0 }
360
+ count: { from: count, default: 35 }
361
+ unwrap: data.itemList
362
+ params_schema:
363
+ sec_uid: { type: string, required: true, description: "the user's secUid" }
364
+ cursor: { type: number, required: false, description: "page cursor, default 0" }
365
+ count: { type: number, required: false, description: "page size, default 35" }
366
+ - id: tiktok-user-playlist
367
+ adapter: Douyin_TikTok_Download_API
368
+ title: 用户播放列表
369
+ description: 获取特定创作者名下的视频合辑或播放列表内容。
370
+ topics: [tiktok, 播放列表, video, social-media]
371
+ categories: [social-media, video]
372
+ example_queries:
373
+ - this tiktok user's playlist
374
+ capabilities: [timeline]
375
+ normalizer: tiktok
376
+ auth: { type: none }
377
+ cadence_hint_seconds: 3600
378
+ api:
379
+ endpoint: /api/tiktok/web/fetch_user_play_list
380
+ query:
381
+ secUid: { from: sec_uid, required: true }
382
+ cursor: { from: cursor, default: 0 }
383
+ count: { from: count, default: 30 }
384
+ unwrap: data.itemList
385
+ params_schema:
386
+ sec_uid: { type: string, required: true, description: "the user's secUid" }
387
+ cursor: { type: number, required: false, description: "page cursor, default 0" }
388
+ count: { type: number, required: false, description: "page size, default 30" }
389
+ - id: tiktok-user-mix
390
+ adapter: Douyin_TikTok_Download_API
391
+ title: 合辑视频列表
392
+ description: 根据合辑 ID(mixId)拉取归属于该合辑的视频列表。
393
+ topics: [tiktok, 合辑, video, social-media]
394
+ categories: [social-media, video]
395
+ example_queries:
396
+ - videos in this tiktok mix/collection
397
+ capabilities: [timeline]
398
+ normalizer: tiktok
399
+ auth: { type: none }
400
+ cadence_hint_seconds: 3600
401
+ api:
402
+ endpoint: /api/tiktok/web/fetch_user_mix
403
+ query:
404
+ mixId: { from: mix_id, required: true }
405
+ cursor: { from: cursor, default: 0 }
406
+ count: { from: count, default: 30 }
407
+ unwrap: data.itemList
408
+ params_schema:
409
+ mix_id: { type: string, required: true, description: "the mix/collection id" }
410
+ cursor: { type: number, required: false, description: "page cursor, default 0" }
411
+ count: { type: number, required: false, description: "page size, default 30" }
412
+ - id: tiktok-user-like
413
+ adapter: Douyin_TikTok_Download_API
414
+ title: 点赞列表
415
+ description: 获取指定用户公开展示的获赞/喜欢视频列表(列表需设为公开可见)。
416
+ topics: [tiktok, 点赞, video, social-media]
417
+ categories: [social-media, video]
418
+ example_queries:
419
+ - this tiktok user's liked videos
420
+ capabilities: [timeline]
421
+ normalizer: tiktok
422
+ auth: { type: none }
423
+ cadence_hint_seconds: 3600
424
+ api:
425
+ endpoint: /api/tiktok/web/fetch_user_like
426
+ query:
427
+ secUid: { from: sec_uid, required: true }
428
+ cursor: { from: cursor, default: 0 }
429
+ count: { from: count, default: 30 }
430
+ unwrap: data.itemList
431
+ params_schema:
432
+ sec_uid: { type: string, required: true, description: "the user's secUid" }
433
+ cursor: { type: number, required: false, description: "page cursor, default 0" }
434
+ count: { type: number, required: false, description: "page size, default 30" }
435
+ - id: tiktok-user-collect
436
+ adapter: Douyin_TikTok_Download_API
437
+ title: 收藏列表
438
+ description: 获取当前已登录账号自身收藏的视频列表。
439
+ topics: [tiktok, 收藏, video, social-media]
440
+ categories: [social-media, video]
441
+ example_queries:
442
+ - my tiktok favorites
443
+ capabilities: [timeline]
444
+ normalizer: tiktok
445
+ auth:
446
+ type: cookie
447
+ domain: tiktok.com
448
+ inject: { kind: env, name: TIKTOK_COOKIE }
449
+ cadence_hint_seconds: 3600
450
+ api: { handler: tiktok-user-collect } # 注入 tiktok cookie 作 query
451
+ params_schema:
452
+ sec_uid: { type: string, required: true, description: "the user's secUid (your own, for this endpoint)" }
453
+ cursor: { type: number, required: false, description: "page cursor, default 0" }
454
+ count: { type: number, required: false, description: "page size, default 30" }
455
+ - id: tiktok-comments
456
+ adapter: Douyin_TikTok_Download_API
457
+ title: 视频评论
458
+ description: 获取指定视频下方的评论列表,支持按 comment_id 进一步获取回复。
459
+ topics: [tiktok, 评论, video, social-media]
460
+ categories: [social-media]
461
+ example_queries:
462
+ - comments on this tiktok video
463
+ capabilities: [timeline]
464
+ normalizer: tiktok
465
+ auth: { type: none }
466
+ cadence_hint_seconds: 1800
467
+ api: { handler: tiktok-comments } # comment_id 有无 → 回复端点/评论端点
468
+ params_schema:
469
+ aweme_id: { type: string, required: true, description: "the video's item id" }
470
+ comment_id: { type: string, required: false, description: "comment id — when set, fetches replies to this comment" }
471
+ cursor: { type: number, required: false, description: "page cursor, default 0" }
472
+ - id: tiktok-user-fans
473
+ adapter: Douyin_TikTok_Download_API
474
+ title: 粉丝列表
475
+ description: 获取指定用户的粉丝列表。
476
+ topics: [tiktok, 粉丝, social-media]
477
+ categories: [social-media]
478
+ example_queries:
479
+ - this tiktok user's followers
480
+ capabilities: [timeline]
481
+ normalizer: tiktok
482
+ auth: { type: none }
483
+ cadence_hint_seconds: 21600
484
+ api:
485
+ endpoint: /api/tiktok/web/fetch_user_fans
486
+ query:
487
+ secUid: { from: sec_uid, required: true }
488
+ count: { from: count, default: 30 }
489
+ maxCursor: { from: max_cursor, default: 0 }
490
+ minCursor: { from: min_cursor, default: 0 }
491
+ unwrap: data.userList
492
+ params_schema:
493
+ sec_uid: { type: string, required: true, description: "the user's secUid" }
494
+ count: { type: number, required: false, description: "page size, default 30" }
495
+ max_cursor: { type: number, required: false, description: "max pagination cursor, default 0" }
496
+ min_cursor: { type: number, required: false, description: "min pagination cursor, default 0" }
497
+ - id: tiktok-user-follow
498
+ adapter: Douyin_TikTok_Download_API
499
+ title: 关注列表
500
+ description: 获取指定用户的关注创作者列表。
501
+ topics: [tiktok, 关注, social-media]
502
+ categories: [social-media]
503
+ example_queries:
504
+ - who this tiktok user follows
505
+ capabilities: [timeline]
506
+ normalizer: tiktok
507
+ auth: { type: none }
508
+ cadence_hint_seconds: 21600
509
+ api:
510
+ endpoint: /api/tiktok/web/fetch_user_follow
511
+ query:
512
+ secUid: { from: sec_uid, required: true }
513
+ count: { from: count, default: 30 }
514
+ maxCursor: { from: max_cursor, default: 0 }
515
+ minCursor: { from: min_cursor, default: 0 }
516
+ unwrap: data.userList
517
+ params_schema:
518
+ sec_uid: { type: string, required: true, description: "the user's secUid" }
519
+ count: { type: number, required: false, description: "page size, default 30" }
520
+ max_cursor: { type: number, required: false, description: "max pagination cursor, default 0" }
521
+ min_cursor: { type: number, required: false, description: "min pagination cursor, default 0" }
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@streamapp/douyin-tiktok-download-api",
3
+ "version": "1.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "stream": {
7
+ "id": "Douyin_TikTok_Download_API",
8
+ "name": "抖音 / TikTok",
9
+ "tagline": "视频平台搜索与解析服务",
10
+ "description": "抖音搜索、用户作品、关注流、合集与视频媒体解析。",
11
+ "backend": {
12
+ "image": "ghcr.io/jaggerh/video-service:latest",
13
+ "service": "douyin-tiktok-download-api",
14
+ "port": 80,
15
+ "health": "/health",
16
+ "standby": {
17
+ "idleMinutes": 30
18
+ }
19
+ },
20
+ "credentials": ["douyin.com", "tiktok.com"],
21
+ "normalizer": "douyin",
22
+ "sourceGrouping": {
23
+ "enabled": true,
24
+ "resolver": "plugin.groupByPlatform"
25
+ },
26
+ "code": {
27
+ "entry": "./activate.ts",
28
+ "adapters": ["Douyin_TikTok_Download_API"],
29
+ "normalizers": ["douyin"]
30
+ }
31
+ }
32
+ }
@@ -0,0 +1,14 @@
1
+ # AList
2
+
3
+ 网盘聚合直链(内置托管容器,Stream 全权接管,不暴露 AList 自身 UI/密码)。
4
+
5
+ ## backend
6
+
7
+ - `image: xhofe/alist:latest` —— 设施官方镜像(§1.2:Stream 永不重新打包)。
8
+ - `service: alist` —— 同网络 DNS:`http://alist:5244`(仅内网,不发布宿主端口)。
9
+ - `health: /ping` —— 2xx = ready(返回 pong)。
10
+ - `volumes` —— 存储挂载配置 + 账号数据持久化,重启不丢。
11
+ - `standby.idleMinutes: 240` —— 网盘挂载/播放随时可能来,不能像冷查询那样几十分钟就停——4 小时空闲
12
+ 才睡,避免播放中途或紧接着的下一次点播撞上频繁启停。trade-off:AList 没有自带管理 UI 的 host
13
+ 直发口(本插件未声明 `publish`),所以 standby 停它不影响外部可达性;但若日后为管理 UI 加
14
+ `publish`,停机窗口里那个口也会跟着不可达,直到下次唤醒。
@@ -0,0 +1,12 @@
1
+ import type { ActivateFn } from '../../src/packages/activate.ts'
2
+ import { AlistAdapter } from './adapter.ts'
3
+ import { alistNormalizer } from '../../src/content/alist.ts'
4
+
5
+ /** 这个包贡献的东西:一个 adapter + 一个 normalizer。
6
+ * `config.url` / `config.token` 都由宿主解析好——token 尤其:它来自 bootstrap 里那段可能跑
7
+ * `provisionAlist` 的异步接管流程,所以 `activatePackages` 的调用点必须排在那之后
8
+ * (`AlistAdapter` 构造时就把 token 收进字段,惰性的只有 client 的构造)。 */
9
+ export const activate: ActivateFn = (ctx) => ({
10
+ adapters: { alist: new AlistAdapter(ctx.config.url as string | undefined, ctx.config.token as string | undefined) },
11
+ normalizers: { alist: alistNormalizer },
12
+ })
@@ -0,0 +1,74 @@
1
+ import type { Adapter, AdapterFetchResult } from '../../src/adapters/types.ts'
2
+ import type { SourceManifest } from '../../src/manifest/types.ts'
3
+ import { AlistClient } from '../../src/netdisk/alist-client.ts'
4
+ import { displayTitle } from '../../src/content/alist.ts'
5
+
6
+ /**
7
+ * token 解析:显式 ctor 参数(bootstrap 传 config.alist_token)→ ALIST_TOKEN env。
8
+ * 对齐 pansou 的三级回退风格(base url 的回退由 AlistClient.resolveAlistUrl 负责:
9
+ * 显式 → ALIST_URL env → 插件网关)。
10
+ */
11
+ export function resolveAlistToken(explicit?: string): string | undefined {
12
+ return explicit ?? process.env.ALIST_TOKEN
13
+ }
14
+
15
+ /**
16
+ * AList 插件适配器 —— 一个 adapter 服务整个 alist 插件的两条 source:
17
+ * - alist-list(fixed_params.mode = 'list'):列目录/枚举文件;
18
+ * - alist-resolve(fixed_params.mode = 'resolve'):文件路径 → 临时直链 raw_url。
19
+ * 复用 src/netdisk/alist-client.ts(fs/list + fs/get + 30min 直链缓存),不重复 HTTP 逻辑。
20
+ *
21
+ * why 惰性建 client:token 走 config/env(非 manifest auth),未配置 token 时插件仍要在
22
+ * 插件页/Provider 成员候选里可见(source 已入 registry),但真正 fetch 才需要 token——
23
+ * 所以 client 到首次 fetch 才构造,未配置时不影响可见性,只在被实际调用时 fail loud。
24
+ */
25
+ export class AlistAdapter implements Adapter {
26
+ readonly id = 'alist'
27
+ private client?: AlistClient
28
+
29
+ constructor(
30
+ private readonly baseUrl?: string,
31
+ private readonly token?: string,
32
+ /** 托管模式的 401 自动重登通道(bootstrap 注入 provision-login);外接模式缺省。 */
33
+ private readonly refresh?: () => Promise<string>,
34
+ ) {}
35
+
36
+ async init(_env: Record<string, string>): Promise<void> {} // 凭证走 config/env,非 manifest broker
37
+
38
+ private ensureClient(): AlistClient {
39
+ if (this.client) return this.client
40
+ const token = resolveAlistToken(this.token)
41
+ if (!token) throw new Error('[alist] 缺少 token:请配置 config.alist_token 或 ALIST_TOKEN 环境变量')
42
+ this.client = new AlistClient({ baseUrl: this.baseUrl, token, refresh: this.refresh })
43
+ return this.client
44
+ }
45
+
46
+ async fetch(params: Record<string, unknown>, manifest: SourceManifest): Promise<unknown[] | AdapterFetchResult> {
47
+ const mode = String(manifest.fixed_params?.mode ?? params.mode ?? 'list')
48
+ const path = String(params.path ?? '/')
49
+ const client = this.ensureClient()
50
+ if (mode === 'resolve') {
51
+ const rawUrl = await client.rawUrl(path)
52
+ return [{ path, raw_url: rawUrl }]
53
+ }
54
+ if (mode === 'audio') {
55
+ const dir = path.replace(/\/$/, '')
56
+ const AUDIO_EXT = /\.(mp3|m4a|aac|flac|ogg|wav|opus)$/i
57
+ const files = await client.listDirRecursive(dir)
58
+ const items = files
59
+ .filter((f) => !f.isDir && AUDIO_EXT.test(f.name))
60
+ .map((f) => {
61
+ const abs = `${dir}/${f.name}`
62
+ const name = f.name.split('/').pop() ?? f.name
63
+ // title 用共享的 displayTitle(剥扩展名/水印/分享者电台名前缀)——前端各处显示的是
64
+ // 顶层 item.title,光在 normalizer 里清洗看不见效果。`name`/`path` 保留真实文件名。
65
+ return { guid: abs, title: displayTitle(name), path: abs, name, size: f.size }
66
+ })
67
+ // 一条 audio 流 = 一个目录,目录名就是电台/专辑名 → 订阅时自动填进流名(backfillLabel)。
68
+ // 只有这一档报:list/resolve 不产订阅流。scheduler 的作者推断兜不住网盘文件(没有 author)。
69
+ return { items, title: dir.split('/').pop() || undefined }
70
+ }
71
+ // 默认 list:枚举目录内文件(AlistFile[]),供绑定向导选目录与增量同步 diff。
72
+ return client.listDir(path)
73
+ }
74
+ }