node-av-lgpl 0.0.0 → 7.1.0-beta.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 (311) hide show
  1. package/LICENSE.md +22 -0
  2. package/README.md +711 -0
  3. package/dist/api/audio-frame-buffer.d.ts +636 -0
  4. package/dist/api/audio-frame-buffer.js +1027 -0
  5. package/dist/api/audio-frame-buffer.js.map +1 -0
  6. package/dist/api/bitstream-filter.d.ts +938 -0
  7. package/dist/api/bitstream-filter.js +1427 -0
  8. package/dist/api/bitstream-filter.js.map +1 -0
  9. package/dist/api/constants.d.ts +44 -0
  10. package/dist/api/constants.js +45 -0
  11. package/dist/api/constants.js.map +1 -0
  12. package/dist/api/data/test_av1.ivf +0 -0
  13. package/dist/api/data/test_h264.h264 +0 -0
  14. package/dist/api/data/test_hevc.h265 +0 -0
  15. package/dist/api/data/test_mjpeg.mjpeg +0 -0
  16. package/dist/api/data/test_vp8.ivf +0 -0
  17. package/dist/api/data/test_vp9.ivf +0 -0
  18. package/dist/api/decoder.d.ts +1413 -0
  19. package/dist/api/decoder.js +2367 -0
  20. package/dist/api/decoder.js.map +1 -0
  21. package/dist/api/demuxer.d.ts +1295 -0
  22. package/dist/api/demuxer.js +2344 -0
  23. package/dist/api/demuxer.js.map +1 -0
  24. package/dist/api/device.d.ts +589 -0
  25. package/dist/api/device.js +964 -0
  26. package/dist/api/device.js.map +1 -0
  27. package/dist/api/encoder-pool.d.ts +262 -0
  28. package/dist/api/encoder-pool.js +397 -0
  29. package/dist/api/encoder-pool.js.map +1 -0
  30. package/dist/api/encoder.d.ts +1509 -0
  31. package/dist/api/encoder.js +2619 -0
  32. package/dist/api/encoder.js.map +1 -0
  33. package/dist/api/filter-complex.d.ts +828 -0
  34. package/dist/api/filter-complex.js +1661 -0
  35. package/dist/api/filter-complex.js.map +1 -0
  36. package/dist/api/filter-presets.d.ts +800 -0
  37. package/dist/api/filter-presets.js +1554 -0
  38. package/dist/api/filter-presets.js.map +1 -0
  39. package/dist/api/filter.d.ts +1339 -0
  40. package/dist/api/filter.js +2075 -0
  41. package/dist/api/filter.js.map +1 -0
  42. package/dist/api/fmp4-stream.d.ts +797 -0
  43. package/dist/api/fmp4-stream.js +1428 -0
  44. package/dist/api/fmp4-stream.js.map +1 -0
  45. package/dist/api/hardware.d.ts +677 -0
  46. package/dist/api/hardware.js +1300 -0
  47. package/dist/api/hardware.js.map +1 -0
  48. package/dist/api/index.d.ts +21 -0
  49. package/dist/api/index.js +38 -0
  50. package/dist/api/index.js.map +1 -0
  51. package/dist/api/io-stream.d.ts +308 -0
  52. package/dist/api/io-stream.js +358 -0
  53. package/dist/api/io-stream.js.map +1 -0
  54. package/dist/api/muxer.d.ts +1311 -0
  55. package/dist/api/muxer.js +2672 -0
  56. package/dist/api/muxer.js.map +1 -0
  57. package/dist/api/pipeline.d.ts +801 -0
  58. package/dist/api/pipeline.js +1344 -0
  59. package/dist/api/pipeline.js.map +1 -0
  60. package/dist/api/probe.d.ts +128 -0
  61. package/dist/api/probe.js +227 -0
  62. package/dist/api/probe.js.map +1 -0
  63. package/dist/api/rtp-stream.d.ts +497 -0
  64. package/dist/api/rtp-stream.js +1131 -0
  65. package/dist/api/rtp-stream.js.map +1 -0
  66. package/dist/api/scaler.d.ts +561 -0
  67. package/dist/api/scaler.js +918 -0
  68. package/dist/api/scaler.js.map +1 -0
  69. package/dist/api/types.d.ts +17 -0
  70. package/dist/api/types.js +2 -0
  71. package/dist/api/types.js.map +1 -0
  72. package/dist/api/utilities/async-queue.d.ts +149 -0
  73. package/dist/api/utilities/async-queue.js +254 -0
  74. package/dist/api/utilities/async-queue.js.map +1 -0
  75. package/dist/api/utilities/audio-sample.d.ts +117 -0
  76. package/dist/api/utilities/audio-sample.js +112 -0
  77. package/dist/api/utilities/audio-sample.js.map +1 -0
  78. package/dist/api/utilities/audio-transcode.d.ts +20 -0
  79. package/dist/api/utilities/audio-transcode.js +27 -0
  80. package/dist/api/utilities/audio-transcode.js.map +1 -0
  81. package/dist/api/utilities/channel-layout.d.ts +76 -0
  82. package/dist/api/utilities/channel-layout.js +80 -0
  83. package/dist/api/utilities/channel-layout.js.map +1 -0
  84. package/dist/api/utilities/codec-format.d.ts +87 -0
  85. package/dist/api/utilities/codec-format.js +117 -0
  86. package/dist/api/utilities/codec-format.js.map +1 -0
  87. package/dist/api/utilities/context-options.d.ts +25 -0
  88. package/dist/api/utilities/context-options.js +23 -0
  89. package/dist/api/utilities/context-options.js.map +1 -0
  90. package/dist/api/utilities/electron-shared-texture.d.ts +368 -0
  91. package/dist/api/utilities/electron-shared-texture.js +540 -0
  92. package/dist/api/utilities/electron-shared-texture.js.map +1 -0
  93. package/dist/api/utilities/image.d.ts +207 -0
  94. package/dist/api/utilities/image.js +213 -0
  95. package/dist/api/utilities/image.js.map +1 -0
  96. package/dist/api/utilities/index.d.ts +14 -0
  97. package/dist/api/utilities/index.js +27 -0
  98. package/dist/api/utilities/index.js.map +1 -0
  99. package/dist/api/utilities/live-decoding.d.ts +15 -0
  100. package/dist/api/utilities/live-decoding.js +32 -0
  101. package/dist/api/utilities/live-decoding.js.map +1 -0
  102. package/dist/api/utilities/media-type.d.ts +49 -0
  103. package/dist/api/utilities/media-type.js +53 -0
  104. package/dist/api/utilities/media-type.js.map +1 -0
  105. package/dist/api/utilities/packet-age-watchdog.d.ts +198 -0
  106. package/dist/api/utilities/packet-age-watchdog.js +594 -0
  107. package/dist/api/utilities/packet-age-watchdog.js.map +1 -0
  108. package/dist/api/utilities/pixel-format.d.ts +89 -0
  109. package/dist/api/utilities/pixel-format.js +97 -0
  110. package/dist/api/utilities/pixel-format.js.map +1 -0
  111. package/dist/api/utilities/sample-format.d.ts +129 -0
  112. package/dist/api/utilities/sample-format.js +141 -0
  113. package/dist/api/utilities/sample-format.js.map +1 -0
  114. package/dist/api/utilities/scale-size.d.ts +51 -0
  115. package/dist/api/utilities/scale-size.js +55 -0
  116. package/dist/api/utilities/scale-size.js.map +1 -0
  117. package/dist/api/utilities/scheduler.d.ts +138 -0
  118. package/dist/api/utilities/scheduler.js +98 -0
  119. package/dist/api/utilities/scheduler.js.map +1 -0
  120. package/dist/api/utilities/streaming.d.ts +186 -0
  121. package/dist/api/utilities/streaming.js +309 -0
  122. package/dist/api/utilities/streaming.js.map +1 -0
  123. package/dist/api/utilities/timestamp.d.ts +193 -0
  124. package/dist/api/utilities/timestamp.js +206 -0
  125. package/dist/api/utilities/timestamp.js.map +1 -0
  126. package/dist/api/utilities/video-transcode.d.ts +218 -0
  127. package/dist/api/utilities/video-transcode.js +624 -0
  128. package/dist/api/utilities/video-transcode.js.map +1 -0
  129. package/dist/api/utilities/whisper-model.d.ts +330 -0
  130. package/dist/api/utilities/whisper-model.js +587 -0
  131. package/dist/api/utilities/whisper-model.js.map +1 -0
  132. package/dist/api/utils.d.ts +19 -0
  133. package/dist/api/utils.js +39 -0
  134. package/dist/api/utils.js.map +1 -0
  135. package/dist/api/webrtc-stream.d.ts +294 -0
  136. package/dist/api/webrtc-stream.js +546 -0
  137. package/dist/api/webrtc-stream.js.map +1 -0
  138. package/dist/api/whisper.d.ts +326 -0
  139. package/dist/api/whisper.js +402 -0
  140. package/dist/api/whisper.js.map +1 -0
  141. package/dist/constants/bsf-options.d.ts +364 -0
  142. package/dist/constants/bsf-options.js +7 -0
  143. package/dist/constants/bsf-options.js.map +1 -0
  144. package/dist/constants/channel-layouts.d.ts +53 -0
  145. package/dist/constants/channel-layouts.js +57 -0
  146. package/dist/constants/channel-layouts.js.map +1 -0
  147. package/dist/constants/constants.d.ts +2435 -0
  148. package/dist/constants/constants.js +1989 -0
  149. package/dist/constants/constants.js.map +1 -0
  150. package/dist/constants/decoders.d.ts +651 -0
  151. package/dist/constants/decoders.js +641 -0
  152. package/dist/constants/decoders.js.map +1 -0
  153. package/dist/constants/encoders.d.ts +314 -0
  154. package/dist/constants/encoders.js +309 -0
  155. package/dist/constants/encoders.js.map +1 -0
  156. package/dist/constants/filter-options.d.ts +12099 -0
  157. package/dist/constants/filter-options.js +7 -0
  158. package/dist/constants/filter-options.js.map +1 -0
  159. package/dist/constants/format-options.d.ts +4319 -0
  160. package/dist/constants/format-options.js +7 -0
  161. package/dist/constants/format-options.js.map +1 -0
  162. package/dist/constants/formats.d.ts +18 -0
  163. package/dist/constants/formats.js +7 -0
  164. package/dist/constants/formats.js.map +1 -0
  165. package/dist/constants/hardware.d.ts +26 -0
  166. package/dist/constants/hardware.js +27 -0
  167. package/dist/constants/hardware.js.map +1 -0
  168. package/dist/constants/index.d.ts +10 -0
  169. package/dist/constants/index.js +6 -0
  170. package/dist/constants/index.js.map +1 -0
  171. package/dist/constants/options.d.ts +6217 -0
  172. package/dist/constants/options.js +7 -0
  173. package/dist/constants/options.js.map +1 -0
  174. package/dist/ffmpeg/index.d.ts +101 -0
  175. package/dist/ffmpeg/index.js +161 -0
  176. package/dist/ffmpeg/index.js.map +1 -0
  177. package/dist/ffmpeg/version.d.ts +6 -0
  178. package/dist/ffmpeg/version.js +7 -0
  179. package/dist/ffmpeg/version.js.map +1 -0
  180. package/dist/index.d.ts +4 -0
  181. package/dist/index.js +9 -0
  182. package/dist/index.js.map +1 -0
  183. package/dist/lib/audio-fifo.d.ts +399 -0
  184. package/dist/lib/audio-fifo.js +431 -0
  185. package/dist/lib/audio-fifo.js.map +1 -0
  186. package/dist/lib/binding.d.ts +242 -0
  187. package/dist/lib/binding.js +102 -0
  188. package/dist/lib/binding.js.map +1 -0
  189. package/dist/lib/bitstream-filter-context.d.ts +381 -0
  190. package/dist/lib/bitstream-filter-context.js +443 -0
  191. package/dist/lib/bitstream-filter-context.js.map +1 -0
  192. package/dist/lib/bitstream-filter.d.ts +140 -0
  193. package/dist/lib/bitstream-filter.js +154 -0
  194. package/dist/lib/bitstream-filter.js.map +1 -0
  195. package/dist/lib/codec-context.d.ts +1069 -0
  196. package/dist/lib/codec-context.js +1336 -0
  197. package/dist/lib/codec-context.js.map +1 -0
  198. package/dist/lib/codec-parameters.d.ts +664 -0
  199. package/dist/lib/codec-parameters.js +813 -0
  200. package/dist/lib/codec-parameters.js.map +1 -0
  201. package/dist/lib/codec-parser.d.ts +201 -0
  202. package/dist/lib/codec-parser.js +213 -0
  203. package/dist/lib/codec-parser.js.map +1 -0
  204. package/dist/lib/codec.d.ts +617 -0
  205. package/dist/lib/codec.js +746 -0
  206. package/dist/lib/codec.js.map +1 -0
  207. package/dist/lib/device.d.ts +294 -0
  208. package/dist/lib/device.js +326 -0
  209. package/dist/lib/device.js.map +1 -0
  210. package/dist/lib/dictionary.d.ts +333 -0
  211. package/dist/lib/dictionary.js +372 -0
  212. package/dist/lib/dictionary.js.map +1 -0
  213. package/dist/lib/error.d.ts +311 -0
  214. package/dist/lib/error.js +395 -0
  215. package/dist/lib/error.js.map +1 -0
  216. package/dist/lib/fifo.d.ts +416 -0
  217. package/dist/lib/fifo.js +453 -0
  218. package/dist/lib/fifo.js.map +1 -0
  219. package/dist/lib/filter-context.d.ts +714 -0
  220. package/dist/lib/filter-context.js +783 -0
  221. package/dist/lib/filter-context.js.map +1 -0
  222. package/dist/lib/filter-graph-segment.d.ts +161 -0
  223. package/dist/lib/filter-graph-segment.js +172 -0
  224. package/dist/lib/filter-graph-segment.js.map +1 -0
  225. package/dist/lib/filter-graph.d.ts +641 -0
  226. package/dist/lib/filter-graph.js +704 -0
  227. package/dist/lib/filter-graph.js.map +1 -0
  228. package/dist/lib/filter-inout.d.ts +202 -0
  229. package/dist/lib/filter-inout.js +261 -0
  230. package/dist/lib/filter-inout.js.map +1 -0
  231. package/dist/lib/filter.d.ts +243 -0
  232. package/dist/lib/filter.js +272 -0
  233. package/dist/lib/filter.js.map +1 -0
  234. package/dist/lib/format-context.d.ts +1335 -0
  235. package/dist/lib/format-context.js +1455 -0
  236. package/dist/lib/format-context.js.map +1 -0
  237. package/dist/lib/frame-utils.d.ts +116 -0
  238. package/dist/lib/frame-utils.js +98 -0
  239. package/dist/lib/frame-utils.js.map +1 -0
  240. package/dist/lib/frame.d.ts +1315 -0
  241. package/dist/lib/frame.js +1535 -0
  242. package/dist/lib/frame.js.map +1 -0
  243. package/dist/lib/hardware-device-context.d.ts +362 -0
  244. package/dist/lib/hardware-device-context.js +383 -0
  245. package/dist/lib/hardware-device-context.js.map +1 -0
  246. package/dist/lib/hardware-frames-context.d.ts +418 -0
  247. package/dist/lib/hardware-frames-context.js +471 -0
  248. package/dist/lib/hardware-frames-context.js.map +1 -0
  249. package/dist/lib/index.d.ts +35 -0
  250. package/dist/lib/index.js +60 -0
  251. package/dist/lib/index.js.map +1 -0
  252. package/dist/lib/input-format.d.ts +249 -0
  253. package/dist/lib/input-format.js +306 -0
  254. package/dist/lib/input-format.js.map +1 -0
  255. package/dist/lib/io-context.d.ts +698 -0
  256. package/dist/lib/io-context.js +771 -0
  257. package/dist/lib/io-context.js.map +1 -0
  258. package/dist/lib/log.d.ts +174 -0
  259. package/dist/lib/log.js +184 -0
  260. package/dist/lib/log.js.map +1 -0
  261. package/dist/lib/native-types.d.ts +1024 -0
  262. package/dist/lib/native-types.js +2 -0
  263. package/dist/lib/native-types.js.map +1 -0
  264. package/dist/lib/option.d.ts +953 -0
  265. package/dist/lib/option.js +1607 -0
  266. package/dist/lib/option.js.map +1 -0
  267. package/dist/lib/output-format.d.ts +222 -0
  268. package/dist/lib/output-format.js +259 -0
  269. package/dist/lib/output-format.js.map +1 -0
  270. package/dist/lib/packet.d.ts +521 -0
  271. package/dist/lib/packet.js +613 -0
  272. package/dist/lib/packet.js.map +1 -0
  273. package/dist/lib/rational.d.ts +251 -0
  274. package/dist/lib/rational.js +278 -0
  275. package/dist/lib/rational.js.map +1 -0
  276. package/dist/lib/software-resample-context.d.ts +552 -0
  277. package/dist/lib/software-resample-context.js +592 -0
  278. package/dist/lib/software-resample-context.js.map +1 -0
  279. package/dist/lib/software-scale-context.d.ts +344 -0
  280. package/dist/lib/software-scale-context.js +366 -0
  281. package/dist/lib/software-scale-context.js.map +1 -0
  282. package/dist/lib/stream.d.ts +383 -0
  283. package/dist/lib/stream.js +524 -0
  284. package/dist/lib/stream.js.map +1 -0
  285. package/dist/lib/sync-queue.d.ts +179 -0
  286. package/dist/lib/sync-queue.js +197 -0
  287. package/dist/lib/sync-queue.js.map +1 -0
  288. package/dist/lib/types.d.ts +34 -0
  289. package/dist/lib/types.js +2 -0
  290. package/dist/lib/types.js.map +1 -0
  291. package/dist/lib/utilities.d.ts +1198 -0
  292. package/dist/lib/utilities.js +1302 -0
  293. package/dist/lib/utilities.js.map +1 -0
  294. package/dist/utils/electron.d.ts +49 -0
  295. package/dist/utils/electron.js +63 -0
  296. package/dist/utils/electron.js.map +1 -0
  297. package/dist/utils/index.d.ts +6 -0
  298. package/dist/utils/index.js +7 -0
  299. package/dist/utils/index.js.map +1 -0
  300. package/dist/utils/libc.d.ts +11 -0
  301. package/dist/utils/libc.js +35 -0
  302. package/dist/utils/libc.js.map +1 -0
  303. package/dist/utils/variant.d.ts +26 -0
  304. package/dist/utils/variant.js +31 -0
  305. package/dist/utils/variant.js.map +1 -0
  306. package/dist/webrtc/index.d.ts +4 -0
  307. package/dist/webrtc/index.js +7 -0
  308. package/dist/webrtc/index.js.map +1 -0
  309. package/install/check.js +124 -0
  310. package/install/ffmpeg.js +66 -0
  311. package/package.json +165 -3
@@ -0,0 +1,587 @@
1
+ import { createWriteStream, existsSync } from 'node:fs';
2
+ import { access, constants, mkdir, rename, unlink } from 'node:fs/promises';
3
+ import { Agent, get } from 'node:https';
4
+ import { dirname, resolve } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = dirname(__filename);
8
+ /**
9
+ * Download error carrying the HTTP status (and a numeric Retry-After, when sent)
10
+ * so the retry logic can tell transient failures from permanent ones.
11
+ *
12
+ * @internal
13
+ */
14
+ class DownloadHttpError extends Error {
15
+ statusCode;
16
+ retryAfterSeconds;
17
+ constructor(message, statusCode, retryAfterSeconds) {
18
+ super(message);
19
+ this.statusCode = statusCode;
20
+ this.retryAfterSeconds = retryAfterSeconds;
21
+ }
22
+ }
23
+ /**
24
+ * Standard GGML Whisper models
25
+ */
26
+ export const WHISPER_MODELS = [
27
+ 'tiny',
28
+ 'tiny.en',
29
+ 'tiny-q5_1',
30
+ 'tiny.en-q5_1',
31
+ 'tiny-q8_0',
32
+ 'base',
33
+ 'base.en',
34
+ 'base-q5_1',
35
+ 'base.en-q5_1',
36
+ 'base-q8_0',
37
+ 'small',
38
+ 'small.en',
39
+ 'small.en-tdrz',
40
+ 'small-q5_1',
41
+ 'small.en-q5_1',
42
+ 'small-q8_0',
43
+ 'medium',
44
+ 'medium.en',
45
+ 'medium-q5_0',
46
+ 'medium.en-q5_0',
47
+ 'medium-q8_0',
48
+ 'large-v1',
49
+ 'large-v2',
50
+ 'large-v2-q5_0',
51
+ 'large-v2-q8_0',
52
+ 'large-v3',
53
+ 'large-v3-q5_0',
54
+ 'large-v3-turbo',
55
+ 'large-v3-turbo-q5_0',
56
+ 'large-v3-turbo-q8_0',
57
+ ];
58
+ /**
59
+ * Whisper VAD (Voice Activity Detection) models
60
+ */
61
+ export const WHISPER_VAD_MODELS = ['silero-v5.1.2', 'silero-v6.2.0'];
62
+ /**
63
+ * Whisper.cpp model downloader utilities.
64
+ *
65
+ * Provides static methods for downloading GGML and VAD models from HuggingFace,
66
+ * validating model names, and checking model availability. Supports automatic
67
+ * model type detection and prevents concurrent downloads of the same model.
68
+ *
69
+ * @example
70
+ * ```typescript
71
+ * import { WhisperDownloader } from 'node-av';
72
+ *
73
+ * // Download a GGML model
74
+ * const modelPath = await WhisperDownloader.downloadModel({
75
+ * model: 'base',
76
+ * outputPath: './models'
77
+ * });
78
+ *
79
+ * // Download a VAD model
80
+ * const vadPath = await WhisperDownloader.downloadVADModel('silero-v5.1.2', './models');
81
+ *
82
+ * // Check available models
83
+ * const categories = WhisperDownloader.getModelsByCategory();
84
+ * console.log(categories); // Map { 'tiny' => ['tiny', 'tiny.en', ...], ... }
85
+ * ```
86
+ */
87
+ export class WhisperDownloader {
88
+ static DEFAULT_MODEL_PATH = resolve(__dirname, '../../../models');
89
+ static DEFAULT_SRC = 'https://huggingface.co/ggerganov/whisper.cpp';
90
+ static DEFAULT_PFX = 'resolve/main/ggml';
91
+ static TDRZ_SRC = 'https://huggingface.co/akashmjn/tinydiarize-whisper.cpp';
92
+ static TDRZ_PFX = 'resolve/main/ggml';
93
+ static VAD_SRC = 'https://huggingface.co/ggml-org/whisper-vad';
94
+ static VAD_PFX = 'resolve/main/ggml';
95
+ // Global map to track ongoing downloads and prevent race conditions
96
+ static activeDownloads = new Map();
97
+ // Private constructor to prevent instantiation
98
+ constructor() { }
99
+ /**
100
+ * Check if a model name is a valid GGML model.
101
+ *
102
+ * Validates whether the provided string matches one of the available
103
+ * GGML Whisper model names.
104
+ *
105
+ * @param model - Model name to validate
106
+ *
107
+ * @returns True if the model is a valid GGML model name
108
+ *
109
+ * @example
110
+ * ```typescript
111
+ * import { WhisperDownloader } from 'node-av';
112
+ *
113
+ * console.log(WhisperDownloader.isValidModel('base')); // true
114
+ * console.log(WhisperDownloader.isValidModel('large-v3')); // true
115
+ * console.log(WhisperDownloader.isValidModel('invalid')); // false
116
+ * ```
117
+ */
118
+ static isValidModel(model) {
119
+ return WHISPER_MODELS.includes(model);
120
+ }
121
+ /**
122
+ * Check if a model name is a valid VAD model.
123
+ *
124
+ * Validates whether the provided string matches one of the available
125
+ * Silero VAD model names.
126
+ *
127
+ * @param model - Model name to validate
128
+ *
129
+ * @returns True if the model is a valid VAD model name
130
+ *
131
+ * @example
132
+ * ```typescript
133
+ * import { WhisperDownloader } from 'node-av';
134
+ *
135
+ * console.log(WhisperDownloader.isValidVADModel('silero-v5.1.2')); // true
136
+ * console.log(WhisperDownloader.isValidVADModel('invalid')); // false
137
+ * ```
138
+ */
139
+ static isValidVADModel(model) {
140
+ return WHISPER_VAD_MODELS.includes(model);
141
+ }
142
+ /**
143
+ * Get all available GGML models grouped by category.
144
+ *
145
+ * Returns a map of model categories (tiny, base, small, medium, large)
146
+ * with their corresponding model variants.
147
+ *
148
+ * @returns Map of category names to model name arrays
149
+ *
150
+ * @example
151
+ * ```typescript
152
+ * import { WhisperDownloader } from 'node-av';
153
+ *
154
+ * const categories = WhisperDownloader.getModelsByCategory();
155
+ * console.log(categories.get('base'));
156
+ * // ['base', 'base.en', 'base-q5_1', 'base.en-q5_1', 'base-q8_0']
157
+ *
158
+ * // List all categories
159
+ * for (const [category, models] of categories) {
160
+ * console.log(`${category}: ${models.length} variants`);
161
+ * }
162
+ * ```
163
+ */
164
+ static getModelsByCategory() {
165
+ const categories = new Map();
166
+ for (const model of WHISPER_MODELS) {
167
+ const category = model.split(/[.-]/)[0];
168
+ if (!categories.has(category)) {
169
+ categories.set(category, []);
170
+ }
171
+ categories.get(category).push(model);
172
+ }
173
+ return categories;
174
+ }
175
+ /**
176
+ * Get the download URL for a model.
177
+ *
178
+ * Constructs the HuggingFace download URL for a given model name.
179
+ * Automatically detects whether it's a GGML or VAD model if type is not specified.
180
+ * Handles special models like tinydiarize variants.
181
+ *
182
+ * @param model - Model name
183
+ *
184
+ * @param type - Model type (auto-detected if not provided)
185
+ *
186
+ * @returns Full download URL for the model
187
+ *
188
+ * @example
189
+ * ```typescript
190
+ * import { WhisperDownloader } from 'node-av';
191
+ *
192
+ * // GGML model URL
193
+ * const url = WhisperDownloader.getModelUrl('base');
194
+ * console.log(url);
195
+ * // 'https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.bin'
196
+ *
197
+ * // VAD model URL
198
+ * const vadUrl = WhisperDownloader.getModelUrl('silero-v5.1.2');
199
+ * console.log(vadUrl);
200
+ * // 'https://huggingface.co/ggml-org/whisper-vad/resolve/main/ggml-silero-v5.1.2.bin'
201
+ * ```
202
+ */
203
+ static getModelUrl(model, type) {
204
+ // Auto-detect type if not provided
205
+ if (!type) {
206
+ if (this.isValidVADModel(model)) {
207
+ type = 'vad';
208
+ }
209
+ else {
210
+ type = 'ggml';
211
+ }
212
+ }
213
+ if (type === 'vad') {
214
+ return `${this.VAD_SRC}/${this.VAD_PFX}-${model}.bin`;
215
+ }
216
+ // GGML models
217
+ const isTdrz = model.includes('tdrz');
218
+ const src = isTdrz ? this.TDRZ_SRC : this.DEFAULT_SRC;
219
+ const pfx = isTdrz ? this.TDRZ_PFX : this.DEFAULT_PFX;
220
+ return `${src}/${pfx}-${model}.bin`;
221
+ }
222
+ /**
223
+ * Check if a model file already exists.
224
+ *
225
+ * Checks whether a model file has already been downloaded to the specified path.
226
+ * Useful for skipping redundant downloads.
227
+ *
228
+ * @param model - Model name
229
+ *
230
+ * @param outputPath - Directory path to check
231
+ *
232
+ * @returns True if the model file exists
233
+ *
234
+ * @example
235
+ * ```typescript
236
+ * import { WhisperDownloader } from 'node-av';
237
+ *
238
+ * if (WhisperDownloader.modelExists('base', './models')) {
239
+ * console.log('Model already downloaded');
240
+ * } else {
241
+ * await WhisperDownloader.downloadModel({
242
+ * model: 'base',
243
+ * outputPath: './models'
244
+ * });
245
+ * }
246
+ * ```
247
+ */
248
+ static modelExists(model, outputPath) {
249
+ const filePath = resolve(outputPath, `ggml-${model}.bin`);
250
+ return existsSync(filePath);
251
+ }
252
+ /**
253
+ * Find whisper-cli executable in system PATH.
254
+ *
255
+ * Searches for whisper-cli binary in system PATH and local build directory.
256
+ * Returns the path to the executable if found.
257
+ *
258
+ * @returns Path to whisper-cli executable, or null if not found
259
+ *
260
+ * @example
261
+ * ```typescript
262
+ * import { WhisperDownloader } from 'node-av';
263
+ *
264
+ * const cliPath = await WhisperDownloader.findWhisperCli();
265
+ * if (cliPath) {
266
+ * console.log(`Found whisper-cli at: ${cliPath}`);
267
+ * } else {
268
+ * console.log('whisper-cli not found');
269
+ * }
270
+ * ```
271
+ */
272
+ static async findWhisperCli() {
273
+ const pathEnv = process.env.PATH ?? '';
274
+ const paths = pathEnv.split(':');
275
+ for (const path of paths) {
276
+ const whisperPath = resolve(path, 'whisper-cli');
277
+ try {
278
+ await access(whisperPath, constants.X_OK);
279
+ return 'whisper-cli';
280
+ }
281
+ catch {
282
+ continue;
283
+ }
284
+ }
285
+ // Check local build
286
+ const localPath = './build/bin/whisper-cli';
287
+ try {
288
+ await access(localPath, constants.X_OK);
289
+ return localPath;
290
+ }
291
+ catch {
292
+ return null;
293
+ }
294
+ }
295
+ /**
296
+ * Download a Whisper model file.
297
+ *
298
+ * Downloads a GGML or VAD model from HuggingFace to the specified directory.
299
+ * Automatically detects model type based on model name if not specified.
300
+ * Prevents race conditions when the same model is downloaded concurrently.
301
+ * Returns immediately if the model file already exists.
302
+ *
303
+ * @param options - Download configuration options
304
+ *
305
+ * @returns Path to the downloaded model file
306
+ *
307
+ * @example
308
+ * ```typescript
309
+ * import { WhisperDownloader } from 'node-av';
310
+ *
311
+ * // Download GGML model (auto-detected)
312
+ * const path = await WhisperDownloader.downloadModel({
313
+ * model: 'base',
314
+ * outputPath: './models'
315
+ * });
316
+ * console.log(`Downloaded to: ${path}`);
317
+ *
318
+ * // Download VAD model (auto-detected)
319
+ * const vadPath = await WhisperDownloader.downloadModel({
320
+ * model: 'silero-v5.1.2',
321
+ * outputPath: './models'
322
+ * });
323
+ *
324
+ * // Explicit type specification
325
+ * const explicitPath = await WhisperDownloader.downloadModel({
326
+ * model: 'base',
327
+ * outputPath: './models',
328
+ * type: 'ggml'
329
+ * });
330
+ * ```
331
+ */
332
+ static async downloadModel(options) {
333
+ const { model, outputPath = this.DEFAULT_MODEL_PATH, type } = options;
334
+ // Auto-detect type if not provided
335
+ let modelType = type ?? 'ggml';
336
+ if (!type) {
337
+ if (this.isValidVADModel(model)) {
338
+ modelType = 'vad';
339
+ }
340
+ else if (this.isValidModel(model)) {
341
+ modelType = 'ggml';
342
+ }
343
+ else {
344
+ throw new Error(`Invalid model: ${model}. Use getModelsByCategory() to see available GGML models or WHISPER_VAD_MODELS for VAD models.`);
345
+ }
346
+ }
347
+ // Validate model name based on type
348
+ if (modelType === 'vad' && !this.isValidVADModel(model)) {
349
+ throw new Error(`Invalid VAD model: ${model}. Available: ${WHISPER_VAD_MODELS.join(', ')}`);
350
+ }
351
+ else if (modelType === 'ggml' && !this.isValidModel(model)) {
352
+ throw new Error(`Invalid GGML model: ${model}. Use getModelsByCategory() to see available models.`);
353
+ }
354
+ const filePath = resolve(outputPath, `ggml-${model}.bin`);
355
+ // Check if download is already in progress
356
+ const downloadKey = `${modelType}:${model}:${outputPath}`;
357
+ const existingDownload = this.activeDownloads.get(downloadKey);
358
+ if (existingDownload) {
359
+ return existingDownload;
360
+ }
361
+ // If file already exists AND no download in progress, return path immediately
362
+ if (existsSync(filePath)) {
363
+ return filePath;
364
+ }
365
+ // Create output directory recursively if it doesn't exist
366
+ await mkdir(outputPath, { recursive: true });
367
+ // Start new download to temporary file
368
+ const url = this.getModelUrl(model, modelType);
369
+ const tmpFilePath = `${filePath}.tmp`;
370
+ const downloadPromise = this.downloadWithRetry(url, tmpFilePath)
371
+ .then(async () => {
372
+ // Rename temporary file to final name after successful download
373
+ await rename(tmpFilePath, filePath);
374
+ return filePath;
375
+ })
376
+ .catch(async (error) => {
377
+ // Clean up temporary file on error
378
+ try {
379
+ await unlink(tmpFilePath);
380
+ }
381
+ catch {
382
+ // Ignore errors when deleting temp file
383
+ }
384
+ throw error;
385
+ })
386
+ .finally(() => {
387
+ // Clean up from active downloads map
388
+ this.activeDownloads.delete(downloadKey);
389
+ });
390
+ // Store in map to prevent concurrent downloads
391
+ this.activeDownloads.set(downloadKey, downloadPromise);
392
+ return downloadPromise;
393
+ }
394
+ /**
395
+ * Download a VAD model (convenience method).
396
+ *
397
+ * Convenience wrapper for downloading VAD models without specifying type.
398
+ * Equivalent to calling downloadModel() with type: 'vad'.
399
+ *
400
+ * @param model - VAD model name
401
+ *
402
+ * @param outputPath - Directory path for download (default: current directory)
403
+ *
404
+ * @returns Path to the downloaded VAD model file
405
+ *
406
+ * @example
407
+ * ```typescript
408
+ * import { WhisperDownloader } from 'node-av';
409
+ *
410
+ * const vadPath = await WhisperDownloader.downloadVADModel(
411
+ * 'silero-v5.1.2',
412
+ * './models'
413
+ * );
414
+ * console.log(`VAD model downloaded to: ${vadPath}`);
415
+ * ```
416
+ */
417
+ static async downloadVADModel(model, outputPath) {
418
+ return this.downloadModel({ model, outputPath, type: 'vad' });
419
+ }
420
+ /**
421
+ * Download multiple Whisper models.
422
+ *
423
+ * Downloads multiple models sequentially to avoid overwhelming the network.
424
+ * Each model is validated and downloaded using the same logic as downloadModel().
425
+ *
426
+ * @param models - Array of model names to download
427
+ *
428
+ * @param outputPath - Directory path for downloads (default: current directory)
429
+ *
430
+ * @param type - Model type for all models (auto-detected if not provided)
431
+ *
432
+ * @returns Array of paths to downloaded model files
433
+ *
434
+ * @example
435
+ * ```typescript
436
+ * import { WhisperDownloader } from 'node-av';
437
+ *
438
+ * // Download multiple GGML models
439
+ * const paths = await WhisperDownloader.downloadModels(
440
+ * ['tiny', 'base', 'small'],
441
+ * './models'
442
+ * );
443
+ * console.log(`Downloaded ${paths.length} models`);
444
+ *
445
+ * // Download multiple VAD models
446
+ * const vadPaths = await WhisperDownloader.downloadModels(
447
+ * ['silero-v5.1.2', 'silero-v6.2.0'],
448
+ * './models',
449
+ * 'vad'
450
+ * );
451
+ * ```
452
+ */
453
+ static async downloadModels(models, outputPath, type) {
454
+ const downloadedPaths = [];
455
+ for (const model of models) {
456
+ const filePath = await this.downloadModel({ model, outputPath, type });
457
+ downloadedPaths.push(filePath);
458
+ }
459
+ return downloadedPaths;
460
+ }
461
+ /**
462
+ * Download a URL to a file, retrying transient failures.
463
+ *
464
+ * Rate limiting (HTTP 429, common when several CI runners hit the model host
465
+ * from a shared IP pool), server errors (5xx), and network errors are retried
466
+ * with exponential backoff, honoring a numeric `Retry-After` header as the
467
+ * lower bound (capped at 30 s per wait). Other HTTP errors (e.g. 404) fail
468
+ * immediately. Each attempt truncates and rewrites the output file.
469
+ *
470
+ * @param url - URL to download
471
+ *
472
+ * @param outputPath - Local file path to save the download
473
+ *
474
+ * @returns Promise that resolves when the download is complete
475
+ *
476
+ * @throws {Error} The last download error once the retries are exhausted
477
+ *
478
+ * @internal
479
+ */
480
+ static async downloadWithRetry(url, outputPath) {
481
+ const maxRetries = 3;
482
+ for (let attempt = 0;; attempt++) {
483
+ try {
484
+ await this.followRedirect(url, outputPath, 0);
485
+ return;
486
+ }
487
+ catch (error) {
488
+ // Permanent client errors (404 wrong URL, 403, ...) are not retryable;
489
+ // 429/5xx and plain network errors (no statusCode) are.
490
+ const status = error instanceof DownloadHttpError ? error.statusCode : undefined;
491
+ const retryable = status === undefined || status === 429 || status >= 500;
492
+ if (!retryable || attempt >= maxRetries) {
493
+ throw error;
494
+ }
495
+ const backoffMs = 1000 * 2 ** attempt;
496
+ const retryAfterMs = error instanceof DownloadHttpError && error.retryAfterSeconds !== undefined ? error.retryAfterSeconds * 1000 : 0;
497
+ await new Promise((r) => setTimeout(r, Math.min(Math.max(backoffMs, retryAfterMs), 30_000)));
498
+ }
499
+ }
500
+ }
501
+ /**
502
+ * Follow HTTP redirects recursively to download a file.
503
+ *
504
+ * Handles HTTP redirects (301, 302, 307, 308) up to a maximum of 5 redirects.
505
+ * Downloads the file to the specified output path.
506
+ *
507
+ * @param url - URL to download
508
+ *
509
+ * @param outputPath - Local file path to save the download
510
+ *
511
+ * @param redirectCount - Current redirect count (used internally)
512
+ *
513
+ * @returns Promise that resolves when the download is complete
514
+ *
515
+ * @internal
516
+ */
517
+ static followRedirect(url, outputPath, redirectCount = 0) {
518
+ return new Promise((resolve, reject) => {
519
+ if (redirectCount > 5) {
520
+ reject(new Error('Too many redirects'));
521
+ return;
522
+ }
523
+ // Use an agent with keepAlive disabled to ensure connections are closed
524
+ const agent = new Agent({ keepAlive: false });
525
+ const request = get(url, { agent }, (response) => {
526
+ // Handle redirects
527
+ if ([301, 302, 307, 308].includes(response.statusCode ?? 0)) {
528
+ const redirectUrl = response.headers.location;
529
+ if (redirectUrl) {
530
+ // Destroy the response to close the connection
531
+ response.destroy();
532
+ this.followRedirect(redirectUrl, outputPath, redirectCount + 1)
533
+ .then(resolve)
534
+ .catch(reject);
535
+ return;
536
+ }
537
+ }
538
+ if (response.statusCode !== 200) {
539
+ // Destroy the response to close the connection
540
+ response.destroy();
541
+ // Carry the status (and a numeric Retry-After, e.g. on 429 rate limits)
542
+ // so downloadWithRetry can decide whether and how long to back off.
543
+ const retryAfter = Number(response.headers['retry-after']);
544
+ const retryAfterSeconds = Number.isFinite(retryAfter) ? retryAfter : undefined;
545
+ reject(new DownloadHttpError(`Failed to download: HTTP ${response.statusCode}`, response.statusCode ?? 0, retryAfterSeconds));
546
+ return;
547
+ }
548
+ const fileStream = createWriteStream(outputPath);
549
+ let hasError = false;
550
+ response.pipe(fileStream);
551
+ fileStream.on('finish', () => {
552
+ // Don't close if we already had an error
553
+ if (!hasError) {
554
+ fileStream.close((err) => {
555
+ // Destroy the response to close the HTTP connection
556
+ response.destroy();
557
+ if (err) {
558
+ reject(err);
559
+ }
560
+ else {
561
+ resolve();
562
+ }
563
+ });
564
+ }
565
+ });
566
+ fileStream.on('error', (err) => {
567
+ hasError = true;
568
+ // Destroy the response to close the HTTP connection
569
+ response.destroy();
570
+ fileStream.close(() => {
571
+ reject(err);
572
+ });
573
+ });
574
+ response.on('error', (err) => {
575
+ hasError = true;
576
+ fileStream.close(() => {
577
+ reject(err);
578
+ });
579
+ });
580
+ });
581
+ request.on('error', (err) => {
582
+ reject(err);
583
+ });
584
+ });
585
+ }
586
+ }
587
+ //# sourceMappingURL=whisper-model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whisper-model.js","sourceRoot":"","sources":["../../../src/api/utilities/whisper-model.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Parse bitrate string to bigint.
3
+ *
4
+ * Supports suffixes: K (kilo), M (mega), G (giga).
5
+ *
6
+ * Converts human-readable bitrate strings to numeric values.
7
+ *
8
+ * @param str - Bitrate string (e.g., '5M', '192k')
9
+ *
10
+ * @returns Bitrate as bigint
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * parseBitrate('5M') // 5000000n
15
+ * parseBitrate('192k') // 192000n
16
+ * parseBitrate('1.5G') // 1500000000n
17
+ * ```
18
+ */
19
+ export declare function parseBitrate(str: string): bigint;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Parse bitrate string to bigint.
3
+ *
4
+ * Supports suffixes: K (kilo), M (mega), G (giga).
5
+ *
6
+ * Converts human-readable bitrate strings to numeric values.
7
+ *
8
+ * @param str - Bitrate string (e.g., '5M', '192k')
9
+ *
10
+ * @returns Bitrate as bigint
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * parseBitrate('5M') // 5000000n
15
+ * parseBitrate('192k') // 192000n
16
+ * parseBitrate('1.5G') // 1500000000n
17
+ * ```
18
+ */
19
+ export function parseBitrate(str) {
20
+ const match = /^(\d+(?:\.\d+)?)\s*([KMG])?$/i.exec(str);
21
+ if (!match) {
22
+ throw new Error(`Invalid bitrate: ${str}`);
23
+ }
24
+ let value = parseFloat(match[1]);
25
+ const unit = match[2]?.toUpperCase();
26
+ switch (unit) {
27
+ case 'K':
28
+ value *= 1000;
29
+ break;
30
+ case 'M':
31
+ value *= 1000000;
32
+ break;
33
+ case 'G':
34
+ value *= 1000000000;
35
+ break;
36
+ }
37
+ return BigInt(Math.floor(value));
38
+ }
39
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/api/utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,MAAM,KAAK,GAAG,+BAA+B,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACxD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,oBAAoB,GAAG,EAAE,CAAC,CAAC;IAC7C,CAAC;IAED,IAAI,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACjC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC;IAErC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,GAAG;YACN,KAAK,IAAI,IAAI,CAAC;YACd,MAAM;QACR,KAAK,GAAG;YACN,KAAK,IAAI,OAAO,CAAC;YACjB,MAAM;QACR,KAAK,GAAG;YACN,KAAK,IAAI,UAAU,CAAC;YACpB,MAAM;IACV,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;AACnC,CAAC"}