specific-ai-cli 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (277) hide show
  1. package/LICENSE +21 -0
  2. package/README.en.md +177 -0
  3. package/README.ja.md +177 -0
  4. package/README.ko.md +177 -0
  5. package/README.md +174 -2
  6. package/README.zh-TW.md +177 -0
  7. package/assets/banner.txt +3 -0
  8. package/dist/cli/argv.js +98 -0
  9. package/dist/cli/commands/auth.js +11 -0
  10. package/dist/cli/commands/config.js +23 -0
  11. package/dist/cli/commands/doctor.js +134 -0
  12. package/dist/cli/commands/platforms.js +24 -0
  13. package/dist/cli/commands/version.js +4 -0
  14. package/dist/cli/confirm.js +22 -0
  15. package/dist/cli/dispatch.js +440 -0
  16. package/dist/cli/help.js +223 -0
  17. package/dist/cli/hints.js +60 -0
  18. package/dist/cli/main.js +18 -0
  19. package/dist/cli/output.js +66 -0
  20. package/dist/core/auth-handlers.js +41 -0
  21. package/dist/core/auth-store.js +119 -0
  22. package/dist/core/capabilities.js +163 -0
  23. package/dist/core/config.js +121 -0
  24. package/dist/core/cookies.js +164 -0
  25. package/dist/core/errors.js +37 -0
  26. package/dist/core/files.js +89 -0
  27. package/dist/core/fsutil.js +52 -0
  28. package/dist/core/hash.js +4 -0
  29. package/dist/core/http.js +331 -0
  30. package/dist/core/image.js +280 -0
  31. package/dist/core/log.js +40 -0
  32. package/dist/core/login.js +191 -0
  33. package/dist/core/mp4.js +130 -0
  34. package/dist/core/normalize.js +207 -0
  35. package/dist/core/options.js +110 -0
  36. package/dist/core/paths.js +38 -0
  37. package/dist/core/pb.js +59 -0
  38. package/dist/core/py.js +181 -0
  39. package/dist/core/rand.js +131 -0
  40. package/dist/core/registry.js +129 -0
  41. package/dist/core/schemas.js +41 -0
  42. package/dist/core/stream.js +104 -0
  43. package/dist/core/toolkit.js +35 -0
  44. package/dist/core/vm.js +73 -0
  45. package/dist/core/vocab.js +157 -0
  46. package/dist/platforms/_shared/impaas.js +410 -0
  47. package/dist/platforms/bilibili/index.js +216 -0
  48. package/dist/platforms/bilibili/web/api.js +806 -0
  49. package/dist/platforms/bilibili/web/client.js +311 -0
  50. package/dist/platforms/bilibili/web/commands.js +783 -0
  51. package/dist/platforms/bilibili/web/ddddocr.js +342 -0
  52. package/dist/platforms/bilibili/web/gaia.js +130 -0
  53. package/dist/platforms/bilibili/web/geetest-manual.js +154 -0
  54. package/dist/platforms/bilibili/web/geetest-vision.js +232 -0
  55. package/dist/platforms/bilibili/web/geetest.js +450 -0
  56. package/dist/platforms/bilibili/web/normalize.js +234 -0
  57. package/dist/platforms/bilibili/web/profile.js +135 -0
  58. package/dist/platforms/bilibili/web/resolve.js +112 -0
  59. package/dist/platforms/bilibili/web/sign.js +223 -0
  60. package/dist/platforms/bilibili/web/upos.js +102 -0
  61. package/dist/platforms/douyin/index.js +142 -0
  62. package/dist/platforms/douyin/web/api.js +863 -0
  63. package/dist/platforms/douyin/web/client.js +413 -0
  64. package/dist/platforms/douyin/web/commands.js +712 -0
  65. package/dist/platforms/douyin/web/creator.js +601 -0
  66. package/dist/platforms/douyin/web/crypto.js +247 -0
  67. package/dist/platforms/douyin/web/dtrait.js +190 -0
  68. package/dist/platforms/douyin/web/im.js +502 -0
  69. package/dist/platforms/douyin/web/image.js +5 -0
  70. package/dist/platforms/douyin/web/live.js +225 -0
  71. package/dist/platforms/douyin/web/mssdk.js +148 -0
  72. package/dist/platforms/douyin/web/normalize.js +326 -0
  73. package/dist/platforms/douyin/web/passport.js +1247 -0
  74. package/dist/platforms/douyin/web/profile.js +221 -0
  75. package/dist/platforms/douyin/web/proto.js +26 -0
  76. package/dist/platforms/douyin/web/resolve.js +88 -0
  77. package/dist/platforms/douyin/web/sign.js +436 -0
  78. package/dist/platforms/douyin/web/tos.js +78 -0
  79. package/dist/platforms/index.js +17 -0
  80. package/dist/platforms/jd/index.js +67 -0
  81. package/dist/platforms/jd/web/aks.js +115 -0
  82. package/dist/platforms/jd/web/api.js +549 -0
  83. package/dist/platforms/jd/web/chat.js +132 -0
  84. package/dist/platforms/jd/web/client.js +470 -0
  85. package/dist/platforms/jd/web/commands.js +557 -0
  86. package/dist/platforms/jd/web/jcap/helper.js +90 -0
  87. package/dist/platforms/jd/web/jcap/host.js +107 -0
  88. package/dist/platforms/jd/web/jcap/lsd.js +300 -0
  89. package/dist/platforms/jd/web/jcap/solver.js +995 -0
  90. package/dist/platforms/jd/web/jcap.js +150 -0
  91. package/dist/platforms/jd/web/js.js +420 -0
  92. package/dist/platforms/jd/web/login.js +775 -0
  93. package/dist/platforms/jd/web/normalize.js +297 -0
  94. package/dist/platforms/jd/web/profile.js +256 -0
  95. package/dist/platforms/jd/web/util.js +175 -0
  96. package/dist/platforms/jd/web/webm.js +133 -0
  97. package/dist/platforms/kuaishou/index.js +98 -0
  98. package/dist/platforms/kuaishou/web/api.js +694 -0
  99. package/dist/platforms/kuaishou/web/captcha-crypto.js +134 -0
  100. package/dist/platforms/kuaishou/web/captcha-fp.js +180 -0
  101. package/dist/platforms/kuaishou/web/captcha.js +273 -0
  102. package/dist/platforms/kuaishou/web/client.js +487 -0
  103. package/dist/platforms/kuaishou/web/commands.js +863 -0
  104. package/dist/platforms/kuaishou/web/gap.js +144 -0
  105. package/dist/platforms/kuaishou/web/gdfp.js +376 -0
  106. package/dist/platforms/kuaishou/web/gql.js +11 -0
  107. package/dist/platforms/kuaishou/web/live.js +125 -0
  108. package/dist/platforms/kuaishou/web/normalize.js +241 -0
  109. package/dist/platforms/kuaishou/web/oracle.js +329 -0
  110. package/dist/platforms/kuaishou/web/profile.js +259 -0
  111. package/dist/platforms/kuaishou/web/resolve.js +84 -0
  112. package/dist/platforms/kuaishou/web/session.js +592 -0
  113. package/dist/platforms/kuaishou/web/sign.js +568 -0
  114. package/dist/platforms/taobao/index.js +56 -0
  115. package/dist/platforms/taobao/web/api.js +96 -0
  116. package/dist/platforms/taobao/web/client.js +102 -0
  117. package/dist/platforms/taobao/web/commands.js +172 -0
  118. package/dist/platforms/taobao/web/im.js +68 -0
  119. package/dist/platforms/taobao/web/normalize.js +103 -0
  120. package/dist/platforms/taobao/web/profile.js +85 -0
  121. package/dist/platforms/taobao/web/resolve.js +51 -0
  122. package/dist/platforms/taobao/web/sign.js +35 -0
  123. package/dist/platforms/tiktok/index.js +120 -0
  124. package/dist/platforms/tiktok/web/api.js +1234 -0
  125. package/dist/platforms/tiktok/web/client.js +362 -0
  126. package/dist/platforms/tiktok/web/commands.js +821 -0
  127. package/dist/platforms/tiktok/web/im.js +133 -0
  128. package/dist/platforms/tiktok/web/jsrun.js +126 -0
  129. package/dist/platforms/tiktok/web/normalize.js +286 -0
  130. package/dist/platforms/tiktok/web/profile.js +169 -0
  131. package/dist/platforms/tiktok/web/resolve.js +156 -0
  132. package/dist/platforms/tiktok/web/sign.js +585 -0
  133. package/dist/platforms/tiktok/web/upload.js +805 -0
  134. package/dist/platforms/tiktok/web/wire.js +490 -0
  135. package/dist/platforms/weibo/index.js +91 -0
  136. package/dist/platforms/weibo/web/api.js +206 -0
  137. package/dist/platforms/weibo/web/client.js +155 -0
  138. package/dist/platforms/weibo/web/commands.js +202 -0
  139. package/dist/platforms/weibo/web/normalize.js +137 -0
  140. package/dist/platforms/weibo/web/profile.js +246 -0
  141. package/dist/platforms/weibo/web/resolve.js +60 -0
  142. package/dist/platforms/weibo/web/sign.js +85 -0
  143. package/dist/platforms/x/index.js +107 -0
  144. package/dist/platforms/x/web/api.js +443 -0
  145. package/dist/platforms/x/web/article.js +212 -0
  146. package/dist/platforms/x/web/client.js +202 -0
  147. package/dist/platforms/x/web/commands.js +363 -0
  148. package/dist/platforms/x/web/graphql.js +108 -0
  149. package/dist/platforms/x/web/normalize.js +235 -0
  150. package/dist/platforms/x/web/profile.js +99 -0
  151. package/dist/platforms/x/web/resolve.js +44 -0
  152. package/dist/platforms/x/web/transaction.js +171 -0
  153. package/dist/platforms/xhs/index.js +101 -0
  154. package/dist/platforms/xhs/web/api.js +278 -0
  155. package/dist/platforms/xhs/web/client.js +540 -0
  156. package/dist/platforms/xhs/web/commands.js +1046 -0
  157. package/dist/platforms/xhs/web/creator-api.js +609 -0
  158. package/dist/platforms/xhs/web/creator.js +203 -0
  159. package/dist/platforms/xhs/web/js.js +194 -0
  160. package/dist/platforms/xhs/web/login.js +230 -0
  161. package/dist/platforms/xhs/web/normalize.js +166 -0
  162. package/dist/platforms/xhs/web/profile.js +127 -0
  163. package/dist/platforms/xhs/web/push.js +361 -0
  164. package/dist/platforms/xhs/web/resolve.js +69 -0
  165. package/dist/platforms/xhs/web/state.js +368 -0
  166. package/dist/platforms/xianyu/index.js +59 -0
  167. package/dist/platforms/xianyu/web/api.js +312 -0
  168. package/dist/platforms/xianyu/web/client.js +134 -0
  169. package/dist/platforms/xianyu/web/commands.js +305 -0
  170. package/dist/platforms/xianyu/web/im.js +73 -0
  171. package/dist/platforms/xianyu/web/normalize.js +123 -0
  172. package/dist/platforms/xianyu/web/profile.js +146 -0
  173. package/dist/platforms/xianyu/web/resolve.js +48 -0
  174. package/dist/platforms/xianyu/web/sign.js +79 -0
  175. package/package.json +77 -4
  176. package/static/douyin/Live.proto +194 -0
  177. package/static/douyin/Request.proto +89 -0
  178. package/static/douyin/Response.proto +46 -0
  179. package/static/douyin/acrawler_runtime/ac_vm.js +2 -0
  180. package/static/douyin/acrawler_runtime/browser_window_shape.json +1 -0
  181. package/static/douyin/acrawler_runtime/canvas_actual_exact.json +1 -0
  182. package/static/douyin/acrawler_runtime/run_ac_node.js +1005 -0
  183. package/static/douyin/acrawler_runtime/runner_window_keys_baseline.txt +240 -0
  184. package/static/douyin/challenge_profile.json +801 -0
  185. package/static/douyin/challenge_template_runner.js +217 -0
  186. package/static/douyin/dtrait_profile.json +66 -0
  187. package/static/douyin/mstoken_common_profile.json +1 -0
  188. package/static/douyin/mstoken_profile.json +214 -0
  189. package/static/jd/h5st5_env.js +750 -0
  190. package/static/jd/h5st5_lib.js +5 -0
  191. package/static/jd/h5st5_server.js +49 -0
  192. package/static/jd/jcap/env/env_core.js +512 -0
  193. package/static/jd/jcap/env/run.js +1307 -0
  194. package/static/jd/jcap/run/jcap_ujb96b.js +39 -0
  195. package/static/jd/package.json +4 -0
  196. package/static/jd/pc_tk_lib.js +1 -0
  197. package/static/jd/pc_tk_server.js +63 -0
  198. package/static/jd/summer_cryptico_runner.js +50 -0
  199. package/static/jd/webm/env/run.js +453 -0
  200. package/static/jd/webm/run/jdwebm-riskhandle.js +49 -0
  201. package/static/kuaishou/bundles/weapon/kwf-0.0.2.2cee19b4b7dec496.js +1 -0
  202. package/static/kuaishou/bundles/weapon/kws-0-0.0.1-obfuscated.4b7f3de1ab0ddcc2.js +1 -0
  203. package/static/kuaishou/bundles/weapon/kws-1-0.0.1-obfuscated.346ebdb1c78df316.js +1 -0
  204. package/static/kuaishou/bundles/weapon/kws-10-0.0.1-obfuscated.a33db41897b983af.js +1 -0
  205. package/static/kuaishou/bundles/weapon/kws-11-0.0.1-obfuscated.5e0a90af726d8a7e.js +1 -0
  206. package/static/kuaishou/bundles/weapon/kws-12-0.0.1-obfuscated.20ea29345706ec8c.js +1 -0
  207. package/static/kuaishou/bundles/weapon/kws-13-0.0.1-obfuscated.6b74e9640ff18648.js +1 -0
  208. package/static/kuaishou/bundles/weapon/kws-14-0.0.1-obfuscated.551e4429d156bf66.js +1 -0
  209. package/static/kuaishou/bundles/weapon/kws-15-0.0.1-obfuscated.8625b087aaba4a60.js +1 -0
  210. package/static/kuaishou/bundles/weapon/kws-16-0.0.1-obfuscated.d5ffa4020f3be99a.js +1 -0
  211. package/static/kuaishou/bundles/weapon/kws-17-0.0.1-obfuscated.6d13e19b22f50a80.js +1 -0
  212. package/static/kuaishou/bundles/weapon/kws-18-0.0.1-obfuscated.6d31405044166289.js +1 -0
  213. package/static/kuaishou/bundles/weapon/kws-19-0.0.1-obfuscated.a9a8d925942f19e4.js +1 -0
  214. package/static/kuaishou/bundles/weapon/kws-2-0.0.1-obfuscated.b849a136ae4a6b3e.js +1 -0
  215. package/static/kuaishou/bundles/weapon/kws-3-0.0.1-obfuscated.f9e77ebf6186e2ac.js +1 -0
  216. package/static/kuaishou/bundles/weapon/kws-4-0.0.1-obfuscated.2c3c155aa52ceb0e.js +1 -0
  217. package/static/kuaishou/bundles/weapon/kws-5-0.0.1-obfuscated.4e553d17691b3c5a.js +1 -0
  218. package/static/kuaishou/bundles/weapon/kws-6-0.0.1-obfuscated.f73ddd3ff13e1217.js +1 -0
  219. package/static/kuaishou/bundles/weapon/kws-7-0.0.1-obfuscated.1628b8729beaab7e.js +1 -0
  220. package/static/kuaishou/bundles/weapon/kws-8-0.0.1-obfuscated.6da6baef7aa81fff.js +1 -0
  221. package/static/kuaishou/bundles/weapon/kws-9-0.0.1-obfuscated.8645d55e5323b743.js +1 -0
  222. package/static/kuaishou/fixtures/current_follow_script_813.network-response +2 -0
  223. package/static/kuaishou/fixtures/live_ws_maps.json +61 -0
  224. package/static/kuaishou/fixtures/live_ws_proto.json +1342 -0
  225. package/static/kuaishou/js/cp-kwf.js +1 -0
  226. package/static/kuaishou/tools/kwf_oracle.js +799 -0
  227. package/static/kuaishou/tools/kws_oracle.js +885 -0
  228. package/static/kuaishou/tools/like_token_oracle.js +70 -0
  229. package/static/taobao/taobao_js_20260407.js +570 -0
  230. package/static/tiktok/Tiktok_Request.json +597 -0
  231. package/static/tiktok/package.json +3 -0
  232. package/static/tiktok/shop_bsid/core.js +1 -0
  233. package/static/tiktok/shop_bsid/env_core.js +512 -0
  234. package/static/tiktok/shop_bsid/loader.js +1 -0
  235. package/static/tiktok/shop_bsid/run.js +753 -0
  236. package/static/tiktok/shop_bsid/sign.js +100 -0
  237. package/static/tiktok/shop_bsid/webmssdk.js +1 -0
  238. package/static/tiktok/shop_bsid/webmssdk_ex.js +1 -0
  239. package/static/tiktok/signing/env/env_core.js +512 -0
  240. package/static/tiktok/signing/env/sign.js +455 -0
  241. package/static/tiktok/signing/sdk_config.json +230 -0
  242. package/static/tiktok/signing/source/webmssdk.js +1 -0
  243. package/static/tiktok/signing/source/webmssdk_ex.js +1 -0
  244. package/static/tiktok/signing/source/webmssdk_legacy.js +1 -0
  245. package/static/x/graphql.json +7777 -0
  246. package/static/x/transaction_l1.json +12 -0
  247. package/static/xhs/package.json +3 -0
  248. package/static/xhs/xhs_core/js/b1.js +210 -0
  249. package/static/xhs/xhs_core/js/mns.js +340 -0
  250. package/static/xhs/xhs_core/js/mns_0101_keystream.json +5 -0
  251. package/static/xhs/xhs_core/js/mns_keystreams.json +1 -0
  252. package/static/xhs/xhs_core/js/sign.js +225 -0
  253. package/static/xhs/xhs_core/js/websectiga_cli.js +220 -0
  254. package/static/xhs/xhs_core/js/websectiga_env.js +512 -0
  255. package/static/xhs/xhs_core/js/xs_common.js +79 -0
  256. package/static/xhs/xhs_creator/js/profile.js +115 -0
  257. package/static/xhs/xhs_creator/js/rap_fingerprint_creator.json +6 -0
  258. package/static/xhs/xhs_creator/js/reference_profile.json +282 -0
  259. package/static/xhs/xhs_creator/js/xhs_creator_sign.js +29 -0
  260. package/static/xhs/xhs_creator/js/xhs_creator_signature.js +23 -0
  261. package/static/xhs/xhs_pc/js/aes_decrypt.js +22 -0
  262. package/static/xhs/xhs_pc/js/aes_encrypt.js +30 -0
  263. package/static/xhs/xhs_pc/js/b1.js +9 -0
  264. package/static/xhs/xhs_pc/js/deflate.js +320 -0
  265. package/static/xhs/xhs_pc/js/mns.js +4 -0
  266. package/static/xhs/xhs_pc/js/profile.js +141 -0
  267. package/static/xhs/xhs_pc/js/rap.js +173 -0
  268. package/static/xhs/xhs_pc/js/rap_cli.js +30 -0
  269. package/static/xhs/xhs_pc/js/rap_crypto.js +73 -0
  270. package/static/xhs/xhs_pc/js/rap_fingerprint_template.json +8 -0
  271. package/static/xhs/xhs_pc/js/reference_profile.json +262 -0
  272. package/static/xhs/xhs_pc/js/sign.js +6 -0
  273. package/static/xhs/xhs_pc/js/web_ssk.js +82 -0
  274. package/static/xhs/xhs_pc/js/xs_common.js +4 -0
  275. package/static/xianyu/et_f.js +2 -0
  276. package/static/xianyu/gen_tfstk.js +410 -0
  277. package/static/xianyu/goofish_js_version_2.js +568 -0
@@ -0,0 +1,107 @@
1
+ import cp from 'node:child_process';
2
+ import { createRequire } from 'node:module';
3
+ import { dirname, join } from 'node:path';
4
+ /**
5
+ * JCAP 子进程的预加载(node --import),run.js 原样运行,这里只做两处宿主适配:
6
+ *
7
+ * 1. run.js 用 `spawnSync(python, [http_bridge.py | captcha_solver.py, ...])` 起网络桥和图像求解器,
8
+ * 这两种调用换成 `node helper.js bridge|solve ...`,入参出参协议不变。
9
+ * 2. env_core.js 用递归 Proxy 包住 document / navigator 及其返回的对象。上游的 jsdom 25 靠 impl 符号做品牌检查,
10
+ * Proxy 能透传;jsdom 30 用私有字段,Proxy 当 this 或参数时一律报"不是合法实例"。这里记下 env_core 的每个 Proxy
11
+ * 包的目标,jsdom 取 impl 时先换回目标,效果与 jsdom 25 下一致。
12
+ * 3. env_core.init() 把全局的 Buffer / process 藏成 undefined(让 JCAP 看不出 Node);jsdom 30 的依赖
13
+ * (@exodus/bytes 等)解析 URL 时要用 Buffer。藏起来的这两个全局改成访问器:调用方在 node_modules 里时
14
+ * 给真对象,其余(JCAP 包)仍是 undefined。
15
+ */
16
+ const execPath = process.execPath;
17
+ const helper = process.env.SPECIFIC_AI_JD_HELPER ?? '';
18
+ const original = cp.spawnSync;
19
+ cp.spawnSync = function (command, args, options) {
20
+ const list = Array.isArray(args) ? args : [];
21
+ const script = String(list[0] ?? '');
22
+ if (helper && script.endsWith('http_bridge.py'))
23
+ return original.call(cp, execPath, [helper, 'bridge'], options ?? {});
24
+ if (helper && script.endsWith('captcha_solver.py'))
25
+ return original.call(cp, execPath, [helper, 'solve', ...list.slice(1)], options ?? {});
26
+ return original.call(cp, command, args, options);
27
+ };
28
+ const targets = new WeakMap();
29
+ const NativeProxy = Proxy;
30
+ const source = Function.prototype.toString;
31
+ /** 只处理 env_core.createProxy 造的 Proxy(jsdom 自己也用 Proxy,那些不能动)。 */
32
+ const isEnvCoreHandler = (h) => {
33
+ const get = h?.get;
34
+ try {
35
+ return typeof get === 'function' && source.call(get).includes('recordUndefined');
36
+ }
37
+ catch {
38
+ return false;
39
+ }
40
+ };
41
+ globalThis.Proxy = new NativeProxy(NativeProxy, {
42
+ construct(T, args, newTarget) {
43
+ const p = Reflect.construct(T, args, newTarget);
44
+ if (args[0] && (typeof args[0] === 'object' || typeof args[0] === 'function') && isEnvCoreHandler(args[1]))
45
+ targets.set(p, args[0]);
46
+ return p;
47
+ },
48
+ });
49
+ const unwrap = (v) => (v && (typeof v === 'object' || typeof v === 'function') && targets.has(v) ? unwrap(targets.get(v)) : v);
50
+ // jsdom 30 用私有字段做品牌检查(`#impl in wrapper`),Proxy 永远过不了;生成代码经 utils 的这几个函数取 impl。
51
+ // 在 jsdom 加载之前先载入它的 utils 并替换:参数或 this 是 env_core 的 Proxy 时先换成被包的对象。
52
+ {
53
+ const req = createRequire(process.argv[1] ?? import.meta.url);
54
+ const utils = req(join(dirname(req.resolve('jsdom')), 'generated', 'idl', 'utils.js'));
55
+ for (const name of ['implForWrapper', 'implForWrapperWithInterface', 'tryImplForWrapper']) {
56
+ const fn = utils[name];
57
+ utils[name] = (wrapper, ...rest) => fn(unwrap(wrapper), ...rest);
58
+ }
59
+ }
60
+ const nativeLike = (fn, name) => {
61
+ Object.defineProperty(fn, 'name', { value: name });
62
+ Object.defineProperty(fn, 'toString', { value: () => `function ${name}() { [native code] }` });
63
+ return fn;
64
+ };
65
+ const realGlobals = { Buffer: globalThis.Buffer, process: globalThis.process };
66
+ const nativeDefine = Object.defineProperty;
67
+ /** 访问全局的调用方是否在依赖包里(不经 run.js 自定义的 prepareStackTrace)。 */
68
+ function fromDependency(self) {
69
+ const prepare = Error.prepareStackTrace;
70
+ const limit = Error.stackTraceLimit;
71
+ try {
72
+ Error.stackTraceLimit = 2;
73
+ Error.prepareStackTrace = (_e, frames) => frames;
74
+ const holder = {};
75
+ Error.captureStackTrace(holder, self);
76
+ const frames = holder.stack;
77
+ const file = String(frames?.[0]?.getFileName() ?? '');
78
+ return /[\\/]node_modules[\\/]/.test(file) || file.startsWith('node:');
79
+ }
80
+ catch {
81
+ return false;
82
+ }
83
+ finally {
84
+ Error.prepareStackTrace = prepare;
85
+ Error.stackTraceLimit = limit;
86
+ }
87
+ }
88
+ Object.defineProperty = nativeLike(function defineProperty(o, key, d) {
89
+ if (o === globalThis && (key === 'Buffer' || key === 'process') && d && 'value' in d && d.value === undefined) {
90
+ const real = realGlobals[key];
91
+ let override = null;
92
+ const get = function () {
93
+ if (override)
94
+ return override.value;
95
+ return fromDependency(get) ? real : undefined;
96
+ };
97
+ return nativeDefine(o, key, {
98
+ configurable: true,
99
+ enumerable: false,
100
+ get,
101
+ set(value) {
102
+ override = { value };
103
+ },
104
+ });
105
+ }
106
+ return nativeDefine(o, key, d);
107
+ }, 'defineProperty');
@@ -0,0 +1,300 @@
1
+ import { fromMat, toMat, withMats } from '../../../../core/image.js';
2
+ /**
3
+ * OpenCV 5.0 的 LineSegmentDetector(modules/imgproc/src/lsd.cpp,LSD_REFINE_STD,默认参数)移植。
4
+ * opencv-js 没有编译进 LSD;这里逐行照搬,C++ 里的 float 运算用 Math.fround 模拟。
5
+ * 返回 float32 的线段 (x1, y1, x2, y2)。
6
+ */
7
+ const f = Math.fround;
8
+ const PI = Math.PI;
9
+ const M_3_2_PI = (3 * PI) / 2;
10
+ const M_2__PI = 2 * PI;
11
+ const NOTDEF = -1024.0;
12
+ const DEG_TO_RADS = PI / 180;
13
+ const P1 = f(f(0.9997878412794807) * f(180 / PI));
14
+ const P3 = f(f(-0.3258083974640975) * f(180 / PI));
15
+ const P5 = f(f(0.1555786518463281) * f(180 / PI));
16
+ const P7 = f(f(-0.04432655554792128) * f(180 / PI));
17
+ const EPS = f(2.220446049250313e-16);
18
+ /** cv::fastAtan2(桌面版多项式近似,单位度)。 */
19
+ export function fastAtan2(y, x) {
20
+ y = f(y);
21
+ x = f(x);
22
+ const ax = Math.abs(x);
23
+ const ay = Math.abs(y);
24
+ const poly = (c) => {
25
+ const c2 = f(c * c);
26
+ let t = f(P7 * c2);
27
+ t = f(t + P5);
28
+ t = f(t * c2);
29
+ t = f(t + P3);
30
+ t = f(t * c2);
31
+ t = f(t + P1);
32
+ return f(t * c);
33
+ };
34
+ let a;
35
+ if (ax >= ay)
36
+ a = poly(f(ay / f(ax + EPS)));
37
+ else
38
+ a = f(90 - poly(f(ax / f(ay + EPS))));
39
+ if (x < 0)
40
+ a = f(180 - a);
41
+ if (y < 0)
42
+ a = f(360 - a);
43
+ return a;
44
+ }
45
+ function angleDiffSigned(a, b) {
46
+ let diff = a - b;
47
+ while (diff <= -PI)
48
+ diff += M_2__PI;
49
+ while (diff > PI)
50
+ diff -= M_2__PI;
51
+ return diff;
52
+ }
53
+ const angleDiff = (a, b) => Math.abs(angleDiffSigned(a, b));
54
+ const distSq = (x1, y1, x2, y2) => (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
55
+ const dist = (x1, y1, x2, y2) => Math.sqrt(distSq(x1, y1, x2, y2));
56
+ function doubleEqual(a, b) {
57
+ if (a === b)
58
+ return true;
59
+ const absDiff = Math.abs(a - b);
60
+ let absMax = Math.max(Math.abs(a), Math.abs(b));
61
+ if (absMax < 2.2250738585072014e-308)
62
+ absMax = 2.2250738585072014e-308;
63
+ return absDiff / absMax <= 100.0 * 2.220446049250313e-16;
64
+ }
65
+ /** cv2.createLineSegmentDetector(cv2.LSD_REFINE_STD).detect(gray)[0]。gray 是 8 位单通道。 */
66
+ export function detectLines(cv, gray) {
67
+ const SCALE = 0.8;
68
+ const SIGMA_SCALE = 0.6;
69
+ const QUANT = 2.0;
70
+ const ANG_TH = 22.5;
71
+ const DENSITY_TH = 0.7;
72
+ const N_BINS = 1024;
73
+ const prec = (PI * ANG_TH) / 180;
74
+ const p = ANG_TH / 180;
75
+ const rho = QUANT / Math.sin(prec);
76
+ // GaussianBlur + resize(INTER_LINEAR_EXACT)
77
+ const scaled = withMats((keep) => {
78
+ const src = keep(toMat(cv, gray));
79
+ const blurred = keep(new cv.Mat());
80
+ const sigma = SIGMA_SCALE / SCALE;
81
+ const h = Math.ceil(sigma * Math.sqrt(2 * 3 * Math.log(10.0))) >>> 0;
82
+ cv.GaussianBlur(src, blurred, new cv.Size(1 + 2 * h, 1 + 2 * h), sigma);
83
+ const out = keep(new cv.Mat());
84
+ cv.resize(blurred, out, new cv.Size(0, 0), SCALE, SCALE, cv.INTER_LINEAR_EXACT);
85
+ return fromMat(cv, out);
86
+ });
87
+ const W = scaled.width;
88
+ const H = scaled.height;
89
+ const px = scaled.data;
90
+ const angles = new Float64Array(W * H);
91
+ const modgrad = new Float64Array(W * H);
92
+ for (let x = 0; x < W; x++)
93
+ angles[(H - 1) * W + x] = NOTDEF;
94
+ for (let y = 0; y < H; y++)
95
+ angles[y * W + W - 1] = NOTDEF;
96
+ // ll_angle
97
+ let maxGrad = -1;
98
+ for (let y = 0; y < H - 1; y++) {
99
+ for (let x = 0; x < W - 1; x++) {
100
+ const DA = px[(y + 1) * W + x + 1] - px[y * W + x];
101
+ const BC = px[y * W + x + 1] - px[(y + 1) * W + x];
102
+ const gx = DA + BC;
103
+ const gy = DA - BC;
104
+ const norm = Math.sqrt((gx * gx + gy * gy) / 4.0);
105
+ modgrad[y * W + x] = norm;
106
+ if (norm <= rho)
107
+ angles[y * W + x] = NOTDEF;
108
+ else {
109
+ angles[y * W + x] = fastAtan2(gx, -gy) * DEG_TO_RADS;
110
+ if (norm > maxGrad)
111
+ maxGrad = norm;
112
+ }
113
+ }
114
+ }
115
+ const binCoef = maxGrad > 0 ? (N_BINS - 1) / maxGrad : 0;
116
+ const ordered = [];
117
+ for (let y = 0; y < H - 1; y++)
118
+ for (let x = 0; x < W - 1; x++)
119
+ ordered.push({ x, y, norm: Math.trunc(modgrad[y * W + x] * binCoef) });
120
+ ordered.sort((a, b) => b.norm - a.norm);
121
+ const LOG_NT = (5 * (Math.log10(W) + Math.log10(H))) / 2 + Math.log10(11.0);
122
+ const minRegSize = Math.trunc(-LOG_NT / Math.log10(p));
123
+ const used = new Uint8Array(W * H);
124
+ const isAligned = (x, y, theta, pr) => {
125
+ if (x < 0 || y < 0 || x >= W || y >= H)
126
+ return false;
127
+ const a = angles[y * W + x];
128
+ if (a === NOTDEF)
129
+ return false;
130
+ let n = theta - a;
131
+ if (n < 0)
132
+ n = -n;
133
+ if (n > M_3_2_PI) {
134
+ n -= M_2__PI;
135
+ if (n < 0)
136
+ n = -n;
137
+ }
138
+ return n <= pr;
139
+ };
140
+ const regionGrow = (sx, sy, reg, pr) => {
141
+ reg.length = 0;
142
+ let regAngle = angles[sy * W + sx];
143
+ reg.push({ x: sx, y: sy, angle: regAngle, modgrad: modgrad[sy * W + sx] });
144
+ let sumdx = f(Math.cos(regAngle));
145
+ let sumdy = f(Math.sin(regAngle));
146
+ used[sy * W + sx] = 1;
147
+ for (let i = 0; i < reg.length; i++) {
148
+ const r = reg[i];
149
+ const xxMin = Math.max(r.x - 1, 0);
150
+ const xxMax = Math.min(r.x + 1, W - 1);
151
+ const yyMin = Math.max(r.y - 1, 0);
152
+ const yyMax = Math.min(r.y + 1, H - 1);
153
+ for (let yy = yyMin; yy <= yyMax; yy++) {
154
+ for (let xx = xxMin; xx <= xxMax; xx++) {
155
+ const k = yy * W + xx;
156
+ if (used[k] !== 1 && isAligned(xx, yy, regAngle, pr)) {
157
+ const angle = angles[k];
158
+ used[k] = 1;
159
+ reg.push({ x: xx, y: yy, angle, modgrad: modgrad[k] });
160
+ sumdx = f(sumdx + f(Math.cos(f(angle))));
161
+ sumdy = f(sumdy + f(Math.sin(f(angle))));
162
+ regAngle = fastAtan2(sumdy, sumdx) * DEG_TO_RADS;
163
+ }
164
+ }
165
+ }
166
+ }
167
+ return regAngle;
168
+ };
169
+ const getTheta = (reg, x, y, regAngle, pr) => {
170
+ let Ixx = 0;
171
+ let Iyy = 0;
172
+ let Ixy = 0;
173
+ for (const r of reg) {
174
+ const dx = r.x - x;
175
+ const dy = r.y - y;
176
+ Ixx += dy * dy * r.modgrad;
177
+ Iyy += dx * dx * r.modgrad;
178
+ Ixy -= dx * dy * r.modgrad;
179
+ }
180
+ if (doubleEqual(Ixx, 0) && doubleEqual(Iyy, 0) && doubleEqual(Ixy, 0))
181
+ throw new Error('LSD: 惯性矩阵为零');
182
+ const lambda = 0.5 * (Ixx + Iyy - Math.sqrt((Ixx - Iyy) * (Ixx - Iyy) + 4.0 * Ixy * Ixy));
183
+ let theta = Math.abs(Ixx) > Math.abs(Iyy) ? fastAtan2(lambda - Ixx, Ixy) : fastAtan2(Ixy, lambda - Iyy);
184
+ theta *= DEG_TO_RADS;
185
+ if (angleDiff(theta, regAngle) > pr)
186
+ theta += PI;
187
+ return theta;
188
+ };
189
+ const region2rect = (reg, regAngle, pr, pp) => {
190
+ let x = 0;
191
+ let y = 0;
192
+ let sum = 0;
193
+ for (const r of reg) {
194
+ x += r.x * r.modgrad;
195
+ y += r.y * r.modgrad;
196
+ sum += r.modgrad;
197
+ }
198
+ if (!(sum > 0))
199
+ throw new Error('LSD: 权重和为零');
200
+ x /= sum;
201
+ y /= sum;
202
+ const theta = getTheta(reg, x, y, regAngle, pr);
203
+ const dx = Math.cos(theta);
204
+ const dy = Math.sin(theta);
205
+ let lMin = 0;
206
+ let lMax = 0;
207
+ let wMin = 0;
208
+ let wMax = 0;
209
+ for (const r of reg) {
210
+ const rdx = r.x - x;
211
+ const rdy = r.y - y;
212
+ const l = rdx * dx + rdy * dy;
213
+ const w = -rdx * dy + rdy * dx;
214
+ if (l > lMax)
215
+ lMax = l;
216
+ else if (l < lMin)
217
+ lMin = l;
218
+ if (w > wMax)
219
+ wMax = w;
220
+ else if (w < wMin)
221
+ wMin = w;
222
+ }
223
+ const rec = { x1: x + lMin * dx, y1: y + lMin * dy, x2: x + lMax * dx, y2: y + lMax * dy, width: wMax - wMin, x, y, theta, dx, dy, prec: pr, p: pp };
224
+ if (rec.width < 1.0)
225
+ rec.width = 1.0;
226
+ return rec;
227
+ };
228
+ const reduceRegionRadius = (reg, regAngle, pr, pp, rec, density) => {
229
+ const xc = reg[0].x;
230
+ const yc = reg[0].y;
231
+ const r1 = distSq(xc, yc, rec.x1, rec.y1);
232
+ const r2 = distSq(xc, yc, rec.x2, rec.y2);
233
+ let radSq = r1 > r2 ? r1 : r2;
234
+ while (density < DENSITY_TH) {
235
+ radSq *= 0.75 * 0.75;
236
+ for (let i = 0; i < reg.length; i++) {
237
+ if (distSq(xc, yc, reg[i].x, reg[i].y) > radSq) {
238
+ used[reg[i].y * W + reg[i].x] = 0;
239
+ const last = reg.length - 1;
240
+ [reg[i], reg[last]] = [reg[last], reg[i]];
241
+ reg.pop();
242
+ i--;
243
+ }
244
+ }
245
+ if (reg.length < 2)
246
+ return null;
247
+ rec = region2rect(reg, regAngle, pr, pp);
248
+ density = reg.length / (dist(rec.x1, rec.y1, rec.x2, rec.y2) * rec.width);
249
+ }
250
+ return rec;
251
+ };
252
+ const refine = (reg, regAngle, pr, pp, rec) => {
253
+ let density = reg.length / (dist(rec.x1, rec.y1, rec.x2, rec.y2) * rec.width);
254
+ if (density >= DENSITY_TH)
255
+ return rec;
256
+ const xc = reg[0].x;
257
+ const yc = reg[0].y;
258
+ const angC = reg[0].angle;
259
+ let sum = 0;
260
+ let sSum = 0;
261
+ let n = 0;
262
+ for (const r of reg) {
263
+ used[r.y * W + r.x] = 0;
264
+ if (dist(xc, yc, r.x, r.y) < rec.width) {
265
+ const d = angleDiffSigned(r.angle, angC);
266
+ sum += d;
267
+ sSum += d * d;
268
+ n++;
269
+ }
270
+ }
271
+ if (n <= 0)
272
+ throw new Error('LSD: refine 没有点');
273
+ const mean = sum / n;
274
+ const tau = 2.0 * Math.sqrt((sSum - 2.0 * mean * sum) / n + mean * mean);
275
+ regAngle = regionGrow(xc, yc, reg, tau);
276
+ if (reg.length < 2)
277
+ return null;
278
+ rec = region2rect(reg, regAngle, pr, pp);
279
+ density = reg.length / (dist(rec.x1, rec.y1, rec.x2, rec.y2) * rec.width);
280
+ if (density < DENSITY_TH)
281
+ return reduceRegionRadius(reg, regAngle, pr, pp, rec, density);
282
+ return rec;
283
+ };
284
+ const lines = [];
285
+ const reg = [];
286
+ for (const pt of ordered) {
287
+ const k = pt.y * W + pt.x;
288
+ if (used[k] !== 0 || angles[k] === NOTDEF)
289
+ continue;
290
+ const regAngle = regionGrow(pt.x, pt.y, reg, prec);
291
+ if (reg.length < minRegSize)
292
+ continue;
293
+ let rec = region2rect(reg, regAngle, prec, p);
294
+ rec = refine(reg, regAngle, prec, p, rec);
295
+ if (!rec)
296
+ continue;
297
+ lines.push([f((rec.x1 + 0.5) / SCALE), f((rec.y1 + 0.5) / SCALE), f((rec.x2 + 0.5) / SCALE), f((rec.y2 + 0.5) / SCALE)]);
298
+ }
299
+ return lines;
300
+ }