youtube-knowledge-mcp 2.0.2 → 2.2.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 (390) hide show
  1. package/README.md +166 -33
  2. package/dist/brain-schemas.d.ts +502 -0
  3. package/dist/brain-schemas.d.ts.map +1 -0
  4. package/dist/brain-schemas.js +109 -0
  5. package/dist/brain-schemas.js.map +1 -0
  6. package/dist/http/app.d.ts +16 -0
  7. package/dist/http/app.d.ts.map +1 -0
  8. package/dist/http/app.js +176 -0
  9. package/dist/http/app.js.map +1 -0
  10. package/dist/http/auth.d.ts +38 -0
  11. package/dist/http/auth.d.ts.map +1 -0
  12. package/dist/http/auth.js +79 -0
  13. package/dist/http/auth.js.map +1 -0
  14. package/dist/http/config.d.ts +41 -0
  15. package/dist/http/config.d.ts.map +1 -0
  16. package/dist/http/config.js +65 -0
  17. package/dist/http/config.js.map +1 -0
  18. package/dist/http/rate-limiter.d.ts +24 -0
  19. package/dist/http/rate-limiter.d.ts.map +1 -0
  20. package/dist/http/rate-limiter.js +55 -0
  21. package/dist/http/rate-limiter.js.map +1 -0
  22. package/dist/http/sessions.d.ts +34 -0
  23. package/dist/http/sessions.d.ts.map +1 -0
  24. package/dist/http/sessions.js +62 -0
  25. package/dist/http/sessions.js.map +1 -0
  26. package/dist/http.d.ts +6 -48
  27. package/dist/http.d.ts.map +1 -1
  28. package/dist/http.js +35 -252
  29. package/dist/http.js.map +1 -1
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +11 -431
  32. package/dist/index.js.map +1 -1
  33. package/dist/prompts-brain.d.ts +4 -0
  34. package/dist/prompts-brain.d.ts.map +1 -0
  35. package/dist/prompts-brain.js +48 -0
  36. package/dist/prompts-brain.js.map +1 -0
  37. package/dist/prompts-research.d.ts +4 -0
  38. package/dist/prompts-research.d.ts.map +1 -0
  39. package/dist/prompts-research.js +74 -0
  40. package/dist/prompts-research.js.map +1 -0
  41. package/dist/prompts-shared.d.ts +13 -0
  42. package/dist/prompts-shared.d.ts.map +1 -0
  43. package/dist/prompts-shared.js +7 -0
  44. package/dist/prompts-shared.js.map +1 -0
  45. package/dist/prompts.d.ts.map +1 -1
  46. package/dist/prompts.js +5 -58
  47. package/dist/prompts.js.map +1 -1
  48. package/dist/registry/brain-tools.d.ts +4 -0
  49. package/dist/registry/brain-tools.d.ts.map +1 -0
  50. package/dist/registry/brain-tools.js +104 -0
  51. package/dist/registry/brain-tools.js.map +1 -0
  52. package/dist/registry/channel-tools.d.ts +4 -0
  53. package/dist/registry/channel-tools.d.ts.map +1 -0
  54. package/dist/registry/channel-tools.js +53 -0
  55. package/dist/registry/channel-tools.js.map +1 -0
  56. package/dist/registry/health-tools.d.ts +4 -0
  57. package/dist/registry/health-tools.d.ts.map +1 -0
  58. package/dist/registry/health-tools.js +21 -0
  59. package/dist/registry/health-tools.js.map +1 -0
  60. package/dist/registry/index.d.ts +8 -0
  61. package/dist/registry/index.d.ts.map +1 -0
  62. package/dist/registry/index.js +27 -0
  63. package/dist/registry/index.js.map +1 -0
  64. package/dist/registry/library-tools.d.ts +4 -0
  65. package/dist/registry/library-tools.d.ts.map +1 -0
  66. package/dist/registry/library-tools.js +116 -0
  67. package/dist/registry/library-tools.js.map +1 -0
  68. package/dist/registry/media-tools.d.ts +4 -0
  69. package/dist/registry/media-tools.d.ts.map +1 -0
  70. package/dist/registry/media-tools.js +100 -0
  71. package/dist/registry/media-tools.js.map +1 -0
  72. package/dist/registry/thumbnail-tools.d.ts +7 -0
  73. package/dist/registry/thumbnail-tools.d.ts.map +1 -0
  74. package/dist/registry/thumbnail-tools.js +72 -0
  75. package/dist/registry/thumbnail-tools.js.map +1 -0
  76. package/dist/registry/transcript-tools.d.ts +4 -0
  77. package/dist/registry/transcript-tools.d.ts.map +1 -0
  78. package/dist/registry/transcript-tools.js +68 -0
  79. package/dist/registry/transcript-tools.js.map +1 -0
  80. package/dist/registry/types.d.ts +41 -0
  81. package/dist/registry/types.d.ts.map +1 -0
  82. package/dist/registry/types.js +17 -0
  83. package/dist/registry/types.js.map +1 -0
  84. package/dist/registry/video-tools.d.ts +4 -0
  85. package/dist/registry/video-tools.d.ts.map +1 -0
  86. package/dist/registry/video-tools.js +101 -0
  87. package/dist/registry/video-tools.js.map +1 -0
  88. package/dist/resources.d.ts.map +1 -1
  89. package/dist/resources.js +75 -6
  90. package/dist/resources.js.map +1 -1
  91. package/dist/schemas.d.ts +74 -54
  92. package/dist/schemas.d.ts.map +1 -1
  93. package/dist/schemas.js +30 -4
  94. package/dist/schemas.js.map +1 -1
  95. package/dist/thumbnail-resource.d.ts +8 -0
  96. package/dist/thumbnail-resource.d.ts.map +1 -0
  97. package/dist/thumbnail-resource.js +38 -0
  98. package/dist/thumbnail-resource.js.map +1 -0
  99. package/dist/thumbnail-schemas.d.ts +512 -0
  100. package/dist/thumbnail-schemas.d.ts.map +1 -0
  101. package/dist/thumbnail-schemas.js +95 -0
  102. package/dist/thumbnail-schemas.js.map +1 -0
  103. package/dist/tools/ask-brain.d.ts +62 -0
  104. package/dist/tools/ask-brain.d.ts.map +1 -0
  105. package/dist/tools/ask-brain.js +70 -0
  106. package/dist/tools/ask-brain.js.map +1 -0
  107. package/dist/tools/batch.d.ts +10 -10
  108. package/dist/tools/batch.js +3 -3
  109. package/dist/tools/batch.js.map +1 -1
  110. package/dist/tools/brain-info.d.ts +180 -0
  111. package/dist/tools/brain-info.d.ts.map +1 -0
  112. package/dist/tools/brain-info.js +108 -0
  113. package/dist/tools/brain-info.js.map +1 -0
  114. package/dist/tools/build-brain.d.ts +120 -0
  115. package/dist/tools/build-brain.d.ts.map +1 -0
  116. package/dist/tools/build-brain.js +123 -0
  117. package/dist/tools/build-brain.js.map +1 -0
  118. package/dist/tools/check-health.d.ts +2 -0
  119. package/dist/tools/check-health.d.ts.map +1 -1
  120. package/dist/tools/check-health.js +9 -0
  121. package/dist/tools/check-health.js.map +1 -1
  122. package/dist/tools/clips.d.ts +13 -45
  123. package/dist/tools/clips.d.ts.map +1 -1
  124. package/dist/tools/clips.js +52 -128
  125. package/dist/tools/clips.js.map +1 -1
  126. package/dist/tools/fetch-channel-thumbnails.d.ts +179 -0
  127. package/dist/tools/fetch-channel-thumbnails.d.ts.map +1 -0
  128. package/dist/tools/fetch-channel-thumbnails.js +123 -0
  129. package/dist/tools/fetch-channel-thumbnails.js.map +1 -0
  130. package/dist/tools/fetch-videos.d.ts +11 -8
  131. package/dist/tools/fetch-videos.d.ts.map +1 -1
  132. package/dist/tools/fetch-videos.js +3 -0
  133. package/dist/tools/fetch-videos.js.map +1 -1
  134. package/dist/tools/frames-subtitles.d.ts +44 -0
  135. package/dist/tools/frames-subtitles.d.ts.map +1 -0
  136. package/dist/tools/frames-subtitles.js +104 -0
  137. package/dist/tools/frames-subtitles.js.map +1 -0
  138. package/dist/tools/get-channel-info.d.ts +2 -0
  139. package/dist/tools/get-channel-info.d.ts.map +1 -1
  140. package/dist/tools/get-channel-info.js +8 -1
  141. package/dist/tools/get-channel-info.js.map +1 -1
  142. package/dist/tools/get-chapters.d.ts +2 -2
  143. package/dist/tools/get-comments.d.ts +2 -2
  144. package/dist/tools/get-playlist-info.d.ts.map +1 -1
  145. package/dist/tools/get-playlist-info.js +1 -0
  146. package/dist/tools/get-playlist-info.js.map +1 -1
  147. package/dist/tools/get-thumbnail.d.ts +38 -0
  148. package/dist/tools/get-thumbnail.d.ts.map +1 -0
  149. package/dist/tools/get-thumbnail.js +152 -0
  150. package/dist/tools/get-thumbnail.js.map +1 -0
  151. package/dist/tools/get-transcript.d.ts +2 -2
  152. package/dist/tools/get-transcript.d.ts.map +1 -1
  153. package/dist/tools/get-transcript.js +2 -14
  154. package/dist/tools/get-transcript.js.map +1 -1
  155. package/dist/tools/library.d.ts +9 -7
  156. package/dist/tools/library.d.ts.map +1 -1
  157. package/dist/tools/library.js +23 -7
  158. package/dist/tools/library.js.map +1 -1
  159. package/dist/tools/list-channel-thumbnails.d.ts +235 -0
  160. package/dist/tools/list-channel-thumbnails.d.ts.map +1 -0
  161. package/dist/tools/list-channel-thumbnails.js +79 -0
  162. package/dist/tools/list-channel-thumbnails.js.map +1 -0
  163. package/dist/tools/list-library.d.ts +4 -4
  164. package/dist/tools/manage-brain.d.ts +39 -0
  165. package/dist/tools/manage-brain.d.ts.map +1 -0
  166. package/dist/tools/manage-brain.js +53 -0
  167. package/dist/tools/manage-brain.js.map +1 -0
  168. package/dist/tools/save-to-library.d.ts.map +1 -1
  169. package/dist/tools/save-to-library.js +5 -1
  170. package/dist/tools/save-to-library.js.map +1 -1
  171. package/dist/tools/search-channels.d.ts +10 -4
  172. package/dist/tools/search-channels.d.ts.map +1 -1
  173. package/dist/tools/search-transcript.d.ts +2 -2
  174. package/dist/tools/search-transcript.d.ts.map +1 -1
  175. package/dist/tools/search-transcript.js +6 -13
  176. package/dist/tools/search-transcript.js.map +1 -1
  177. package/dist/tools/search-videos.d.ts +11 -8
  178. package/dist/tools/search-videos.d.ts.map +1 -1
  179. package/dist/utils/batches.d.ts +15 -0
  180. package/dist/utils/batches.d.ts.map +1 -0
  181. package/dist/utils/batches.js +31 -0
  182. package/dist/utils/batches.js.map +1 -0
  183. package/dist/utils/brain-build.d.ts +40 -0
  184. package/dist/utils/brain-build.d.ts.map +1 -0
  185. package/dist/utils/brain-build.js +200 -0
  186. package/dist/utils/brain-build.js.map +1 -0
  187. package/dist/utils/brain-chunks.d.ts +33 -0
  188. package/dist/utils/brain-chunks.d.ts.map +1 -0
  189. package/dist/utils/brain-chunks.js +87 -0
  190. package/dist/utils/brain-chunks.js.map +1 -0
  191. package/dist/utils/brain-index.d.ts +27 -0
  192. package/dist/utils/brain-index.d.ts.map +1 -0
  193. package/dist/utils/brain-index.js +101 -0
  194. package/dist/utils/brain-index.js.map +1 -0
  195. package/dist/utils/brain-ingest.d.ts +57 -0
  196. package/dist/utils/brain-ingest.d.ts.map +1 -0
  197. package/dist/utils/brain-ingest.js +127 -0
  198. package/dist/utils/brain-ingest.js.map +1 -0
  199. package/dist/utils/brain-lock.d.ts +4 -0
  200. package/dist/utils/brain-lock.d.ts.map +1 -0
  201. package/dist/utils/brain-lock.js +17 -0
  202. package/dist/utils/brain-lock.js.map +1 -0
  203. package/dist/utils/brain-lookup.d.ts +11 -0
  204. package/dist/utils/brain-lookup.d.ts.map +1 -0
  205. package/dist/utils/brain-lookup.js +36 -0
  206. package/dist/utils/brain-lookup.js.map +1 -0
  207. package/dist/utils/brain-paths.d.ts +19 -0
  208. package/dist/utils/brain-paths.d.ts.map +1 -0
  209. package/dist/utils/brain-paths.js +34 -0
  210. package/dist/utils/brain-paths.js.map +1 -0
  211. package/dist/utils/brain-phrases.d.ts +31 -0
  212. package/dist/utils/brain-phrases.d.ts.map +1 -0
  213. package/dist/utils/brain-phrases.js +116 -0
  214. package/dist/utils/brain-phrases.js.map +1 -0
  215. package/dist/utils/brain-stats.d.ts +25 -0
  216. package/dist/utils/brain-stats.d.ts.map +1 -0
  217. package/dist/utils/brain-stats.js +64 -0
  218. package/dist/utils/brain-stats.js.map +1 -0
  219. package/dist/utils/brain-storage.d.ts +28 -0
  220. package/dist/utils/brain-storage.d.ts.map +1 -0
  221. package/dist/utils/brain-storage.js +87 -0
  222. package/dist/utils/brain-storage.js.map +1 -0
  223. package/dist/utils/caption-probe.d.ts +7 -0
  224. package/dist/utils/caption-probe.d.ts.map +1 -0
  225. package/dist/utils/caption-probe.js +36 -0
  226. package/dist/utils/caption-probe.js.map +1 -0
  227. package/dist/utils/channel-images.d.ts +16 -0
  228. package/dist/utils/channel-images.d.ts.map +1 -0
  229. package/dist/utils/channel-images.js +35 -0
  230. package/dist/utils/channel-images.js.map +1 -0
  231. package/dist/utils/channel-lookup.d.ts +5 -0
  232. package/dist/utils/channel-lookup.d.ts.map +1 -0
  233. package/dist/utils/channel-lookup.js +37 -0
  234. package/dist/utils/channel-lookup.js.map +1 -0
  235. package/dist/utils/chapters.d.ts +11 -0
  236. package/dist/utils/chapters.d.ts.map +1 -0
  237. package/dist/utils/chapters.js +24 -0
  238. package/dist/utils/chapters.js.map +1 -0
  239. package/dist/utils/clips.d.ts.map +1 -1
  240. package/dist/utils/clips.js +22 -30
  241. package/dist/utils/clips.js.map +1 -1
  242. package/dist/utils/env.d.ts +26 -0
  243. package/dist/utils/env.d.ts.map +1 -0
  244. package/dist/utils/env.js +72 -0
  245. package/dist/utils/env.js.map +1 -0
  246. package/dist/utils/errors.d.ts +1 -1
  247. package/dist/utils/errors.d.ts.map +1 -1
  248. package/dist/utils/errors.js +20 -2
  249. package/dist/utils/errors.js.map +1 -1
  250. package/dist/utils/file-lock.d.ts +34 -0
  251. package/dist/utils/file-lock.d.ts.map +1 -0
  252. package/dist/utils/file-lock.js +91 -0
  253. package/dist/utils/file-lock.js.map +1 -0
  254. package/dist/utils/flat-listing.d.ts +89 -0
  255. package/dist/utils/flat-listing.d.ts.map +1 -0
  256. package/dist/utils/flat-listing.js +68 -0
  257. package/dist/utils/flat-listing.js.map +1 -0
  258. package/dist/utils/format.d.ts +1 -3
  259. package/dist/utils/format.d.ts.map +1 -1
  260. package/dist/utils/format.js +1 -5
  261. package/dist/utils/format.js.map +1 -1
  262. package/dist/utils/guard.d.ts +21 -0
  263. package/dist/utils/guard.d.ts.map +1 -0
  264. package/dist/utils/guard.js +105 -0
  265. package/dist/utils/guard.js.map +1 -0
  266. package/dist/utils/image-dimensions.d.ts +19 -0
  267. package/dist/utils/image-dimensions.d.ts.map +1 -0
  268. package/dist/utils/image-dimensions.js +93 -0
  269. package/dist/utils/image-dimensions.js.map +1 -0
  270. package/dist/utils/image-fetch.d.ts +31 -0
  271. package/dist/utils/image-fetch.d.ts.map +1 -0
  272. package/dist/utils/image-fetch.js +141 -0
  273. package/dist/utils/image-fetch.js.map +1 -0
  274. package/dist/utils/json-file.d.ts +45 -0
  275. package/dist/utils/json-file.d.ts.map +1 -0
  276. package/dist/utils/json-file.js +60 -0
  277. package/dist/utils/json-file.js.map +1 -0
  278. package/dist/utils/paths.d.ts +19 -0
  279. package/dist/utils/paths.d.ts.map +1 -0
  280. package/dist/utils/paths.js +27 -0
  281. package/dist/utils/paths.js.map +1 -0
  282. package/dist/utils/pattern.d.ts +30 -0
  283. package/dist/utils/pattern.d.ts.map +1 -0
  284. package/dist/utils/pattern.js +130 -0
  285. package/dist/utils/pattern.js.map +1 -0
  286. package/dist/utils/search-index.d.ts +22 -7
  287. package/dist/utils/search-index.d.ts.map +1 -1
  288. package/dist/utils/search-index.js +26 -8
  289. package/dist/utils/search-index.js.map +1 -1
  290. package/dist/utils/storage.d.ts +14 -44
  291. package/dist/utils/storage.d.ts.map +1 -1
  292. package/dist/utils/storage.js +47 -84
  293. package/dist/utils/storage.js.map +1 -1
  294. package/dist/utils/subtitles.d.ts +7 -0
  295. package/dist/utils/subtitles.d.ts.map +1 -0
  296. package/dist/utils/subtitles.js +30 -0
  297. package/dist/utils/subtitles.js.map +1 -0
  298. package/dist/utils/thumbnail-entry.d.ts +19 -0
  299. package/dist/utils/thumbnail-entry.d.ts.map +1 -0
  300. package/dist/utils/thumbnail-entry.js +119 -0
  301. package/dist/utils/thumbnail-entry.js.map +1 -0
  302. package/dist/utils/thumbnail-fetch.d.ts +37 -0
  303. package/dist/utils/thumbnail-fetch.d.ts.map +1 -0
  304. package/dist/utils/thumbnail-fetch.js +89 -0
  305. package/dist/utils/thumbnail-fetch.js.map +1 -0
  306. package/dist/utils/thumbnail-ladder.d.ts +44 -0
  307. package/dist/utils/thumbnail-ladder.d.ts.map +1 -0
  308. package/dist/utils/thumbnail-ladder.js +68 -0
  309. package/dist/utils/thumbnail-ladder.js.map +1 -0
  310. package/dist/utils/thumbnail-listing.d.ts +16 -0
  311. package/dist/utils/thumbnail-listing.d.ts.map +1 -0
  312. package/dist/utils/thumbnail-listing.js +26 -0
  313. package/dist/utils/thumbnail-listing.js.map +1 -0
  314. package/dist/utils/thumbnail-paths.d.ts +20 -0
  315. package/dist/utils/thumbnail-paths.d.ts.map +1 -0
  316. package/dist/utils/thumbnail-paths.js +35 -0
  317. package/dist/utils/thumbnail-paths.js.map +1 -0
  318. package/dist/utils/thumbnail-store.d.ts +19 -0
  319. package/dist/utils/thumbnail-store.d.ts.map +1 -0
  320. package/dist/utils/thumbnail-store.js +125 -0
  321. package/dist/utils/thumbnail-store.js.map +1 -0
  322. package/dist/utils/transcript-cache.d.ts +20 -0
  323. package/dist/utils/transcript-cache.d.ts.map +1 -0
  324. package/dist/utils/transcript-cache.js +127 -0
  325. package/dist/utils/transcript-cache.js.map +1 -0
  326. package/dist/utils/transcript-search.d.ts +20 -0
  327. package/dist/utils/transcript-search.d.ts.map +1 -0
  328. package/dist/utils/transcript-search.js +35 -0
  329. package/dist/utils/transcript-search.js.map +1 -0
  330. package/dist/utils/transcript.d.ts +14 -34
  331. package/dist/utils/transcript.d.ts.map +1 -1
  332. package/dist/utils/transcript.js +5 -64
  333. package/dist/utils/transcript.js.map +1 -1
  334. package/dist/utils/validate-youtube.d.ts +35 -0
  335. package/dist/utils/validate-youtube.d.ts.map +1 -0
  336. package/dist/utils/validate-youtube.js +87 -0
  337. package/dist/utils/validate-youtube.js.map +1 -0
  338. package/dist/utils/validate.d.ts +11 -3
  339. package/dist/utils/validate.d.ts.map +1 -1
  340. package/dist/utils/validate.js +43 -18
  341. package/dist/utils/validate.js.map +1 -1
  342. package/dist/utils/version.d.ts +2 -0
  343. package/dist/utils/version.d.ts.map +1 -0
  344. package/dist/utils/version.js +19 -0
  345. package/dist/utils/version.js.map +1 -0
  346. package/dist/utils/youtube-channel.d.ts +44 -0
  347. package/dist/utils/youtube-channel.d.ts.map +1 -0
  348. package/dist/utils/youtube-channel.js +61 -0
  349. package/dist/utils/youtube-channel.js.map +1 -0
  350. package/dist/utils/youtube-download.d.ts +27 -0
  351. package/dist/utils/youtube-download.d.ts.map +1 -0
  352. package/dist/utils/youtube-download.js +118 -0
  353. package/dist/utils/youtube-download.js.map +1 -0
  354. package/dist/utils/youtube-schemas.d.ts +394 -0
  355. package/dist/utils/youtube-schemas.d.ts.map +1 -0
  356. package/dist/utils/youtube-schemas.js +118 -0
  357. package/dist/utils/youtube-schemas.js.map +1 -0
  358. package/dist/utils/youtube-search.d.ts +14 -0
  359. package/dist/utils/youtube-search.d.ts.map +1 -0
  360. package/dist/utils/youtube-search.js +39 -0
  361. package/dist/utils/youtube-search.js.map +1 -0
  362. package/dist/utils/youtube-url.d.ts +25 -0
  363. package/dist/utils/youtube-url.d.ts.map +1 -0
  364. package/dist/utils/youtube-url.js +75 -0
  365. package/dist/utils/youtube-url.js.map +1 -0
  366. package/dist/utils/youtube-video.d.ts +47 -0
  367. package/dist/utils/youtube-video.d.ts.map +1 -0
  368. package/dist/utils/youtube-video.js +98 -0
  369. package/dist/utils/youtube-video.js.map +1 -0
  370. package/dist/utils/youtube.d.ts +13 -111
  371. package/dist/utils/youtube.d.ts.map +1 -1
  372. package/dist/utils/youtube.js +11 -480
  373. package/dist/utils/youtube.js.map +1 -1
  374. package/dist/utils/ytdlp-env.d.ts +33 -0
  375. package/dist/utils/ytdlp-env.d.ts.map +1 -0
  376. package/dist/utils/ytdlp-env.js +121 -0
  377. package/dist/utils/ytdlp-env.js.map +1 -0
  378. package/dist/utils/ytdlp-limiter.d.ts +24 -0
  379. package/dist/utils/ytdlp-limiter.d.ts.map +1 -0
  380. package/dist/utils/ytdlp-limiter.js +69 -0
  381. package/dist/utils/ytdlp-limiter.js.map +1 -0
  382. package/dist/utils/ytdlp-parse.d.ts +13 -0
  383. package/dist/utils/ytdlp-parse.d.ts.map +1 -0
  384. package/dist/utils/ytdlp-parse.js +48 -0
  385. package/dist/utils/ytdlp-parse.js.map +1 -0
  386. package/dist/utils/ytdlp.d.ts +13 -18
  387. package/dist/utils/ytdlp.d.ts.map +1 -1
  388. package/dist/utils/ytdlp.js +21 -110
  389. package/dist/utils/ytdlp.js.map +1 -1
  390. package/package.json +2 -1
@@ -0,0 +1,125 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { readdir, rm, stat } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { thumbnailManifestSchema, } from '../thumbnail-schemas.js';
5
+ import { findByChannel } from './channel-lookup.js';
6
+ import { YouTubeError } from './errors.js';
7
+ import { readJsonFile, writeJsonAtomic } from './json-file.js';
8
+ import { ensurePrivateDir } from './paths.js';
9
+ import { channelImagePath, thumbnailDir, thumbnailManifestPath, thumbnailsDir, videoThumbnailPath, } from './thumbnail-paths.js';
10
+ /** The manifest of a channel's thumbnails: reading, writing, finding and forgetting it. */
11
+ export const THUMBNAIL_MANIFEST_VERSION = 1;
12
+ export async function ensureThumbnailDirs(channelId, tabs) {
13
+ const directory = await ensurePrivateDir(thumbnailDir(channelId));
14
+ await ensurePrivateDir(join(directory, 'channel'));
15
+ for (const tab of tabs)
16
+ await ensurePrivateDir(join(directory, tab));
17
+ return directory;
18
+ }
19
+ export async function readThumbnailManifest(channelId) {
20
+ return readJsonFile(thumbnailManifestPath(channelId), thumbnailManifestSchema);
21
+ }
22
+ export async function requireThumbnailManifest(channelId) {
23
+ const manifest = await readThumbnailManifest(channelId);
24
+ if (manifest === undefined) {
25
+ throw new YouTubeError('NOT_FOUND', `No thumbnails have been fetched for channel ${channelId}.`, {
26
+ nextStep: 'Call fetch_channel_thumbnails with the channel URL or handle.',
27
+ });
28
+ }
29
+ return manifest;
30
+ }
31
+ export async function writeThumbnailManifest(manifest) {
32
+ await ensurePrivateDir(thumbnailDir(manifest.channel.channelId));
33
+ await writeJsonAtomic(thumbnailManifestPath(manifest.channel.channelId), manifest);
34
+ }
35
+ /** Every thumbnail set on disk, newest first. Unreadable directories are skipped. */
36
+ export async function listThumbnailManifests() {
37
+ if (!existsSync(thumbnailsDir()))
38
+ return [];
39
+ const manifests = [];
40
+ for (const entry of await readdir(thumbnailsDir(), { withFileTypes: true })) {
41
+ if (!entry.isDirectory())
42
+ continue;
43
+ const manifest = await readJsonFile(join(thumbnailsDir(), entry.name, 'manifest.json'), thumbnailManifestSchema);
44
+ if (manifest !== undefined)
45
+ manifests.push(manifest);
46
+ }
47
+ return manifests.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
48
+ }
49
+ /** The thumbnail set for a channel named any way the caller likes, from disk alone. */
50
+ export async function resolveThumbnails(channel) {
51
+ const manifests = await listThumbnailManifests();
52
+ const [first, second] = findByChannel(manifests, channel);
53
+ if (first === undefined) {
54
+ const fetched = manifests.map((m) => m.channel.handle || m.channel.name);
55
+ throw new YouTubeError('NOT_FOUND', `No thumbnails have been fetched for "${channel}".`, {
56
+ nextStep: fetched.length === 0
57
+ ? 'Call fetch_channel_thumbnails with the channel URL or handle.'
58
+ : `Call fetch_channel_thumbnails to fetch them. Channels with thumbnails: ${fetched.join(', ')}.`,
59
+ });
60
+ }
61
+ if (second !== undefined) {
62
+ throw new YouTubeError('INVALID_INPUT', `"${channel}" matches more than one channel.`, {
63
+ nextStep: `Use the channel id instead: ${[first, second].map((m) => m.channel.channelId).join(', ')}.`,
64
+ });
65
+ }
66
+ return first;
67
+ }
68
+ export async function deleteThumbnails(channelId) {
69
+ const directory = thumbnailDir(channelId);
70
+ const existed = existsSync(directory);
71
+ await rm(directory, { recursive: true, force: true });
72
+ return existed;
73
+ }
74
+ /** Where a saved entry's file is, recomputed from validated parts; never read from the manifest. */
75
+ export function entryPath(channelId, entry) {
76
+ if (entry.state !== 'saved' || entry.format === undefined)
77
+ return undefined;
78
+ return videoThumbnailPath(channelId, entry.tab, entry.videoId, entry.format);
79
+ }
80
+ export function channelImageFile(channelId, image) {
81
+ if (image.state !== 'saved' || image.format === undefined)
82
+ return undefined;
83
+ return channelImagePath(channelId, image.kind, image.format);
84
+ }
85
+ /** True when the file a saved record describes is on disk at the recorded size. */
86
+ export async function isIntact(path, bytes) {
87
+ if (path === undefined)
88
+ return false;
89
+ try {
90
+ return (await stat(path)).size === bytes;
91
+ }
92
+ catch {
93
+ return false;
94
+ }
95
+ }
96
+ export function computeThumbnailStats(entries) {
97
+ const tabs = new Map();
98
+ let saved = 0;
99
+ let failed = 0;
100
+ let pending = 0;
101
+ let totalBytes = 0;
102
+ for (const entry of entries) {
103
+ const tab = tabs.get(entry.tab) ?? { videoCount: 0, savedCount: 0 };
104
+ tab.videoCount++;
105
+ if (entry.state === 'saved') {
106
+ saved++;
107
+ tab.savedCount++;
108
+ totalBytes += entry.bytes ?? 0;
109
+ }
110
+ else if (entry.state === 'failed')
111
+ failed++;
112
+ else
113
+ pending++;
114
+ tabs.set(entry.tab, tab);
115
+ }
116
+ return {
117
+ videoCount: entries.length,
118
+ savedCount: saved,
119
+ failedCount: failed,
120
+ pendingCount: pending,
121
+ totalBytes,
122
+ tabs: [...tabs.entries()].map(([tab, counts]) => ({ tab, ...counts })),
123
+ };
124
+ }
125
+ //# sourceMappingURL=thumbnail-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thumbnail-store.js","sourceRoot":"","sources":["../../src/utils/thumbnail-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EACL,uBAAuB,GAMxB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,qBAAqB,EACrB,aAAa,EACb,kBAAkB,GACnB,MAAM,sBAAsB,CAAC;AAE9B,2FAA2F;AAE3F,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC;AAE5C,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,SAAiB,EACjB,IAAoB;IAEpB,MAAM,SAAS,GAAG,MAAM,gBAAgB,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC;IAClE,MAAM,gBAAgB,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;IACnD,KAAK,MAAM,GAAG,IAAI,IAAI;QAAE,MAAM,gBAAgB,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC;IACrE,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,SAAiB;IAEjB,OAAO,YAAY,CAAC,qBAAqB,CAAC,SAAS,CAAC,EAAE,uBAAuB,CAAC,CAAC;AACjF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,SAAiB;IAC9D,MAAM,QAAQ,GAAG,MAAM,qBAAqB,CAAC,SAAS,CAAC,CAAC;IACxD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,IAAI,YAAY,CACpB,WAAW,EACX,+CAA+C,SAAS,GAAG,EAC3D;YACE,QAAQ,EAAE,+DAA+D;SAC1E,CACF,CAAC;IACJ,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,QAA2B;IACtE,MAAM,gBAAgB,CAAC,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;IACjE,MAAM,eAAe,CAAC,qBAAqB,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,CAAC;AACrF,CAAC;AAED,qFAAqF;AACrF,MAAM,CAAC,KAAK,UAAU,sBAAsB;IAC1C,IAAI,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC;QAAE,OAAO,EAAE,CAAC;IAE5C,MAAM,SAAS,GAAwB,EAAE,CAAC;IAC1C,KAAK,MAAM,KAAK,IAAI,MAAM,OAAO,CAAC,aAAa,EAAE,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QAC5E,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;YAAE,SAAS;QACnC,MAAM,QAAQ,GAAG,MAAM,YAAY,CACjC,IAAI,CAAC,aAAa,EAAE,EAAE,KAAK,CAAC,IAAI,EAAE,eAAe,CAAC,EAClD,uBAAuB,CACxB,CAAC;QACF,IAAI,QAAQ,KAAK,SAAS;YAAE,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AAC1E,CAAC;AAED,uFAAuF;AACvF,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,OAAe;IACrD,MAAM,SAAS,GAAG,MAAM,sBAAsB,EAAE,CAAC;IACjD,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,aAAa,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAE1D,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACzE,MAAM,IAAI,YAAY,CAAC,WAAW,EAAE,wCAAwC,OAAO,IAAI,EAAE;YACvF,QAAQ,EACN,OAAO,CAAC,MAAM,KAAK,CAAC;gBAClB,CAAC,CAAC,+DAA+D;gBACjE,CAAC,CAAC,0EAA0E,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;SACtG,CAAC,CAAC;IACL,CAAC;IACD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,MAAM,IAAI,YAAY,CAAC,eAAe,EAAE,IAAI,OAAO,kCAAkC,EAAE;YACrF,QAAQ,EAAE,+BAA+B,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;SACvG,CAAC,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,SAAiB;IACtD,MAAM,SAAS,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;IACtC,MAAM,EAAE,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,oGAAoG;AACpG,MAAM,UAAU,SAAS,CAAC,SAAiB,EAAE,KAAqB;IAChE,IAAI,KAAK,CAAC,KAAK,KAAK,OAAO,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC5E,OAAO,kBAAkB,CAAC,SAAS,EAAE,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;AAC/E,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,SAAiB,EAAE,KAAmB;IACrE,IAAI,KAAK,CAAC,KAAK,KAAK,OAAO,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC5E,OAAO,gBAAgB,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;AAC/D,CAAC;AAED,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,IAAwB,EACxB,KAAyB;IAEzB,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACrC,IAAI,CAAC;QACH,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,OAAyB;IAC7D,MAAM,IAAI,GAAG,IAAI,GAAG,EAA4D,CAAC;IACjF,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,UAAU,GAAG,CAAC,CAAC;IAEnB,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;QACpE,GAAG,CAAC,UAAU,EAAE,CAAC;QACjB,IAAI,KAAK,CAAC,KAAK,KAAK,OAAO,EAAE,CAAC;YAC5B,KAAK,EAAE,CAAC;YACR,GAAG,CAAC,UAAU,EAAE,CAAC;YACjB,UAAU,IAAI,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC;QACjC,CAAC;aAAM,IAAI,KAAK,CAAC,KAAK,KAAK,QAAQ;YAAE,MAAM,EAAE,CAAC;;YACzC,OAAO,EAAE,CAAC;QACf,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC3B,CAAC;IAED,OAAO;QACL,UAAU,EAAE,OAAO,CAAC,MAAM;QAC1B,UAAU,EAAE,KAAK;QACjB,WAAW,EAAE,MAAM;QACnB,YAAY,EAAE,OAAO;QACrB,UAAU;QACV,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;KACvE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { type TranscriptSegment } from './transcript.js';
2
+ export interface TranscriptResult {
3
+ /** The whole transcript as plain text, unchanged from previous releases. */
4
+ transcript: string;
5
+ /** The same content with cue timings preserved. */
6
+ segments: TranscriptSegment[];
7
+ language: string;
8
+ videoId: string;
9
+ /** True when served from the local cache rather than refetched. */
10
+ cached: boolean;
11
+ }
12
+ export interface GetTranscriptOptions {
13
+ language?: string;
14
+ /** Ignore any cached copy and refetch from YouTube. */
15
+ refresh?: boolean;
16
+ }
17
+ /** True when a usable transcript is already on disk, in any language. */
18
+ export declare function hasCachedTranscript(videoId: string): boolean;
19
+ export declare function getTranscript(urlOrId: string, options?: GetTranscriptOptions): Promise<TranscriptResult>;
20
+ //# sourceMappingURL=transcript-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transcript-cache.d.ts","sourceRoot":"","sources":["../../src/utils/transcript-cache.ts"],"names":[],"mappings":"AAUA,OAAO,EAML,KAAK,iBAAiB,EACvB,MAAM,iBAAiB,CAAC;AAOzB,MAAM,WAAW,gBAAgB;IAC/B,4EAA4E;IAC5E,UAAU,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uDAAuD;IACvD,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAqCD,yEAAyE;AACzE,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAK5D;AAED,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,gBAAgB,CAAC,CAqF3B"}
@@ -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":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,IAAI,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EACL,wBAAwB,EACxB,sBAAsB,EACtB,QAAQ,EACR,cAAc,GAGf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5D,iEAAiE;AAEjE,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;AAmBzC,qFAAqF;AACrF,MAAM,iBAAiB,GAAG,MAAM,CAAC,+BAA+B,EAAE,EAAE,GAAG,UAAU,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;AAE/F,SAAS,SAAS,CAAC,OAAe,EAAE,QAAgB;IAClD,OAAO,IAAI,CAAC,SAAS,EAAE,GAAG,OAAO,IAAI,QAAQ,OAAO,CAAC,CAAC;AACxD,CAAC;AAED,KAAK,UAAU,oBAAoB,CACjC,OAAe,EACf,QAAgB;IAEhB,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC1C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IAExC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,sBAAsB,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;QAC3F,0EAA0E;QAC1E,gEAAgE;QAChE,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,OAAO,SAAS,CAAC;QAEtC,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC;QAE3B,wEAAwE;QACxE,oDAAoD;QACpD,IAAI,MAAM,CAAC,OAAO,KAAK,wBAAwB;YAAE,OAAO,SAAS,CAAC;QAElE,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC/C,IAAI,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,GAAG,iBAAiB;YAAE,OAAO,SAAS,CAAC;QAE/F,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,KAAK,CAAC;IACzC,OAAO,WAAW,CAAC,SAAS,CAAC,CAAC,IAAI,CAChC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,OAAO,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CACnE,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,OAAe,EACf,UAAgC,EAAE;IAElC,MAAM,aAAa,GAAG,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC;IAE/C,MAAM,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IACxC,iBAAiB,CAAC,aAAa,CAAC,CAAC;IACjC,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IAE9B,MAAM,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAElC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACrB,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;QAClE,IAAI,MAAM,EAAE,CAAC;YACX,OAAO;gBACL,UAAU,EAAE,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC;gBAC3C,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,OAAO;gBACP,MAAM,EAAE,IAAI;aACb,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACxC,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAChC,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAE9C,IAAI,CAAC;QACH,MAAM,QAAQ,CACZ;YACE,iBAAiB;YACjB,kBAAkB;YAClB,aAAa;YACb,YAAY;YACZ,GAAG,aAAa,IAAI,aAAa,OAAO;YACxC,cAAc;YACd,KAAK;YACL,gBAAgB;YAChB,KAAK;YACL,IAAI;YACJ,cAAc;SACf,EACD,EAAE,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,CACzE,CAAC;QAEF,MAAM,UAAU,GAAG;YACjB,EAAE,IAAI,EAAE,GAAG,cAAc,IAAI,aAAa,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE;YAC3E;gBACE,IAAI,EAAE,GAAG,cAAc,IAAI,aAAa,WAAW;gBACnD,QAAQ,EAAE,GAAG,aAAa,mBAAmB;aAC9C;YACD,EAAE,IAAI,EAAE,GAAG,cAAc,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE;SACrD,CAAC;QAEF,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;QACzE,IAAI,CAAC,KAAK;YAAE,MAAM,MAAM,eAAe,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;QAE5D,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;QAC/D,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,MAAM,MAAM,eAAe,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;QAE3E,MAAM,KAAK,GAAqB;YAC9B,OAAO,EAAE,wBAAwB;YACjC,OAAO;YACP,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,QAAQ;SACT,CAAC;QACF,MAAM,eAAe,CAAC,SAAS,CAAC,OAAO,EAAE,aAAa,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QACnF,MAAM,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAEhD,OAAO;YACL,UAAU,EAAE,cAAc,CAAC,QAAQ,CAAC;YACpC,QAAQ;YACR,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,OAAO;YACP,MAAM,EAAE,KAAK;SACd,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,2EAA2E;QAC3E,6EAA6E;QAC7E,IAAI,KAAK,YAAY,YAAY;YAAE,MAAM,KAAK,CAAC;QAC/C,MAAM,IAAI,YAAY,CAAC,cAAc,EAAE,qCAAqC,OAAO,GAAG,EAAE;YACtF,QAAQ,EAAE,iEAAiE;YAC3E,KAAK,EAAE,KAAK;SACb,CAAC,CAAC;IACL,CAAC;AACH,CAAC"}
@@ -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, {
57
+ videoId: string;
58
58
  version: number;
59
+ language: string;
60
+ fetchedAt: string;
59
61
  segments: {
60
62
  text: string;
61
- start: number;
62
63
  end: number;
64
+ start: number;
63
65
  }[];
66
+ }, {
64
67
  videoId: string;
68
+ version: number;
65
69
  language: string;
66
70
  fetchedAt: string;
67
- }, {
68
- version: number;
69
71
  segments: {
70
72
  text: string;
71
- start: number;
72
73
  end: number;
74
+ start: number;
73
75
  }[];
74
- videoId: string;
75
- language: string;
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
  *
@@ -96,6 +93,7 @@ export declare function formatSrtTimestamp(totalSeconds: number): string;
96
93
  */
97
94
  export declare function parseVtt(vttContent: string): TranscriptSegment[];
98
95
  export declare function segmentsToText(segments: TranscriptSegment[]): string;
96
+ export declare function countWords(text: string): number;
99
97
  export declare function segmentsToTimestamped(segments: TranscriptSegment[]): string;
100
98
  /** A URL that opens the video at this moment. */
101
99
  export declare function deepLink(videoId: string, seconds: number): string;
@@ -104,24 +102,6 @@ export declare function sliceSegments(segments: TranscriptSegment[], range: {
104
102
  startTime?: number;
105
103
  endTime?: number;
106
104
  }): TranscriptSegment[];
107
- export interface TranscriptMatch {
108
- segment: TranscriptSegment;
109
- /** The matched text, for highlighting. */
110
- match: string;
111
- url: string;
112
- }
113
- /**
114
- * Find a phrase or pattern in a transcript.
115
- *
116
- * Matching runs over the joined text of a small window of segments, not each
117
- * segment alone, so a phrase split across a caption boundary is still found —
118
- * which is most phrases, since caption breaks fall mid-sentence.
119
- */
120
- export declare function searchSegments(segments: TranscriptSegment[], query: string, options?: {
121
- regex?: boolean;
122
- caseSensitive?: boolean;
123
- limit?: number;
124
- }): TranscriptMatch[];
125
105
  export interface TruncationResult {
126
106
  text: string;
127
107
  truncated: boolean;
@@ -137,6 +117,6 @@ export interface TruncationResult {
137
117
  * continue from.
138
118
  */
139
119
  export declare function windowText(text: string, offset?: number, maxChars?: number): TruncationResult;
140
- export declare function toSrt(segments: TranscriptSegment[]): string;
141
- export declare function toVtt(segments: TranscriptSegment[]): string;
120
+ export * from './subtitles.js';
121
+ export * from './transcript-search.js';
142
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,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,
@@ -123,6 +113,9 @@ export function segmentsToText(segments) {
123
113
  .replace(/\s+/g, ' ')
124
114
  .trim();
125
115
  }
116
+ export function countWords(text) {
117
+ return text.split(/\s+/).filter(Boolean).length;
118
+ }
126
119
  export function segmentsToTimestamped(segments) {
127
120
  return segments
128
121
  .map((segment) => `[${formatTimestamp(segment.start)}] ${segment.text}`)
@@ -140,42 +133,6 @@ export function sliceSegments(segments, range) {
140
133
  // relevant to the range the caller asked about.
141
134
  return segments.filter((segment) => segment.end > from && segment.start < to);
142
135
  }
143
- /**
144
- * Find a phrase or pattern in a transcript.
145
- *
146
- * Matching runs over the joined text of a small window of segments, not each
147
- * segment alone, so a phrase split across a caption boundary is still found —
148
- * which is most phrases, since caption breaks fall mid-sentence.
149
- */
150
- export function searchSegments(segments, query, options = {}) {
151
- const { regex = false, caseSensitive = false, limit = 20 } = options;
152
- const flags = caseSensitive ? 'g' : 'gi';
153
- const pattern = regex
154
- ? new RegExp(query, flags)
155
- : new RegExp(query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), flags);
156
- const matches = [];
157
- for (let index = 0; index < segments.length && matches.length < limit; index++) {
158
- const current = segments[index];
159
- if (!current)
160
- continue;
161
- // Two segments of lookahead covers phrases spanning a caption break.
162
- const haystack = segments
163
- .slice(index, index + 3)
164
- .map((segment) => segment.text)
165
- .join(' ');
166
- pattern.lastIndex = 0;
167
- const found = pattern.exec(haystack);
168
- if (!found)
169
- continue;
170
- // The lookahead window means a hit can start in a *later* segment. Only
171
- // accept it here if it begins inside this one; otherwise the same hit is
172
- // reported once per preceding segment, and attributed to the wrong time.
173
- if (found.index > current.text.length)
174
- continue;
175
- matches.push({ segment: current, match: found[0], url: '' });
176
- }
177
- return matches;
178
- }
179
136
  /**
180
137
  * Window a long string.
181
138
  *
@@ -195,22 +152,6 @@ export function windowText(text, offset = 0, maxChars) {
195
152
  const end = softEnd > from ? softEnd : hardEnd;
196
153
  return { text: text.slice(from, end), truncated: true, nextOffset: end, totalChars };
197
154
  }
198
- export function toSrt(segments) {
199
- return (segments
200
- .map((segment, index) => [
201
- index + 1,
202
- `${formatSrtTimestamp(segment.start)} --> ${formatSrtTimestamp(segment.end)}`,
203
- segment.text,
204
- ].join('\n'))
205
- .join('\n\n') + '\n');
206
- }
207
- export function toVtt(segments) {
208
- const body = segments
209
- .map((segment) => [
210
- `${formatSrtTimestamp(segment.start).replace(',', '.')} --> ${formatSrtTimestamp(segment.end).replace(',', '.')}`,
211
- segment.text,
212
- ].join('\n'))
213
- .join('\n\n');
214
- return `WEBVTT\n\n${body}\n`;
215
- }
155
+ export * from './subtitles.js';
156
+ export * from './transcript-search.js';
216
157
  //# sourceMappingURL=transcript.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"transcript.js","sourceRoot":"","sources":["../../src/utils/transcript.ts"],"names":[],"mappings":"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"}
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"}