youtube-knowledge-mcp 2.1.0 → 3.0.0

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 (478) hide show
  1. package/README.md +153 -38
  2. package/dist/brain-schemas.d.ts +10 -10
  3. package/dist/brain-schemas.d.ts.map +1 -1
  4. package/dist/brain-schemas.js +0 -4
  5. package/dist/brain-schemas.js.map +1 -1
  6. package/dist/harvest-schemas.d.ts +75 -0
  7. package/dist/harvest-schemas.d.ts.map +1 -0
  8. package/dist/harvest-schemas.js +106 -0
  9. package/dist/harvest-schemas.js.map +1 -0
  10. package/dist/http/app.d.ts +16 -0
  11. package/dist/http/app.d.ts.map +1 -0
  12. package/dist/http/app.js +176 -0
  13. package/dist/http/app.js.map +1 -0
  14. package/dist/http/auth.d.ts +38 -0
  15. package/dist/http/auth.d.ts.map +1 -0
  16. package/dist/http/auth.js +79 -0
  17. package/dist/http/auth.js.map +1 -0
  18. package/dist/http/config.d.ts +41 -0
  19. package/dist/http/config.d.ts.map +1 -0
  20. package/dist/http/config.js +65 -0
  21. package/dist/http/config.js.map +1 -0
  22. package/dist/http/rate-limiter.d.ts +24 -0
  23. package/dist/http/rate-limiter.d.ts.map +1 -0
  24. package/dist/http/rate-limiter.js +55 -0
  25. package/dist/http/rate-limiter.js.map +1 -0
  26. package/dist/http/sessions.d.ts +34 -0
  27. package/dist/http/sessions.d.ts.map +1 -0
  28. package/dist/http/sessions.js +62 -0
  29. package/dist/http/sessions.js.map +1 -0
  30. package/dist/http.d.ts +6 -48
  31. package/dist/http.d.ts.map +1 -1
  32. package/dist/http.js +35 -252
  33. package/dist/http.js.map +1 -1
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +11 -517
  36. package/dist/index.js.map +1 -1
  37. package/dist/prompts-brain.d.ts +4 -0
  38. package/dist/prompts-brain.d.ts.map +1 -0
  39. package/dist/prompts-brain.js +48 -0
  40. package/dist/prompts-brain.js.map +1 -0
  41. package/dist/prompts-research.d.ts +4 -0
  42. package/dist/prompts-research.d.ts.map +1 -0
  43. package/dist/prompts-research.js +74 -0
  44. package/dist/prompts-research.js.map +1 -0
  45. package/dist/prompts-shared.d.ts +13 -0
  46. package/dist/prompts-shared.d.ts.map +1 -0
  47. package/dist/prompts-shared.js +7 -0
  48. package/dist/prompts-shared.js.map +1 -0
  49. package/dist/prompts.d.ts.map +1 -1
  50. package/dist/prompts.js +5 -100
  51. package/dist/prompts.js.map +1 -1
  52. package/dist/registry/brain-tools.d.ts +4 -0
  53. package/dist/registry/brain-tools.d.ts.map +1 -0
  54. package/dist/registry/brain-tools.js +104 -0
  55. package/dist/registry/brain-tools.js.map +1 -0
  56. package/dist/registry/channel-tools.d.ts +4 -0
  57. package/dist/registry/channel-tools.d.ts.map +1 -0
  58. package/dist/registry/channel-tools.js +53 -0
  59. package/dist/registry/channel-tools.js.map +1 -0
  60. package/dist/registry/harvest-tools.d.ts +10 -0
  61. package/dist/registry/harvest-tools.d.ts.map +1 -0
  62. package/dist/registry/harvest-tools.js +109 -0
  63. package/dist/registry/harvest-tools.js.map +1 -0
  64. package/dist/registry/health-tools.d.ts +4 -0
  65. package/dist/registry/health-tools.d.ts.map +1 -0
  66. package/dist/registry/health-tools.js +39 -0
  67. package/dist/registry/health-tools.js.map +1 -0
  68. package/dist/registry/index.d.ts +8 -0
  69. package/dist/registry/index.d.ts.map +1 -0
  70. package/dist/registry/index.js +29 -0
  71. package/dist/registry/index.js.map +1 -0
  72. package/dist/registry/library-tools.d.ts +4 -0
  73. package/dist/registry/library-tools.d.ts.map +1 -0
  74. package/dist/registry/library-tools.js +116 -0
  75. package/dist/registry/library-tools.js.map +1 -0
  76. package/dist/registry/media-tools.d.ts +4 -0
  77. package/dist/registry/media-tools.d.ts.map +1 -0
  78. package/dist/registry/media-tools.js +100 -0
  79. package/dist/registry/media-tools.js.map +1 -0
  80. package/dist/registry/thumbnail-tools.d.ts +7 -0
  81. package/dist/registry/thumbnail-tools.d.ts.map +1 -0
  82. package/dist/registry/thumbnail-tools.js +72 -0
  83. package/dist/registry/thumbnail-tools.js.map +1 -0
  84. package/dist/registry/transcript-tools.d.ts +4 -0
  85. package/dist/registry/transcript-tools.d.ts.map +1 -0
  86. package/dist/registry/transcript-tools.js +68 -0
  87. package/dist/registry/transcript-tools.js.map +1 -0
  88. package/dist/registry/types.d.ts +41 -0
  89. package/dist/registry/types.d.ts.map +1 -0
  90. package/dist/registry/types.js +17 -0
  91. package/dist/registry/types.js.map +1 -0
  92. package/dist/registry/video-tools.d.ts +4 -0
  93. package/dist/registry/video-tools.d.ts.map +1 -0
  94. package/dist/registry/video-tools.js +101 -0
  95. package/dist/registry/video-tools.js.map +1 -0
  96. package/dist/resources.d.ts.map +1 -1
  97. package/dist/resources.js +13 -10
  98. package/dist/resources.js.map +1 -1
  99. package/dist/schemas.d.ts +250 -2
  100. package/dist/schemas.d.ts.map +1 -1
  101. package/dist/schemas.js +61 -0
  102. package/dist/schemas.js.map +1 -1
  103. package/dist/thumbnail-resource.d.ts +8 -0
  104. package/dist/thumbnail-resource.d.ts.map +1 -0
  105. package/dist/thumbnail-resource.js +38 -0
  106. package/dist/thumbnail-resource.js.map +1 -0
  107. package/dist/thumbnail-schemas.d.ts +512 -0
  108. package/dist/thumbnail-schemas.d.ts.map +1 -0
  109. package/dist/thumbnail-schemas.js +95 -0
  110. package/dist/thumbnail-schemas.js.map +1 -0
  111. package/dist/tools/ask-brain.js +1 -1
  112. package/dist/tools/ask-brain.js.map +1 -1
  113. package/dist/tools/batch.js +1 -1
  114. package/dist/tools/batch.js.map +1 -1
  115. package/dist/tools/brain-info.js +1 -1
  116. package/dist/tools/brain-info.js.map +1 -1
  117. package/dist/tools/build-brain.js +1 -1
  118. package/dist/tools/build-brain.js.map +1 -1
  119. package/dist/tools/check-health.d.ts +61 -0
  120. package/dist/tools/check-health.d.ts.map +1 -1
  121. package/dist/tools/check-health.js +94 -6
  122. package/dist/tools/check-health.js.map +1 -1
  123. package/dist/tools/clips.d.ts +9 -41
  124. package/dist/tools/clips.d.ts.map +1 -1
  125. package/dist/tools/clips.js +52 -128
  126. package/dist/tools/clips.js.map +1 -1
  127. package/dist/tools/fetch-channel-thumbnails.d.ts +179 -0
  128. package/dist/tools/fetch-channel-thumbnails.d.ts.map +1 -0
  129. package/dist/tools/fetch-channel-thumbnails.js +123 -0
  130. package/dist/tools/fetch-channel-thumbnails.js.map +1 -0
  131. package/dist/tools/fetch-videos.d.ts +18 -4
  132. package/dist/tools/fetch-videos.d.ts.map +1 -1
  133. package/dist/tools/fetch-videos.js +64 -20
  134. package/dist/tools/fetch-videos.js.map +1 -1
  135. package/dist/tools/frames-subtitles.d.ts +44 -0
  136. package/dist/tools/frames-subtitles.d.ts.map +1 -0
  137. package/dist/tools/frames-subtitles.js +104 -0
  138. package/dist/tools/frames-subtitles.js.map +1 -0
  139. package/dist/tools/get-channel-info.d.ts +2 -0
  140. package/dist/tools/get-channel-info.d.ts.map +1 -1
  141. package/dist/tools/get-channel-info.js +8 -1
  142. package/dist/tools/get-channel-info.js.map +1 -1
  143. package/dist/tools/get-comments.d.ts +238 -6
  144. package/dist/tools/get-comments.d.ts.map +1 -1
  145. package/dist/tools/get-comments.js +85 -21
  146. package/dist/tools/get-comments.js.map +1 -1
  147. package/dist/tools/get-coverage.d.ts +122 -0
  148. package/dist/tools/get-coverage.d.ts.map +1 -0
  149. package/dist/tools/get-coverage.js +105 -0
  150. package/dist/tools/get-coverage.js.map +1 -0
  151. package/dist/tools/get-playlist-info.d.ts.map +1 -1
  152. package/dist/tools/get-playlist-info.js +1 -0
  153. package/dist/tools/get-playlist-info.js.map +1 -1
  154. package/dist/tools/get-thumbnail.d.ts +38 -0
  155. package/dist/tools/get-thumbnail.d.ts.map +1 -0
  156. package/dist/tools/get-thumbnail.js +152 -0
  157. package/dist/tools/get-thumbnail.js.map +1 -0
  158. package/dist/tools/get-transcript.d.ts.map +1 -1
  159. package/dist/tools/get-transcript.js +2 -14
  160. package/dist/tools/get-transcript.js.map +1 -1
  161. package/dist/tools/harvest-channel.d.ts +92 -0
  162. package/dist/tools/harvest-channel.d.ts.map +1 -0
  163. package/dist/tools/harvest-channel.js +62 -0
  164. package/dist/tools/harvest-channel.js.map +1 -0
  165. package/dist/tools/harvest-comments.d.ts +81 -0
  166. package/dist/tools/harvest-comments.d.ts.map +1 -0
  167. package/dist/tools/harvest-comments.js +115 -0
  168. package/dist/tools/harvest-comments.js.map +1 -0
  169. package/dist/tools/library.d.ts.map +1 -1
  170. package/dist/tools/library.js +14 -4
  171. package/dist/tools/library.js.map +1 -1
  172. package/dist/tools/list-channel-thumbnails.d.ts +235 -0
  173. package/dist/tools/list-channel-thumbnails.d.ts.map +1 -0
  174. package/dist/tools/list-channel-thumbnails.js +79 -0
  175. package/dist/tools/list-channel-thumbnails.js.map +1 -0
  176. package/dist/tools/list-library.js +1 -1
  177. package/dist/tools/list-library.js.map +1 -1
  178. package/dist/tools/prune-harvest.d.ts +59 -0
  179. package/dist/tools/prune-harvest.d.ts.map +1 -0
  180. package/dist/tools/prune-harvest.js +108 -0
  181. package/dist/tools/prune-harvest.js.map +1 -0
  182. package/dist/tools/query-comments.d.ts +125 -0
  183. package/dist/tools/query-comments.d.ts.map +1 -0
  184. package/dist/tools/query-comments.js +106 -0
  185. package/dist/tools/query-comments.js.map +1 -0
  186. package/dist/tools/query-videos.d.ts +118 -0
  187. package/dist/tools/query-videos.d.ts.map +1 -0
  188. package/dist/tools/query-videos.js +97 -0
  189. package/dist/tools/query-videos.js.map +1 -0
  190. package/dist/tools/repair-store.d.ts +34 -0
  191. package/dist/tools/repair-store.d.ts.map +1 -0
  192. package/dist/tools/repair-store.js +58 -0
  193. package/dist/tools/repair-store.js.map +1 -0
  194. package/dist/tools/save-to-library.d.ts.map +1 -1
  195. package/dist/tools/save-to-library.js +5 -1
  196. package/dist/tools/save-to-library.js.map +1 -1
  197. package/dist/tools/search-channels.d.ts +6 -0
  198. package/dist/tools/search-channels.d.ts.map +1 -1
  199. package/dist/tools/search-channels.js +5 -1
  200. package/dist/tools/search-channels.js.map +1 -1
  201. package/dist/tools/search-transcript.d.ts.map +1 -1
  202. package/dist/tools/search-transcript.js +6 -13
  203. package/dist/tools/search-transcript.js.map +1 -1
  204. package/dist/tools/search-videos.d.ts +3 -0
  205. package/dist/tools/search-videos.d.ts.map +1 -1
  206. package/dist/tools/search-videos.js +1 -1
  207. package/dist/tools/search-videos.js.map +1 -1
  208. package/dist/utils/batches.d.ts +15 -0
  209. package/dist/utils/batches.d.ts.map +1 -0
  210. package/dist/utils/batches.js +31 -0
  211. package/dist/utils/batches.js.map +1 -0
  212. package/dist/utils/brain-build.d.ts.map +1 -1
  213. package/dist/utils/brain-build.js +1 -12
  214. package/dist/utils/brain-build.js.map +1 -1
  215. package/dist/utils/brain-index.d.ts.map +1 -1
  216. package/dist/utils/brain-index.js +3 -2
  217. package/dist/utils/brain-index.js.map +1 -1
  218. package/dist/utils/brain-lock.d.ts +2 -18
  219. package/dist/utils/brain-lock.d.ts.map +1 -1
  220. package/dist/utils/brain-lock.js +4 -80
  221. package/dist/utils/brain-lock.js.map +1 -1
  222. package/dist/utils/brain-lookup.d.ts +8 -0
  223. package/dist/utils/brain-lookup.d.ts.map +1 -1
  224. package/dist/utils/brain-lookup.js +5 -31
  225. package/dist/utils/brain-lookup.js.map +1 -1
  226. package/dist/utils/brain-storage.d.ts.map +1 -1
  227. package/dist/utils/brain-storage.js +5 -5
  228. package/dist/utils/brain-storage.js.map +1 -1
  229. package/dist/utils/caption-probe.d.ts +7 -0
  230. package/dist/utils/caption-probe.d.ts.map +1 -0
  231. package/dist/utils/caption-probe.js +36 -0
  232. package/dist/utils/caption-probe.js.map +1 -0
  233. package/dist/utils/channel-images.d.ts +16 -0
  234. package/dist/utils/channel-images.d.ts.map +1 -0
  235. package/dist/utils/channel-images.js +35 -0
  236. package/dist/utils/channel-images.js.map +1 -0
  237. package/dist/utils/channel-lookup.d.ts +5 -0
  238. package/dist/utils/channel-lookup.d.ts.map +1 -0
  239. package/dist/utils/channel-lookup.js +37 -0
  240. package/dist/utils/channel-lookup.js.map +1 -0
  241. package/dist/utils/chapters.d.ts +11 -0
  242. package/dist/utils/chapters.d.ts.map +1 -0
  243. package/dist/utils/chapters.js +24 -0
  244. package/dist/utils/chapters.js.map +1 -0
  245. package/dist/utils/clips.d.ts.map +1 -1
  246. package/dist/utils/clips.js +18 -26
  247. package/dist/utils/clips.js.map +1 -1
  248. package/dist/utils/comment-store.d.ts +71 -0
  249. package/dist/utils/comment-store.d.ts.map +1 -0
  250. package/dist/utils/comment-store.js +129 -0
  251. package/dist/utils/comment-store.js.map +1 -0
  252. package/dist/utils/comment-threads.d.ts +51 -0
  253. package/dist/utils/comment-threads.d.ts.map +1 -0
  254. package/dist/utils/comment-threads.js +76 -0
  255. package/dist/utils/comment-threads.js.map +1 -0
  256. package/dist/utils/coverage-text.d.ts +3 -0
  257. package/dist/utils/coverage-text.d.ts.map +1 -0
  258. package/dist/utils/coverage-text.js +62 -0
  259. package/dist/utils/coverage-text.js.map +1 -0
  260. package/dist/utils/coverage.d.ts +57 -0
  261. package/dist/utils/coverage.d.ts.map +1 -0
  262. package/dist/utils/coverage.js +142 -0
  263. package/dist/utils/coverage.js.map +1 -0
  264. package/dist/utils/env.d.ts +26 -0
  265. package/dist/utils/env.d.ts.map +1 -0
  266. package/dist/utils/env.js +72 -0
  267. package/dist/utils/env.js.map +1 -0
  268. package/dist/utils/errors.d.ts +1 -1
  269. package/dist/utils/errors.d.ts.map +1 -1
  270. package/dist/utils/errors.js +28 -2
  271. package/dist/utils/errors.js.map +1 -1
  272. package/dist/utils/file-lock.d.ts +34 -0
  273. package/dist/utils/file-lock.d.ts.map +1 -0
  274. package/dist/utils/file-lock.js +91 -0
  275. package/dist/utils/file-lock.js.map +1 -0
  276. package/dist/utils/flat-listing.d.ts +89 -0
  277. package/dist/utils/flat-listing.d.ts.map +1 -0
  278. package/dist/utils/flat-listing.js +68 -0
  279. package/dist/utils/flat-listing.js.map +1 -0
  280. package/dist/utils/format.d.ts +18 -4
  281. package/dist/utils/format.d.ts.map +1 -1
  282. package/dist/utils/format.js +2 -6
  283. package/dist/utils/format.js.map +1 -1
  284. package/dist/utils/guard.d.ts +21 -0
  285. package/dist/utils/guard.d.ts.map +1 -0
  286. package/dist/utils/guard.js +105 -0
  287. package/dist/utils/guard.js.map +1 -0
  288. package/dist/utils/harvest-catalog.d.ts +44 -0
  289. package/dist/utils/harvest-catalog.d.ts.map +1 -0
  290. package/dist/utils/harvest-catalog.js +164 -0
  291. package/dist/utils/harvest-catalog.js.map +1 -0
  292. package/dist/utils/harvest-lock.d.ts +3 -0
  293. package/dist/utils/harvest-lock.d.ts.map +1 -0
  294. package/dist/utils/harvest-lock.js +26 -0
  295. package/dist/utils/harvest-lock.js.map +1 -0
  296. package/dist/utils/harvest-receipts.d.ts +14 -0
  297. package/dist/utils/harvest-receipts.d.ts.map +1 -0
  298. package/dist/utils/harvest-receipts.js +110 -0
  299. package/dist/utils/harvest-receipts.js.map +1 -0
  300. package/dist/utils/image-dimensions.d.ts +19 -0
  301. package/dist/utils/image-dimensions.d.ts.map +1 -0
  302. package/dist/utils/image-dimensions.js +93 -0
  303. package/dist/utils/image-dimensions.js.map +1 -0
  304. package/dist/utils/image-fetch.d.ts +31 -0
  305. package/dist/utils/image-fetch.d.ts.map +1 -0
  306. package/dist/utils/image-fetch.js +141 -0
  307. package/dist/utils/image-fetch.js.map +1 -0
  308. package/dist/utils/json-file.d.ts +14 -5
  309. package/dist/utils/json-file.d.ts.map +1 -1
  310. package/dist/utils/json-file.js +24 -9
  311. package/dist/utils/json-file.js.map +1 -1
  312. package/dist/utils/listing-cursor.d.ts +31 -0
  313. package/dist/utils/listing-cursor.d.ts.map +1 -0
  314. package/dist/utils/listing-cursor.js +39 -0
  315. package/dist/utils/listing-cursor.js.map +1 -0
  316. package/dist/utils/paths.d.ts +10 -0
  317. package/dist/utils/paths.d.ts.map +1 -1
  318. package/dist/utils/paths.js +14 -0
  319. package/dist/utils/paths.js.map +1 -1
  320. package/dist/utils/pattern.d.ts +30 -0
  321. package/dist/utils/pattern.d.ts.map +1 -0
  322. package/dist/utils/pattern.js +130 -0
  323. package/dist/utils/pattern.js.map +1 -0
  324. package/dist/utils/pot-preflight.d.ts +53 -0
  325. package/dist/utils/pot-preflight.d.ts.map +1 -0
  326. package/dist/utils/pot-preflight.js +146 -0
  327. package/dist/utils/pot-preflight.js.map +1 -0
  328. package/dist/utils/search-index.d.ts.map +1 -1
  329. package/dist/utils/search-index.js +9 -4
  330. package/dist/utils/search-index.js.map +1 -1
  331. package/dist/utils/sleep.d.ts +9 -0
  332. package/dist/utils/sleep.d.ts.map +1 -0
  333. package/dist/utils/sleep.js +25 -0
  334. package/dist/utils/sleep.js.map +1 -0
  335. package/dist/utils/storage.d.ts.map +1 -1
  336. package/dist/utils/storage.js +14 -8
  337. package/dist/utils/storage.js.map +1 -1
  338. package/dist/utils/store-health.d.ts +37 -0
  339. package/dist/utils/store-health.d.ts.map +1 -0
  340. package/dist/utils/store-health.js +92 -0
  341. package/dist/utils/store-health.js.map +1 -0
  342. package/dist/utils/store-migrations.d.ts +33 -0
  343. package/dist/utils/store-migrations.d.ts.map +1 -0
  344. package/dist/utils/store-migrations.js +41 -0
  345. package/dist/utils/store-migrations.js.map +1 -0
  346. package/dist/utils/store-paths.d.ts +33 -0
  347. package/dist/utils/store-paths.d.ts.map +1 -0
  348. package/dist/utils/store-paths.js +48 -0
  349. package/dist/utils/store-paths.js.map +1 -0
  350. package/dist/utils/store-rows.d.ts +22 -0
  351. package/dist/utils/store-rows.d.ts.map +1 -0
  352. package/dist/utils/store-rows.js +62 -0
  353. package/dist/utils/store-rows.js.map +1 -0
  354. package/dist/utils/store-schema.d.ts +16 -0
  355. package/dist/utils/store-schema.d.ts.map +1 -0
  356. package/dist/utils/store-schema.js +168 -0
  357. package/dist/utils/store-schema.js.map +1 -0
  358. package/dist/utils/store.d.ts +34 -0
  359. package/dist/utils/store.d.ts.map +1 -0
  360. package/dist/utils/store.js +157 -0
  361. package/dist/utils/store.js.map +1 -0
  362. package/dist/utils/subtitles.d.ts +7 -0
  363. package/dist/utils/subtitles.d.ts.map +1 -0
  364. package/dist/utils/subtitles.js +30 -0
  365. package/dist/utils/subtitles.js.map +1 -0
  366. package/dist/utils/thumbnail-entry.d.ts +19 -0
  367. package/dist/utils/thumbnail-entry.d.ts.map +1 -0
  368. package/dist/utils/thumbnail-entry.js +119 -0
  369. package/dist/utils/thumbnail-entry.js.map +1 -0
  370. package/dist/utils/thumbnail-fetch.d.ts +37 -0
  371. package/dist/utils/thumbnail-fetch.d.ts.map +1 -0
  372. package/dist/utils/thumbnail-fetch.js +89 -0
  373. package/dist/utils/thumbnail-fetch.js.map +1 -0
  374. package/dist/utils/thumbnail-ladder.d.ts +44 -0
  375. package/dist/utils/thumbnail-ladder.d.ts.map +1 -0
  376. package/dist/utils/thumbnail-ladder.js +68 -0
  377. package/dist/utils/thumbnail-ladder.js.map +1 -0
  378. package/dist/utils/thumbnail-listing.d.ts +16 -0
  379. package/dist/utils/thumbnail-listing.d.ts.map +1 -0
  380. package/dist/utils/thumbnail-listing.js +26 -0
  381. package/dist/utils/thumbnail-listing.js.map +1 -0
  382. package/dist/utils/thumbnail-paths.d.ts +20 -0
  383. package/dist/utils/thumbnail-paths.d.ts.map +1 -0
  384. package/dist/utils/thumbnail-paths.js +35 -0
  385. package/dist/utils/thumbnail-paths.js.map +1 -0
  386. package/dist/utils/thumbnail-store.d.ts +19 -0
  387. package/dist/utils/thumbnail-store.d.ts.map +1 -0
  388. package/dist/utils/thumbnail-store.js +125 -0
  389. package/dist/utils/thumbnail-store.js.map +1 -0
  390. package/dist/utils/transcript-cache.d.ts +20 -0
  391. package/dist/utils/transcript-cache.d.ts.map +1 -0
  392. package/dist/utils/transcript-cache.js +127 -0
  393. package/dist/utils/transcript-cache.js.map +1 -0
  394. package/dist/utils/transcript-search.d.ts +20 -0
  395. package/dist/utils/transcript-search.d.ts.map +1 -0
  396. package/dist/utils/transcript-search.js +35 -0
  397. package/dist/utils/transcript-search.js.map +1 -0
  398. package/dist/utils/transcript.d.ts +10 -31
  399. package/dist/utils/transcript.d.ts.map +1 -1
  400. package/dist/utils/transcript.js +2 -64
  401. package/dist/utils/transcript.js.map +1 -1
  402. package/dist/utils/validate-youtube.d.ts +35 -0
  403. package/dist/utils/validate-youtube.d.ts.map +1 -0
  404. package/dist/utils/validate-youtube.js +87 -0
  405. package/dist/utils/validate-youtube.js.map +1 -0
  406. package/dist/utils/validate.d.ts +11 -4
  407. package/dist/utils/validate.d.ts.map +1 -1
  408. package/dist/utils/validate.js +43 -36
  409. package/dist/utils/validate.js.map +1 -1
  410. package/dist/utils/version.d.ts +2 -0
  411. package/dist/utils/version.d.ts.map +1 -0
  412. package/dist/utils/version.js +19 -0
  413. package/dist/utils/version.js.map +1 -0
  414. package/dist/utils/video-stats-cache.d.ts +16 -0
  415. package/dist/utils/video-stats-cache.d.ts.map +1 -0
  416. package/dist/utils/video-stats-cache.js +81 -0
  417. package/dist/utils/video-stats-cache.js.map +1 -0
  418. package/dist/utils/video-stats.d.ts +186 -0
  419. package/dist/utils/video-stats.d.ts.map +1 -0
  420. package/dist/utils/video-stats.js +168 -0
  421. package/dist/utils/video-stats.js.map +1 -0
  422. package/dist/utils/video-store.d.ts +69 -0
  423. package/dist/utils/video-store.d.ts.map +1 -0
  424. package/dist/utils/video-store.js +77 -0
  425. package/dist/utils/video-store.js.map +1 -0
  426. package/dist/utils/youtube-channel.d.ts +51 -0
  427. package/dist/utils/youtube-channel.d.ts.map +1 -0
  428. package/dist/utils/youtube-channel.js +91 -0
  429. package/dist/utils/youtube-channel.js.map +1 -0
  430. package/dist/utils/youtube-download.d.ts +27 -0
  431. package/dist/utils/youtube-download.d.ts.map +1 -0
  432. package/dist/utils/youtube-download.js +118 -0
  433. package/dist/utils/youtube-download.js.map +1 -0
  434. package/dist/utils/youtube-schemas.d.ts +492 -0
  435. package/dist/utils/youtube-schemas.d.ts.map +1 -0
  436. package/dist/utils/youtube-schemas.js +148 -0
  437. package/dist/utils/youtube-schemas.js.map +1 -0
  438. package/dist/utils/youtube-search.d.ts +14 -0
  439. package/dist/utils/youtube-search.d.ts.map +1 -0
  440. package/dist/utils/youtube-search.js +39 -0
  441. package/dist/utils/youtube-search.js.map +1 -0
  442. package/dist/utils/youtube-url.d.ts +25 -0
  443. package/dist/utils/youtube-url.d.ts.map +1 -0
  444. package/dist/utils/youtube-url.js +75 -0
  445. package/dist/utils/youtube-url.js.map +1 -0
  446. package/dist/utils/youtube-video.d.ts +68 -0
  447. package/dist/utils/youtube-video.d.ts.map +1 -0
  448. package/dist/utils/youtube-video.js +110 -0
  449. package/dist/utils/youtube-video.js.map +1 -0
  450. package/dist/utils/youtube.d.ts +10 -122
  451. package/dist/utils/youtube.d.ts.map +1 -1
  452. package/dist/utils/youtube.js +11 -486
  453. package/dist/utils/youtube.js.map +1 -1
  454. package/dist/utils/ytdlp-env.d.ts +33 -0
  455. package/dist/utils/ytdlp-env.d.ts.map +1 -0
  456. package/dist/utils/ytdlp-env.js +121 -0
  457. package/dist/utils/ytdlp-env.js.map +1 -0
  458. package/dist/utils/ytdlp-limiter.d.ts +27 -0
  459. package/dist/utils/ytdlp-limiter.d.ts.map +1 -0
  460. package/dist/utils/ytdlp-limiter.js +85 -0
  461. package/dist/utils/ytdlp-limiter.js.map +1 -0
  462. package/dist/utils/ytdlp-pacer.d.ts +64 -0
  463. package/dist/utils/ytdlp-pacer.d.ts.map +1 -0
  464. package/dist/utils/ytdlp-pacer.js +165 -0
  465. package/dist/utils/ytdlp-pacer.js.map +1 -0
  466. package/dist/utils/ytdlp-parse.d.ts +13 -0
  467. package/dist/utils/ytdlp-parse.d.ts.map +1 -0
  468. package/dist/utils/ytdlp-parse.js +48 -0
  469. package/dist/utils/ytdlp-parse.js.map +1 -0
  470. package/dist/utils/ytdlp-stream.d.ts +32 -0
  471. package/dist/utils/ytdlp-stream.d.ts.map +1 -0
  472. package/dist/utils/ytdlp-stream.js +61 -0
  473. package/dist/utils/ytdlp-stream.js.map +1 -0
  474. package/dist/utils/ytdlp.d.ts +23 -18
  475. package/dist/utils/ytdlp.d.ts.map +1 -1
  476. package/dist/utils/ytdlp.js +56 -134
  477. package/dist/utils/ytdlp.js.map +1 -1
  478. package/package.json +3 -2
@@ -0,0 +1,127 @@
1
+ import { join } from 'path';
2
+ import { readFile, unlink } from 'fs/promises';
3
+ import { existsSync, readdirSync } from 'fs';
4
+ import { YouTubeError } from './errors.js';
5
+ import { TIMEOUTS, runYtDlp } from './ytdlp.js';
6
+ import { noCaptionsError } from './caption-probe.js';
7
+ import { assertLanguageTag } from './validate.js';
8
+ import { envInt } from './env.js';
9
+ import { dataDir, ensurePrivateDir } from './paths.js';
10
+ import { writeJsonAtomic } from './json-file.js';
11
+ import { TRANSCRIPT_CACHE_VERSION, cachedTranscriptSchema, parseVtt, segmentsToText, } from './transcript.js';
12
+ import { extractVideoId, watchUrl } from './youtube-url.js';
13
+ /** Fetching a transcript from YouTube and keeping it on disk. */
14
+ const CACHE_DIR = dataDir('transcripts');
15
+ /** Captions rarely change, but a cache with no expiry is a cache that goes wrong. */
16
+ const TRANSCRIPT_TTL_MS = envInt('YOUTUBE_MCP_TRANSCRIPT_TTL_MS', 30 * 86_400_000, { min: 0 });
17
+ function cachePath(videoId, language) {
18
+ return join(CACHE_DIR, `${videoId}.${language}.json`);
19
+ }
20
+ async function readCachedTranscript(videoId, language) {
21
+ const path = cachePath(videoId, language);
22
+ if (!existsSync(path))
23
+ return undefined;
24
+ try {
25
+ const parsed = cachedTranscriptSchema.safeParse(JSON.parse(await readFile(path, 'utf-8')));
26
+ // Anything unreadable — an older layout, a truncated write, a hand-edit —
27
+ // is treated as absent and refetched, rather than half-trusted.
28
+ if (!parsed.success)
29
+ return undefined;
30
+ const cached = parsed.data;
31
+ // A cache written by an older version holds untimed text; regenerate it
32
+ // rather than reading it back as if it had timings.
33
+ if (cached.version !== TRANSCRIPT_CACHE_VERSION)
34
+ return undefined;
35
+ const fetchedAt = Date.parse(cached.fetchedAt);
36
+ if (Number.isFinite(fetchedAt) && Date.now() - fetchedAt > TRANSCRIPT_TTL_MS)
37
+ return undefined;
38
+ return cached;
39
+ }
40
+ catch {
41
+ return undefined;
42
+ }
43
+ }
44
+ /** True when a usable transcript is already on disk, in any language. */
45
+ export function hasCachedTranscript(videoId) {
46
+ if (!existsSync(CACHE_DIR))
47
+ return false;
48
+ return readdirSync(CACHE_DIR).some((name) => name.startsWith(`${videoId}.`) && name.endsWith('.json'));
49
+ }
50
+ export async function getTranscript(urlOrId, options = {}) {
51
+ const preferredLang = options.language ?? 'en';
52
+ const videoId = extractVideoId(urlOrId);
53
+ assertLanguageTag(preferredLang);
54
+ const url = watchUrl(videoId);
55
+ await ensurePrivateDir(CACHE_DIR);
56
+ if (!options.refresh) {
57
+ const cached = await readCachedTranscript(videoId, preferredLang);
58
+ if (cached) {
59
+ return {
60
+ transcript: segmentsToText(cached.segments),
61
+ segments: cached.segments,
62
+ language: cached.language,
63
+ videoId,
64
+ cached: true,
65
+ };
66
+ }
67
+ }
68
+ const tempDir = join(CACHE_DIR, 'temp');
69
+ await ensurePrivateDir(tempDir);
70
+ const outputTemplate = join(tempDir, videoId);
71
+ try {
72
+ await runYtDlp([
73
+ '--skip-download',
74
+ '--write-auto-sub',
75
+ '--write-sub',
76
+ '--sub-lang',
77
+ `${preferredLang},${preferredLang}-orig`,
78
+ '--sub-format',
79
+ 'vtt',
80
+ '--convert-subs',
81
+ 'vtt',
82
+ '-o',
83
+ outputTemplate,
84
+ ], { label: 'get_transcript', timeoutMs: TIMEOUTS.transcript, target: url });
85
+ const candidates = [
86
+ { file: `${outputTemplate}.${preferredLang}.vtt`, language: preferredLang },
87
+ {
88
+ file: `${outputTemplate}.${preferredLang}-orig.vtt`,
89
+ language: `${preferredLang} (auto-generated)`,
90
+ },
91
+ { file: `${outputTemplate}.en.vtt`, language: 'en' },
92
+ ];
93
+ const found = candidates.find((candidate) => existsSync(candidate.file));
94
+ if (!found)
95
+ throw await noCaptionsError(url, preferredLang);
96
+ const segments = parseVtt(await readFile(found.file, 'utf-8'));
97
+ if (segments.length === 0)
98
+ throw await noCaptionsError(url, preferredLang);
99
+ const entry = {
100
+ version: TRANSCRIPT_CACHE_VERSION,
101
+ videoId,
102
+ language: found.language,
103
+ fetchedAt: new Date().toISOString(),
104
+ segments,
105
+ };
106
+ await writeJsonAtomic(cachePath(videoId, preferredLang), entry, { pretty: false });
107
+ await unlink(found.file).catch(() => undefined);
108
+ return {
109
+ transcript: segmentsToText(segments),
110
+ segments,
111
+ language: found.language,
112
+ videoId,
113
+ cached: false,
114
+ };
115
+ }
116
+ catch (error) {
117
+ // Already typed and actionable — pass it through rather than flattening it
118
+ // into a generic string, which is what the old wrapper did to every failure.
119
+ if (error instanceof YouTubeError)
120
+ throw error;
121
+ throw new YouTubeError('YTDLP_FAILED', `Could not read the transcript for ${videoId}.`, {
122
+ nextStep: 'Verify the video exists and has captions, or call check_health.',
123
+ cause: error,
124
+ });
125
+ }
126
+ }
127
+ //# sourceMappingURL=transcript-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transcript-cache.js","sourceRoot":"","sources":["../../src/utils/transcript-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { TranscriptSegment } from './transcript.js';
2
+ /** Finding a phrase in a transcript. */
3
+ export interface TranscriptMatch {
4
+ segment: TranscriptSegment;
5
+ /** The matched text, for highlighting. */
6
+ match: string;
7
+ url: string;
8
+ }
9
+ /**
10
+ * Find a compiled pattern in a transcript.
11
+ *
12
+ * Matching runs over the joined text of a small window of segments, not each
13
+ * segment alone, so a phrase split across a caption boundary is still found —
14
+ * which is most phrases, since caption breaks fall mid-sentence.
15
+ *
16
+ * The pattern arrives compiled (see `compilePattern`), so it was validated
17
+ * exactly once, with the flags in force here.
18
+ */
19
+ export declare function searchSegments(segments: TranscriptSegment[], pattern: RegExp, limit?: number): TranscriptMatch[];
20
+ //# sourceMappingURL=transcript-search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transcript-search.d.ts","sourceRoot":"","sources":["../../src/utils/transcript-search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,wCAAwC;AAExC,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,iBAAiB,CAAC;IAC3B,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,iBAAiB,EAAE,EAC7B,OAAO,EAAE,MAAM,EACf,KAAK,SAAK,GACT,eAAe,EAAE,CA0BnB"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Find a compiled pattern in a transcript.
3
+ *
4
+ * Matching runs over the joined text of a small window of segments, not each
5
+ * segment alone, so a phrase split across a caption boundary is still found —
6
+ * which is most phrases, since caption breaks fall mid-sentence.
7
+ *
8
+ * The pattern arrives compiled (see `compilePattern`), so it was validated
9
+ * exactly once, with the flags in force here.
10
+ */
11
+ export function searchSegments(segments, pattern, limit = 20) {
12
+ const matches = [];
13
+ for (let index = 0; index < segments.length && matches.length < limit; index++) {
14
+ const current = segments[index];
15
+ if (!current)
16
+ continue;
17
+ // Two segments of lookahead covers phrases spanning a caption break.
18
+ const haystack = segments
19
+ .slice(index, index + 3)
20
+ .map((segment) => segment.text)
21
+ .join(' ');
22
+ pattern.lastIndex = 0;
23
+ const found = pattern.exec(haystack);
24
+ if (!found)
25
+ continue;
26
+ // The lookahead window means a hit can start in a *later* segment. Only
27
+ // accept it here if it begins inside this one; otherwise the same hit is
28
+ // reported once per preceding segment, and attributed to the wrong time.
29
+ if (found.index > current.text.length)
30
+ continue;
31
+ matches.push({ segment: current, match: found[0], url: '' });
32
+ }
33
+ return matches;
34
+ }
35
+ //# sourceMappingURL=transcript-search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transcript-search.js","sourceRoot":"","sources":["../../src/utils/transcript-search.ts"],"names":[],"mappings":"AAWA;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAC5B,QAA6B,EAC7B,OAAe,EACf,KAAK,GAAG,EAAE;IAEV,MAAM,OAAO,GAAsB,EAAE,CAAC;IAEtC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,GAAG,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC;QAC/E,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;QAChC,IAAI,CAAC,OAAO;YAAE,SAAS;QAEvB,qEAAqE;QACrE,MAAM,QAAQ,GAAG,QAAQ;aACtB,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC;aACvB,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;aAC9B,IAAI,CAAC,GAAG,CAAC,CAAC;QAEb,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;QACtB,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACrC,IAAI,CAAC,KAAK;YAAE,SAAS;QAErB,wEAAwE;QACxE,yEAAyE;QACzE,yEAAyE;QACzE,IAAI,KAAK,CAAC,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM;YAAE,SAAS;QAEhD,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -15,15 +15,14 @@ export declare const transcriptSegmentSchema: z.ZodObject<{
15
15
  text: z.ZodString;
16
16
  }, "strip", z.ZodTypeAny, {
17
17
  text: string;
18
- start: number;
19
18
  end: number;
19
+ start: number;
20
20
  }, {
21
21
  text: string;
22
- start: number;
23
22
  end: number;
23
+ start: number;
24
24
  }>;
25
25
  export type TranscriptSegment = z.infer<typeof transcriptSegmentSchema>;
26
- export type TranscriptFormat = 'text' | 'timestamped' | 'segments';
27
26
  /** Bumped whenever the cache representation changes, so old files are refetched. */
28
27
  export declare const TRANSCRIPT_CACHE_VERSION = 2;
29
28
  /**
@@ -47,39 +46,37 @@ export declare const cachedTranscriptSchema: z.ZodObject<{
47
46
  text: z.ZodString;
48
47
  }, "strip", z.ZodTypeAny, {
49
48
  text: string;
50
- start: number;
51
49
  end: number;
50
+ start: number;
52
51
  }, {
53
52
  text: string;
54
- start: number;
55
53
  end: number;
54
+ start: number;
56
55
  }>, "many">;
57
56
  }, "strip", z.ZodTypeAny, {
58
57
  videoId: string;
59
58
  version: number;
60
59
  language: string;
60
+ fetchedAt: string;
61
61
  segments: {
62
62
  text: string;
63
- start: number;
64
63
  end: number;
64
+ start: number;
65
65
  }[];
66
- fetchedAt: string;
67
66
  }, {
68
67
  videoId: string;
69
68
  version: number;
70
69
  language: string;
70
+ fetchedAt: string;
71
71
  segments: {
72
72
  text: string;
73
- start: number;
74
73
  end: number;
74
+ start: number;
75
75
  }[];
76
- fetchedAt: string;
77
76
  }>;
78
77
  export type CachedTranscript = z.infer<typeof cachedTranscriptSchema>;
79
78
  /** 3723.5 -> "1:02:03", 62 -> "1:02" */
80
79
  export declare function formatTimestamp(totalSeconds: number): string;
81
- /** 3723.5 -> "01:02:03,500" — the SRT wire format. */
82
- export declare function formatSrtTimestamp(totalSeconds: number): string;
83
80
  /**
84
81
  * Parse WebVTT into segments.
85
82
  *
@@ -105,24 +102,6 @@ export declare function sliceSegments(segments: TranscriptSegment[], range: {
105
102
  startTime?: number;
106
103
  endTime?: number;
107
104
  }): TranscriptSegment[];
108
- export interface TranscriptMatch {
109
- segment: TranscriptSegment;
110
- /** The matched text, for highlighting. */
111
- match: string;
112
- url: string;
113
- }
114
- /**
115
- * Find a phrase or pattern in a transcript.
116
- *
117
- * Matching runs over the joined text of a small window of segments, not each
118
- * segment alone, so a phrase split across a caption boundary is still found —
119
- * which is most phrases, since caption breaks fall mid-sentence.
120
- */
121
- export declare function searchSegments(segments: TranscriptSegment[], query: string, options?: {
122
- regex?: boolean;
123
- caseSensitive?: boolean;
124
- limit?: number;
125
- }): TranscriptMatch[];
126
105
  export interface TruncationResult {
127
106
  text: string;
128
107
  truncated: boolean;
@@ -138,6 +117,6 @@ export interface TruncationResult {
138
117
  * continue from.
139
118
  */
140
119
  export declare function windowText(text: string, offset?: number, maxChars?: number): TruncationResult;
141
- export declare function toSrt(segments: TranscriptSegment[]): string;
142
- export declare function toVtt(segments: TranscriptSegment[]): string;
120
+ export * from './subtitles.js';
121
+ export * from './transcript-search.js';
143
122
  //# sourceMappingURL=transcript.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"transcript.d.ts","sourceRoot":"","sources":["../../src/utils/transcript.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;;;;;;GAQG;AAEH,eAAO,MAAM,uBAAuB;IAClC,2CAA2C;;;;;;;;;;;;EAI3C,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,aAAa,GAAG,UAAU,CAAC;AAEnE,oFAAoF;AACpF,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB;;;;;;QAtBjC,2CAA2C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4B3C,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,wCAAwC;AACxC,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAS5D;AAED,sDAAsD;AACtD,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAS/D;AA0BD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,iBAAiB,EAAE,CA4BhE;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,MAAM,CAMpE;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,MAAM,CAI3E;AAED,iDAAiD;AACjD,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED,8EAA8E;AAC9E,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,iBAAiB,EAAE,EAC7B,KAAK,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9C,iBAAiB,EAAE,CAOrB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,iBAAiB,CAAC;IAC3B,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,iBAAiB,EAAE,EAC7B,KAAK,EAAE,MAAM,EACb,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GACzE,eAAe,EAAE,CAiCnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,SAAI,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAcxF;AAED,wBAAgB,KAAK,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,MAAM,CAY3D;AAED,wBAAgB,KAAK,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,MAAM,CAW3D"}
1
+ {"version":3,"file":"transcript.d.ts","sourceRoot":"","sources":["../../src/utils/transcript.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;;;;;;GAQG;AAEH,eAAO,MAAM,uBAAuB;IAClC,2CAA2C;;;;;;;;;;;;EAI3C,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE,oFAAoF;AACpF,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB;;;;;;QApBjC,2CAA2C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0B3C,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,wCAAwC;AACxC,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAS5D;AA0BD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,iBAAiB,EAAE,CA4BhE;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,MAAM,CAMpE;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,MAAM,CAI3E;AAED,iDAAiD;AACjD,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED,8EAA8E;AAC9E,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,iBAAiB,EAAE,EAC7B,KAAK,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9C,iBAAiB,EAAE,CAOrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,SAAI,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAcxF;AAED,cAAc,gBAAgB,CAAC;AAC/B,cAAc,wBAAwB,CAAC"}
@@ -44,16 +44,6 @@ export function formatTimestamp(totalSeconds) {
44
44
  return `${hours}:${minutes.toString().padStart(2, '0')}:${paddedSeconds}`;
45
45
  return `${minutes}:${paddedSeconds}`;
46
46
  }
47
- /** 3723.5 -> "01:02:03,500" — the SRT wire format. */
48
- export function formatSrtTimestamp(totalSeconds) {
49
- const clamped = Math.max(0, totalSeconds);
50
- const hours = Math.floor(clamped / 3600);
51
- const minutes = Math.floor((clamped % 3600) / 60);
52
- const seconds = Math.floor(clamped % 60);
53
- const millis = Math.round((clamped - Math.floor(clamped)) * 1000);
54
- const pad = (value, width = 2) => value.toString().padStart(width, '0');
55
- return `${pad(hours)}:${pad(minutes)}:${pad(seconds)},${pad(millis, 3)}`;
56
- }
57
47
  /**
58
48
  * WebVTT cue text is a small markup language: inline timestamps and <c> spans
59
49
  * for karaoke-style highlighting. The parser hands back the spec's parsed tree,
@@ -143,42 +133,6 @@ export function sliceSegments(segments, range) {
143
133
  // relevant to the range the caller asked about.
144
134
  return segments.filter((segment) => segment.end > from && segment.start < to);
145
135
  }
146
- /**
147
- * Find a phrase or pattern in a transcript.
148
- *
149
- * Matching runs over the joined text of a small window of segments, not each
150
- * segment alone, so a phrase split across a caption boundary is still found —
151
- * which is most phrases, since caption breaks fall mid-sentence.
152
- */
153
- export function searchSegments(segments, query, options = {}) {
154
- const { regex = false, caseSensitive = false, limit = 20 } = options;
155
- const flags = caseSensitive ? 'g' : 'gi';
156
- const pattern = regex
157
- ? new RegExp(query, flags)
158
- : new RegExp(query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), flags);
159
- const matches = [];
160
- for (let index = 0; index < segments.length && matches.length < limit; index++) {
161
- const current = segments[index];
162
- if (!current)
163
- continue;
164
- // Two segments of lookahead covers phrases spanning a caption break.
165
- const haystack = segments
166
- .slice(index, index + 3)
167
- .map((segment) => segment.text)
168
- .join(' ');
169
- pattern.lastIndex = 0;
170
- const found = pattern.exec(haystack);
171
- if (!found)
172
- continue;
173
- // The lookahead window means a hit can start in a *later* segment. Only
174
- // accept it here if it begins inside this one; otherwise the same hit is
175
- // reported once per preceding segment, and attributed to the wrong time.
176
- if (found.index > current.text.length)
177
- continue;
178
- matches.push({ segment: current, match: found[0], url: '' });
179
- }
180
- return matches;
181
- }
182
136
  /**
183
137
  * Window a long string.
184
138
  *
@@ -198,22 +152,6 @@ export function windowText(text, offset = 0, maxChars) {
198
152
  const end = softEnd > from ? softEnd : hardEnd;
199
153
  return { text: text.slice(from, end), truncated: true, nextOffset: end, totalChars };
200
154
  }
201
- export function toSrt(segments) {
202
- return (segments
203
- .map((segment, index) => [
204
- index + 1,
205
- `${formatSrtTimestamp(segment.start)} --> ${formatSrtTimestamp(segment.end)}`,
206
- segment.text,
207
- ].join('\n'))
208
- .join('\n\n') + '\n');
209
- }
210
- export function toVtt(segments) {
211
- const body = segments
212
- .map((segment) => [
213
- `${formatSrtTimestamp(segment.start).replace(',', '.')} --> ${formatSrtTimestamp(segment.end).replace(',', '.')}`,
214
- segment.text,
215
- ].join('\n'))
216
- .join('\n\n');
217
- return `WEBVTT\n\n${body}\n`;
218
- }
155
+ export * from './subtitles.js';
156
+ export * from './transcript-search.js';
219
157
  //# sourceMappingURL=transcript.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"transcript.js","sourceRoot":"","sources":["../../src/utils/transcript.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,MAAM,MAAM,eAAe,CAAC;AAEnC;;;;;;;;GAQG;AAEH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,2CAA2C;IAC3C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE;IACf,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;CACjB,CAAC,CAAC;AAMH,oFAAoF;AACpF,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC;AAE1C;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7C,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;IACpB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,uBAAuB,CAAC;CAC3C,CAAC,CAAC;AAIH,wCAAwC;AACxC,MAAM,UAAU,eAAe,CAAC,YAAoB;IAClD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC;IACpD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,KAAK,GAAG,EAAE,CAAC;IAE3B,MAAM,aAAa,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC1D,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,GAAG,KAAK,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,aAAa,EAAE,CAAC;IACzF,OAAO,GAAG,OAAO,IAAI,aAAa,EAAE,CAAC;AACvC,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,kBAAkB,CAAC,YAAoB;IACrD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAElE,MAAM,GAAG,GAAG,CAAC,KAAa,EAAE,KAAK,GAAG,CAAC,EAAU,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACxF,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC;AAC3E,CAAC;AAED;;;;;GAKG;AACH,SAAS,aAAa,CAAC,IAAyD;IAC9E,8EAA8E;IAC9E,sEAAsE;IACtE,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,MAAM;YACT,OAAO,IAAI,CAAC,KAAK,CAAC;QACpB,KAAK,WAAW;YACd,sDAAsD;YACtD,OAAO,EAAE,CAAC;QACZ,KAAK,QAAQ;YACX,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACrD,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,IAAiB;IACtC,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACnD,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,QAAQ,CAAC,UAAkB;IACzC,0EAA0E;IAC1E,0EAA0E;IAC1E,kDAAkD;IAClD,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IAEzE,MAAM,QAAQ,GAAwB,EAAE,CAAC;IACzC,IAAI,QAAQ,GAAG,EAAE,CAAC;IAElB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,KAAK,MAAM,IAAI,IAAI,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACvD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YACzB,IAAI,IAAI,KAAK,EAAE,IAAI,IAAI,KAAK,QAAQ;gBAAE,SAAS;YAE/C,MAAM,QAAQ,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YACjC,IAAI,QAAQ,EAAE,KAAK,KAAK,GAAG,CAAC,SAAS,EAAE,CAAC;gBACtC,+CAA+C;gBAC/C,QAAQ,CAAC,IAAI,GAAG,GAAG,QAAQ,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;gBAC3C,QAAQ,CAAC,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC;YAC7B,CAAC;iBAAM,CAAC;gBACN,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YAClE,CAAC;YAED,QAAQ,GAAG,IAAI,CAAC;QAClB,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,QAA6B;IAC1D,OAAO,QAAQ;SACZ,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;SAC9B,IAAI,CAAC,GAAG,CAAC;SACT,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,QAA6B;IACjE,OAAO,QAAQ;SACZ,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,eAAe,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,OAAO,CAAC,IAAI,EAAE,CAAC;SACvE,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,QAAQ,CAAC,OAAe,EAAE,OAAe;IACvD,OAAO,mCAAmC,OAAO,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC;AAC7F,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,aAAa,CAC3B,QAA6B,EAC7B,KAA+C;IAE/C,MAAM,IAAI,GAAG,KAAK,CAAC,SAAS,IAAI,MAAM,CAAC,iBAAiB,CAAC;IACzD,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,IAAI,MAAM,CAAC,iBAAiB,CAAC;IAErD,uEAAuE;IACvE,gDAAgD;IAChD,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,GAAG,IAAI,IAAI,OAAO,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC;AAChF,CAAC;AASD;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,QAA6B,EAC7B,KAAa,EACb,UAAwE,EAAE;IAE1E,MAAM,EAAE,KAAK,GAAG,KAAK,EAAE,aAAa,GAAG,KAAK,EAAE,KAAK,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC;IAErE,MAAM,KAAK,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;IACzC,MAAM,OAAO,GAAG,KAAK;QACnB,CAAC,CAAC,IAAI,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC;QAC1B,CAAC,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,EAAE,KAAK,CAAC,CAAC;IAEpE,MAAM,OAAO,GAAsB,EAAE,CAAC;IAEtC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,GAAG,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC;QAC/E,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;QAChC,IAAI,CAAC,OAAO;YAAE,SAAS;QAEvB,qEAAqE;QACrE,MAAM,QAAQ,GAAG,QAAQ;aACtB,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC;aACvB,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;aAC9B,IAAI,CAAC,GAAG,CAAC,CAAC;QAEb,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;QACtB,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACrC,IAAI,CAAC,KAAK;YAAE,SAAS;QAErB,wEAAwE;QACxE,yEAAyE;QACzE,yEAAyE;QACzE,IAAI,KAAK,CAAC,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM;YAAE,SAAS;QAEhD,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAUD;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,MAAM,GAAG,CAAC,EAAE,QAAiB;IACpE,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC;IAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC;IAEvD,IAAI,QAAQ,KAAK,SAAS,IAAI,IAAI,GAAG,QAAQ,IAAI,UAAU,EAAE,CAAC;QAC5D,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;IAClE,CAAC;IAED,gEAAgE;IAChE,MAAM,OAAO,GAAG,IAAI,GAAG,QAAQ,CAAC;IAChC,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC/C,MAAM,GAAG,GAAG,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;IAE/C,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC;AACvF,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,QAA6B;IACjD,OAAO,CACL,QAAQ;SACL,GAAG,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CACtB;QACE,KAAK,GAAG,CAAC;QACT,GAAG,kBAAkB,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;QAC7E,OAAO,CAAC,IAAI;KACb,CAAC,IAAI,CAAC,IAAI,CAAC,CACb;SACA,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CACvB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,QAA6B;IACjD,MAAM,IAAI,GAAG,QAAQ;SAClB,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CACf;QACE,GAAG,kBAAkB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,QAAQ,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE;QACjH,OAAO,CAAC,IAAI;KACb,CAAC,IAAI,CAAC,IAAI,CAAC,CACb;SACA,IAAI,CAAC,MAAM,CAAC,CAAC;IAEhB,OAAO,aAAa,IAAI,IAAI,CAAC;AAC/B,CAAC"}
1
+ {"version":3,"file":"transcript.js","sourceRoot":"","sources":["../../src/utils/transcript.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * The identifiers and URLs this server is willing to hand to yt-dlp.
3
+ *
4
+ * A tool argument is model-controlled, and yt-dlp's generic extractor will
5
+ * fetch any URL it is given — including internal addresses — so anything that
6
+ * becomes a yt-dlp target is checked here first. Ids are also filenames, so the
7
+ * real formats are matched exactly rather than sanitised.
8
+ */
9
+ /** YouTube video ids are 11 base64url characters. */
10
+ export declare const VIDEO_ID_PATTERN: RegExp;
11
+ export declare function assertVideoId(videoId: string): string;
12
+ /**
13
+ * YouTube channel ids are `UC` followed by 22 base64url characters.
14
+ *
15
+ * This is stricter than it looks like it needs to be. A channel id arrives from
16
+ * yt-dlp's output and is then used as a directory name under
17
+ * `~/.youtube-knowledge/brains`, so a value containing a separator or `..`
18
+ * would write outside that tree. Matching the real format exactly is cheaper
19
+ * than sanitising a value that should never have been unusual.
20
+ */
21
+ export declare const CHANNEL_ID_PATTERN: RegExp;
22
+ export declare function assertChannelId(channelId: string): string;
23
+ /** The hosts yt-dlp may be pointed at. Anything else is refused before it spawns. */
24
+ export declare const YOUTUBE_HOSTS: readonly ["youtube.com", "www.youtube.com", "m.youtube.com", "music.youtube.com", "youtu.be", "www.youtube-nocookie.com"];
25
+ /**
26
+ * Validate a caller-supplied URL and return it normalised to https.
27
+ *
28
+ * `http:` is upgraded rather than refused, and a URL written without a scheme
29
+ * but starting with a YouTube host is accepted, because both are things people
30
+ * paste. Everything else — other hosts, other schemes, credentials, ports — is
31
+ * an `INVALID_INPUT`, since the only reason to send one is to make yt-dlp fetch
32
+ * something that is not YouTube.
33
+ */
34
+ export declare function assertYouTubeUrl(input: string): string;
35
+ //# sourceMappingURL=validate-youtube.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-youtube.d.ts","sourceRoot":"","sources":["../../src/utils/validate-youtube.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,qDAAqD;AACrD,eAAO,MAAM,gBAAgB,QAAwB,CAAC;AAEtD,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAOrD;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,QAA0B,CAAC;AAE1D,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAYzD;AAED,qFAAqF;AACrF,eAAO,MAAM,aAAa,2HAOhB,CAAC;AAKX;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAqBtD"}
@@ -0,0 +1,87 @@
1
+ import { YouTubeError } from './errors.js';
2
+ /**
3
+ * The identifiers and URLs this server is willing to hand to yt-dlp.
4
+ *
5
+ * A tool argument is model-controlled, and yt-dlp's generic extractor will
6
+ * fetch any URL it is given — including internal addresses — so anything that
7
+ * becomes a yt-dlp target is checked here first. Ids are also filenames, so the
8
+ * real formats are matched exactly rather than sanitised.
9
+ */
10
+ /** YouTube video ids are 11 base64url characters. */
11
+ export const VIDEO_ID_PATTERN = /^[A-Za-z0-9_-]{11}$/;
12
+ export function assertVideoId(videoId) {
13
+ if (!VIDEO_ID_PATTERN.test(videoId)) {
14
+ throw new YouTubeError('INVALID_INPUT', `"${clip(videoId)}" is not a valid YouTube video id.`, {
15
+ nextStep: 'Video ids are 11 characters, for example dQw4w9WgXcQ.',
16
+ });
17
+ }
18
+ return videoId;
19
+ }
20
+ /**
21
+ * YouTube channel ids are `UC` followed by 22 base64url characters.
22
+ *
23
+ * This is stricter than it looks like it needs to be. A channel id arrives from
24
+ * yt-dlp's output and is then used as a directory name under
25
+ * `~/.youtube-knowledge/brains`, so a value containing a separator or `..`
26
+ * would write outside that tree. Matching the real format exactly is cheaper
27
+ * than sanitising a value that should never have been unusual.
28
+ */
29
+ export const CHANNEL_ID_PATTERN = /^UC[A-Za-z0-9_-]{22}$/;
30
+ export function assertChannelId(channelId) {
31
+ if (!CHANNEL_ID_PATTERN.test(channelId)) {
32
+ throw new YouTubeError('INVALID_INPUT', `"${clip(channelId)}" is not a valid YouTube channel id.`, {
33
+ nextStep: 'Channel ids look like UCxxxxxxxxxxxxxxxxxxxxxx. Call get_channel_info or list_brains to get one.',
34
+ });
35
+ }
36
+ return channelId;
37
+ }
38
+ /** The hosts yt-dlp may be pointed at. Anything else is refused before it spawns. */
39
+ export const YOUTUBE_HOSTS = [
40
+ 'youtube.com',
41
+ 'www.youtube.com',
42
+ 'm.youtube.com',
43
+ 'music.youtube.com',
44
+ 'youtu.be',
45
+ 'www.youtube-nocookie.com',
46
+ ];
47
+ const HOST_SET = new Set(YOUTUBE_HOSTS);
48
+ const SCHEMELESS_YOUTUBE = /^(?:www\.|m\.|music\.)?(?:youtube\.com|youtu\.be)\//i;
49
+ /**
50
+ * Validate a caller-supplied URL and return it normalised to https.
51
+ *
52
+ * `http:` is upgraded rather than refused, and a URL written without a scheme
53
+ * but starting with a YouTube host is accepted, because both are things people
54
+ * paste. Everything else — other hosts, other schemes, credentials, ports — is
55
+ * an `INVALID_INPUT`, since the only reason to send one is to make yt-dlp fetch
56
+ * something that is not YouTube.
57
+ */
58
+ export function assertYouTubeUrl(input) {
59
+ const trimmed = input.trim();
60
+ const candidate = SCHEMELESS_YOUTUBE.test(trimmed) ? `https://${trimmed}` : trimmed;
61
+ let url;
62
+ try {
63
+ url = new URL(candidate);
64
+ }
65
+ catch {
66
+ throw notYouTube(input);
67
+ }
68
+ if (url.protocol === 'http:')
69
+ url.protocol = 'https:';
70
+ const wrongScheme = url.protocol !== 'https:';
71
+ const wrongHost = !HOST_SET.has(url.hostname.toLowerCase());
72
+ const hasCredentials = url.username !== '' || url.password !== '';
73
+ const hasPort = url.port !== '';
74
+ if (wrongScheme || wrongHost || hasCredentials || hasPort)
75
+ throw notYouTube(input);
76
+ return url.toString();
77
+ }
78
+ function notYouTube(input) {
79
+ return new YouTubeError('INVALID_INPUT', `"${clip(input)}" is not a YouTube URL.`, {
80
+ nextStep: `Pass an https URL on one of: ${YOUTUBE_HOSTS.join(', ')}.`,
81
+ });
82
+ }
83
+ /** Keeps a rejected value from flooding the error message it is quoted in. */
84
+ function clip(value) {
85
+ return value.length > 64 ? `${value.slice(0, 61)}...` : value;
86
+ }
87
+ //# sourceMappingURL=validate-youtube.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-youtube.js","sourceRoot":"","sources":["../../src/utils/validate-youtube.ts"],"names":[],"mappings":"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"}
@@ -1,17 +1,24 @@
1
1
  /**
2
2
  * Input validation for the values that reach the filesystem or yt-dlp's
3
- * language negotiation. Zod already constrains shapes at the tool boundary;
3
+ * language negotiation. The YouTube-specific checks — ids and URLs — live in
4
+ * validate-youtube.ts and are re-exported here. Zod already constrains shapes at the tool boundary;
4
5
  * these are the checks Zod cannot express.
5
6
  */
6
7
  /**
7
- * Resolve a caller-supplied output directory.
8
+ * Prove that a caller-supplied path lies inside the home directory.
8
9
  *
9
10
  * A tool argument is model-controlled, so it must not be able to write outside
10
- * the user's home directory or reach the filesystem root through `..`.
11
+ * the user's home directory or reach the filesystem root through `..`. The
12
+ * check is made on the real path: a symlink inside home that points outside it
13
+ * passed a purely lexical comparison, and yt-dlp and ffmpeg then wrote through
14
+ * it. The nearest existing ancestor is resolved and the missing tail re-joined,
15
+ * so a directory that does not exist yet is judged by where it would be created.
11
16
  */
17
+ export declare function assertInsideHome(input: string, what: string): string;
18
+ /** Resolve a caller-supplied output directory, or the fallback when none is given. */
12
19
  export declare function resolveOutputDir(outputDir: string | undefined, fallback: string): string;
13
20
  export declare function assertLanguageTag(language: string): string;
14
- export declare function assertChannelId(channelId: string): string;
15
21
  /** Accepts `90`, `1:30`, `01:02:03`, `1:30.5` and returns seconds. */
16
22
  export declare function parseTimestamp(value: string | number, field: string): number;
23
+ export * from './validate-youtube.js';
17
24
  //# sourceMappingURL=validate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/utils/validate.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AAEH;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAyBxF;AAKD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAO1D;AAaD,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAQzD;AAED,sEAAsE;AACtE,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAoB5E"}
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/utils/validate.ts"],"names":[],"mappings":"AAKA;;;;;GAKG;AAEH;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAqBpE;AAkBD,sFAAsF;AACtF,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGxF;AAKD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAO1D;AAED,sEAAsE;AACtE,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAoB5E;AAED,cAAc,uBAAuB,CAAC"}