publishport-opencli 1.0.19 → 1.0.21

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 (1042) hide show
  1. package/cli-manifest.json +35 -0
  2. package/clis/12306/me.js +2 -2
  3. package/clis/12306/orders.js +3 -3
  4. package/clis/12306/passengers.js +3 -3
  5. package/clis/12306/price.js +1 -1
  6. package/clis/12306/stations.js +1 -1
  7. package/clis/12306/train.js +1 -1
  8. package/clis/12306/trains.js +1 -1
  9. package/clis/12306/utils.js +1 -1
  10. package/clis/1688/download.js +1 -1
  11. package/clis/1688/item.js +4 -4
  12. package/clis/1688/search.js +4 -4
  13. package/clis/1688/store.js +4 -4
  14. package/clis/1point3acres/forum.js +1 -1
  15. package/clis/1point3acres/forums.js +1 -1
  16. package/clis/1point3acres/notifications.js +1 -1
  17. package/clis/1point3acres/search.js +1 -1
  18. package/clis/1point3acres/thread.js +2 -2
  19. package/clis/1point3acres/user.js +1 -1
  20. package/clis/1point3acres/utils.js +2 -2
  21. package/clis/36kr/article.js +2 -2
  22. package/clis/36kr/hot.js +2 -2
  23. package/clis/36kr/news.js +1 -1
  24. package/clis/36kr/search.js +2 -2
  25. package/clis/51job/company.js +2 -2
  26. package/clis/51job/detail.js +2 -2
  27. package/clis/51job/hot.js +1 -1
  28. package/clis/51job/search.js +1 -1
  29. package/clis/51job/utils.js +7 -7
  30. package/clis/_atlassian/shared.js +9 -9
  31. package/clis/_shared/article/auth.js +4 -4
  32. package/clis/_shared/article/douban-md2draft.js +4 -4
  33. package/clis/_shared/article/format.js +1 -1
  34. package/clis/_shared/article/images.js +7 -7
  35. package/clis/_shared/article/login.js +1 -1
  36. package/clis/_shared/article/publish.js +11 -11
  37. package/clis/_shared/common.js +1 -1
  38. package/clis/_shared/content-guard.js +1 -1
  39. package/clis/_shared/desktop-commands.js +1 -1
  40. package/clis/_shared/file-inject.js +12 -12
  41. package/clis/_shared/self-hosted-sites.js +2 -2
  42. package/clis/_shared/site-auth.js +1 -1
  43. package/clis/_shared/token-auth.js +2 -2
  44. package/clis/_shared/video-publish.js +9 -9
  45. package/clis/amazon/offer.js +3 -3
  46. package/clis/amazon/product.js +5 -5
  47. package/clis/amazon/shared.js +6 -6
  48. package/clis/antigravity/_actions.js +13 -13
  49. package/clis/antigravity/audit-extras.js +10 -10
  50. package/clis/antigravity/delete.js +1 -1
  51. package/clis/antigravity/model.js +6 -6
  52. package/clis/antigravity/new.js +2 -2
  53. package/clis/antigravity/read.js +2 -2
  54. package/clis/antigravity/rename.js +1 -1
  55. package/clis/antigravity/send.js +3 -3
  56. package/clis/antigravity/serve.js +17 -17
  57. package/clis/antigravity/storage.js +6 -6
  58. package/clis/antigravity/watch.js +2 -2
  59. package/clis/apple-podcasts/episodes.js +1 -1
  60. package/clis/apple-podcasts/top.js +1 -1
  61. package/clis/apple-podcasts/utils.js +1 -1
  62. package/clis/archive/item.js +1 -1
  63. package/clis/archive/search.js +1 -1
  64. package/clis/archive/snapshots.js +1 -1
  65. package/clis/archive/wayback.js +1 -1
  66. package/clis/arxiv/author.js +1 -1
  67. package/clis/arxiv/utils.js +1 -1
  68. package/clis/autohome/brand.js +1 -1
  69. package/clis/autohome/score.js +1 -1
  70. package/clis/autohome/utils.js +1 -1
  71. package/clis/baijiahao/article.js +1 -1
  72. package/clis/baijiahao/lists.js +1 -1
  73. package/clis/baijiahao/login.js +1 -1
  74. package/clis/baijiahao/publish.js +9 -9
  75. package/clis/baijiahao/stats.js +1 -1
  76. package/clis/baijiahao/whoami.js +1 -1
  77. package/clis/band/bands.js +2 -2
  78. package/clis/band/mentions.js +2 -2
  79. package/clis/band/post.js +4 -4
  80. package/clis/band/posts.js +3 -3
  81. package/clis/barchart/flow.js +3 -3
  82. package/clis/barchart/greeks.js +2 -2
  83. package/clis/barchart/quote.js +3 -3
  84. package/clis/bbc/news.js +1 -1
  85. package/clis/bbc/topic.js +1 -1
  86. package/clis/bbc/utils.js +1 -1
  87. package/clis/bilibili/article.js +1 -1
  88. package/clis/bilibili/categories.js +1 -1
  89. package/clis/bilibili/coin.js +1 -1
  90. package/clis/bilibili/comment-del.js +1 -1
  91. package/clis/bilibili/comment-like.js +1 -1
  92. package/clis/bilibili/comment.js +1 -1
  93. package/clis/bilibili/comments.js +1 -1
  94. package/clis/bilibili/dm-list.js +1 -1
  95. package/clis/bilibili/dm-read.js +1 -1
  96. package/clis/bilibili/dm-send.js +1 -1
  97. package/clis/bilibili/download.js +2 -2
  98. package/clis/bilibili/drafts.js +1 -1
  99. package/clis/bilibili/dynamic-post.js +3 -3
  100. package/clis/bilibili/favorite-add.js +1 -1
  101. package/clis/bilibili/favorite.js +1 -1
  102. package/clis/bilibili/feed.js +2 -2
  103. package/clis/bilibili/follow.js +1 -1
  104. package/clis/bilibili/following.js +1 -1
  105. package/clis/bilibili/like.js +1 -1
  106. package/clis/bilibili/partitions.js +1 -1
  107. package/clis/bilibili/stats.js +1 -1
  108. package/clis/bilibili/subtitle.js +3 -3
  109. package/clis/bilibili/summary.js +1 -1
  110. package/clis/bilibili/topics.js +1 -1
  111. package/clis/bilibili/unfollow.js +1 -1
  112. package/clis/bilibili/upload.js +1 -1
  113. package/clis/bilibili/utils.js +10 -10
  114. package/clis/bilibili/video-drafts.js +1 -1
  115. package/clis/bilibili/video.js +1 -1
  116. package/clis/bloomberg/businessweek.js +4 -4
  117. package/clis/bloomberg/news.js +2 -2
  118. package/clis/bloomberg/utils.js +13 -13
  119. package/clis/bluesky/post.js +1 -1
  120. package/clis/bluesky/shared.js +11 -11
  121. package/clis/bluesky/whoami.js +1 -1
  122. package/clis/booking/search.js +2 -2
  123. package/clis/boss/accept.js +1 -1
  124. package/clis/boss/applied.js +1 -1
  125. package/clis/boss/auth.js +1 -1
  126. package/clis/boss/batchgreet.js +1 -1
  127. package/clis/boss/bossinfo.js +1 -1
  128. package/clis/boss/chatlist.js +1 -1
  129. package/clis/boss/chatmsg.js +1 -1
  130. package/clis/boss/cities.js +1 -1
  131. package/clis/boss/detail.js +1 -1
  132. package/clis/boss/exchange.js +1 -1
  133. package/clis/boss/greet.js +1 -1
  134. package/clis/boss/interviews.js +1 -1
  135. package/clis/boss/invite.js +1 -1
  136. package/clis/boss/joblist.js +1 -1
  137. package/clis/boss/mark.js +1 -1
  138. package/clis/boss/me.js +2 -2
  139. package/clis/boss/recommend.js +1 -1
  140. package/clis/boss/resumedelete.js +1 -1
  141. package/clis/boss/resumelist.js +1 -1
  142. package/clis/boss/resumeupload.js +11 -11
  143. package/clis/boss/search.js +1 -1
  144. package/clis/boss/send.js +1 -1
  145. package/clis/boss/sendresume.js +1 -1
  146. package/clis/boss/stats.js +1 -1
  147. package/clis/boss/unread.js +1 -1
  148. package/clis/boss/utils.js +13 -13
  149. package/clis/chaoxing/assignments.js +1 -1
  150. package/clis/chaoxing/exams.js +1 -1
  151. package/clis/chaoxing/utils.js +9 -9
  152. package/clis/chatgpt/ask.js +1 -1
  153. package/clis/chatgpt/auth.js +2 -2
  154. package/clis/chatgpt/detail.js +1 -1
  155. package/clis/chatgpt/image.js +1 -1
  156. package/clis/chatgpt/read.js +1 -1
  157. package/clis/chatgpt/send.js +1 -1
  158. package/clis/chatgpt/utils.js +59 -59
  159. package/clis/chatgpt-app/ask.js +1 -1
  160. package/clis/chatgpt-app/send.js +1 -1
  161. package/clis/chatwise/model.js +6 -6
  162. package/clis/chess/analyze.js +1 -1
  163. package/clis/chess/game.js +1 -1
  164. package/clis/chess/games.js +1 -1
  165. package/clis/chess/stats.js +1 -1
  166. package/clis/chess/utils.js +1 -1
  167. package/clis/claude/ask.js +2 -2
  168. package/clis/claude/detail.js +1 -1
  169. package/clis/claude/new.js +1 -1
  170. package/clis/claude/read.js +1 -1
  171. package/clis/claude/send.js +1 -1
  172. package/clis/claude/utils.js +23 -23
  173. package/clis/cnblogs/article.js +1 -1
  174. package/clis/cnblogs/login.js +1 -1
  175. package/clis/cnblogs/stats.js +7 -7
  176. package/clis/cnblogs/whoami.js +1 -1
  177. package/clis/codex/_actions.js +3 -3
  178. package/clis/codex/archive.js +1 -1
  179. package/clis/codex/ask.js +6 -6
  180. package/clis/codex/model.js +8 -8
  181. package/clis/codex/pin.js +1 -1
  182. package/clis/codex/rename.js +4 -4
  183. package/clis/codex/send.js +3 -3
  184. package/clis/codex/sidebar.js +1 -1
  185. package/clis/coingecko/categories.js +1 -1
  186. package/clis/coingecko/coin.js +1 -1
  187. package/clis/coingecko/derivatives.js +1 -1
  188. package/clis/coingecko/exchanges.js +1 -1
  189. package/clis/coingecko/global.js +1 -1
  190. package/clis/coingecko/trending.js +1 -1
  191. package/clis/confluence/search.js +1 -1
  192. package/clis/coupang/product.js +3 -3
  193. package/clis/coupang/utils.js +1 -1
  194. package/clis/crates/crate.js +1 -1
  195. package/clis/crates/search.js +1 -1
  196. package/clis/crates/utils.js +1 -1
  197. package/clis/csdn/article.js +13 -13
  198. package/clis/csdn/columns.js +1 -1
  199. package/clis/csdn/login.js +1 -1
  200. package/clis/csdn/stats.js +4 -4
  201. package/clis/csdn/whoami.js +1 -1
  202. package/clis/cto51/article.js +1 -1
  203. package/clis/cto51/whoami.js +1 -1
  204. package/clis/ctrip/flight.js +2 -2
  205. package/clis/ctrip/hotel-search.js +3 -3
  206. package/clis/ctrip/hotel-suggest.js +1 -1
  207. package/clis/ctrip/search.js +1 -1
  208. package/clis/ctrip/utils.js +6 -6
  209. package/clis/cursor/ask.js +5 -5
  210. package/clis/cursor/composer.js +2 -2
  211. package/clis/cursor/model.js +4 -4
  212. package/clis/cursor/send.js +2 -2
  213. package/clis/dblp/author.js +1 -1
  214. package/clis/dblp/paper.js +1 -1
  215. package/clis/dblp/search.js +1 -1
  216. package/clis/dblp/utils.js +1 -1
  217. package/clis/dblp/venue.js +1 -1
  218. package/clis/deepseek/ask.js +1 -1
  219. package/clis/deepseek/auth.js +2 -2
  220. package/clis/deepseek/detail.js +1 -1
  221. package/clis/deepseek/new.js +1 -1
  222. package/clis/deepseek/read.js +1 -1
  223. package/clis/deepseek/send.js +7 -7
  224. package/clis/deepseek/utils.js +25 -25
  225. package/clis/defillama/protocol.js +1 -1
  226. package/clis/defillama/protocols.js +1 -1
  227. package/clis/defillama/utils.js +1 -1
  228. package/clis/devto/auth.js +2 -2
  229. package/clis/devto/latest.js +1 -1
  230. package/clis/devto/publish.js +5 -5
  231. package/clis/devto/read.js +2 -2
  232. package/clis/devto/stats.js +3 -3
  233. package/clis/dianping/auth.js +2 -2
  234. package/clis/dianping/cityResolver.js +2 -2
  235. package/clis/dianping/search.js +1 -1
  236. package/clis/dianping/shop.js +1 -1
  237. package/clis/dianping/utils.js +1 -1
  238. package/clis/discord-app/delete.js +3 -3
  239. package/clis/discord-app/read.js +1 -1
  240. package/clis/discord-app/thread-read.js +1 -1
  241. package/clis/discord-web/auth.js +2 -2
  242. package/clis/discord-web/send.js +5 -5
  243. package/clis/dockerhub/image.js +1 -1
  244. package/clis/dockerhub/search.js +1 -1
  245. package/clis/dockerhub/utils.js +1 -1
  246. package/clis/dongchedi/koubei.js +1 -1
  247. package/clis/dongchedi/models.js +1 -1
  248. package/clis/dongchedi/score.js +1 -1
  249. package/clis/dongchedi/search.js +1 -1
  250. package/clis/dongchedi/series.js +1 -1
  251. package/clis/dongchedi/specs.js +1 -1
  252. package/clis/dongchedi/utils.js +1 -1
  253. package/clis/douban/article.js +3 -3
  254. package/clis/douban/auth.js +2 -2
  255. package/clis/douban/download.js +1 -1
  256. package/clis/douban/utils.js +23 -23
  257. package/clis/doubao/auth.js +3 -3
  258. package/clis/doubao/utils.js +39 -39
  259. package/clis/doubao-app/ask.js +1 -1
  260. package/clis/doubao-app/utils.js +4 -4
  261. package/clis/douyin/_shared/browser-fetch.js +7 -7
  262. package/clis/douyin/_shared/draft-cache.js +1 -1
  263. package/clis/douyin/_shared/imagex-upload.js +1 -1
  264. package/clis/douyin/_shared/sts2.js +1 -1
  265. package/clis/douyin/_shared/text-extra.js +1 -1
  266. package/clis/douyin/_shared/tos-upload.js +4 -4
  267. package/clis/douyin/_shared/transcode.js +1 -1
  268. package/clis/douyin/_shared/vod-upload.js +4 -4
  269. package/clis/douyin/draft.js +18 -18
  270. package/clis/douyin/drafts.js +1 -1
  271. package/clis/douyin/publish-image.js +12 -12
  272. package/clis/douyin/publish.js +9 -9
  273. package/clis/douyin/search.js +3 -3
  274. package/clis/douyin/videos.js +1 -1
  275. package/clis/eastmoney/_secid.js +1 -1
  276. package/clis/eastmoney/announcement.js +1 -1
  277. package/clis/eastmoney/article.js +1 -1
  278. package/clis/eastmoney/convertible.js +1 -1
  279. package/clis/eastmoney/etf.js +1 -1
  280. package/clis/eastmoney/holders.js +1 -1
  281. package/clis/eastmoney/index-board.js +1 -1
  282. package/clis/eastmoney/kline.js +1 -1
  283. package/clis/eastmoney/kuaixun.js +1 -1
  284. package/clis/eastmoney/longhu.js +1 -1
  285. package/clis/eastmoney/money-flow.js +1 -1
  286. package/clis/eastmoney/northbound.js +1 -1
  287. package/clis/eastmoney/quote.js +1 -1
  288. package/clis/eastmoney/rank.js +1 -1
  289. package/clis/eastmoney/sectors.js +1 -1
  290. package/clis/endoflife/product.js +1 -1
  291. package/clis/endoflife/utils.js +1 -1
  292. package/clis/facebook/comment.js +8 -8
  293. package/clis/facebook/feed.js +4 -4
  294. package/clis/facebook/like.js +5 -5
  295. package/clis/facebook/notifications.js +3 -3
  296. package/clis/facebook/post.js +11 -11
  297. package/clis/facebook/search.js +3 -3
  298. package/clis/flathub/app.js +1 -1
  299. package/clis/flathub/search.js +1 -1
  300. package/clis/flathub/utils.js +1 -1
  301. package/clis/flomo/memos.js +1 -1
  302. package/clis/gemini/deep-research-result.js +4 -4
  303. package/clis/gemini/deep-research.js +1 -1
  304. package/clis/gemini/detail.js +1 -1
  305. package/clis/gemini/history.js +1 -1
  306. package/clis/gemini/image.js +2 -2
  307. package/clis/gemini/status.js +1 -1
  308. package/clis/gemini/utils.js +43 -43
  309. package/clis/geogebra/hexagon.js +1 -1
  310. package/clis/geogebra/info.js +3 -3
  311. package/clis/geogebra/triangle.js +1 -1
  312. package/clis/geogebra/utils.js +11 -11
  313. package/clis/ghost/login.js +1 -1
  314. package/clis/ghost/shared.js +2 -2
  315. package/clis/gitee/auth.js +2 -2
  316. package/clis/github-trending/repos.js +1 -1
  317. package/clis/google/news.js +1 -1
  318. package/clis/google/search.js +2 -2
  319. package/clis/google/suggest.js +1 -1
  320. package/clis/google/trends.js +1 -1
  321. package/clis/google/utils.js +1 -1
  322. package/clis/goproxy/module.js +1 -1
  323. package/clis/goproxy/utils.js +1 -1
  324. package/clis/goproxy/versions.js +1 -1
  325. package/clis/gov-policy/recent.js +2 -2
  326. package/clis/gov-policy/search.js +2 -2
  327. package/clis/grok/ask.js +1 -1
  328. package/clis/grok/detail.js +1 -1
  329. package/clis/grok/image.js +8 -8
  330. package/clis/grok/pin.js +1 -1
  331. package/clis/grok/send.js +1 -1
  332. package/clis/grok/status.js +1 -1
  333. package/clis/grok/utils.js +21 -21
  334. package/clis/guazi/browse.js +1 -1
  335. package/clis/guazi/car.js +1 -1
  336. package/clis/guazi/utils.js +1 -1
  337. package/clis/hackernews/auth.js +2 -2
  338. package/clis/hackernews/comment.js +8 -8
  339. package/clis/hackernews/read.js +7 -7
  340. package/clis/hackernews/submit.js +7 -7
  341. package/clis/hashnode/auth.js +3 -3
  342. package/clis/hashnode/publish.js +14 -14
  343. package/clis/hf/auth.js +2 -2
  344. package/clis/hf/models.js +1 -1
  345. package/clis/hf/paper.js +1 -1
  346. package/clis/hf/spaces.js +1 -1
  347. package/clis/hf/top.js +1 -1
  348. package/clis/homebrew/cask.js +1 -1
  349. package/clis/homebrew/formula.js +1 -1
  350. package/clis/homebrew/popular.js +1 -1
  351. package/clis/homebrew/utils.js +1 -1
  352. package/clis/huodongxing/events.js +1 -1
  353. package/clis/hupu/detail.js +4 -4
  354. package/clis/hupu/hot.js +3 -3
  355. package/clis/hupu/reply.js +1 -1
  356. package/clis/hupu/search.js +1 -1
  357. package/clis/hupu/unlike.js +1 -1
  358. package/clis/hupu/utils.js +10 -10
  359. package/clis/imdb/person.js +2 -2
  360. package/clis/imdb/reviews.js +3 -3
  361. package/clis/imdb/search.js +2 -2
  362. package/clis/imdb/title.js +1 -1
  363. package/clis/imdb/top.js +1 -1
  364. package/clis/imdb/trending.js +1 -1
  365. package/clis/imdb/utils.js +13 -13
  366. package/clis/imooc/article.js +6 -6
  367. package/clis/imooc/login.js +1 -1
  368. package/clis/imooc/whoami.js +1 -1
  369. package/clis/indeed/job.js +2 -2
  370. package/clis/indeed/search.js +2 -2
  371. package/clis/indeed/utils.js +1 -1
  372. package/clis/infoq/article.js +2 -2
  373. package/clis/infoq/login.js +1 -1
  374. package/clis/infoq/whoami.js +1 -1
  375. package/clis/instagram/_shared/private-publish.js +4 -4
  376. package/clis/instagram/_shared/protocol-capture.js +9 -9
  377. package/clis/instagram/detail.js +3 -3
  378. package/clis/instagram/post.js +25 -25
  379. package/clis/instagram/reel.js +18 -18
  380. package/clis/instagram/story.js +4 -4
  381. package/clis/instagram/user.js +2 -2
  382. package/clis/jd/item.js +65 -65
  383. package/clis/jianshu/article.js +1 -1
  384. package/clis/jianshu/login.js +1 -1
  385. package/clis/jianshu/notebooks.js +1 -1
  386. package/clis/jianshu/whoami.js +1 -1
  387. package/clis/jianyu/search.js +6 -6
  388. package/clis/jianyu/shared/procurement-contract.js +1 -1
  389. package/clis/jike/api.js +6 -6
  390. package/clis/jike/auth.js +3 -3
  391. package/clis/jike/comment.js +1 -1
  392. package/clis/jike/create.js +6 -6
  393. package/clis/jike/feed.js +3 -3
  394. package/clis/jike/like.js +1 -1
  395. package/clis/jike/notifications.js +3 -3
  396. package/clis/jike/repost.js +13 -13
  397. package/clis/jike/search.js +3 -3
  398. package/clis/jimeng/auth.js +2 -2
  399. package/clis/jimeng/generate.js +10 -10
  400. package/clis/jira/shared.js +1 -1
  401. package/clis/juejin/article.js +4 -4
  402. package/clis/juejin/categories.js +1 -1
  403. package/clis/juejin/hot.js +1 -1
  404. package/clis/juejin/login.js +1 -1
  405. package/clis/juejin/recommend.js +1 -1
  406. package/clis/juejin/stats.js +3 -3
  407. package/clis/juejin/tags.js +1 -1
  408. package/clis/juejin/utils.js +1 -1
  409. package/clis/juejin/whoami.js +1 -1
  410. package/clis/ke/utils.js +4 -4
  411. package/clis/kimi/_utils.js +7 -7
  412. package/clis/kimi/audit-extras.js +14 -14
  413. package/clis/kimi/auth.js +3 -3
  414. package/clis/kimi/chat.js +15 -15
  415. package/clis/kimi/storage.js +5 -5
  416. package/clis/kimi/ui.js +13 -13
  417. package/clis/kimi/usage.js +3 -3
  418. package/clis/kuaishou/auth.js +1 -1
  419. package/clis/kuaishou/publish.js +6 -6
  420. package/clis/lesswrong/_helpers.js +5 -5
  421. package/clis/lesswrong/comments.js +5 -5
  422. package/clis/lichess/top.js +1 -1
  423. package/clis/lichess/user.js +1 -1
  424. package/clis/lichess/utils.js +1 -1
  425. package/clis/linkedin/comment.js +1 -1
  426. package/clis/linkedin/connect.js +11 -11
  427. package/clis/linkedin/create.js +5 -5
  428. package/clis/linkedin/follow.js +1 -1
  429. package/clis/linkedin/inbox.js +1 -1
  430. package/clis/linkedin/job-detail.js +3 -3
  431. package/clis/linkedin/like.js +1 -1
  432. package/clis/linkedin/notifications.js +1 -1
  433. package/clis/linkedin/people-search.js +1 -1
  434. package/clis/linkedin/post-comments.js +1 -1
  435. package/clis/linkedin/post-detail.js +1 -1
  436. package/clis/linkedin/profile-analytics.js +1 -1
  437. package/clis/linkedin/profile-api.js +13 -13
  438. package/clis/linkedin/profile-experience.js +1 -1
  439. package/clis/linkedin/profile-projects.js +1 -1
  440. package/clis/linkedin/profile-read.js +3 -3
  441. package/clis/linkedin/reply.js +1 -1
  442. package/clis/linkedin/repost.js +1 -1
  443. package/clis/linkedin/safe-send.js +8 -8
  444. package/clis/linkedin/salesnav-inbox.js +5 -5
  445. package/clis/linkedin/salesnav-message.js +3 -3
  446. package/clis/linkedin/salesnav-search.js +4 -4
  447. package/clis/linkedin/salesnav-thread.js +1 -1
  448. package/clis/linkedin/search-api.js +3 -3
  449. package/clis/linkedin/search.js +8 -8
  450. package/clis/linkedin/social-api.js +31 -31
  451. package/clis/linkedin/timeline.js +3 -3
  452. package/clis/linkedin-learning/search.js +2 -2
  453. package/clis/linkedin-learning/trending.js +2 -2
  454. package/clis/linux-do/feed.js +4 -4
  455. package/clis/linux-do/topic-content.js +8 -8
  456. package/clis/lobsters/domain.js +1 -1
  457. package/clis/lobsters/read.js +7 -7
  458. package/clis/maimai/auth.js +2 -2
  459. package/clis/maimai/search-talents.js +4 -4
  460. package/clis/manus/_utils.js +1 -1
  461. package/clis/mastodon/login.js +1 -1
  462. package/clis/mastodon/post.js +1 -1
  463. package/clis/mastodon/shared.js +12 -12
  464. package/clis/mastodon/whoami.js +1 -1
  465. package/clis/maven/artifact.js +1 -1
  466. package/clis/maven/search.js +1 -1
  467. package/clis/maven/utils.js +1 -1
  468. package/clis/mdn/search.js +1 -1
  469. package/clis/medium/article.js +5 -5
  470. package/clis/medium/login.js +1 -1
  471. package/clis/medium/stats.js +3 -3
  472. package/clis/medium/tag.js +1 -1
  473. package/clis/medium/whoami.js +1 -1
  474. package/clis/mubu/notes.js +1 -1
  475. package/clis/mubu/utils.js +15 -15
  476. package/clis/note/auth.js +2 -2
  477. package/clis/note/note-utils.js +2 -2
  478. package/clis/note/publish.js +8 -8
  479. package/clis/notebooklm/add-source.js +8 -8
  480. package/clis/notebooklm/create.js +1 -1
  481. package/clis/notebooklm/generate-slides.js +1 -1
  482. package/clis/notebooklm/notes-get.js +1 -1
  483. package/clis/notebooklm/rpc.js +8 -8
  484. package/clis/notebooklm/source-fulltext.js +1 -1
  485. package/clis/notebooklm/utils.js +10 -10
  486. package/clis/nowcoder/auth.js +2 -2
  487. package/clis/nowcoder/comment.js +1 -1
  488. package/clis/nowcoder/comments.js +1 -1
  489. package/clis/nowcoder/dm-list.js +1 -1
  490. package/clis/nowcoder/dm-read.js +1 -1
  491. package/clis/nowcoder/dm-send.js +1 -1
  492. package/clis/nowcoder/drafts.js +1 -1
  493. package/clis/nowcoder/inbox.js +1 -1
  494. package/clis/nowcoder/like.js +1 -1
  495. package/clis/nowcoder/my.js +1 -1
  496. package/clis/nowcoder/post.js +1 -1
  497. package/clis/nowcoder/utils.js +13 -13
  498. package/clis/npm/downloads.js +1 -1
  499. package/clis/npm/package.js +1 -1
  500. package/clis/npm/search.js +1 -1
  501. package/clis/npm/utils.js +1 -1
  502. package/clis/nuget/package.js +1 -1
  503. package/clis/nuget/search.js +1 -1
  504. package/clis/nuget/utils.js +1 -1
  505. package/clis/nvd/cve.js +1 -1
  506. package/clis/oeis/search.js +1 -1
  507. package/clis/oeis/sequence.js +1 -1
  508. package/clis/oeis/utils.js +1 -1
  509. package/clis/ones/common.js +6 -6
  510. package/clis/ones/enrich-tasks.js +1 -1
  511. package/clis/ones/my-tasks.js +1 -1
  512. package/clis/ones/resolve-labels.js +1 -1
  513. package/clis/ones/task-helpers.js +1 -1
  514. package/clis/ones/task.js +1 -1
  515. package/clis/ones/worklog.js +7 -7
  516. package/clis/openalex/search.js +1 -1
  517. package/clis/openalex/utils.js +1 -1
  518. package/clis/openalex/work.js +1 -1
  519. package/clis/openfda/drug-label.js +1 -1
  520. package/clis/openfda/food-recall.js +1 -1
  521. package/clis/openfda/utils.js +1 -1
  522. package/clis/openreview/author.js +1 -1
  523. package/clis/openreview/paper.js +1 -1
  524. package/clis/openreview/reviews.js +3 -3
  525. package/clis/openreview/search.js +1 -1
  526. package/clis/openreview/utils.js +1 -1
  527. package/clis/openreview/venue.js +1 -1
  528. package/clis/oschina/article.js +1 -1
  529. package/clis/oschina/catalogs.js +1 -1
  530. package/clis/oschina/login.js +1 -1
  531. package/clis/oschina/stats.js +6 -6
  532. package/clis/oschina/whoami.js +1 -1
  533. package/clis/osv/query.js +1 -1
  534. package/clis/osv/utils.js +1 -1
  535. package/clis/osv/vulnerability.js +1 -1
  536. package/clis/packagist/package.js +1 -1
  537. package/clis/packagist/search.js +1 -1
  538. package/clis/packagist/utils.js +1 -1
  539. package/clis/pinterest/api.js +1 -1
  540. package/clis/pinterest/auth.js +1 -1
  541. package/clis/pinterest/boards.js +1 -1
  542. package/clis/pinterest/client.js +6 -6
  543. package/clis/pinterest/publish.js +5 -5
  544. package/clis/pixiv/auth.js +2 -2
  545. package/clis/pixiv/download.js +1 -1
  546. package/clis/pixiv/illusts.js +1 -1
  547. package/clis/pixiv/search.js +1 -1
  548. package/clis/pixiv/utils.js +3 -3
  549. package/clis/powerchina/auth.js +2 -2
  550. package/clis/powerchina/search.js +1 -1
  551. package/clis/producthunt/browse.js +2 -2
  552. package/clis/producthunt/hot.js +2 -2
  553. package/clis/producthunt/posts.js +1 -1
  554. package/clis/producthunt/today.js +1 -1
  555. package/clis/producthunt/utils.js +1 -1
  556. package/clis/pypi/downloads.js +1 -1
  557. package/clis/pypi/package.js +1 -1
  558. package/clis/pypi/utils.js +1 -1
  559. package/clis/qiita/auth.js +1 -1
  560. package/clis/qiita/gql.js +6 -6
  561. package/clis/qiita/publish.js +4 -4
  562. package/clis/qiita/stats.js +4 -4
  563. package/clis/qoder/_utils.js +16 -16
  564. package/clis/qoder/composer.js +1 -1
  565. package/clis/qoder/quest.js +1 -1
  566. package/clis/qoder/ui.js +14 -14
  567. package/clis/quark/auth.js +2 -2
  568. package/clis/quark/utils.js +2 -2
  569. package/clis/quora/answer-comments.js +3 -3
  570. package/clis/quora/create-answer.js +4 -4
  571. package/clis/quora/create-question.js +3 -3
  572. package/clis/quora/shared.js +17 -17
  573. package/clis/quora/whoami.js +1 -1
  574. package/clis/qwen/ask.js +1 -1
  575. package/clis/qwen/auth.js +3 -3
  576. package/clis/qwen/detail.js +1 -1
  577. package/clis/qwen/image.js +5 -5
  578. package/clis/qwen/status.js +1 -1
  579. package/clis/qwen/utils.js +16 -16
  580. package/clis/reddit/home.js +3 -3
  581. package/clis/reddit/read.js +10 -10
  582. package/clis/reddit/reply.js +4 -4
  583. package/clis/reddit/submit.js +11 -11
  584. package/clis/reddit/subreddit-info.js +3 -3
  585. package/clis/reddit/subscribed.js +4 -4
  586. package/clis/reddit/whoami.js +2 -2
  587. package/clis/rednote/comments.js +1 -1
  588. package/clis/rednote/download.js +1 -1
  589. package/clis/rednote/feed.js +1 -1
  590. package/clis/rednote/note.js +1 -1
  591. package/clis/rednote/notifications.js +2 -2
  592. package/clis/rednote/search.js +2 -2
  593. package/clis/rest-countries/country.js +1 -1
  594. package/clis/rest-countries/region.js +1 -1
  595. package/clis/rest-countries/utils.js +1 -1
  596. package/clis/reuters/article-detail.js +1 -1
  597. package/clis/reuters/auth.js +3 -3
  598. package/clis/reuters/search.js +1 -1
  599. package/clis/reuters/utils.js +4 -4
  600. package/clis/rfc/rfc.js +1 -1
  601. package/clis/rfc/utils.js +1 -1
  602. package/clis/rubygems/gem.js +1 -1
  603. package/clis/rubygems/search.js +1 -1
  604. package/clis/rubygems/utils.js +1 -1
  605. package/clis/segmentfault/article.js +3 -3
  606. package/clis/segmentfault/channels.js +1 -1
  607. package/clis/segmentfault/login.js +1 -1
  608. package/clis/segmentfault/stats.js +4 -4
  609. package/clis/segmentfault/tags.js +1 -1
  610. package/clis/segmentfault/whoami.js +1 -1
  611. package/clis/semanticscholar/citations.js +1 -1
  612. package/clis/semanticscholar/paper.js +1 -1
  613. package/clis/semanticscholar/recommendations.js +1 -1
  614. package/clis/semanticscholar/search.js +1 -1
  615. package/clis/semanticscholar/utils.js +1 -1
  616. package/clis/sinafinance/news.js +1 -1
  617. package/clis/sinafinance/stock-rank.js +1 -1
  618. package/clis/sinafinance/stock.js +1 -1
  619. package/clis/slock/attachment-download.js +1 -1
  620. package/clis/slock/attachment-upload.js +7 -7
  621. package/clis/slock/attachment-url.js +1 -1
  622. package/clis/slock/auth-verify.js +1 -1
  623. package/clis/slock/bookmark-add.js +1 -1
  624. package/clis/slock/bookmark-remove.js +1 -1
  625. package/clis/slock/channel-action.js +1 -1
  626. package/clis/slock/channel-create.js +1 -1
  627. package/clis/slock/channel-files.js +1 -1
  628. package/clis/slock/channel-list.js +1 -1
  629. package/clis/slock/channel-mark.js +1 -1
  630. package/clis/slock/channel-members.js +1 -1
  631. package/clis/slock/channel-unarchive.js +1 -1
  632. package/clis/slock/dm-list.js +1 -1
  633. package/clis/slock/errors.js +1 -1
  634. package/clis/slock/in-page.js +28 -28
  635. package/clis/slock/inbox-done.js +5 -5
  636. package/clis/slock/inbox.js +1 -1
  637. package/clis/slock/message-read.js +22 -22
  638. package/clis/slock/message-search.js +10 -10
  639. package/clis/slock/message-send.js +25 -25
  640. package/clis/slock/reaction-add.js +1 -1
  641. package/clis/slock/reaction-remove.js +1 -1
  642. package/clis/slock/resolve.js +1 -1
  643. package/clis/slock/server-list.js +2 -2
  644. package/clis/slock/task-claim.js +4 -4
  645. package/clis/slock/task-convert.js +13 -13
  646. package/clis/slock/task-create.js +1 -1
  647. package/clis/slock/task-delete.js +5 -5
  648. package/clis/slock/task-get.js +5 -5
  649. package/clis/slock/task-list-server.js +4 -4
  650. package/clis/slock/task-list.js +5 -5
  651. package/clis/slock/task-status.js +3 -3
  652. package/clis/slock/task-unclaim.js +3 -3
  653. package/clis/slock/thread-follow.js +1 -1
  654. package/clis/slock/thread-state.js +1 -1
  655. package/clis/slock/unread-summary.js +5 -5
  656. package/clis/slock/whoami.js +1 -1
  657. package/clis/smzdm/search.js +3 -3
  658. package/clis/sohu/article.js +1 -1
  659. package/clis/sohu/attributes.js +1 -1
  660. package/clis/sohu/categories.js +1 -1
  661. package/clis/sohu/channels.js +1 -1
  662. package/clis/sohu/columns.js +1 -1
  663. package/clis/sohu/login.js +1 -1
  664. package/clis/sohu/stats.js +3 -3
  665. package/clis/sohu/topics.js +1 -1
  666. package/clis/sohu/whoami.js +1 -1
  667. package/clis/spotify/spotify.js +1 -1
  668. package/clis/stackoverflow/read.js +6 -6
  669. package/clis/stackoverflow/related.js +1 -1
  670. package/clis/stackoverflow/tag.js +1 -1
  671. package/clis/stackoverflow/user.js +1 -1
  672. package/clis/stackoverflow/utils.js +1 -1
  673. package/clis/steam/app.js +1 -1
  674. package/clis/steam/search.js +1 -1
  675. package/clis/steam/utils.js +1 -1
  676. package/clis/substack/auth.js +2 -2
  677. package/clis/substack/post-utils.js +2 -2
  678. package/clis/substack/publish.js +5 -5
  679. package/clis/suno/auth.js +2 -2
  680. package/clis/suno/download.js +5 -5
  681. package/clis/suno/generate.js +3 -3
  682. package/clis/suno/list.js +1 -1
  683. package/clis/suno/status.js +1 -1
  684. package/clis/suno/utils.js +29 -29
  685. package/clis/telegram/send.js +7 -7
  686. package/clis/telegram/shared.js +2 -2
  687. package/clis/telegram/whoami.js +1 -1
  688. package/clis/test-utils.js +1 -1
  689. package/clis/threads/post.js +23 -23
  690. package/clis/threads/shared.js +3 -3
  691. package/clis/threads/whoami.js +1 -1
  692. package/clis/tieba/hot.js +3 -3
  693. package/clis/tieba/posts.js +1 -1
  694. package/clis/tieba/read.js +2 -2
  695. package/clis/tieba/search.js +3 -3
  696. package/clis/tieba/utils.js +1 -1
  697. package/clis/tiktok/comment.js +2 -2
  698. package/clis/tiktok/creator-videos.js +3 -3
  699. package/clis/tiktok/explore.js +3 -3
  700. package/clis/tiktok/follow.js +8 -8
  701. package/clis/tiktok/following.js +4 -4
  702. package/clis/tiktok/friends.js +7 -7
  703. package/clis/tiktok/live.js +3 -3
  704. package/clis/tiktok/notifications.js +6 -6
  705. package/clis/tiktok/publish.js +16 -16
  706. package/clis/tiktok/unfollow.js +4 -4
  707. package/clis/tiktok/user.js +2 -2
  708. package/clis/tiktok/utils.js +1 -1
  709. package/clis/toutiao/article.js +1 -1
  710. package/clis/toutiao/articles.js +2 -2
  711. package/clis/toutiao/auth.js +2 -2
  712. package/clis/toutiao/hot.js +1 -1
  713. package/clis/toutiao/recommend.js +1 -1
  714. package/clis/toutiao/utils.js +2 -2
  715. package/clis/trae-solo/_actions.js +4 -4
  716. package/clis/trae-solo/_fs.js +5 -5
  717. package/clis/trae-solo/_state.js +2 -2
  718. package/clis/trae-solo/automation.js +4 -4
  719. package/clis/trae-solo/mode.js +4 -4
  720. package/clis/trae-solo/model.js +4 -4
  721. package/clis/trae-solo/renderer-storage.js +4 -4
  722. package/clis/trae-solo/settings.js +1 -1
  723. package/clis/trae-solo/skill-fs.js +1 -1
  724. package/clis/trae-solo/skill.js +12 -12
  725. package/clis/trae-solo/state-fs.js +2 -2
  726. package/clis/trae-solo/task-fs.js +5 -5
  727. package/clis/trae-solo/workspaces-fs.js +1 -1
  728. package/clis/tumblr/auth.js +2 -2
  729. package/clis/tumblr/publish.js +3 -3
  730. package/clis/tvmaze/search.js +1 -1
  731. package/clis/tvmaze/show.js +1 -1
  732. package/clis/tvmaze/utils.js +1 -1
  733. package/clis/twitter/accept.js +7 -7
  734. package/clis/twitter/article.js +7 -7
  735. package/clis/twitter/bookmark-folder.js +3 -3
  736. package/clis/twitter/bookmark-folders.js +3 -3
  737. package/clis/twitter/bookmarks.js +4 -4
  738. package/clis/twitter/delete.js +5 -5
  739. package/clis/twitter/device-follow.js +3 -3
  740. package/clis/twitter/dm-list.js +1 -1
  741. package/clis/twitter/dm-read.js +1 -1
  742. package/clis/twitter/dm-send.js +5 -5
  743. package/clis/twitter/dm-shared.js +3 -3
  744. package/clis/twitter/download.js +6 -6
  745. package/clis/twitter/followers.js +5 -5
  746. package/clis/twitter/following.js +2 -2
  747. package/clis/twitter/like.js +3 -3
  748. package/clis/twitter/likes.js +8 -8
  749. package/clis/twitter/list-add-core.js +9 -9
  750. package/clis/twitter/list-create.js +5 -5
  751. package/clis/twitter/list-remove-core.js +9 -9
  752. package/clis/twitter/list-tweets.js +7 -7
  753. package/clis/twitter/lists.js +6 -6
  754. package/clis/twitter/notifications.js +2 -2
  755. package/clis/twitter/post.js +24 -24
  756. package/clis/twitter/profile.js +7 -7
  757. package/clis/twitter/quote.js +7 -7
  758. package/clis/twitter/reply-dm.js +7 -7
  759. package/clis/twitter/reply.js +12 -12
  760. package/clis/twitter/retweet.js +3 -3
  761. package/clis/twitter/scheduled-delete.js +3 -3
  762. package/clis/twitter/scheduled-list.js +2 -2
  763. package/clis/twitter/scheduled-utils.js +3 -3
  764. package/clis/twitter/search.js +5 -5
  765. package/clis/twitter/shared.js +6 -6
  766. package/clis/twitter/thread.js +4 -4
  767. package/clis/twitter/timeline.js +3 -3
  768. package/clis/twitter/trending.js +2 -2
  769. package/clis/twitter/tweets.js +11 -11
  770. package/clis/twitter/unlike.js +3 -3
  771. package/clis/twitter/unretweet.js +3 -3
  772. package/clis/twitter/utils.js +6 -6
  773. package/clis/upwork/detail.js +2 -2
  774. package/clis/upwork/feed.js +2 -2
  775. package/clis/upwork/search.js +2 -2
  776. package/clis/upwork/utils.js +1 -1
  777. package/clis/v2ex/auth.js +2 -2
  778. package/clis/v2ex/daily.js +3 -3
  779. package/clis/v2ex/me.js +2 -2
  780. package/clis/v2ex/notifications.js +2 -2
  781. package/clis/vk/post.js +1 -1
  782. package/clis/vk/shared.js +2 -2
  783. package/clis/vk/whoami.js +1 -1
  784. package/clis/web/read.js +8 -8
  785. package/clis/wechat-channels/auth.js +2 -2
  786. package/clis/wechat-channels/publish.js +30 -30
  787. package/clis/weibo/article.js +1 -1
  788. package/clis/weibo/auth.js +3 -3
  789. package/clis/weibo/comments.js +1 -1
  790. package/clis/weibo/delete.js +2 -2
  791. package/clis/weibo/feed.js +3 -3
  792. package/clis/weibo/hot.js +1 -1
  793. package/clis/weibo/publish.js +10 -10
  794. package/clis/weibo/search.js +2 -2
  795. package/clis/weibo/user-posts.js +3 -3
  796. package/clis/weibo/user.js +2 -2
  797. package/clis/weibo/utils.js +3 -3
  798. package/clis/weixin/article.js +1 -1
  799. package/clis/weixin/create-draft.js +26 -26
  800. package/clis/weixin/download.js +2 -2
  801. package/clis/weixin/login.js +1 -1
  802. package/clis/weixin/search.js +2 -2
  803. package/clis/weixin/stats.js +3 -3
  804. package/clis/weixin/whoami.js +1 -1
  805. package/clis/weread/ai-outline.js +2 -2
  806. package/clis/weread/book-search.js +2 -2
  807. package/clis/weread/book.js +2 -2
  808. package/clis/weread/notebooks.js +1 -1
  809. package/clis/weread/search.js +1 -1
  810. package/clis/weread/shelf.js +1 -1
  811. package/clis/weread/utils.js +6 -6
  812. package/clis/weread-official/book.js +1 -1
  813. package/clis/weread-official/discover.js +1 -1
  814. package/clis/weread-official/list-apis.js +1 -1
  815. package/clis/weread-official/notes.js +1 -1
  816. package/clis/weread-official/readdata.js +1 -1
  817. package/clis/weread-official/review.js +1 -1
  818. package/clis/weread-official/search.js +1 -1
  819. package/clis/weread-official/shelf.js +1 -1
  820. package/clis/weread-official/utils.js +1 -1
  821. package/clis/wikidata/entity.js +1 -1
  822. package/clis/wikidata/search.js +1 -1
  823. package/clis/wikidata/utils.js +1 -1
  824. package/clis/wikipedia/page.js +1 -1
  825. package/clis/wikipedia/trending.js +1 -1
  826. package/clis/wikipedia/utils.js +1 -1
  827. package/clis/wordpress/login.js +1 -1
  828. package/clis/wordpress/publish.js +1 -1
  829. package/clis/wordpress/shared.js +3 -3
  830. package/clis/wordpress/whoami.js +1 -1
  831. package/clis/woshipm/article.js +1 -1
  832. package/clis/woshipm/login.js +1 -1
  833. package/clis/woshipm/stats.js +4 -4
  834. package/clis/woshipm/whoami.js +1 -1
  835. package/clis/wttr/current.js +1 -1
  836. package/clis/wttr/forecast.js +1 -1
  837. package/clis/wttr/utils.js +1 -1
  838. package/clis/xianyu/collect.js +1 -1
  839. package/clis/xianyu/inbox.js +1 -1
  840. package/clis/xianyu/item-stats.js +2 -2
  841. package/clis/xianyu/location.js +1 -1
  842. package/clis/xianyu/manage.js +1 -1
  843. package/clis/xianyu/messages.js +1 -1
  844. package/clis/xianyu/mtop.js +5 -5
  845. package/clis/xianyu/order.js +1 -1
  846. package/clis/xianyu/promote-stats.js +2 -2
  847. package/clis/xianyu/publish.js +17 -17
  848. package/clis/xianyu/rate.js +1 -1
  849. package/clis/xianyu/reply.js +1 -1
  850. package/clis/xianyu/search.js +8 -8
  851. package/clis/xianyu/seller-data.js +1 -1
  852. package/clis/xianyu/seller-list.js +1 -1
  853. package/clis/xianyu/user.js +1 -1
  854. package/clis/xiaoe/catalog.js +2 -2
  855. package/clis/xiaoe/content.js +2 -2
  856. package/clis/xiaoe/courses.js +2 -2
  857. package/clis/xiaohongshu/ask.js +6 -6
  858. package/clis/xiaohongshu/comments.js +6 -6
  859. package/clis/xiaohongshu/creator-note-detail.js +7 -7
  860. package/clis/xiaohongshu/creator-notes-summary.js +1 -1
  861. package/clis/xiaohongshu/creator-notes.js +13 -13
  862. package/clis/xiaohongshu/creator-profile.js +2 -2
  863. package/clis/xiaohongshu/creator-stats.js +2 -2
  864. package/clis/xiaohongshu/delete-note.js +7 -7
  865. package/clis/xiaohongshu/download.js +4 -4
  866. package/clis/xiaohongshu/feed.js +2 -2
  867. package/clis/xiaohongshu/follow.js +3 -3
  868. package/clis/xiaohongshu/human.js +3 -3
  869. package/clis/xiaohongshu/note-helpers.js +1 -1
  870. package/clis/xiaohongshu/note.js +2 -2
  871. package/clis/xiaohongshu/notifications.js +1 -1
  872. package/clis/xiaohongshu/publish-video.js +8 -8
  873. package/clis/xiaohongshu/publish.js +59 -59
  874. package/clis/xiaohongshu/search.js +8 -8
  875. package/clis/xiaohongshu/unfollow.js +4 -4
  876. package/clis/xiaohongshu/user-helpers.js +1 -1
  877. package/clis/xiaohongshu/user.js +2 -2
  878. package/clis/xiaoyuzhou/auth.js +3 -3
  879. package/clis/xiaoyuzhou/download.js +1 -1
  880. package/clis/xiaoyuzhou/utils.js +1 -1
  881. package/clis/xueqiu/article.js +4 -4
  882. package/clis/xueqiu/comments.js +4 -4
  883. package/clis/xueqiu/danjuan-utils.js +4 -4
  884. package/clis/xueqiu/earnings-date.js +1 -1
  885. package/clis/xueqiu/events.js +3 -3
  886. package/clis/xueqiu/hashtags.js +3 -3
  887. package/clis/xueqiu/stocks.js +3 -3
  888. package/clis/xueqiu/users.js +3 -3
  889. package/clis/xueqiu/utils.js +3 -3
  890. package/clis/yahoo-finance/quote.js +1 -1
  891. package/clis/yollomi/background.js +1 -1
  892. package/clis/yollomi/edit.js +1 -1
  893. package/clis/yollomi/face-swap.js +1 -1
  894. package/clis/yollomi/generate.js +1 -1
  895. package/clis/yollomi/object-remover.js +1 -1
  896. package/clis/yollomi/remove-bg.js +1 -1
  897. package/clis/yollomi/restore.js +1 -1
  898. package/clis/yollomi/try-on.js +1 -1
  899. package/clis/yollomi/upload.js +4 -4
  900. package/clis/yollomi/upscale.js +1 -1
  901. package/clis/yollomi/utils.js +4 -4
  902. package/clis/yollomi/video.js +1 -1
  903. package/clis/youtube/channel.js +4 -4
  904. package/clis/youtube/feed.js +2 -2
  905. package/clis/youtube/like.js +5 -5
  906. package/clis/youtube/playlist.js +7 -7
  907. package/clis/youtube/publish.js +11 -11
  908. package/clis/youtube/search.js +3 -3
  909. package/clis/youtube/subscribe.js +7 -7
  910. package/clis/youtube/subscriptions.js +1 -1
  911. package/clis/youtube/transcript-group.js +2 -2
  912. package/clis/youtube/transcript.js +13 -13
  913. package/clis/youtube/unlike.js +5 -5
  914. package/clis/youtube/unsubscribe.js +7 -7
  915. package/clis/youtube/utils.js +3 -3
  916. package/clis/youtube/video.js +4 -4
  917. package/clis/youtube/watch-later.js +2 -2
  918. package/clis/yuanbao/ask.js +18 -18
  919. package/clis/yuanbao/detail.js +1 -1
  920. package/clis/yuanbao/read.js +1 -1
  921. package/clis/yuanbao/shared.js +9 -9
  922. package/clis/yuanbao/status.js +1 -1
  923. package/clis/yuque/article.js +1 -1
  924. package/clis/yuque/whoami.js +1 -1
  925. package/clis/zhihu/answer-comments.js +2 -2
  926. package/clis/zhihu/answer-detail.js +3 -3
  927. package/clis/zhihu/answer.js +1 -1
  928. package/clis/zhihu/article-transform.js +1 -1
  929. package/clis/zhihu/article.js +1 -1
  930. package/clis/zhihu/auth.js +2 -2
  931. package/clis/zhihu/collection.js +3 -3
  932. package/clis/zhihu/collections.js +3 -3
  933. package/clis/zhihu/download.js +2 -2
  934. package/clis/zhihu/image-profile.js +6 -6
  935. package/clis/zhihu/paginate.js +3 -3
  936. package/clis/zhihu/pin.js +4 -4
  937. package/clis/zhihu/question.js +3 -3
  938. package/clis/zhihu/recommend.js +3 -3
  939. package/clis/zhihu/search.js +3 -3
  940. package/clis/zhihu/stats.js +3 -3
  941. package/clis/zhihu/user-arg.js +1 -1
  942. package/clis/zhihu/write-shared.js +7 -7
  943. package/clis/zlibrary/utils.js +6 -6
  944. package/clis/zsxq/auth.js +3 -3
  945. package/clis/zsxq/search.js +1 -1
  946. package/clis/zsxq/topic.js +1 -1
  947. package/clis/zsxq/utils.js +5 -5
  948. package/dist/src/adapter-source.js +1 -1
  949. package/dist/src/browser/analyze.js +1 -1
  950. package/dist/src/browser/article-extract.js +2 -2
  951. package/dist/src/browser/ax-snapshot.js +2 -2
  952. package/dist/src/browser/base-page.js +25 -25
  953. package/dist/src/browser/bridge.js +1 -1
  954. package/dist/src/browser/cdp.js +1 -1
  955. package/dist/src/browser/daemon-client.js +1 -1
  956. package/dist/src/browser/daemon-lifecycle.js +7 -7
  957. package/dist/src/browser/dom-helpers.js +35 -35
  958. package/dist/src/browser/dom-snapshot.js +19 -19
  959. package/dist/src/browser/errors.js +3 -3
  960. package/dist/src/browser/extract.js +5 -5
  961. package/dist/src/browser/find.js +13 -13
  962. package/dist/src/browser/fingerprint.js +2 -2
  963. package/dist/src/browser/html-tree.js +6 -6
  964. package/dist/src/browser/managed-chrome.js +1 -1
  965. package/dist/src/browser/network-cache.js +1 -1
  966. package/dist/src/browser/network-key.js +1 -1
  967. package/dist/src/browser/page.js +7 -7
  968. package/dist/src/browser/profile.js +2 -2
  969. package/dist/src/browser/proxy-test.js +8 -8
  970. package/dist/src/browser/shape-filter.js +1 -1
  971. package/dist/src/browser/shape.js +1 -1
  972. package/dist/src/browser/stealth.js +3 -3
  973. package/dist/src/browser/tabs.js +2 -2
  974. package/dist/src/browser/target-errors.js +1 -1
  975. package/dist/src/browser/target-resolver.js +23 -23
  976. package/dist/src/browser/trace.js +2 -2
  977. package/dist/src/browser/utils.js +1 -1
  978. package/dist/src/browser/verify-fixture.js +2 -2
  979. package/dist/src/browser-session-lock.js +1 -1
  980. package/dist/src/build-manifest.js +11 -11
  981. package/dist/src/capabilityRouting.js +1 -1
  982. package/dist/src/cli-argv-preprocess.js +1 -1
  983. package/dist/src/cli.js +32 -32
  984. package/dist/src/commanderAdapter.js +3 -3
  985. package/dist/src/commands/auth.js +3 -3
  986. package/dist/src/commands/daemon.js +1 -1
  987. package/dist/src/completion-fast.js +1 -1
  988. package/dist/src/completion.js +1 -1
  989. package/dist/src/constants.js +1 -1
  990. package/dist/src/convention-audit.js +2 -2
  991. package/dist/src/daemon-utils.js +1 -1
  992. package/dist/src/daemon.js +1 -1
  993. package/dist/src/discovery.js +2 -2
  994. package/dist/src/doctor.js +9 -9
  995. package/dist/src/download/article-download.js +15 -15
  996. package/dist/src/download/index.js +4 -4
  997. package/dist/src/download/media-download.js +1 -1
  998. package/dist/src/download/progress.js +3 -3
  999. package/dist/src/electron-apps.js +1 -1
  1000. package/dist/src/errors.js +2 -2
  1001. package/dist/src/execution.js +2 -2
  1002. package/dist/src/external.js +1 -1
  1003. package/dist/src/help.js +8 -8
  1004. package/dist/src/hooks.js +1 -1
  1005. package/dist/src/interceptor.js +21 -21
  1006. package/dist/src/launcher.js +7 -7
  1007. package/dist/src/logger.js +8 -8
  1008. package/dist/src/main.js +7 -7
  1009. package/dist/src/observation/artifact.js +5 -5
  1010. package/dist/src/observation/retention.js +1 -1
  1011. package/dist/src/output.js +2 -2
  1012. package/dist/src/package-paths.js +1 -1
  1013. package/dist/src/pipeline/executor.js +1 -1
  1014. package/dist/src/pipeline/registry.js +1 -1
  1015. package/dist/src/pipeline/steps/browser.js +1 -1
  1016. package/dist/src/pipeline/steps/download.js +1 -1
  1017. package/dist/src/pipeline/steps/fetch.js +6 -6
  1018. package/dist/src/pipeline/steps/intercept.js +1 -1
  1019. package/dist/src/pipeline/steps/tap.js +17 -17
  1020. package/dist/src/pipeline/steps/transform.js +1 -1
  1021. package/dist/src/pipeline/template.js +1 -1
  1022. package/dist/src/plugin-manifest.js +1 -1
  1023. package/dist/src/plugin-scaffold.js +19 -19
  1024. package/dist/src/plugin.js +12 -12
  1025. package/dist/src/rate-limit.js +1 -1
  1026. package/dist/src/registry.js +1 -1
  1027. package/dist/src/runtime-detect.js +1 -1
  1028. package/dist/src/runtime.js +1 -1
  1029. package/dist/src/scripts/framework.js +1 -1
  1030. package/dist/src/scripts/interact.js +1 -1
  1031. package/dist/src/scripts/store.js +1 -1
  1032. package/dist/src/serialization.js +2 -2
  1033. package/dist/src/session-lease.js +1 -1
  1034. package/dist/src/snapshotFormatter.js +2 -2
  1035. package/dist/src/tui.js +12 -12
  1036. package/dist/src/user-runtime.js +1 -1
  1037. package/dist/src/utils.d.ts +12 -0
  1038. package/dist/src/utils.js +4 -4
  1039. package/dist/src/validate.js +2 -2
  1040. package/dist/src/verify.js +2 -2
  1041. package/dist/src/version.js +1 -1
  1042. package/package.json +1 -1
package/clis/suno/list.js CHANGED
@@ -1,4 +1,4 @@
1
- import{cli as d,Strategy as u}from"@jackwener/opencli/registry";import{CommandExecutionError as i,EmptyResultError as p}from"@jackwener/opencli/errors";import{STUDIO_API as c,SUNO_DOMAIN as f,SUNO_URL as m,ensureSunoSession as y,requireNonNegativeInt as w,requirePositiveInt as g,unwrapEvaluateResult as k}from"./utils.js";export const listCommand=d({site:"suno",name:"list",access:"read",description:"List recent Suno clips in your library (id, title, status, created_at, link)",domain:f,strategy:u.COOKIE,browser:!0,siteSession:"persistent",navigateBefore:!1,args:[{name:"limit",type:"int",default:20,help:"Max clips to list (default: 20)"},{name:"page",type:"int",default:0,help:"Pagination offset, 0-based (default: 0)"}],columns:["rank","clip","title","status","created","link"],func:async(r,s)=>{const a=g(s.limit,"--limit"),o=w(s.page??0,"--page"),n=(await y(r)).deviceId,t=k(await r.evaluate(`(async () => {
1
+ import{cli as u,Strategy as d}from"@jackwener/opencli/registry";import{CommandExecutionError as i,EmptyResultError as p}from"@jackwener/opencli/errors";import{STUDIO_API as c,SUNO_DOMAIN as f,SUNO_URL as m,ensureSunoSession as y,requireNonNegativeInt as w,requirePositiveInt as k,unwrapEvaluateResult as g}from"./utils.js";export const listCommand=u({site:"suno",name:"list",access:"read",description:"List recent Suno clips in your library (id, title, status, created_at, link)",domain:f,strategy:d.COOKIE,browser:!0,siteSession:"persistent",navigateBefore:!1,args:[{name:"limit",type:"int",default:20,help:"Max clips to list (default: 20)"},{name:"page",type:"int",default:0,help:"Pagination offset, 0-based (default: 0)"}],columns:["rank","clip","title","status","created","link"],func:async(r,s)=>{const a=k(s.limit,"--limit"),o=w(s.page??0,"--page"),n=(await y(r)).deviceId,t=g(await r.evaluate(`(async () => {
2
2
  const browserToken = JSON.stringify({ token: btoa(JSON.stringify({ timestamp: Date.now() })) });
3
3
  const res = await fetch('${c}/api/feed/v2?page=${o}', {
4
4
  headers: {
@@ -1 +1 @@
1
- import{cli as H,Strategy as J}from"@jackwener/opencli/registry";import{AuthRequiredError as K,CommandExecutionError as W}from"@jackwener/opencli/errors";import{SUNO_DOMAIN as L,checkSunoCaptcha as P,ensureSunoSession as Q}from"./utils.js";export const statusCommand=H({site:"suno",name:"status",access:"read",description:"Check Suno login, plan, credit balance, and captcha readiness",domain:L,strategy:J.COOKIE,browser:!0,siteSession:"persistent",navigateBefore:!1,args:[],columns:["Status","Plan","Credits","Monthly","Captcha"],func:async(F)=>{let x;try{x=await Q(F)}catch(B){if(B instanceof K)return[{Status:"Not logged in",Plan:"-",Credits:"-",Monthly:"-",Captcha:"-"}];throw B}let z;try{z=await P(F,x.deviceId)}catch(B){z={required:!0}}const G=x.breakdown;return[{Status:"Connected",Plan:x.planKey,Credits:String(x.totalCreditsAvailable),Monthly:`${G.monthlyRemaining}/${G.monthlyLimit}`,Captcha:z?.required===!0?"Required (solve in UI)":"Not required"}]}});
1
+ import{cli as o,Strategy as i}from"@jackwener/opencli/registry";import{AuthRequiredError as s,CommandExecutionError as m}from"@jackwener/opencli/errors";import{SUNO_DOMAIN as c,checkSunoCaptcha as u,ensureSunoSession as d}from"./utils.js";export const statusCommand=o({site:"suno",name:"status",access:"read",description:"Check Suno login, plan, credit balance, and captcha readiness",domain:c,strategy:i.COOKIE,browser:!0,siteSession:"persistent",navigateBefore:!1,args:[],columns:["Status","Plan","Credits","Monthly","Captcha"],func:async(a)=>{let t;try{t=await d(a)}catch(r){if(r instanceof s)return[{Status:"Not logged in",Plan:"-",Credits:"-",Monthly:"-",Captcha:"-"}];throw r}let e;try{e=await u(a,t.deviceId)}catch(r){e={required:!0}}const n=t.breakdown;return[{Status:"Connected",Plan:t.planKey,Credits:String(t.totalCreditsAvailable),Monthly:`${n.monthlyRemaining}/${n.monthlyLimit}`,Captcha:e?.required===!0?"Required (solve in UI)":"Not required"}]}});
@@ -1,15 +1,15 @@
1
- import*as J from"node:fs";import*as M from"node:path";import{ArgumentError as N,AuthRequiredError as k,CommandExecutionError as L,EmptyResultError as x,TimeoutError as b}from"@jackwener/opencli/errors";export const SUNO_DOMAIN="suno.com",SUNO_URL="https://suno.com",STUDIO_API="https://studio-api-prod.suno.com",SUNO_CDN="https://cdn1.suno.ai",SUNO_MODELS=["chirp-fenix","chirp-bluejay","chirp-v4","chirp-v3-5"],DEFAULT_SUNO_MODEL="chirp-fenix",SUPPORTED_FORMATS=["mp3","m4a","wav","video","cover","metadata"],DEFAULT_FORMATS=["mp3","metadata"];export function parseFormats(G){if(G===void 0||G===null||G==="")return DEFAULT_FORMATS.slice();const V=(Array.isArray(G)?G.join(","):String(G)).split(",").map((Z)=>Z.trim().toLowerCase()).filter(Boolean);if(!V.length)return DEFAULT_FORMATS.slice();const X=V.filter((Z)=>!SUPPORTED_FORMATS.includes(Z));if(X.length)throw new N(`Unsupported --formats value(s): ${X.join(", ")}`,`Supported: ${SUPPORTED_FORMATS.join(", ")}. (stems require multi-step extraction and are not yet wired.)`);return Array.from(new Set(V))}export function resolveSunoOutputDir(G){const Q=String(G||"").trim();if(!Q)return M.join(process.env.HOME||"~","Music","suno");if(Q==="~")return process.env.HOME||"~";if(Q.startsWith("~/"))return M.join(process.env.HOME||"~",Q.slice(2));return M.resolve(Q)}export function sanitizeTitleForFilename(G,Q="untitled"){return String(G||Q).replace(/[\\/:*?"<>|\x00-\x1f]+/g,"-").replace(/\s+/g," ").trim().slice(0,60)||Q}export function ensureDir(G){J.mkdirSync(G,{recursive:!0})}export function normalizeBooleanFlag(G,Q=!1){if(typeof G==="boolean")return G;if(G===null||G===void 0||G==="")return Q;const V=String(G).trim().toLowerCase();return V==="true"||V==="1"||V==="yes"||V==="on"}export function unwrapEvaluateResult(G){if(G&&typeof G==="object"&&"session"in G&&"data"in G)return G.data;return G}export function requirePositiveInt(G,Q){const V=Number(G);if(!Number.isInteger(V)||V<1)throw new N(`${Q} must be a positive integer`);return V}export function requireNonNegativeInt(G,Q){const V=Number(G);if(!Number.isInteger(V)||V<0)throw new N(`${Q} must be a non-negative integer`);return V}export function clampSlider(G,Q,V){if(G===void 0||G===null||G==="")return V;const X=Number(G);if(!Number.isFinite(X)||X<0||X>1)throw new N(`${Q} must be a number between 0 and 1`);return X}const C="JSON.stringify({ token: btoa(JSON.stringify({ timestamp: Date.now() })) })",h="await window.Clerk.session.getToken()";function q(G,Q={}){const V=Object.entries(Q).map(([X,Z])=>`${JSON.stringify(X)}: ${JSON.stringify(Z)}`).join(", ");return`{
2
- 'Authorization': 'Bearer ' + ${h},
3
- 'browser-token': ${C},
4
- 'device-id': ${JSON.stringify(G)},
5
- ${V}${V?",":""}
6
- }`}export function parseSunoBillingInfo(G){const Q=(G?.credit_packs||[]).reduce(($,z)=>$+(z?.amount??z?.credits??0),0),V=Math.max(0,(G?.monthly_limit??0)-(G?.monthly_usage??0)),X=typeof G?.total_credits_left==="number"?G.total_credits_left:(G?.credits??0)+Q+V,Z=Array.isArray(G?.plans)?G.plans:[],W=typeof G?.subscription_type==="string"&&G.subscription_type?G.subscription_type:null,Y=W?Z.find(($)=>$?.plan_key===W):Z.find(($)=>$?.plan_key==="free");return{planId:Y?.id||G?.plan?.id||null,planKey:Y?.plan_key||G?.plan?.plan_key||(W??"free"),totalCreditsAvailable:X,breakdown:{pack:G?.credits??0,purchasedPacks:Q,monthlyRemaining:V,monthlyLimit:G?.monthly_limit??0,monthlyUsed:G?.monthly_usage??0}}}export async function ensureSunoSession(G){await G.goto(`${SUNO_URL}/me`,{settleMs:2000});await G.evaluate(`(() => {
1
+ import*as h from"node:fs";import*as w from"node:path";import{ArgumentError as _,AuthRequiredError as S,CommandExecutionError as m,EmptyResultError as b,TimeoutError as g}from"@jackwener/opencli/errors";export const SUNO_DOMAIN="suno.com",SUNO_URL="https://suno.com",STUDIO_API="https://studio-api-prod.suno.com",SUNO_CDN="https://cdn1.suno.ai",SUNO_MODELS=["chirp-fenix","chirp-bluejay","chirp-v4","chirp-v3-5"],DEFAULT_SUNO_MODEL="chirp-fenix",SUPPORTED_FORMATS=["mp3","m4a","wav","video","cover","metadata"],DEFAULT_FORMATS=["mp3","metadata"];export function parseFormats(e){if(e===void 0||e===null||e==="")return DEFAULT_FORMATS.slice();const n=(Array.isArray(e)?e.join(","):String(e)).split(",").map((s)=>s.trim().toLowerCase()).filter(Boolean);if(!n.length)return DEFAULT_FORMATS.slice();const r=n.filter((s)=>!SUPPORTED_FORMATS.includes(s));if(r.length)throw new _(`Unsupported --formats value(s): ${r.join(", ")}`,`Supported: ${SUPPORTED_FORMATS.join(", ")}. (stems require multi-step extraction and are not yet wired.)`);return Array.from(new Set(n))}export function resolveSunoOutputDir(e){const t=String(e||"").trim();if(!t)return w.join(process.env.HOME||"~","Music","suno");if(t==="~")return process.env.HOME||"~";if(t.startsWith("~/"))return w.join(process.env.HOME||"~",t.slice(2));return w.resolve(t)}export function sanitizeTitleForFilename(e,t="untitled"){return String(e||t).replace(/[\\/:*?"<>|\x00-\x1f]+/g,"-").replace(/\s+/g," ").trim().slice(0,60)||t}export function ensureDir(e){h.mkdirSync(e,{recursive:!0})}export function normalizeBooleanFlag(e,t=!1){if(typeof e==="boolean")return e;if(e===null||e===void 0||e==="")return t;const n=String(e).trim().toLowerCase();return n==="true"||n==="1"||n==="yes"||n==="on"}export function unwrapEvaluateResult(e){if(e&&typeof e==="object"&&"session"in e&&"data"in e)return e.data;return e}export function requirePositiveInt(e,t){const n=Number(e);if(!Number.isInteger(n)||n<1)throw new _(`${t} must be a positive integer`);return n}export function requireNonNegativeInt(e,t){const n=Number(e);if(!Number.isInteger(n)||n<0)throw new _(`${t} must be a non-negative integer`);return n}export function clampSlider(e,t,n){if(e===void 0||e===null||e==="")return n;const r=Number(e);if(!Number.isFinite(r)||r<0||r>1)throw new _(`${t} must be a number between 0 and 1`);return r}const k="JSON.stringify({ token: btoa(JSON.stringify({ timestamp: Date.now() })) })",v="await window.Clerk.session.getToken()";function c(e,t={}){const n=Object.entries(t).map(([r,s])=>`${JSON.stringify(r)}: ${JSON.stringify(s)}`).join(", ");return`{
2
+ 'Authorization': 'Bearer ' + ${v},
3
+ 'browser-token': ${k},
4
+ 'device-id': ${JSON.stringify(e)},
5
+ ${n}${n?",":""}
6
+ }`}export function parseSunoBillingInfo(e){const t=(e?.credit_packs||[]).reduce((i,l)=>i+(l?.amount??l?.credits??0),0),n=Math.max(0,(e?.monthly_limit??0)-(e?.monthly_usage??0)),r=typeof e?.total_credits_left==="number"?e.total_credits_left:(e?.credits??0)+t+n,s=Array.isArray(e?.plans)?e.plans:[],u=typeof e?.subscription_type==="string"&&e.subscription_type?e.subscription_type:null,o=u?s.find((i)=>i?.plan_key===u):s.find((i)=>i?.plan_key==="free");return{planId:o?.id||e?.plan?.id||null,planKey:o?.plan_key||e?.plan?.plan_key||(u??"free"),totalCreditsAvailable:r,breakdown:{pack:e?.credits??0,purchasedPacks:t,monthlyRemaining:n,monthlyLimit:e?.monthly_limit??0,monthlyUsed:e?.monthly_usage??0}}}export async function ensureSunoSession(e){await e.goto(`${SUNO_URL}/me`,{settleMs:2000});await e.evaluate(`(() => {
7
7
  const btn = Array.from(document.querySelectorAll('button')).find(b => /^reject all$|^accept all$|^confirm/i.test((b.innerText || '').trim()));
8
8
  if (btn) btn.click();
9
- })()`);for(let X=0;X<20;X+=1){if(unwrapEvaluateResult(await G.evaluate("!!(window.Clerk && window.Clerk.session)")))break;await G.wait(0.5)}const Q=await getSunoDeviceId(G),V=unwrapEvaluateResult(await G.evaluate(`(async () => {
9
+ })()`);for(let r=0;r<20;r+=1){if(unwrapEvaluateResult(await e.evaluate("!!(window.Clerk && window.Clerk.session)")))break;await e.wait(0.5)}const t=await getSunoDeviceId(e),n=unwrapEvaluateResult(await e.evaluate(`(async () => {
10
10
  try {
11
11
  if (!window.Clerk?.session) return { ok: false, auth: true, error: 'Clerk session unavailable' };
12
- const res = await fetch('${STUDIO_API}/api/billing/info/', { headers: ${q(Q)} });
12
+ const res = await fetch('${STUDIO_API}/api/billing/info/', { headers: ${c(t)} });
13
13
  if (!res.ok) return { ok: false, status: res.status, body: (await res.text()).slice(0, 300) };
14
14
  let data = null;
15
15
  try {
@@ -22,15 +22,15 @@ import*as J from"node:fs";import*as M from"node:path";import{ArgumentError as N,
22
22
  } catch (e) {
23
23
  return { ok: false, error: String(e).slice(0, 200) };
24
24
  }
25
- })()`));if(!V||!V.ok){const X=V?.status||V?.error||"unknown";if(V?.auth||V?.status===401||V?.status===403)throw new k(SUNO_DOMAIN,`Suno session check failed (${X}). Open https://suno.com in Chrome and sign in, then retry.`);throw new L(`Suno session check failed (${X}).`)}return{...V,deviceId:Q}}export async function checkSunoCaptcha(G,Q){return unwrapEvaluateResult(await G.evaluate(`(async () => {
25
+ })()`));if(!n||!n.ok){const r=n?.status||n?.error||"unknown";if(n?.auth||n?.status===401||n?.status===403)throw new S(SUNO_DOMAIN,`Suno session check failed (${r}). Open https://suno.com in Chrome and sign in, then retry.`);throw new m(`Suno session check failed (${r}).`)}return{...n,deviceId:t}}export async function checkSunoCaptcha(e,t){return unwrapEvaluateResult(await e.evaluate(`(async () => {
26
26
  const res = await fetch('${STUDIO_API}/api/c/check', {
27
27
  method: 'POST',
28
- headers: ${q(Q,{"Content-Type":"application/json"})},
28
+ headers: ${c(t,{"Content-Type":"application/json"})},
29
29
  body: JSON.stringify({ ctype: 'generation' }),
30
30
  });
31
31
  if (!res.ok) return { ok: false, status: res.status };
32
32
  return { ok: true, ...(await res.json()) };
33
- })()`))}export async function getSunoDeviceId(G){const Q=unwrapEvaluateResult(await G.evaluate(`(() => {
33
+ })()`))}export async function getSunoDeviceId(e){const t=unwrapEvaluateResult(await e.evaluate(`(() => {
34
34
  try {
35
35
  const fromCookie = document.cookie.split(';').map(s => s.trim()).find(s => s.startsWith('suno_device_id='));
36
36
  if (fromCookie) return decodeURIComponent(fromCookie.split('=')[1]);
@@ -40,53 +40,53 @@ import*as J from"node:fs";import*as M from"node:path";import{ArgumentError as N,
40
40
  }
41
41
  } catch {}
42
42
  return null;
43
- })()`));if(Q&&typeof Q==="string")return Q;return unwrapEvaluateResult(await G.evaluate("crypto.randomUUID()"))}export async function submitSunoGeneration(G,Q){const V=Q.mode==="custom",X={token:null,generation_type:"TEXT",title:Q.title||"",tags:V?Q.tags||"":"",negative_tags:V?Q.negativeTags||"":"",mv:Q.model||DEFAULT_SUNO_MODEL,prompt:V?Q.lyrics||"":Q.description||"",make_instrumental:!!Q.makeInstrumental,user_uploaded_images_b64:null,metadata:{web_client_pathname:"/create",is_max_mode:!1,is_mumble:!1,create_mode:V?"custom":"simple",user_tier:Q.userTier,create_session_token:Q.createSessionToken,disable_volume_normalization:!1,control_sliders:{weirdness_constraint:Q.weirdness,style_weight:Q.styleWeight}},override_fields:[],cover_clip_id:null,cover_start_s:null,cover_end_s:null,persona_id:null,artist_clip_id:null,artist_start_s:null,artist_end_s:null,continue_clip_id:null,continued_aligned_prompt:null,continue_at:null,transaction_uuid:Q.transactionUuid,token_provider:null},Z=JSON.stringify(X),W=Q.deviceId,Y=unwrapEvaluateResult(await G.evaluate(`(async () => {
43
+ })()`));if(t&&typeof t==="string")return t;return unwrapEvaluateResult(await e.evaluate("crypto.randomUUID()"))}export async function submitSunoGeneration(e,t){const n=t.mode==="custom",r={token:null,generation_type:"TEXT",title:t.title||"",tags:n?t.tags||"":"",negative_tags:n?t.negativeTags||"":"",mv:t.model||DEFAULT_SUNO_MODEL,prompt:n?t.lyrics||"":t.description||"",make_instrumental:!!t.makeInstrumental,user_uploaded_images_b64:null,metadata:{web_client_pathname:"/create",is_max_mode:!1,is_mumble:!1,create_mode:n?"custom":"simple",user_tier:t.userTier,create_session_token:t.createSessionToken,disable_volume_normalization:!1,control_sliders:{weirdness_constraint:t.weirdness,style_weight:t.styleWeight}},override_fields:[],cover_clip_id:null,cover_start_s:null,cover_end_s:null,persona_id:null,artist_clip_id:null,artist_start_s:null,artist_end_s:null,continue_clip_id:null,continued_aligned_prompt:null,continue_at:null,transaction_uuid:t.transactionUuid,token_provider:null},s=JSON.stringify(r),u=t.deviceId,o=unwrapEvaluateResult(await e.evaluate(`(async () => {
44
44
  const res = await fetch('${STUDIO_API}/api/generate/v2-web/', {
45
45
  method: 'POST',
46
- headers: ${q(W,{"Content-Type":"application/json"})},
47
- body: ${JSON.stringify(Z)},
46
+ headers: ${c(u,{"Content-Type":"application/json"})},
47
+ body: ${JSON.stringify(s)},
48
48
  });
49
49
  const text = await res.text();
50
50
  let parsed = null;
51
51
  try { parsed = JSON.parse(text); } catch {}
52
52
  return { status: res.status, ok: res.ok, body: parsed, raw: parsed ? null : text.slice(0, 600) };
53
- })()`));if(!Y||!Y.ok){const z=Y?.status||"unknown",j=Y?.body?.detail||Y?.raw||JSON.stringify(Y?.body||{}).slice(0,500);if(z===401||z===403)throw new k(SUNO_DOMAIN,`Suno API rejected request (HTTP ${z}). Re-login on suno.com.`);if(z===402)throw new L(`Suno API: insufficient credits (HTTP 402). ${j}`);throw new L(`Suno generate failed (HTTP ${z}): ${j}`)}if(!Y.body||typeof Y.body!=="object"||Array.isArray(Y.body))throw new L("Suno generate returned malformed JSON payload.");if(!(Y.body?.clips||[]).length)throw new x("suno generate",`Submission accepted but Suno returned no clip ids. Raw: ${JSON.stringify(Y.body).slice(0,300)}`);return Y.body}export async function pollSunoClips(G,Q,V,X,Z=5,W=null){const Y=Date.now()+V*1000,$=new Set(Q),z=JSON.stringify(Q);while(Date.now()<Y){const j=unwrapEvaluateResult(await G.evaluate(`(async () => {
53
+ })()`));if(!o||!o.ok){const l=o?.status||"unknown",a=o?.body?.detail||o?.raw||JSON.stringify(o?.body||{}).slice(0,500);if(l===401||l===403)throw new S(SUNO_DOMAIN,`Suno API rejected request (HTTP ${l}). Re-login on suno.com.`);if(l===402)throw new m(`Suno API: insufficient credits (HTTP 402). ${a}`);throw new m(`Suno generate failed (HTTP ${l}): ${a}`)}if(!o.body||typeof o.body!=="object"||Array.isArray(o.body))throw new m("Suno generate returned malformed JSON payload.");if(!(o.body?.clips||[]).length)throw new b("suno generate",`Submission accepted but Suno returned no clip ids. Raw: ${JSON.stringify(o.body).slice(0,300)}`);return o.body}export async function pollSunoClips(e,t,n,r,s=5,u=null){const o=Date.now()+n*1000,i=new Set(t),l=JSON.stringify(t);while(Date.now()<o){const a=unwrapEvaluateResult(await e.evaluate(`(async () => {
54
54
  const res = await fetch('${STUDIO_API}/api/feed/v3', {
55
55
  method: 'POST',
56
- headers: ${q(X,{"Content-Type":"application/json"})},
57
- body: JSON.stringify({ clip_ids: ${z} }),
56
+ headers: ${c(r,{"Content-Type":"application/json"})},
57
+ body: JSON.stringify({ clip_ids: ${l} }),
58
58
  });
59
59
  const body = await res.json().catch(() => null);
60
60
  return { status: res.status, body };
61
- })()`));if(!j){await G.wait(Z);continue}if(j.status===401||j.status===403)throw new k(SUNO_DOMAIN,`Suno feed API rejected (HTTP ${j.status}). Re-login.`);if(j.status<200||j.status>=300)throw new L(`Suno feed API failed while polling clips (HTTP ${j.status||"?"})`);if(!j.body||typeof j.body!=="object"||Array.isArray(j.body))throw new L("Suno feed API returned malformed JSON while polling clips");const H=j.body.clips||[];if(!Array.isArray(H))throw new L("Suno feed API returned malformed clips payload");const B=H.filter((K)=>$.has(K.id)),F=B.filter((K)=>K.status==="complete"||K.status==="error");if(typeof W==="function")W({total:Q.length,done:F.length,statuses:B.map((K)=>`${K.id.slice(0,8)}:${K.status}`)});if(F.length===Q.length)return B;await G.wait(Z)}throw new b(`Suno generation did not complete within ${V}s. Try --timeout <higher>.`)}function T(G,Q){return(Array.isArray(G.media_urls)?G.media_urls:[]).find((Z)=>(Z.content_type||"").toLowerCase().includes(Q))?.url||null}async function _(G,Q,V){return await G.evaluate(`(async () => {
61
+ })()`));if(!a){await e.wait(s);continue}if(a.status===401||a.status===403)throw new S(SUNO_DOMAIN,`Suno feed API rejected (HTTP ${a.status}). Re-login.`);if(a.status<200||a.status>=300)throw new m(`Suno feed API failed while polling clips (HTTP ${a.status||"?"})`);if(!a.body||typeof a.body!=="object"||Array.isArray(a.body))throw new m("Suno feed API returned malformed JSON while polling clips");const p=a.body.clips||[];if(!Array.isArray(p))throw new m("Suno feed API returned malformed clips payload");const f=p.filter((d)=>i.has(d.id)),y=f.filter((d)=>d.status==="complete"||d.status==="error");if(typeof u==="function")u({total:t.length,done:y.length,statuses:f.map((d)=>`${d.id.slice(0,8)}:${d.status}`)});if(y.length===t.length)return f;await e.wait(s)}throw new g(`Suno generation did not complete within ${n}s. Try --timeout <higher>.`)}function O(e,t){return(Array.isArray(e.media_urls)?e.media_urls:[]).find((s)=>(s.content_type||"").toLowerCase().includes(t))?.url||null}async function x(e,t,n){return await e.evaluate(`(async () => {
62
62
  try {
63
- const res = await fetch('${STUDIO_API}/api/download/clip/${Q.id}?format=mp3', { headers: ${q(V)} });
63
+ const res = await fetch('${STUDIO_API}/api/download/clip/${t.id}?format=mp3', { headers: ${c(n)} });
64
64
  if (!res.ok) return null;
65
65
  const data = await res.json();
66
66
  return data?.download_url || null;
67
67
  } catch { return null; }
68
- })()`)||Q.audio_url||`${SUNO_CDN}/${Q.id}.mp3`}async function U(G,Q,V,X=120,Z=3){await G.evaluate(`(async () => {
68
+ })()`)||t.audio_url||`${SUNO_CDN}/${t.id}.mp3`}async function T(e,t,n,r=120,s=3){await e.evaluate(`(async () => {
69
69
  try {
70
- await fetch('${STUDIO_API}/api/billing/clips/${Q}/download/', {
70
+ await fetch('${STUDIO_API}/api/billing/clips/${t}/download/', {
71
71
  method: 'POST',
72
- headers: ${q(V,{"Content-Type":"application/json"})},
72
+ headers: ${c(n,{"Content-Type":"application/json"})},
73
73
  body: JSON.stringify({}),
74
74
  });
75
75
  } catch {}
76
76
  try {
77
- await fetch('${STUDIO_API}/api/gen/${Q}/convert_wav/', {
77
+ await fetch('${STUDIO_API}/api/gen/${t}/convert_wav/', {
78
78
  method: 'POST',
79
- headers: ${q(V,{"Content-Type":"application/json"})},
79
+ headers: ${c(n,{"Content-Type":"application/json"})},
80
80
  });
81
81
  } catch {}
82
- })()`);const W=Date.now()+X*1000;while(Date.now()<W){const Y=unwrapEvaluateResult(await G.evaluate(`(async () => {
83
- const res = await fetch('${STUDIO_API}/api/gen/${Q}/wav_file/', { headers: ${q(V)} });
82
+ })()`);const u=Date.now()+r*1000;while(Date.now()<u){const o=unwrapEvaluateResult(await e.evaluate(`(async () => {
83
+ const res = await fetch('${STUDIO_API}/api/gen/${t}/wav_file/', { headers: ${c(n)} });
84
84
  if (!res.ok) return { ok: false, status: res.status };
85
85
  const data = await res.json().catch(() => null);
86
86
  return { ok: true, url: data?.wav_file_url || null };
87
- })()`));if(Y?.ok&&Y.url)return Y.url;await G.wait(Z)}return null}async function R(G,Q){return unwrapEvaluateResult(await G.evaluate(`(async () => {
87
+ })()`));if(o?.ok&&o.url)return o.url;await e.wait(s)}return null}async function N(e,t){return unwrapEvaluateResult(await e.evaluate(`(async () => {
88
88
  try {
89
- const res = await fetch(${JSON.stringify(Q)});
89
+ const res = await fetch(${JSON.stringify(t)});
90
90
  if (!res.ok) return { ok: false, status: res.status };
91
91
  const blob = await res.blob();
92
92
  const dataUrl = await new Promise((resolve, reject) => {
@@ -99,4 +99,4 @@ import*as J from"node:fs";import*as M from"node:path";import{ArgumentError as N,
99
99
  } catch (e) {
100
100
  return { ok: false, error: String(e).slice(0, 200) };
101
101
  }
102
- })()`))}async function w(G,Q,V){const X=await R(G,Q);if(!X?.ok)return{ok:!1,reason:X?.status?`HTTP ${X.status}`:X?.error||"unknown"};const Z=String(X.dataUrl||"").replace(/^data:[^;]+;base64,/,"");if(!Z)return{ok:!1,reason:"empty response body"};J.writeFileSync(V,Buffer.from(Z,"base64"));if(!J.statSync(V).size)return{ok:!1,reason:"empty file written"};return{ok:!0}}export async function downloadSunoClip(G,Q,V,X,Z){ensureDir(V);const W=`${sanitizeTitleForFilename(Q.title||Q.id)}_${Q.id.slice(0,8)}`,Y=[];if(X.includes("metadata")){const $=M.join(V,`${W}.json`);J.writeFileSync($,JSON.stringify(Q,null,2),"utf8");Y.push({format:"metadata",file:$,ok:!0})}for(const $ of X){if($==="metadata")continue;let z=null,j="";try{if($==="mp3"){j=".mp3";z=await _(G,Q,Z)}else if($==="m4a"){j=".m4a";z=T(Q,"m4a")}else if($==="video"){j=".mp4";z=Q.video_url||null}else if($==="cover"){j=".jpeg";z=Q.image_large_url||Q.image_url||null}else if($==="wav"){j=".wav";z=await U(G,Q.id,Z)}}catch(F){Y.push({format:$,file:null,ok:!1,reason:`prep failed: ${String(F).slice(0,100)}`});continue}if(!z){Y.push({format:$,file:null,ok:!1,reason:"not available"});continue}const H=M.join(V,`${W}${j}`),B=await w(G,z,H);Y.push({format:$,file:H,ok:B.ok,reason:B.ok?null:B.reason})}return{slug:W,written:Y}}
102
+ })()`))}async function A(e,t,n){const r=await N(e,t);if(!r?.ok)return{ok:!1,reason:r?.status?`HTTP ${r.status}`:r?.error||"unknown"};const s=String(r.dataUrl||"").replace(/^data:[^;]+;base64,/,"");if(!s)return{ok:!1,reason:"empty response body"};h.writeFileSync(n,Buffer.from(s,"base64"));if(!h.statSync(n).size)return{ok:!1,reason:"empty file written"};return{ok:!0}}export async function downloadSunoClip(e,t,n,r,s){ensureDir(n);const u=`${sanitizeTitleForFilename(t.title||t.id)}_${t.id.slice(0,8)}`,o=[];if(r.includes("metadata")){const i=w.join(n,`${u}.json`);h.writeFileSync(i,JSON.stringify(t,null,2),"utf8");o.push({format:"metadata",file:i,ok:!0})}for(const i of r){if(i==="metadata")continue;let l=null,a="";try{if(i==="mp3"){a=".mp3";l=await x(e,t,s)}else if(i==="m4a"){a=".m4a";l=O(t,"m4a")}else if(i==="video"){a=".mp4";l=t.video_url||null}else if(i==="cover"){a=".jpeg";l=t.image_large_url||t.image_url||null}else if(i==="wav"){a=".wav";l=await T(e,t.id,s)}}catch(y){o.push({format:i,file:null,ok:!1,reason:`prep failed: ${String(y).slice(0,100)}`});continue}if(!l){o.push({format:i,file:null,ok:!1,reason:"not available"});continue}const p=w.join(n,`${u}${a}`),f=await A(e,l,p);o.push({format:i,file:p,ok:f.ok,reason:f.ok?null:f.reason})}return{slug:u,written:o}}
@@ -1,18 +1,18 @@
1
- import{ArgumentError as X,AuthRequiredError as G,CommandExecutionError as Z}from"@jackwener/opencli/errors";import{cli as j,Strategy as v}from"@jackwener/opencli/registry";import{assertLiteralContent as y}from"../_shared/content-guard.js";import{WEBK_BASE as K,MESSAGE_INPUT_SELECTOR as Y,SEND_BUTTON_SELECTOR as M,readComposerState as U}from"./shared.js";const B=15;export function resolvePeer(b){const z=String(b??"").trim();if(!z)throw new X("peer 不能为空。",'传频道 @username、t.me/xxx 链接、或 "saved"(发到自己的收藏夹 Saved Messages)。');const J=z.toLowerCase();if(J==="saved"||J==="me"||J==="saved messages"||J==="savedmessages")return{url:K,label:"Saved Messages",savedMessages:!0};let F="";if(/^https?:\/\//i.test(z)){let V;try{V=new URL(z)}catch{throw new X(`无法解析的 peer 链接:${z}`)}const Q=V.hostname.toLowerCase();if(Q==="t.me"||Q.endsWith(".t.me")||Q==="telegram.me")F=V.pathname.split("/").filter(Boolean)[0]||"";else if(Q==="web.telegram.org")return{url:z,label:z,savedMessages:!1};else throw new X("peer 链接必须是 t.me 或 web.telegram.org 的地址。")}else if(z.startsWith("@"))F=z.slice(1);else if(/^[a-z0-9_]{4,32}$/i.test(z))F=z;if(!F||!/^[a-z0-9_]{4,32}$/i.test(F))throw new X(`无法从 ${JSON.stringify(z)} 解析出 Telegram 用户名/频道。`,'用 @username、t.me/username、或 "saved"(收藏夹)。');return{url:`${K}#@${F}`,label:`@${F}`,savedMessages:!1}}async function I(b){return b.evaluate(`(() => {
1
+ import{ArgumentError as l,AuthRequiredError as h,CommandExecutionError as o}from"@jackwener/opencli/errors";import{cli as v,Strategy as S}from"@jackwener/opencli/registry";import{assertLiteralContent as y}from"../_shared/content-guard.js";import{WEBK_BASE as f,MESSAGE_INPUT_SELECTOR as c,SEND_BUTTON_SELECTOR as p,readComposerState as b}from"./shared.js";const E=15;export function resolvePeer(e){const t=String(e??"").trim();if(!t)throw new l("peer 不能为空。",'传频道 @username、t.me/xxx 链接、或 "saved"(发到自己的收藏夹 Saved Messages)。');const a=t.toLowerCase();if(a==="saved"||a==="me"||a==="saved messages"||a==="savedmessages")return{url:f,label:"Saved Messages",savedMessages:!0};let r="";if(/^https?:\/\//i.test(t)){let i;try{i=new URL(t)}catch{throw new l(`无法解析的 peer 链接:${t}`)}const n=i.hostname.toLowerCase();if(n==="t.me"||n.endsWith(".t.me")||n==="telegram.me")r=i.pathname.split("/").filter(Boolean)[0]||"";else if(n==="web.telegram.org")return{url:t,label:t,savedMessages:!1};else throw new l("peer 链接必须是 t.me 或 web.telegram.org 的地址。")}else if(t.startsWith("@"))r=t.slice(1);else if(/^[a-z0-9_]{4,32}$/i.test(t))r=t;if(!r||!/^[a-z0-9_]{4,32}$/i.test(r))throw new l(`无法从 ${JSON.stringify(t)} 解析出 Telegram 用户名/频道。`,'用 @username、t.me/username、或 "saved"(收藏夹)。');return{url:`${f}#@${r}`,label:`@${r}`,savedMessages:!1}}async function k(e){return e.evaluate(`(() => {
2
2
  // Saved Messages 在 webk 通常挂在主菜单;先找 data-* / class 结构锚点(语言无关)。
3
3
  const entry = document.querySelector(
4
4
  '.chatlist a[data-peer-id][href*="saved"], [data-peer-id][class*="saved"], .btn-menu-item[class*="saved"]'
5
5
  );
6
6
  if (entry) { entry.click(); return { ok: true }; }
7
7
  return { ok: false };
8
- })()`)}async function W(b){return b.evaluate(`(() => {
9
- const ed = document.querySelector(${JSON.stringify(Y)});
8
+ })()`)}async function g(e){return e.evaluate(`(() => {
9
+ const ed = document.querySelector(${JSON.stringify(c)});
10
10
  return ed ? (ed.textContent || '').replace(/\\uFEFF/g, '') : null;
11
- })()`)}j({site:"telegram",name:"send",access:"write",description:'Send a text message to a Telegram chat via web.telegram.org/k/. Pass a channel @username / t.me link, or "saved" for your own Saved Messages. You must have permission to post in the target.',domain:"web.telegram.org",strategy:v.UI,browser:!0,args:[{name:"peer",type:"string",required:!0,positional:!0,help:'Target: channel @username, t.me/<name> link, or "saved" (your Saved Messages)'},{name:"text",fromFile:!0,type:"string",required:!0,positional:!0,help:"Message text (multi-line allowed)"}],columns:["status","peer","message"],func:async(b,z)=>{if(!b)throw new Z("Browser session required for telegram send");const J=resolvePeer(z.peer),F=String(z.text??"");y(F,{label:"消息内容"});if(!F.trim())throw new X("消息内容不能为空。");await b.goto(J.url);let V=!1;for(let H=0;H<B;H++){const q=await U(b);if(q==="auth")throw new G("web.telegram.org","Telegram Web 停在登录页 —— 未登录。先 `ppcli telegram login`。");if(q==="ready"){V=!0;break}if(q==="no-chat"&&J.savedMessages)await I(b);await b.wait(1)}if(!V)throw new Z(`未能在 ${J.label} 打开消息输入框 —— 会话可能不存在、你没有发帖权限,或页面未加载完。`);await b.click(Y);await b.pressKey("Control+A");await b.pressKey("Delete");const Q=F.split(`
12
- `);for(let H=0;H<Q.length;H++){if(H>0)await b.pressKey("Shift+Enter");if(Q[H].length)await b.typeText(Y,Q[H])}const $=await W(b),f=(H)=>String(H||"").replace(/\s+/g," ").trim();if($===null||f($)!==f(F))throw new Z(`发送前组文失败(输入框内容为 ${JSON.stringify(($||"").slice(0,60))})。`);if(!(await b.evaluate(`(() => {
11
+ })()`)}v({site:"telegram",name:"send",access:"write",description:'Send a text message to a Telegram chat via web.telegram.org/k/. Pass a channel @username / t.me link, or "saved" for your own Saved Messages. You must have permission to post in the target.',domain:"web.telegram.org",strategy:S.UI,browser:!0,args:[{name:"peer",type:"string",required:!0,positional:!0,help:'Target: channel @username, t.me/<name> link, or "saved" (your Saved Messages)'},{name:"text",fromFile:!0,type:"string",required:!0,positional:!0,help:"Message text (multi-line allowed)"}],columns:["status","peer","message"],func:async(e,t)=>{if(!e)throw new o("Browser session required for telegram send");const a=resolvePeer(t.peer),r=String(t.text??"");y(r,{label:"消息内容"});if(!r.trim())throw new l("消息内容不能为空。");await e.goto(a.url);let i=!1;for(let s=0;s<E;s++){const m=await b(e);if(m==="auth")throw new h("web.telegram.org","Telegram Web 停在登录页 —— 未登录。先 `ppcli telegram login`。");if(m==="ready"){i=!0;break}if(m==="no-chat"&&a.savedMessages)await k(e);await e.wait(1)}if(!i)throw new o(`未能在 ${a.label} 打开消息输入框 —— 会话可能不存在、你没有发帖权限,或页面未加载完。`);await e.click(c);await e.pressKey("Control+A");await e.pressKey("Delete");const n=r.split(`
12
+ `);for(let s=0;s<n.length;s++){if(s>0)await e.pressKey("Shift+Enter");if(n[s].length)await e.typeText(c,n[s])}const u=await g(e),d=(s)=>String(s||"").replace(/\s+/g," ").trim();if(u===null||d(u)!==d(r))throw new o(`发送前组文失败(输入框内容为 ${JSON.stringify((u||"").slice(0,60))})。`);if(!(await e.evaluate(`(() => {
13
13
  const visible = (el) => !!el && (el.offsetParent !== null || el.getClientRects().length > 0);
14
- const btn = Array.from(document.querySelectorAll(${JSON.stringify(M)})).find(visible);
14
+ const btn = Array.from(document.querySelectorAll(${JSON.stringify(p)})).find(visible);
15
15
  if (!btn) return { ok: false };
16
16
  btn.click();
17
17
  return { ok: true };
18
- })()`))?.ok)throw new Z("未找到发送按钮(btn-send)—— 页面结构可能已变或输入框未激活。");await b.wait(1);const D=await W(b);if(D!==null&&D.trim().length>0)throw new Z("点击发送后消息仍留在输入框 —— 未发出(可能限流、慢速模式、或你没有该会话的发帖权限)。发布前请回查确认再重试。");return[{status:"success",peer:J.label,message:"Message sent"}]}});
18
+ })()`))?.ok)throw new o("未找到发送按钮(btn-send)—— 页面结构可能已变或输入框未激活。");await e.wait(1);const w=await g(e);if(w!==null&&w.trim().length>0)throw new o("点击发送后消息仍留在输入框 —— 未发出(可能限流、慢速模式、或你没有该会话的发帖权限)。发布前请回查确认再重试。");return[{status:"success",peer:a.label,message:"Message sent"}]}});
@@ -1,4 +1,4 @@
1
- export const WEBK_BASE="https://web.telegram.org/k/",MESSAGE_INPUT_SELECTOR='div.input-message-input[contenteditable="true"], .input-message-input[contenteditable]',SEND_BUTTON_SELECTOR="button.btn-send";export async function readComposerState(j){return j.evaluate(`(() => {
1
+ export const WEBK_BASE="https://web.telegram.org/k/",MESSAGE_INPUT_SELECTOR='div.input-message-input[contenteditable="true"], .input-message-input[contenteditable]',SEND_BUTTON_SELECTOR="button.btn-send";export async function readComposerState(e){return e.evaluate(`(() => {
2
2
  // webk 未登录时路由停在 auth:URL 里带 #/login 或页面里渲染 auth 页容器。
3
3
  const authByRoute = /(?:^|[#/])(?:auth|login)(?:[#/?]|$)/i.test(location.hash + location.pathname);
4
4
  const authPage = document.querySelector('.page-authCode, .page-signIn, .page-sign, #auth-pages, .auth-pages, [class*="page-sign"], [class*="page-auth"]');
@@ -6,7 +6,7 @@ export const WEBK_BASE="https://web.telegram.org/k/",MESSAGE_INPUT_SELECTOR='div
6
6
  const editor = document.querySelector('div.input-message-input[contenteditable="true"], .input-message-input[contenteditable]');
7
7
  if (editor) return 'ready';
8
8
  return 'no-chat';
9
- })()`)}export async function readLoginState(j){return j.evaluate(`(() => {
9
+ })()`)}export async function readLoginState(e){return e.evaluate(`(() => {
10
10
  const authByRoute = /(?:^|[#/])(?:auth|login)(?:[#/?]|$)/i.test(location.hash + location.pathname);
11
11
  const authPage = document.querySelector('.page-authCode, .page-signIn, .page-sign, #auth-pages, .auth-pages, [class*="page-sign"], [class*="page-auth"]');
12
12
  if (authByRoute || authPage) return { logged_in: false };
@@ -1 +1 @@
1
- import{AuthRequiredError as F}from"@jackwener/opencli/errors";import{registerSiteAuthCommands as H}from"../_shared/site-auth.js";import{WEBK_BASE as G,readLoginState as J}from"./shared.js";async function D(b){await b.goto(G);for(let x=0;x<10;x++){const z=await J(b);if(z?.logged_in)return z.name?{name:z.name}:{};await b.wait(1)}throw new F("web.telegram.org","Telegram Web 停在登录页或会话列表未渲染 —— 未登录(webk 登录态在 localStorage/IndexedDB,不是 cookie)。")}H({site:"telegram",domain:"web.telegram.org",loginUrl:G,columns:["name"],quickCheckRequiresNavigation:!0,quickCheck:async(b)=>{try{return{logged_in:!0,...await D(b)}}catch(x){if(x instanceof F)return{logged_in:!1};throw x}},verify:D,poll:async(b)=>D(b)});
1
+ import{AuthRequiredError as o}from"@jackwener/opencli/errors";import{registerSiteAuthCommands as n}from"../_shared/site-auth.js";import{WEBK_BASE as a,readLoginState as m}from"./shared.js";async function i(e){await e.goto(a);for(let t=0;t<10;t++){const r=await m(e);if(r?.logged_in)return r.name?{name:r.name}:{};await e.wait(1)}throw new o("web.telegram.org","Telegram Web 停在登录页或会话列表未渲染 —— 未登录(webk 登录态在 localStorage/IndexedDB,不是 cookie)。")}n({site:"telegram",domain:"web.telegram.org",loginUrl:a,columns:["name"],quickCheckRequiresNavigation:!0,quickCheck:async(e)=>{try{return{logged_in:!0,...await i(e)}}catch(t){if(t instanceof o)return{logged_in:!1};throw t}},verify:i,poll:async(e)=>i(e)});
@@ -1 +1 @@
1
- import{vi as z}from"vitest";export function createPageMock(D=[],E={}){const B=z.fn();for(const G of D)B.mockResolvedValueOnce(G);return{goto:z.fn().mockResolvedValue(void 0),tabs:z.fn().mockResolvedValue([]),selectTab:z.fn().mockResolvedValue(void 0),closeTab:z.fn().mockResolvedValue(void 0),newTab:z.fn().mockResolvedValue(void 0),evaluate:B,snapshot:z.fn().mockResolvedValue(void 0),screenshot:z.fn().mockResolvedValue(""),click:z.fn().mockResolvedValue(void 0),typeText:z.fn().mockResolvedValue(void 0),pressKey:z.fn().mockResolvedValue(void 0),scrollTo:z.fn().mockResolvedValue(void 0),scroll:z.fn().mockResolvedValue(void 0),autoScroll:z.fn().mockResolvedValue(void 0),setFileInput:z.fn().mockResolvedValue(void 0),getFormState:z.fn().mockResolvedValue({forms:[],orphanFields:[]}),networkRequests:z.fn().mockResolvedValue([]),consoleMessages:z.fn().mockResolvedValue([]),installInterceptor:z.fn().mockResolvedValue(void 0),getInterceptedRequests:z.fn().mockResolvedValue([]),waitForCapture:z.fn().mockResolvedValue(void 0),startNetworkCapture:z.fn().mockResolvedValue(void 0),readNetworkCapture:z.fn().mockResolvedValue([]),getCookies:z.fn().mockResolvedValue([]),wait:z.fn().mockResolvedValue(void 0),...E}}
1
+ import{vi as e}from"vitest";export function createPageMock(n=[],l={}){const o=e.fn();for(const d of n)o.mockResolvedValueOnce(d);return{goto:e.fn().mockResolvedValue(void 0),tabs:e.fn().mockResolvedValue([]),selectTab:e.fn().mockResolvedValue(void 0),closeTab:e.fn().mockResolvedValue(void 0),newTab:e.fn().mockResolvedValue(void 0),evaluate:o,snapshot:e.fn().mockResolvedValue(void 0),screenshot:e.fn().mockResolvedValue(""),click:e.fn().mockResolvedValue(void 0),typeText:e.fn().mockResolvedValue(void 0),pressKey:e.fn().mockResolvedValue(void 0),scrollTo:e.fn().mockResolvedValue(void 0),scroll:e.fn().mockResolvedValue(void 0),autoScroll:e.fn().mockResolvedValue(void 0),setFileInput:e.fn().mockResolvedValue(void 0),getFormState:e.fn().mockResolvedValue({forms:[],orphanFields:[]}),networkRequests:e.fn().mockResolvedValue([]),consoleMessages:e.fn().mockResolvedValue([]),installInterceptor:e.fn().mockResolvedValue(void 0),getInterceptedRequests:e.fn().mockResolvedValue([]),waitForCapture:e.fn().mockResolvedValue(void 0),startNetworkCapture:e.fn().mockResolvedValue(void 0),readNetworkCapture:e.fn().mockResolvedValue([]),getCookies:e.fn().mockResolvedValue([]),wait:e.fn().mockResolvedValue(void 0),...l}}
@@ -1,13 +1,13 @@
1
- import*as D from"node:fs";import*as v from"node:path";import{cli as V,Strategy as H}from"@jackwener/opencli/registry";import{ArgumentError as q,AuthRequiredError as f,CommandExecutionError as G}from"@jackwener/opencli/errors";import{assertLiteralContent as B}from"../_shared/content-guard.js";import{setInputFiles as A}from"../_shared/file-inject.js";import{THREADS_HOME_URL as k}from"./shared.js";const C=new Set([".jpg",".jpeg",".png",".webp",".gif"]),F=30000,J=500,U=1e4,j=250,h=30000,y=1000,R='input[type="file"]',$=`
1
+ import*as x from"node:fs";import*as f from"node:path";import{cli as g,Strategy as w}from"@jackwener/opencli/registry";import{ArgumentError as c,AuthRequiredError as h,CommandExecutionError as i}from"@jackwener/opencli/errors";import{assertLiteralContent as y}from"../_shared/content-guard.js";import{setInputFiles as T}from"../_shared/file-inject.js";import{THREADS_HOME_URL as S}from"./shared.js";const k=new Set([".jpg",".jpeg",".png",".webp",".gif"]),u=30000,b=500,v=1e4,m=250,A=30000,p=1000,C='input[type="file"]',a=`
2
2
  const isVisible = (el) => {
3
3
  if (!(el instanceof HTMLElement)) return false;
4
4
  const style = window.getComputedStyle(el);
5
5
  const rect = el.getBoundingClientRect();
6
6
  return style.display !== 'none' && style.visibility !== 'hidden' && rect.width > 0 && rect.height > 0;
7
7
  };
8
- `;function w(z){if(!z)throw new G("Browser session required for threads post");return z}function T(z){const K=String(z??"").trim();if(!K)return null;const Q=v.resolve(K),W=v.extname(Q).toLowerCase();if(!C.has(W))throw new q(`Unsupported image format "${W}"`,"Supported formats: jpg, jpeg, png, webp, gif");const Y=D.statSync(Q,{throwIfNoEntry:!1});if(!Y||!Y.isFile())throw new q(`Not a valid file: ${Q}`);return Q}export function buildEnsureComposerOpenJs(){return`
8
+ `;function E(e){if(!e)throw new i("Browser session required for threads post");return e}function O(e){const t=String(e??"").trim();if(!t)return null;const o=f.resolve(t),r=f.extname(o).toLowerCase();if(!k.has(r))throw new c(`Unsupported image format "${r}"`,"Supported formats: jpg, jpeg, png, webp, gif");const n=x.statSync(o,{throwIfNoEntry:!1});if(!n||!n.isFile())throw new c(`Not a valid file: ${o}`);return o}export function buildEnsureComposerOpenJs(){return`
9
9
  (() => {
10
- ${$}
10
+ ${a}
11
11
  const pathName = (window.location && window.location.pathname) || '';
12
12
  const onLoginRoute = /\\/login\\/?$/.test(pathName) || /\\/accounts\\/login/.test(pathName);
13
13
  const hasLoginField = !!document.querySelector('input[name="username"], input[name="password"], input[autocomplete="username"], input[autocomplete="current-password"]');
@@ -34,24 +34,24 @@ import*as D from"node:fs";import*as v from"node:path";import{cli as V,Strategy a
34
34
  // 没有登录墙、也没找到入口:composer 可能延迟渲染,交给后续 focus 步骤重试。
35
35
  return { ok: true, opened: false };
36
36
  })()
37
- `}async function c(z){const K=await z.evaluate(buildEnsureComposerOpenJs());if(K?.reason==="auth")throw new f("www.threads.com","Threads login required before posting");if(!K?.ok)throw new G("Failed to open Threads composer")}async function x(z){return z.evaluate(`(() => {
38
- ${$}
37
+ `}async function L(e){const t=await e.evaluate(buildEnsureComposerOpenJs());if(t?.reason==="auth")throw new h("www.threads.com","Threads login required before posting");if(!t?.ok)throw new i("Failed to open Threads composer")}async function P(e){return e.evaluate(`(() => {
38
+ ${a}
39
39
  const boxes = Array.from(document.querySelectorAll('[contenteditable="true"], textarea'));
40
40
  const box = boxes.find(isVisible) || boxes[0];
41
41
  if (!box) return { ok: false, message: 'Could not find the Threads composer text box. Are you logged in?' };
42
42
  box.focus();
43
43
  return { ok: true };
44
- })()`)}export function buildVerifyComposerTextJs(z,K,Q){return`(async () => {
45
- ${$}
46
- const expected = ${JSON.stringify(z)};
44
+ })()`)}export function buildVerifyComposerTextJs(e,t,o){return`(async () => {
45
+ ${a}
46
+ const expected = ${JSON.stringify(e)};
47
47
  const normalize = (s) => String(s || '').replace(/\\u00a0/g, ' ').replace(/\\s+/g, ' ').trim();
48
48
  const normalizedExpected = normalize(expected);
49
- for (let i = 0; i < ${JSON.stringify(K)}; i++) {
49
+ for (let i = 0; i < ${JSON.stringify(t)}; i++) {
50
50
  const boxes = Array.from(document.querySelectorAll('[contenteditable="true"], textarea'));
51
51
  const box = boxes.find(isVisible) || boxes[0];
52
52
  const actual = box ? (box.value || box.innerText || box.textContent || '') : '';
53
53
  if (box && normalize(actual).includes(normalizedExpected)) return { ok: true };
54
- await new Promise((r) => setTimeout(r, ${JSON.stringify(Q)}));
54
+ await new Promise((r) => setTimeout(r, ${JSON.stringify(o)}));
55
55
  }
56
56
  const boxes = Array.from(document.querySelectorAll('[contenteditable="true"], textarea'));
57
57
  const box = boxes.find(isVisible) || boxes[0];
@@ -60,13 +60,13 @@ import*as D from"node:fs";import*as v from"node:path";import{cli as V,Strategy a
60
60
  message: 'Could not verify Threads post text in the composer after typing.',
61
61
  actualText: box ? (box.value || box.innerText || box.textContent || '') : '',
62
62
  };
63
- })()`}async function M(z,K){const Q=Math.ceil(U/j);return z.evaluate(buildVerifyComposerTextJs(K,Q,j))}function O(z){const K=(z instanceof Error?z.message:String(z)).toLowerCase();return K.includes("unknown action")||K.includes("not supported")||K.includes("inserttext returned no inserted flag")}async function b(z,K){const Q=await x(z);if(!Q?.ok)return Q;const W=[z.nativeType?.bind(z),z.insertText?.bind(z)].filter(Boolean);for(const Y of W)try{await Y(K);const Z=await M(z,K);if(Z?.ok)return Z}catch(Z){if(!O(Z))throw Z}return z.evaluate(`(async () => {
63
+ })()`}async function I(e,t){const o=Math.ceil(v/m);return e.evaluate(buildVerifyComposerTextJs(t,o,m))}function _(e){const t=(e instanceof Error?e.message:String(e)).toLowerCase();return t.includes("unknown action")||t.includes("not supported")||t.includes("inserttext returned no inserted flag")}async function q(e,t){const o=await P(e);if(!o?.ok)return o;const r=[e.nativeType?.bind(e),e.insertText?.bind(e)].filter(Boolean);for(const n of r)try{await n(t);const s=await I(e,t);if(s?.ok)return s}catch(s){if(!_(s))throw s}return e.evaluate(`(async () => {
64
64
  try {
65
- ${$}
65
+ ${a}
66
66
  const boxes = Array.from(document.querySelectorAll('[contenteditable="true"], textarea'));
67
67
  const box = boxes.find(isVisible) || boxes[0];
68
68
  if (!box) return { ok: false, message: 'Could not find the Threads composer text box. Are you logged in?' };
69
- const textToInsert = ${JSON.stringify(K)};
69
+ const textToInsert = ${JSON.stringify(t)};
70
70
  const normalize = (s) => String(s || '').replace(/\\u00a0/g, ' ').replace(/\\s+/g, ' ').trim();
71
71
  box.focus();
72
72
  if (box instanceof HTMLTextAreaElement) {
@@ -84,17 +84,17 @@ import*as D from"node:fs";import*as v from"node:path";import{cli as V,Strategy a
84
84
  if (normalize(actual).includes(normalize(textToInsert))) return { ok: true };
85
85
  return { ok: false, message: 'Could not verify Threads post text in the composer after typing.', actualText: actual };
86
86
  } catch (e) { return { ok: false, message: String(e) }; }
87
- })()`)}export function buildUploadProbeJs(z,K){return`(async () => {
88
- ${$}
89
- for (let i = 0; i < ${JSON.stringify(z)}; i++) {
90
- await new Promise((r) => setTimeout(r, ${JSON.stringify(K)}));
87
+ })()`)}export function buildUploadProbeJs(e,t){return`(async () => {
88
+ ${a}
89
+ for (let i = 0; i < ${JSON.stringify(e)}; i++) {
90
+ await new Promise((r) => setTimeout(r, ${JSON.stringify(t)}));
91
91
  const previewCount = document.querySelectorAll('img[src^="blob:"], video[src^="blob:"], [data-testid*="attachment"] img, [role="dialog"] img[alt]').length;
92
92
  if (previewCount > 0) return { ok: true, previewCount };
93
93
  }
94
- return { ok: false, message: 'Threads image upload timed out (${F/1000}s).' };
95
- })()`}async function d(z,K){await A(z,R,[K]);const Q=Math.ceil(F/J),W=await z.evaluate(buildUploadProbeJs(Q,J));if(!W?.ok)throw new G(W?.message??`Threads image upload timed out (${F/1000}s).`)}export function buildSubmitJs(){return`
94
+ return { ok: false, message: 'Threads image upload timed out (${u/1000}s).' };
95
+ })()`}async function M(e,t){await T(e,C,[t]);const o=Math.ceil(u/b),r=await e.evaluate(buildUploadProbeJs(o,b));if(!r?.ok)throw new i(r?.message??`Threads image upload timed out (${u/1000}s).`)}export function buildSubmitJs(){return`
96
96
  (() => {
97
- ${$}
97
+ ${a}
98
98
  const boxes = Array.from(document.querySelectorAll('[contenteditable="true"], textarea'));
99
99
  const box = boxes.find(isVisible) || boxes[0];
100
100
  const container = (box && (box.closest('[role="dialog"]') || box.closest('form'))) || document.body;
@@ -117,9 +117,9 @@ import*as D from"node:fs";import*as v from"node:path";import{cli as V,Strategy a
117
117
  target.click();
118
118
  return { ok: true, label: labelOf(target) };
119
119
  })()
120
- `}async function I(z){return z.evaluate(buildSubmitJs())}export function buildPublishStatusProbeJs(){return`
120
+ `}async function N(e){return e.evaluate(buildSubmitJs())}export function buildPublishStatusProbeJs(){return`
121
121
  (() => {
122
- ${$}
122
+ ${a}
123
123
  const box = Array.from(document.querySelectorAll('[contenteditable="true"], textarea')).find(isVisible);
124
124
  const dialogOpen = Array.from(document.querySelectorAll('[role="dialog"]')).some(isVisible);
125
125
  const alertText = Array.from(document.querySelectorAll('[role="alert"]'))
@@ -130,4 +130,4 @@ import*as D from"node:fs";import*as v from"node:path";import{cli as V,Strategy a
130
130
  const done = !box && !dialogOpen;
131
131
  return { ok: done && !failed, failed, settled: done };
132
132
  })()
133
- `}async function L(z){const K=Math.ceil(h/y);let Q=0;for(let W=0;W<K;W++){const Y=await z.evaluate(buildPublishStatusProbeJs());if(Y?.failed)return{ok:!1,message:"Threads post could not be published (share failed)."};if(Y?.ok)return{ok:!0,message:"Threads post published successfully."};if(Y?.settled){Q+=1;if(Q>=3)return{ok:!0,message:"Threads post published successfully."}}else Q=0;if(W<K-1)await z.wait(y/1000)}return{ok:!1,message:"Threads post was not confirmed sent; verify via readback before retrying."}}V({site:"threads",name:"post",access:"write",description:"Post a new thread (text, optional single image) on Threads",domain:"www.threads.com",strategy:H.UI,browser:!0,args:[{name:"text",fromFile:!0,type:"string",required:!0,positional:!0,help:"The text content of the thread"},{name:"image",type:"string",required:!1,valueRequired:!0,help:"Optional single image path (jpg/jpeg/png/webp/gif)"}],columns:["status","message","text","url"],func:async(z,K)=>{const Q=w(z),W=K.image?T(K.image):null,Y=String(K.text??"");B(Y,{label:"串文正文"});if(!Y.trim()&&!W)throw new q("Thread text is required.","Provide the post text as the positional argument");await Q.goto(k);await Q.wait(2);await c(Q);await Q.wait(1);if(W)await d(Q,W);const Z=await b(Q,Y);if(!Z?.ok)throw new G(Z?.message??"Could not type Threads post text.");await Q.wait(1);const N=await I(Q);if(!N?.ok)throw new G(N?.message??"Threads post button not found.");const X=await L(Q);if(!X?.ok)throw new G(X?.message??"Threads post was not confirmed sent; verify via readback before retrying.");return[{status:"success",message:X.message,text:Y,url:""}]}});
133
+ `}async function R(e){const t=Math.ceil(A/p);let o=0;for(let r=0;r<t;r++){const n=await e.evaluate(buildPublishStatusProbeJs());if(n?.failed)return{ok:!1,message:"Threads post could not be published (share failed)."};if(n?.ok)return{ok:!0,message:"Threads post published successfully."};if(n?.settled){o+=1;if(o>=3)return{ok:!0,message:"Threads post published successfully."}}else o=0;if(r<t-1)await e.wait(p/1000)}return{ok:!1,message:"Threads post was not confirmed sent; verify via readback before retrying."}}g({site:"threads",name:"post",access:"write",description:"Post a new thread (text, optional single image) on Threads",domain:"www.threads.com",strategy:w.UI,browser:!0,args:[{name:"text",fromFile:!0,type:"string",required:!0,positional:!0,help:"The text content of the thread"},{name:"image",type:"string",required:!1,valueRequired:!0,help:"Optional single image path (jpg/jpeg/png/webp/gif)"}],columns:["status","message","text","url"],func:async(e,t)=>{const o=E(e),r=t.image?O(t.image):null,n=String(t.text??"");y(n,{label:"串文正文"});if(!n.trim()&&!r)throw new c("Thread text is required.","Provide the post text as the positional argument");await o.goto(S);await o.wait(2);await L(o);await o.wait(1);if(r)await M(o,r);const s=await q(o,n);if(!s?.ok)throw new i(s?.message??"Could not type Threads post text.");await o.wait(1);const d=await N(o);if(!d?.ok)throw new i(d?.message??"Threads post button not found.");const l=await R(o);if(!l?.ok)throw new i(l?.message??"Threads post was not confirmed sent; verify via readback before retrying.");return[{status:"success",message:l.message,text:n,url:""}]}});
@@ -1,10 +1,10 @@
1
- import{AuthRequiredError as K,CommandExecutionError as F}from"@jackwener/opencli/errors";export const THREADS_HOME_URL="https://www.threads.com/",THREADS_LOGIN_URL="https://www.threads.com/login";const Q="https://www.instagram.com/",V="936619743392459";export async function hasThreadsSessionCookie(y){for(const b of["https://www.threads.com",Q])try{if((await y.getCookies({url:b})).some((J)=>J.name==="sessionid"&&J.value))return!0}catch{}return!1}export async function verifyThreadsIdentity(y){if(!await hasThreadsSessionCookie(y))throw new K("www.threads.com","Threads/Instagram sessionid cookie missing");await y.goto(Q);await y.wait(2);const b=await y.evaluate(`(async () => {
1
+ import{AuthRequiredError as n,CommandExecutionError as r}from"@jackwener/opencli/errors";export const THREADS_HOME_URL="https://www.threads.com/",THREADS_LOGIN_URL="https://www.threads.com/login";const o="https://www.instagram.com/",a="936619743392459";export async function hasThreadsSessionCookie(e){for(const t of["https://www.threads.com",o])try{if((await e.getCookies({url:t})).some((i)=>i.name==="sessionid"&&i.value))return!0}catch{}return!1}export async function verifyThreadsIdentity(e){if(!await hasThreadsSessionCookie(e))throw new n("www.threads.com","Threads/Instagram sessionid cookie missing");await e.goto(o);await e.wait(2);const t=await e.evaluate(`(async () => {
2
2
  try {
3
3
  const uid = (document.cookie.split('; ').find(c => c.startsWith('ds_user_id=')) || '').split('=')[1] || '';
4
4
  if (!uid) return { kind: 'auth', detail: 'Threads ds_user_id cookie missing' };
5
5
  const r = await fetch('/api/v1/users/' + uid + '/info/', {
6
6
  credentials: 'include',
7
- headers: { 'X-IG-App-ID': ${JSON.stringify(V)}, 'Accept': 'application/json' },
7
+ headers: { 'X-IG-App-ID': ${JSON.stringify(a)}, 'Accept': 'application/json' },
8
8
  });
9
9
  if (r.status === 401 || r.status === 403) {
10
10
  return { kind: 'auth', detail: 'Threads /users/info HTTP ' + r.status };
@@ -24,4 +24,4 @@ import{AuthRequiredError as K,CommandExecutionError as F}from"@jackwener/opencli
24
24
  } catch (e) {
25
25
  return { kind: 'exception', detail: String(e && e.message || e) };
26
26
  }
27
- })()`);if(b?.kind==="auth")throw new K("www.threads.com",b.detail);if(b?.kind==="http")throw new F(`HTTP ${b.httpStatus} from Threads /users/info`);if(b?.kind==="exception")throw new F(`Threads whoami failed: ${b.detail}`);if(!b?.ok)throw new F(`Unexpected Threads probe: ${JSON.stringify(b)}`);const z=b.username;return{user_id:b.user_id,username:z,full_name:b.full_name,profile_url:z?`https://www.threads.com/@${z}`:""}}
27
+ })()`);if(t?.kind==="auth")throw new n("www.threads.com",t.detail);if(t?.kind==="http")throw new r(`HTTP ${t.httpStatus} from Threads /users/info`);if(t?.kind==="exception")throw new r(`Threads whoami failed: ${t.detail}`);if(!t?.ok)throw new r(`Unexpected Threads probe: ${JSON.stringify(t)}`);const s=t.username;return{user_id:t.user_id,username:s,full_name:t.full_name,profile_url:s?`https://www.threads.com/@${s}`:""}}
@@ -1 +1 @@
1
- import{AuthRequiredError as B}from"@jackwener/opencli/errors";import{registerSiteAuthCommands as D}from"../_shared/site-auth.js";import{hasThreadsSessionCookie as x,verifyThreadsIdentity as z}from"./shared.js";D({site:"threads",domain:"threads.com",loginUrl:"https://www.threads.com/login",columns:["user_id","username","full_name","profile_url"],quickCheck:x,verify:z,poll:async(b)=>{if(!await x(b))throw new B("www.threads.com","Waiting for Threads/Instagram sessionid cookie");return z(b)}});
1
+ import{AuthRequiredError as o}from"@jackwener/opencli/errors";import{registerSiteAuthCommands as s}from"../_shared/site-auth.js";import{hasThreadsSessionCookie as e,verifyThreadsIdentity as i}from"./shared.js";s({site:"threads",domain:"threads.com",loginUrl:"https://www.threads.com/login",columns:["user_id","username","full_name","profile_url"],quickCheck:e,verify:i,poll:async(r)=>{if(!await e(r))throw new o("www.threads.com","Waiting for Threads/Instagram sessionid cookie");return i(r)}});
package/clis/tieba/hot.js CHANGED
@@ -1,4 +1,4 @@
1
- import{EmptyResultError as H}from"@jackwener/opencli/errors";import{cli as I,Strategy as J}from"@jackwener/opencli/registry";import{normalizeTiebaLimit as K}from"./utils.js";I({site:"tieba",name:"hot",access:"read",description:"Tieba hot topics",domain:"tieba.baidu.com",strategy:J.PUBLIC,browser:!0,args:[{name:"limit",type:"int",default:20,help:"Number of items to return"}],columns:["rank","title","discussions","description","url"],func:async(A,D)=>{const F=K(D.limit);await A.goto("https://tieba.baidu.com/hottopic/browse/topicList?res_type=1");const B=await A.evaluate(`(() => {
1
+ import{EmptyResultError as n}from"@jackwener/opencli/errors";import{cli as a,Strategy as m}from"@jackwener/opencli/registry";import{normalizeTiebaLimit as l}from"./utils.js";a({site:"tieba",name:"hot",access:"read",description:"Tieba hot topics",domain:"tieba.baidu.com",strategy:m.PUBLIC,browser:!0,args:[{name:"limit",type:"int",default:20,help:"Number of items to return"}],columns:["rank","title","discussions","description","url"],func:async(e,o)=>{const s=l(o.limit);await e.goto("https://tieba.baidu.com/hottopic/browse/topicList?res_type=1");const i=await e.evaluate(`(() => {
2
2
  const items = document.querySelectorAll('li.topic-top-item');
3
3
  return Array.from(items).map((item) => {
4
4
  const titleEl = item.querySelector('a.topic-text');
@@ -12,5 +12,5 @@ import{EmptyResultError as H}from"@jackwener/opencli/errors";import{cli as I,Str
12
12
  description: descEl?.textContent?.trim() || '',
13
13
  url: href.startsWith('http') ? href : 'https://tieba.baidu.com' + href,
14
14
  };
15
- }).filter((item) => item.title).slice(0, ${F});
16
- })()`),C=Array.isArray(B)?B:[];if(!C.length)throw new H("tieba hot","Tieba may have blocked the hot page, or the DOM structure may have changed");return C.map((q,G)=>({rank:G+1,title:q.title||"",discussions:q.discussions||"",description:q.description||"",url:q.url||""}))}});
15
+ }).filter((item) => item.title).slice(0, ${s});
16
+ })()`),r=Array.isArray(i)?i:[];if(!r.length)throw new n("tieba hot","Tieba may have blocked the hot page, or the DOM structure may have changed");return r.map((t,c)=>({rank:c+1,title:t.title||"",discussions:t.discussions||"",description:t.description||"",url:t.url||""}))}});
@@ -1 +1 @@
1
- import{EmptyResultError as W}from"@jackwener/opencli/errors";import{cli as X,Strategy as Y}from"@jackwener/opencli/registry";import{buildTiebaPostCardsFromPagePc as Z,buildTiebaPostItems as _,normalizeTiebaLimit as $,signTiebaPcParams as q}from"./utils.js";function O(v){return Math.max(1,Number(v.page||1))}function Q(v){const A=String(v.forum||"");return`https://tieba.baidu.com/f?kw=${encodeURIComponent(A)}&ie=utf-8&pn=${(O(v)-1)*50}`}function z(v,A){return{kw:encodeURIComponent(String(v.forum||"")),pn:String(O(v)),sort_type:"-1",is_newfrs:"1",is_newfeed:"1",rn:"30",rn_need:String(Math.min(Math.max(A+10,10),30)),tbs:"",subapp_type:"pc",_client_type:"20"}}async function H(v,A,D){await v.goto(Q(A),{waitUntil:"none"});await v.wait(2);const B=z(A,D),J=(await v.getCookies({domain:"tieba.baidu.com"})).map((M)=>`${M.name}=${M.value}`).join("; "),G=new URLSearchParams({...B,sign:q(B)}).toString(),V=await(await fetch("https://tieba.baidu.com/c/f/frs/page_pc",{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded;charset=UTF-8",cookie:J,"x-requested-with":"XMLHttpRequest",referer:Q(A),"user-agent":"Mozilla/5.0"},body:G})).text();try{return JSON.parse(V)}catch{return{}}}X({site:"tieba",name:"posts",access:"read",description:"Browse posts in a tieba forum",domain:"tieba.baidu.com",strategy:Y.COOKIE,browser:!0,navigateBefore:!1,args:[{name:"forum",positional:!0,required:!0,type:"string",help:"Forum name in Chinese"},{name:"page",type:"int",default:1,help:"Page number"},{name:"limit",type:"int",default:20,help:"Number of items to return"}],columns:["rank","title","author","replies"],func:async(v,A)=>{const D=$(A.limit),B=await H(v,A,D),K=Array.isArray(B.page_data?.feed_list)?B.page_data.feed_list:[],J=Z(K),G=_(J,D);if(!G.length||B.error_code)throw new W("tieba posts","Tieba may have blocked the forum page, or the DOM structure may have changed");return G}});
1
+ import{EmptyResultError as p}from"@jackwener/opencli/errors";import{cli as d,Strategy as f}from"@jackwener/opencli/registry";import{buildTiebaPostCardsFromPagePc as l,buildTiebaPostItems as b,normalizeTiebaLimit as h,signTiebaPcParams as g}from"./utils.js";function c(e){return Math.max(1,Number(e.page||1))}function m(e){const t=String(e.forum||"");return`https://tieba.baidu.com/f?kw=${encodeURIComponent(t)}&ie=utf-8&pn=${(c(e)-1)*50}`}function y(e,t){return{kw:encodeURIComponent(String(e.forum||"")),pn:String(c(e)),sort_type:"-1",is_newfrs:"1",is_newfeed:"1",rn:"30",rn_need:String(Math.min(Math.max(t+10,10),30)),tbs:"",subapp_type:"pc",_client_type:"20"}}async function w(e,t,r){await e.goto(m(t),{waitUntil:"none"});await e.wait(2);const a=y(t,r),i=(await e.getCookies({domain:"tieba.baidu.com"})).map((s)=>`${s.name}=${s.value}`).join("; "),o=new URLSearchParams({...a,sign:g(a)}).toString(),u=await(await fetch("https://tieba.baidu.com/c/f/frs/page_pc",{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded;charset=UTF-8",cookie:i,"x-requested-with":"XMLHttpRequest",referer:m(t),"user-agent":"Mozilla/5.0"},body:o})).text();try{return JSON.parse(u)}catch{return{}}}d({site:"tieba",name:"posts",access:"read",description:"Browse posts in a tieba forum",domain:"tieba.baidu.com",strategy:f.COOKIE,browser:!0,navigateBefore:!1,args:[{name:"forum",positional:!0,required:!0,type:"string",help:"Forum name in Chinese"},{name:"page",type:"int",default:1,help:"Page number"},{name:"limit",type:"int",default:20,help:"Number of items to return"}],columns:["rank","title","author","replies"],func:async(e,t)=>{const r=h(t.limit),a=await w(e,t,r),n=Array.isArray(a.page_data?.feed_list)?a.page_data.feed_list:[],i=l(n),o=b(i,r);if(!o.length||a.error_code)throw new p("tieba posts","Tieba may have blocked the forum page, or the DOM structure may have changed");return o}});
@@ -1,4 +1,4 @@
1
- import{EmptyResultError as F}from"@jackwener/opencli/errors";import{cli as J,Strategy as K}from"@jackwener/opencli/registry";import{buildTiebaReadItems as L}from"./utils.js";function Q(z){const q=String(z.id||""),A=Math.max(1,Number(z.page||1));return`https://tieba.baidu.com/p/${encodeURIComponent(q)}?pn=${A}`}function V(z,q){const A=String(q.id||"").trim(),B=Math.max(1,Number(q.page||1)),G=String(z.pageMeta?.pathname||"").trim().match(/^\/p\/(\d+)/)?.[1]||"",H=String(z.pageMeta?.pn||"").trim();if(!G||G!==A)throw new F("tieba read","Tieba did not land on the requested thread page");if(B>1&&H!==String(B))throw new F("tieba read","Tieba did not land on the requested page")}function W(){return`
1
+ import{EmptyResultError as o}from"@jackwener/opencli/errors";import{cli as m,Strategy as s}from"@jackwener/opencli/registry";import{buildTiebaReadItems as u}from"./utils.js";function p(e){const t=String(e.id||""),r=Math.max(1,Number(e.page||1));return`https://tieba.baidu.com/p/${encodeURIComponent(t)}?pn=${r}`}function l(e,t){const r=String(t.id||"").trim(),n=Math.max(1,Number(t.page||1)),i=String(e.pageMeta?.pathname||"").trim().match(/^\/p\/(\d+)/)?.[1]||"",c=String(e.pageMeta?.pn||"").trim();if(!i||i!==r)throw new o("tieba read","Tieba did not land on the requested thread page");if(n>1&&c!==String(n))throw new o("tieba read","Tieba did not land on the requested page")}function d(){return`
2
2
  (async () => {
3
3
  const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
4
4
  const waitFor = async (predicate, timeoutMs = 4000) => {
@@ -81,4 +81,4 @@ import{EmptyResultError as F}from"@jackwener/opencli/errors";import{cli as J,Str
81
81
  }),
82
82
  };
83
83
  })()
84
- `}J({site:"tieba",name:"read",access:"read",description:"Read a tieba thread",domain:"tieba.baidu.com",strategy:K.COOKIE,browser:!0,navigateBefore:!1,args:[{name:"id",positional:!0,required:!0,type:"string",help:"Thread ID"},{name:"page",type:"int",default:1,help:"Page number"},{name:"limit",type:"int",default:30,help:"Number of replies to return"}],columns:["floor","author","content","time"],func:async(z,q)=>{const A=Math.max(1,Number(q.page||1));await z.goto(Q(q));const B=await z.evaluate(W())||{};V(B,q);const C=L(B,{limit:q.limit,includeMainPost:A===1});if(!C.length)throw new F("tieba read","Tieba may have blocked the thread page, or the DOM structure may have changed");return C}});
84
+ `}m({site:"tieba",name:"read",access:"read",description:"Read a tieba thread",domain:"tieba.baidu.com",strategy:s.COOKIE,browser:!0,navigateBefore:!1,args:[{name:"id",positional:!0,required:!0,type:"string",help:"Thread ID"},{name:"page",type:"int",default:1,help:"Page number"},{name:"limit",type:"int",default:30,help:"Number of replies to return"}],columns:["floor","author","content","time"],func:async(e,t)=>{const r=Math.max(1,Number(t.page||1));await e.goto(p(t));const n=await e.evaluate(d())||{};l(n,t);const a=u(n,{limit:t.limit,includeMainPost:r===1});if(!a.length)throw new o("tieba read","Tieba may have blocked the thread page, or the DOM structure may have changed");return a}});
@@ -1,4 +1,4 @@
1
- import{ArgumentError as F,EmptyResultError as H}from"@jackwener/opencli/errors";import{cli as I,Strategy as J}from"@jackwener/opencli/registry";import{buildTiebaSearchItems as K,normalizeTiebaLimit as L}from"./utils.js";const z="1";function Q(f){return`
1
+ import{ArgumentError as i,EmptyResultError as s}from"@jackwener/opencli/errors";import{cli as m,Strategy as u}from"@jackwener/opencli/registry";import{buildTiebaSearchItems as c,normalizeTiebaLimit as l}from"./utils.js";const a="1";function p(e){return`
2
2
  (async () => {
3
3
  const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
4
4
  const waitFor = async (predicate, timeoutMs = 5000) => {
@@ -22,7 +22,7 @@ import{ArgumentError as F,EmptyResultError as H}from"@jackwener/opencli/errors";
22
22
  );
23
23
  });
24
24
  const items = document.querySelectorAll('.threadcardclass.thread-new3.index-feed-cards');
25
- return Array.from(items).slice(0, ${f}).map((item) => {
25
+ return Array.from(items).slice(0, ${e}).map((item) => {
26
26
  const forum = item.querySelector('.forum-name-text, .forum-name')?.textContent?.trim() || '';
27
27
  const meta = item.querySelector('.user-forum-info')?.textContent?.replace(/\\s+/g, ' ').trim() || '';
28
28
  const metaWithoutForum = forum && meta.startsWith(forum)
@@ -51,4 +51,4 @@ import{ArgumentError as F,EmptyResultError as H}from"@jackwener/opencli/errors";
51
51
  };
52
52
  }).filter((item) => item.title);
53
53
  })()
54
- `}function V(f){const j=String(f.keyword||""),q=Number(f.page||1);return`https://tieba.baidu.com/f/search/res?qw=${encodeURIComponent(j)}&ie=utf-8&pn=${q}`}function W(f){if(String(f.page||1)===z)return;throw new F(`tieba search currently only supports --page ${z}`,`Baidu Tieba search no longer exposes stable browser pagination; omit --page or use --page ${z}`)}I({site:"tieba",name:"search",access:"read",description:"Search posts across tieba",domain:"tieba.baidu.com",strategy:J.COOKIE,browser:!0,navigateBefore:!1,args:[{name:"keyword",positional:!0,required:!0,type:"string",help:"Search keyword"},{name:"page",type:"int",default:1,choices:["1"],help:"Page number (currently only 1 is supported)"},{name:"limit",type:"int",default:20,help:"Number of items to return"}],columns:["rank","id","title","forum","author","time","url"],func:async(f,j)=>{W(j);const q=L(j.limit);await f.goto(V(j));const B=await f.evaluate(Q(q)),C=K(Array.isArray(B)?B:[],q);if(!C.length)throw new H("tieba search","Tieba may have blocked the result page, or the DOM structure may have changed");return C}});
54
+ `}function d(e){const t=String(e.keyword||""),r=Number(e.page||1);return`https://tieba.baidu.com/f/search/res?qw=${encodeURIComponent(t)}&ie=utf-8&pn=${r}`}function h(e){if(String(e.page||1)===a)return;throw new i(`tieba search currently only supports --page ${a}`,`Baidu Tieba search no longer exposes stable browser pagination; omit --page or use --page ${a}`)}m({site:"tieba",name:"search",access:"read",description:"Search posts across tieba",domain:"tieba.baidu.com",strategy:u.COOKIE,browser:!0,navigateBefore:!1,args:[{name:"keyword",positional:!0,required:!0,type:"string",help:"Search keyword"},{name:"page",type:"int",default:1,choices:["1"],help:"Page number (currently only 1 is supported)"},{name:"limit",type:"int",default:20,help:"Number of items to return"}],columns:["rank","id","title","forum","author","time","url"],func:async(e,t)=>{h(t);const r=l(t.limit);await e.goto(d(t));const o=await e.evaluate(p(r)),n=c(Array.isArray(o)?o:[],r);if(!n.length)throw new s("tieba search","Tieba may have blocked the result page, or the DOM structure may have changed");return n}});
@@ -1 +1 @@
1
- import{createHash as q}from"node:crypto";export const MAX_TIEBA_LIMIT=20;const B="36770b1f34c9bbf2e7d1a99d2b82fa9e",S="Asia/Shanghai";export function normalizeTiebaLimit(j,K=MAX_TIEBA_LIMIT){const Q=Number(j??K);if(!Number.isFinite(Q)||Q<1)return K;return Math.min(Math.trunc(Q),MAX_TIEBA_LIMIT)}export function normalizeText(j){return typeof j==="string"?j.replace(/\s+/g," ").trim():""}export function signTiebaPcParams(j){const K=Object.keys(j).sort((Q,J)=>Q.localeCompare(J)).map((Q)=>`${Q}=${j[Q]}`).join("")+B;return q("md5").update(K).digest("hex")}export function parseTiebaCount(j){const K=normalizeText(j).toUpperCase();if(!K)return 0;const Q=K.replace(/[^\d.W万]/g,"");if(Q.endsWith("万"))return Math.round(parseFloat(Q.slice(0,-1))*1e4);if(Q.endsWith("W"))return Math.round(parseFloat(Q.slice(0,-1))*1e4);return parseInt(Q.replace(/[^\d]/g,""),10)||0}export function parseTiebaLastReply(j){const K=normalizeText(j).replace(/^回复于/,"").trim(),Q=K.match(/(刚刚|\d+\s*(?:分钟|小时|天)前|\d{2}-\d{2}(?:\s+\d{2}:\d{2})?|\d{4}-\d{2}-\d{2}(?:\s+\d{2}:\d{2})?)/);return Q?Q[1].trim():K}function N(j,K){const Q=normalizeText(K);if(Q)return Q;return j?`https://tieba.baidu.com/p/${j}`:""}function R(j){const K=normalizeText(j.threadId);if(K)return K;const Q=normalizeText(j.url).match(/\/p\/(\d+)/);return Q?Q[1]:""}function H(j,K){const J=(Array.isArray(j?.components)?j.components:[]).find((W)=>normalizeText(W.component)===K);if(!J)return{};const V=J[K];return V&&typeof V==="object"?V:{}}function E(j){const K=H(j,"feed_head"),Q=Array.isArray(K.main_data)?K.main_data:[];for(const J of Q){const V=J.text,W=normalizeText(V?.text);if(W)return W}return""}function A(j){const K=H(j,"feed_title"),V=(Array.isArray(K.data)?K.data:[])[0]?.text_info;return normalizeText(V?.text)||normalizeText(j?.business_info_map?.title)}function M(j){const K=H(j,"feed_social"),Q=Number(K.comment_num??j?.business_info_map?.comment_num??0);return Number.isFinite(Q)?Q:0}function k(j){const K=normalizeText(j?.business_info_map?.thread_id);if(K)return K;const Q=Array.isArray(j?.log_param)?j.log_param:[],J=normalizeText(Q.find((W)=>normalizeText(W?.key)==="tid")?.value);if(J)return J;const V=normalizeText(j?.schema).match(/[?&]tid=(\d+)/);return V?V[1]:""}function _(j){const K=H(j,"feed_head"),J=(Array.isArray(K.extra_data)?K.extra_data:[])[0],V=normalizeText(J?.business_info_map?.time_prefix),W=J?.text,Y=normalizeText(W?.text),$=/^\d+$/.test(Y)?X(Y):Y;return[V,$].filter(Boolean).join("")}export function buildTiebaPostCardsFromPagePc(j){return j.filter((K)=>normalizeText(K.layout)==="feed"&&K.feed).map((K)=>{const Q=K.feed,J=k(Q);return{title:A(Q),author:E(Q),descInfo:_(Q),commentCount:M(Q),actionTexts:[],threadId:J,url:N(J)}}).filter((K)=>normalizeText(K.title))}export function buildTiebaPostItems(j,K){const Q=normalizeTiebaLimit(K);return j.map((J)=>{const V=normalizeText(J.title),W=R(J),Y=Array.isArray(J.actionTexts)?J.actionTexts.map(normalizeText).filter(Boolean):[],$=Y.find((D)=>/评论/.test(D))||Y[Y.length-1]||"";return{title:V,author:normalizeText(J.author),replies:Number.isFinite(Number(J.commentCount))?Number(J.commentCount):parseTiebaCount($),last_reply:parseTiebaLastReply(String(J.descInfo??"")),id:W,url:N(W,J.url)}}).filter((J)=>J.title).slice(0,Q).map((J,V)=>({rank:V+1,...J}))}export function buildTiebaSearchItems(j,K){const Q=normalizeTiebaLimit(K);return j.map((J)=>{const V=normalizeText(J.url),W=normalizeText(J.id),Y=V.match(/\/p\/(\d+)/)?.[1]||"";return{title:normalizeText(J.title),forum:normalizeText(J.forum),author:normalizeText(J.author),time:normalizeText(J.time),snippet:normalizeText(J.snippet).slice(0,200),id:W||Y,url:V}}).filter((J)=>J.title).slice(0,Q).map((J,V)=>({rank:V+1,...J}))}function X(j){const K=Number(j||0);if(!Number.isFinite(K)||K<=0)return"";const Q=new Intl.DateTimeFormat("sv-SE",{timeZone:S,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hour12:!1}).formatToParts(new Date(K*1000)),J=Object.fromEntries(Q.map((V)=>[V.type,V.value]));return`${J.year}-${J.month}-${J.day} ${J.hour}:${J.minute}`}function g(j){const Q=normalizeText(j).replace(/^第\d+楼\s+/,"").trim(),J=Q.match(/^(刚刚|昨天|前天|\d+\s*(?:分钟|小时|天)前|\d{2}-\d{2}(?:\s+\d{2}:\d{2})?|\d{4}-\d{2}-\d{2}(?:\s+\d{2}:\d{2})?)/);return J?J[1].trim():Q}function U(j){if(!j)return null;const K=normalizeText(j.title),Q=normalizeText(j.author)||normalizeText(j.fallbackAuthor),J=normalizeText(j.contentText)||normalizeText(j.structuredText),V=Boolean(j.hasMedia),W=[K,J||(V?"[media]":"")].filter(Boolean).join(" ").trim();if(!W)return null;return{floor:1,author:Q,content:W,time:normalizeText(j.visibleTime)||X(j.structuredTime)}}export function buildTiebaReadItems(j,K={}){const Q=Number.isFinite(Number(K.limit))?Number(K.limit):30,J=Math.max(1,Math.trunc(Q)),V=K.includeMainPost!==!1,W=[],Y=U(j.mainPost);if(V&&Y)W.push(Y);const $=Array.isArray(j.replies)?j.replies:[],D=[];for(const G of $){const O=Number(G.floor||0),Z=normalizeText(G.content);if(!Number.isFinite(O)||O<1||!Z)continue;D.push({floor:O,author:normalizeText(G.author),content:Z,time:g(String(G.time??""))})}return W.concat(D.slice(0,J))}
1
+ import{createHash as h}from"node:crypto";export const MAX_TIEBA_LIMIT=20;const b="36770b1f34c9bbf2e7d1a99d2b82fa9e",T="Asia/Shanghai";export function normalizeTiebaLimit(t,n=MAX_TIEBA_LIMIT){const r=Number(t??n);if(!Number.isFinite(r)||r<1)return n;return Math.min(Math.trunc(r),MAX_TIEBA_LIMIT)}export function normalizeText(t){return typeof t==="string"?t.replace(/\s+/g," ").trim():""}export function signTiebaPcParams(t){const n=Object.keys(t).sort((r,e)=>r.localeCompare(e)).map((r)=>`${r}=${t[r]}`).join("")+b;return h("md5").update(n).digest("hex")}export function parseTiebaCount(t){const n=normalizeText(t).toUpperCase();if(!n)return 0;const r=n.replace(/[^\d.W万]/g,"");if(r.endsWith("万"))return Math.round(parseFloat(r.slice(0,-1))*1e4);if(r.endsWith("W"))return Math.round(parseFloat(r.slice(0,-1))*1e4);return parseInt(r.replace(/[^\d]/g,""),10)||0}export function parseTiebaLastReply(t){const n=normalizeText(t).replace(/^回复于/,"").trim(),r=n.match(/(刚刚|\d+\s*(?:分钟|小时|天)前|\d{2}-\d{2}(?:\s+\d{2}:\d{2})?|\d{4}-\d{2}-\d{2}(?:\s+\d{2}:\d{2})?)/);return r?r[1].trim():n}function f(t,n){const r=normalizeText(n);if(r)return r;return t?`https://tieba.baidu.com/p/${t}`:""}function x(t){const n=normalizeText(t.threadId);if(n)return n;const r=normalizeText(t.url).match(/\/p\/(\d+)/);return r?r[1]:""}function m(t,n){const e=(Array.isArray(t?.components)?t.components:[]).find((o)=>normalizeText(o.component)===n);if(!e)return{};const i=e[n];return i&&typeof i==="object"?i:{}}function _(t){const n=m(t,"feed_head"),r=Array.isArray(n.main_data)?n.main_data:[];for(const e of r){const i=e.text,o=normalizeText(i?.text);if(o)return o}return""}function y(t){const n=m(t,"feed_title"),i=(Array.isArray(n.data)?n.data:[])[0]?.text_info;return normalizeText(i?.text)||normalizeText(t?.business_info_map?.title)}function A(t){const n=m(t,"feed_social"),r=Number(n.comment_num??t?.business_info_map?.comment_num??0);return Number.isFinite(r)?r:0}function I(t){const n=normalizeText(t?.business_info_map?.thread_id);if(n)return n;const r=Array.isArray(t?.log_param)?t.log_param:[],e=normalizeText(r.find((o)=>normalizeText(o?.key)==="tid")?.value);if(e)return e;const i=normalizeText(t?.schema).match(/[?&]tid=(\d+)/);return i?i[1]:""}function g(t){const n=m(t,"feed_head"),e=(Array.isArray(n.extra_data)?n.extra_data:[])[0],i=normalizeText(e?.business_info_map?.time_prefix),o=e?.text,a=normalizeText(o?.text),s=/^\d+$/.test(a)?p(a):a;return[i,s].filter(Boolean).join("")}export function buildTiebaPostCardsFromPagePc(t){return t.filter((n)=>normalizeText(n.layout)==="feed"&&n.feed).map((n)=>{const r=n.feed,e=I(r);return{title:y(r),author:_(r),descInfo:g(r),commentCount:A(r),actionTexts:[],threadId:e,url:f(e)}}).filter((n)=>normalizeText(n.title))}export function buildTiebaPostItems(t,n){const r=normalizeTiebaLimit(n);return t.map((e)=>{const i=normalizeText(e.title),o=x(e),a=Array.isArray(e.actionTexts)?e.actionTexts.map(normalizeText).filter(Boolean):[],s=a.find((c)=>/评论/.test(c))||a[a.length-1]||"";return{title:i,author:normalizeText(e.author),replies:Number.isFinite(Number(e.commentCount))?Number(e.commentCount):parseTiebaCount(s),last_reply:parseTiebaLastReply(String(e.descInfo??"")),id:o,url:f(o,e.url)}}).filter((e)=>e.title).slice(0,r).map((e,i)=>({rank:i+1,...e}))}export function buildTiebaSearchItems(t,n){const r=normalizeTiebaLimit(n);return t.map((e)=>{const i=normalizeText(e.url),o=normalizeText(e.id),a=i.match(/\/p\/(\d+)/)?.[1]||"";return{title:normalizeText(e.title),forum:normalizeText(e.forum),author:normalizeText(e.author),time:normalizeText(e.time),snippet:normalizeText(e.snippet).slice(0,200),id:o||a,url:i}}).filter((e)=>e.title).slice(0,r).map((e,i)=>({rank:i+1,...e}))}function p(t){const n=Number(t||0);if(!Number.isFinite(n)||n<=0)return"";const r=new Intl.DateTimeFormat("sv-SE",{timeZone:T,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hour12:!1}).formatToParts(new Date(n*1000)),e=Object.fromEntries(r.map((i)=>[i.type,i.value]));return`${e.year}-${e.month}-${e.day} ${e.hour}:${e.minute}`}function F(t){const r=normalizeText(t).replace(/^第\d+楼\s+/,"").trim(),e=r.match(/^(刚刚|昨天|前天|\d+\s*(?:分钟|小时|天)前|\d{2}-\d{2}(?:\s+\d{2}:\d{2})?|\d{4}-\d{2}-\d{2}(?:\s+\d{2}:\d{2})?)/);return e?e[1].trim():r}function N(t){if(!t)return null;const n=normalizeText(t.title),r=normalizeText(t.author)||normalizeText(t.fallbackAuthor),e=normalizeText(t.contentText)||normalizeText(t.structuredText),i=Boolean(t.hasMedia),o=[n,e||(i?"[media]":"")].filter(Boolean).join(" ").trim();if(!o)return null;return{floor:1,author:r,content:o,time:normalizeText(t.visibleTime)||p(t.structuredTime)}}export function buildTiebaReadItems(t,n={}){const r=Number.isFinite(Number(n.limit))?Number(n.limit):30,e=Math.max(1,Math.trunc(r)),i=n.includeMainPost!==!1,o=[],a=N(t.mainPost);if(i&&a)o.push(a);const s=Array.isArray(t.replies)?t.replies:[],c=[];for(const u of s){const d=Number(u.floor||0),l=normalizeText(u.content);if(!Number.isFinite(d)||d<1||!l)continue;c.push({floor:d,author:normalizeText(u.author),content:l,time:F(String(u.time??""))})}return o.concat(c.slice(0,e))}