@kvman/kvvideo 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (242) hide show
  1. package/README.md +1 -1
  2. package/dist/api.d.ts +26 -0
  3. package/dist/api.d.ts.map +1 -1
  4. package/dist/brand/brand.d.ts +17 -0
  5. package/dist/brand/brand.d.ts.map +1 -0
  6. package/dist/brand/brand.js +44 -0
  7. package/dist/brand/brand.js.map +1 -0
  8. package/dist/browser/launch.d.ts +2 -0
  9. package/dist/browser/launch.d.ts.map +1 -1
  10. package/dist/browser/launch.js +7 -1
  11. package/dist/browser/launch.js.map +1 -1
  12. package/dist/compose/ass-file.d.ts +5 -0
  13. package/dist/compose/ass-file.d.ts.map +1 -1
  14. package/dist/compose/ass-file.js +32 -3
  15. package/dist/compose/ass-file.js.map +1 -1
  16. package/dist/compose/background.d.ts +23 -0
  17. package/dist/compose/background.d.ts.map +1 -0
  18. package/dist/compose/background.js +31 -0
  19. package/dist/compose/background.js.map +1 -0
  20. package/dist/compose/camera.d.ts +32 -0
  21. package/dist/compose/camera.d.ts.map +1 -0
  22. package/dist/compose/camera.js +98 -0
  23. package/dist/compose/camera.js.map +1 -0
  24. package/dist/compose/caption-font.d.ts +2 -0
  25. package/dist/compose/caption-font.d.ts.map +1 -1
  26. package/dist/compose/caption-font.js +2 -1
  27. package/dist/compose/caption-font.js.map +1 -1
  28. package/dist/compose/compose-drawing.d.ts +19 -0
  29. package/dist/compose/compose-drawing.d.ts.map +1 -0
  30. package/dist/compose/compose-drawing.js +38 -0
  31. package/dist/compose/compose-drawing.js.map +1 -0
  32. package/dist/compose/compose-input.d.ts +139 -0
  33. package/dist/compose/compose-input.d.ts.map +1 -1
  34. package/dist/compose/compose-input.js +48 -9
  35. package/dist/compose/compose-input.js.map +1 -1
  36. package/dist/compose/compose-plan.d.ts +36 -0
  37. package/dist/compose/compose-plan.d.ts.map +1 -0
  38. package/dist/compose/compose-plan.js +55 -0
  39. package/dist/compose/compose-plan.js.map +1 -0
  40. package/dist/compose/compose-size.d.ts +50 -0
  41. package/dist/compose/compose-size.d.ts.map +1 -0
  42. package/dist/compose/compose-size.js +72 -0
  43. package/dist/compose/compose-size.js.map +1 -0
  44. package/dist/compose/drawn-images.d.ts +19 -0
  45. package/dist/compose/drawn-images.d.ts.map +1 -0
  46. package/dist/compose/drawn-images.js +75 -0
  47. package/dist/compose/drawn-images.js.map +1 -0
  48. package/dist/compose/final-pass.d.ts +34 -0
  49. package/dist/compose/final-pass.d.ts.map +1 -0
  50. package/dist/compose/final-pass.js +106 -0
  51. package/dist/compose/final-pass.js.map +1 -0
  52. package/dist/compose/frame-layout.d.ts +30 -0
  53. package/dist/compose/frame-layout.d.ts.map +1 -0
  54. package/dist/compose/frame-layout.js +33 -0
  55. package/dist/compose/frame-layout.js.map +1 -0
  56. package/dist/compose/overlays.d.ts +20 -0
  57. package/dist/compose/overlays.d.ts.map +1 -0
  58. package/dist/compose/overlays.js +30 -0
  59. package/dist/compose/overlays.js.map +1 -0
  60. package/dist/compose/page-again.d.ts +26 -0
  61. package/dist/compose/page-again.d.ts.map +1 -0
  62. package/dist/compose/page-again.js +50 -0
  63. package/dist/compose/page-again.js.map +1 -0
  64. package/dist/compose/player-copies.d.ts +5 -1
  65. package/dist/compose/player-copies.d.ts.map +1 -1
  66. package/dist/compose/player-copies.js +19 -16
  67. package/dist/compose/player-copies.js.map +1 -1
  68. package/dist/compose/register-compose.d.ts.map +1 -1
  69. package/dist/compose/register-compose.js +106 -20
  70. package/dist/compose/register-compose.js.map +1 -1
  71. package/dist/compose/render.d.ts +13 -4
  72. package/dist/compose/render.d.ts.map +1 -1
  73. package/dist/compose/render.js +48 -22
  74. package/dist/compose/render.js.map +1 -1
  75. package/dist/compose/scene-args.d.ts +32 -7
  76. package/dist/compose/scene-args.d.ts.map +1 -1
  77. package/dist/compose/scene-args.js +77 -16
  78. package/dist/compose/scene-args.js.map +1 -1
  79. package/dist/compose/scene-look.d.ts +31 -0
  80. package/dist/compose/scene-look.d.ts.map +1 -0
  81. package/dist/compose/scene-look.js +46 -0
  82. package/dist/compose/scene-look.js.map +1 -0
  83. package/dist/compose/scene-plan.d.ts +0 -2
  84. package/dist/compose/scene-plan.d.ts.map +1 -1
  85. package/dist/compose/scene-plan.js +7 -5
  86. package/dist/compose/scene-plan.js.map +1 -1
  87. package/dist/compose/sound-effects.d.ts +23 -0
  88. package/dist/compose/sound-effects.d.ts.map +1 -0
  89. package/dist/compose/sound-effects.js +40 -0
  90. package/dist/compose/sound-effects.js.map +1 -0
  91. package/dist/compose/srt.d.ts +3 -0
  92. package/dist/compose/srt.d.ts.map +1 -0
  93. package/dist/compose/srt.js +10 -0
  94. package/dist/compose/srt.js.map +1 -0
  95. package/dist/compose/transitions.d.ts +16 -0
  96. package/dist/compose/transitions.d.ts.map +1 -0
  97. package/dist/compose/transitions.js +38 -0
  98. package/dist/compose/transitions.js.map +1 -0
  99. package/dist/connector.d.ts +67 -14
  100. package/dist/connector.d.ts.map +1 -1
  101. package/dist/connector.js +27 -8
  102. package/dist/connector.js.map +1 -1
  103. package/dist/files/sidecar.d.ts +209 -0
  104. package/dist/files/sidecar.d.ts.map +1 -0
  105. package/dist/files/sidecar.js +66 -0
  106. package/dist/files/sidecar.js.map +1 -0
  107. package/dist/index.d.ts.map +1 -1
  108. package/dist/index.js +7 -1
  109. package/dist/index.js.map +1 -1
  110. package/dist/narration/alignment.d.ts +15 -0
  111. package/dist/narration/alignment.d.ts.map +1 -0
  112. package/dist/narration/alignment.js +21 -0
  113. package/dist/narration/alignment.js.map +1 -0
  114. package/dist/narration/captions.d.ts +22 -4
  115. package/dist/narration/captions.d.ts.map +1 -1
  116. package/dist/narration/captions.js +44 -16
  117. package/dist/narration/captions.js.map +1 -1
  118. package/dist/narration/join-args.d.ts +3 -0
  119. package/dist/narration/join-args.d.ts.map +1 -0
  120. package/dist/narration/join-args.js +19 -0
  121. package/dist/narration/join-args.js.map +1 -0
  122. package/dist/narration/narration-cache.d.ts +25 -0
  123. package/dist/narration/narration-cache.d.ts.map +1 -0
  124. package/dist/narration/narration-cache.js +36 -0
  125. package/dist/narration/narration-cache.js.map +1 -0
  126. package/dist/narration/piper.d.ts +2 -6
  127. package/dist/narration/piper.d.ts.map +1 -1
  128. package/dist/narration/piper.js +9 -15
  129. package/dist/narration/piper.js.map +1 -1
  130. package/dist/narration/pronunciations.d.ts +11 -0
  131. package/dist/narration/pronunciations.d.ts.map +1 -0
  132. package/dist/narration/pronunciations.js +40 -0
  133. package/dist/narration/pronunciations.js.map +1 -0
  134. package/dist/narration/register-narration.d.ts +8 -0
  135. package/dist/narration/register-narration.d.ts.map +1 -1
  136. package/dist/narration/register-narration.js +54 -26
  137. package/dist/narration/register-narration.js.map +1 -1
  138. package/dist/narration/register-voice.d.ts +27 -0
  139. package/dist/narration/register-voice.d.ts.map +1 -0
  140. package/dist/narration/register-voice.js +82 -0
  141. package/dist/narration/register-voice.js.map +1 -0
  142. package/dist/narration/sentence-speaker.d.ts +35 -0
  143. package/dist/narration/sentence-speaker.d.ts.map +1 -0
  144. package/dist/narration/sentence-speaker.js +44 -0
  145. package/dist/narration/sentence-speaker.js.map +1 -0
  146. package/dist/narration/speech-services.d.ts +23 -3
  147. package/dist/narration/speech-services.d.ts.map +1 -1
  148. package/dist/narration/speech-services.js +27 -10
  149. package/dist/narration/speech-services.js.map +1 -1
  150. package/dist/narration/voice-args.d.ts +3 -0
  151. package/dist/narration/voice-args.d.ts.map +1 -0
  152. package/dist/narration/voice-args.js +10 -0
  153. package/dist/narration/voice-args.js.map +1 -0
  154. package/dist/programs/media-duration.d.ts +12 -0
  155. package/dist/programs/media-duration.d.ts.map +1 -1
  156. package/dist/programs/media-duration.js +13 -0
  157. package/dist/programs/media-duration.js.map +1 -1
  158. package/dist/programs/run-program.d.ts +1 -0
  159. package/dist/programs/run-program.d.ts.map +1 -1
  160. package/dist/programs/run-program.js +1 -0
  161. package/dist/programs/run-program.js.map +1 -1
  162. package/dist/record/address.d.ts +1 -1
  163. package/dist/record/address.d.ts.map +1 -1
  164. package/dist/record/address.js +5 -7
  165. package/dist/record/address.js.map +1 -1
  166. package/dist/record/cursor-script.d.ts +2 -1
  167. package/dist/record/cursor-script.d.ts.map +1 -1
  168. package/dist/record/cursor-script.js +52 -14
  169. package/dist/record/cursor-script.js.map +1 -1
  170. package/dist/record/encoder-args.js +1 -1
  171. package/dist/record/motion.d.ts +19 -0
  172. package/dist/record/motion.d.ts.map +1 -0
  173. package/dist/record/motion.js +59 -0
  174. package/dist/record/motion.js.map +1 -0
  175. package/dist/record/narration-cues.d.ts +14 -0
  176. package/dist/record/narration-cues.d.ts.map +1 -0
  177. package/dist/record/narration-cues.js +12 -0
  178. package/dist/record/narration-cues.js.map +1 -0
  179. package/dist/record/page-ready.d.ts +4 -0
  180. package/dist/record/page-ready.d.ts.map +1 -0
  181. package/dist/record/page-ready.js +15 -0
  182. package/dist/record/page-ready.js.map +1 -0
  183. package/dist/record/page-route.d.ts +13 -0
  184. package/dist/record/page-route.d.ts.map +1 -0
  185. package/dist/record/page-route.js +64 -0
  186. package/dist/record/page-route.js.map +1 -0
  187. package/dist/record/pointer.d.ts +6 -7
  188. package/dist/record/pointer.d.ts.map +1 -1
  189. package/dist/record/pointer.js +11 -10
  190. package/dist/record/pointer.js.map +1 -1
  191. package/dist/record/recorder.d.ts +17 -7
  192. package/dist/record/recorder.d.ts.map +1 -1
  193. package/dist/record/recorder.js +48 -18
  194. package/dist/record/recorder.js.map +1 -1
  195. package/dist/record/register-record.d.ts.map +1 -1
  196. package/dist/record/register-record.js +47 -13
  197. package/dist/record/register-record.js.map +1 -1
  198. package/dist/record/run-step.d.ts +16 -3
  199. package/dist/record/run-step.d.ts.map +1 -1
  200. package/dist/record/run-step.js +43 -23
  201. package/dist/record/run-step.js.map +1 -1
  202. package/dist/record/screencast.js +1 -1
  203. package/dist/record/steps.d.ts +54 -1
  204. package/dist/record/steps.d.ts.map +1 -1
  205. package/dist/record/steps.js +34 -16
  206. package/dist/record/steps.js.map +1 -1
  207. package/dist/review/analysis.d.ts +19 -0
  208. package/dist/review/analysis.d.ts.map +1 -0
  209. package/dist/review/analysis.js +36 -0
  210. package/dist/review/analysis.js.map +1 -0
  211. package/dist/review/frames.d.ts +9 -0
  212. package/dist/review/frames.d.ts.map +1 -0
  213. package/dist/review/frames.js +28 -0
  214. package/dist/review/frames.js.map +1 -0
  215. package/dist/review/register-review.d.ts +24 -0
  216. package/dist/review/register-review.d.ts.map +1 -0
  217. package/dist/review/register-review.js +81 -0
  218. package/dist/review/register-review.js.map +1 -0
  219. package/dist/review/sheet-args.d.ts +11 -0
  220. package/dist/review/sheet-args.d.ts.map +1 -0
  221. package/dist/review/sheet-args.js +24 -0
  222. package/dist/review/sheet-args.js.map +1 -0
  223. package/dist/settings.d.ts +4 -0
  224. package/dist/settings.d.ts.map +1 -1
  225. package/dist/settings.js +4 -2
  226. package/dist/settings.js.map +1 -1
  227. package/dist/setup/ffmpeg-readiness.js +1 -1
  228. package/dist/setup/ffmpeg-readiness.js.map +1 -1
  229. package/dist/ui.d.ts.map +1 -1
  230. package/dist/ui.js +3 -2
  231. package/dist/ui.js.map +1 -1
  232. package/dist/web/components/player.css +1 -1
  233. package/dist/web/components/player.js +33 -21
  234. package/docs/guide.md +21 -9
  235. package/locales/ar.json +12 -1
  236. package/locales/en.json +12 -1
  237. package/package.json +11 -5
  238. package/sounds/SOURCES.md +13 -0
  239. package/sounds/click.wav +0 -0
  240. package/sounds/keys.wav +0 -0
  241. package/sounds/pop.wav +0 -0
  242. package/sounds/whoosh.wav +0 -0
@@ -0,0 +1,209 @@
1
+ import { z } from '@kvman/sdk';
2
+ export declare const sidecarCaptionSchema: z.ZodObject<{
3
+ text: z.ZodString;
4
+ startMs: z.ZodNumber;
5
+ endMs: z.ZodNumber;
6
+ words: z.ZodExactOptional<z.ZodArray<z.ZodObject<{
7
+ text: z.ZodString;
8
+ startMs: z.ZodNumber;
9
+ endMs: z.ZodNumber;
10
+ }, z.core.$strip>>>;
11
+ }, z.core.$strip>;
12
+ export declare const recordingSidecarSchema: z.ZodObject<{
13
+ kind: z.ZodEnum<{
14
+ page: "page";
15
+ site: "site";
16
+ }>;
17
+ source: z.ZodString;
18
+ width: z.ZodNumber;
19
+ height: z.ZodNumber;
20
+ device: z.ZodEnum<{
21
+ phone: "phone";
22
+ desktop: "desktop";
23
+ }>;
24
+ scale: z.ZodLiteral<2>;
25
+ durationMs: z.ZodNumber;
26
+ steps: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
27
+ do: z.ZodLiteral<"goto">;
28
+ url: z.ZodString;
29
+ atLine: z.ZodExactOptional<z.ZodNumber>;
30
+ }, z.core.$strict>, z.ZodObject<{
31
+ do: z.ZodLiteral<"click">;
32
+ target: z.ZodString;
33
+ atLine: z.ZodExactOptional<z.ZodNumber>;
34
+ }, z.core.$strict>, z.ZodObject<{
35
+ do: z.ZodLiteral<"type">;
36
+ target: z.ZodString;
37
+ text: z.ZodString;
38
+ atLine: z.ZodExactOptional<z.ZodNumber>;
39
+ }, z.core.$strict>, z.ZodObject<{
40
+ do: z.ZodLiteral<"press">;
41
+ key: z.ZodString;
42
+ atLine: z.ZodExactOptional<z.ZodNumber>;
43
+ }, z.core.$strict>, z.ZodObject<{
44
+ do: z.ZodLiteral<"hover">;
45
+ target: z.ZodString;
46
+ atLine: z.ZodExactOptional<z.ZodNumber>;
47
+ }, z.core.$strict>, z.ZodObject<{
48
+ do: z.ZodLiteral<"scroll">;
49
+ pixels: z.ZodNumber;
50
+ atLine: z.ZodExactOptional<z.ZodNumber>;
51
+ }, z.core.$strict>, z.ZodObject<{
52
+ do: z.ZodLiteral<"wait">;
53
+ ms: z.ZodNumber;
54
+ }, z.core.$strict>, z.ZodObject<{
55
+ do: z.ZodLiteral<"waitFor">;
56
+ target: z.ZodString;
57
+ atLine: z.ZodExactOptional<z.ZodNumber>;
58
+ }, z.core.$strict>], "do">>;
59
+ actions: z.ZodArray<z.ZodObject<{
60
+ do: z.ZodString;
61
+ atMs: z.ZodNumber;
62
+ actMs: z.ZodOptional<z.ZodNumber>;
63
+ endMs: z.ZodNumber;
64
+ box: z.ZodOptional<z.ZodObject<{
65
+ x: z.ZodNumber;
66
+ y: z.ZodNumber;
67
+ width: z.ZodNumber;
68
+ height: z.ZodNumber;
69
+ }, z.core.$strip>>;
70
+ }, z.core.$strip>>;
71
+ }, z.core.$strip>;
72
+ export declare const narrationSidecarSchema: z.ZodObject<{
73
+ kind: z.ZodLiteral<"narration">;
74
+ durationMs: z.ZodNumber;
75
+ captions: z.ZodArray<z.ZodObject<{
76
+ text: z.ZodString;
77
+ startMs: z.ZodNumber;
78
+ endMs: z.ZodNumber;
79
+ words: z.ZodExactOptional<z.ZodArray<z.ZodObject<{
80
+ text: z.ZodString;
81
+ startMs: z.ZodNumber;
82
+ endMs: z.ZodNumber;
83
+ }, z.core.$strip>>>;
84
+ }, z.core.$strip>>;
85
+ }, z.core.$strip>;
86
+ export declare const videoSidecarSchema: z.ZodObject<{
87
+ kind: z.ZodLiteral<"video">;
88
+ durationMs: z.ZodNumber;
89
+ width: z.ZodNumber;
90
+ height: z.ZodNumber;
91
+ scenes: z.ZodArray<z.ZodObject<{
92
+ startMs: z.ZodNumber;
93
+ endMs: z.ZodNumber;
94
+ }, z.core.$strip>>;
95
+ captions: z.ZodArray<z.ZodObject<{
96
+ text: z.ZodString;
97
+ startMs: z.ZodNumber;
98
+ endMs: z.ZodNumber;
99
+ words: z.ZodExactOptional<z.ZodArray<z.ZodObject<{
100
+ text: z.ZodString;
101
+ startMs: z.ZodNumber;
102
+ endMs: z.ZodNumber;
103
+ }, z.core.$strip>>>;
104
+ }, z.core.$strip>>;
105
+ }, z.core.$strip>;
106
+ declare const sidecarSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
107
+ kind: z.ZodEnum<{
108
+ page: "page";
109
+ site: "site";
110
+ }>;
111
+ source: z.ZodString;
112
+ width: z.ZodNumber;
113
+ height: z.ZodNumber;
114
+ device: z.ZodEnum<{
115
+ phone: "phone";
116
+ desktop: "desktop";
117
+ }>;
118
+ scale: z.ZodLiteral<2>;
119
+ durationMs: z.ZodNumber;
120
+ steps: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
121
+ do: z.ZodLiteral<"goto">;
122
+ url: z.ZodString;
123
+ atLine: z.ZodExactOptional<z.ZodNumber>;
124
+ }, z.core.$strict>, z.ZodObject<{
125
+ do: z.ZodLiteral<"click">;
126
+ target: z.ZodString;
127
+ atLine: z.ZodExactOptional<z.ZodNumber>;
128
+ }, z.core.$strict>, z.ZodObject<{
129
+ do: z.ZodLiteral<"type">;
130
+ target: z.ZodString;
131
+ text: z.ZodString;
132
+ atLine: z.ZodExactOptional<z.ZodNumber>;
133
+ }, z.core.$strict>, z.ZodObject<{
134
+ do: z.ZodLiteral<"press">;
135
+ key: z.ZodString;
136
+ atLine: z.ZodExactOptional<z.ZodNumber>;
137
+ }, z.core.$strict>, z.ZodObject<{
138
+ do: z.ZodLiteral<"hover">;
139
+ target: z.ZodString;
140
+ atLine: z.ZodExactOptional<z.ZodNumber>;
141
+ }, z.core.$strict>, z.ZodObject<{
142
+ do: z.ZodLiteral<"scroll">;
143
+ pixels: z.ZodNumber;
144
+ atLine: z.ZodExactOptional<z.ZodNumber>;
145
+ }, z.core.$strict>, z.ZodObject<{
146
+ do: z.ZodLiteral<"wait">;
147
+ ms: z.ZodNumber;
148
+ }, z.core.$strict>, z.ZodObject<{
149
+ do: z.ZodLiteral<"waitFor">;
150
+ target: z.ZodString;
151
+ atLine: z.ZodExactOptional<z.ZodNumber>;
152
+ }, z.core.$strict>], "do">>;
153
+ actions: z.ZodArray<z.ZodObject<{
154
+ do: z.ZodString;
155
+ atMs: z.ZodNumber;
156
+ actMs: z.ZodOptional<z.ZodNumber>;
157
+ endMs: z.ZodNumber;
158
+ box: z.ZodOptional<z.ZodObject<{
159
+ x: z.ZodNumber;
160
+ y: z.ZodNumber;
161
+ width: z.ZodNumber;
162
+ height: z.ZodNumber;
163
+ }, z.core.$strip>>;
164
+ }, z.core.$strip>>;
165
+ }, z.core.$strip>, z.ZodObject<{
166
+ kind: z.ZodLiteral<"narration">;
167
+ durationMs: z.ZodNumber;
168
+ captions: z.ZodArray<z.ZodObject<{
169
+ text: z.ZodString;
170
+ startMs: z.ZodNumber;
171
+ endMs: z.ZodNumber;
172
+ words: z.ZodExactOptional<z.ZodArray<z.ZodObject<{
173
+ text: z.ZodString;
174
+ startMs: z.ZodNumber;
175
+ endMs: z.ZodNumber;
176
+ }, z.core.$strip>>>;
177
+ }, z.core.$strip>>;
178
+ }, z.core.$strip>, z.ZodObject<{
179
+ kind: z.ZodLiteral<"video">;
180
+ durationMs: z.ZodNumber;
181
+ width: z.ZodNumber;
182
+ height: z.ZodNumber;
183
+ scenes: z.ZodArray<z.ZodObject<{
184
+ startMs: z.ZodNumber;
185
+ endMs: z.ZodNumber;
186
+ }, z.core.$strip>>;
187
+ captions: z.ZodArray<z.ZodObject<{
188
+ text: z.ZodString;
189
+ startMs: z.ZodNumber;
190
+ endMs: z.ZodNumber;
191
+ words: z.ZodExactOptional<z.ZodArray<z.ZodObject<{
192
+ text: z.ZodString;
193
+ startMs: z.ZodNumber;
194
+ endMs: z.ZodNumber;
195
+ }, z.core.$strip>>>;
196
+ }, z.core.$strip>>;
197
+ }, z.core.$strip>], "kind">;
198
+ /** What a sidecar holds. */
199
+ export type Sidecar = z.output<typeof sidecarSchema>;
200
+ /** The sidecar's path beside a file. */
201
+ export declare function sidecarPath(file: string): string;
202
+ /** The sidecar beside an output; an existing one is replaced only with `replace` (plan 16 §16.3). */
203
+ export declare function sidecarOutputPath(output: string, replace: boolean, shown: string): string;
204
+ /** The sidecar beside `file`, or `undefined` when it is missing or invalid. */
205
+ export declare function readSidecar(file: string): Sidecar | undefined;
206
+ /** Writes a sidecar into a work folder, to be placed beside its output; answers its path there. */
207
+ export declare function writeSidecar(folder: string, sidecar: Sidecar): string;
208
+ export {};
209
+ //# sourceMappingURL=sidecar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sidecar.d.ts","sourceRoot":"","sources":["../../src/files/sidecar.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,YAAY,CAAC;AAS/B,eAAO,MAAM,oBAAoB;;;;;;;;;iBAA6J,CAAC;AAE/L,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAUjC,CAAC;AAEH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;iBAAkI,CAAC;AAEtK,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;iBAO7B,CAAC;AAEH,QAAA,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAAqG,CAAC;AAEzH,4BAA4B;AAC5B,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,aAAa,CAAC,CAAC;AAErD,wCAAwC;AACxC,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,qGAAqG;AACrG,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAIzF;AAWD,+EAA+E;AAC/E,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAK7D;AAED,mGAAmG;AACnG,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CAIrE"}
@@ -0,0 +1,66 @@
1
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { z } from '@kvman/sdk';
4
+ import { invalid } from "../problems.js";
5
+ import { actionSchema, stepSchema } from "../record/steps.js";
6
+ // The sidecar beside an output, `<file>.kvvideo.json` (plan 16 §16.3; ADR 0115, 31): what a later command needs from
7
+ // it, so the agent copies no numbers between calls. It is validated when read; a missing or invalid one is absent.
8
+ const wordSchema = z.object({ text: z.string(), startMs: z.number().int().nonnegative(), endMs: z.number().int().nonnegative() });
9
+ export const sidecarCaptionSchema = z.object({ text: z.string(), startMs: z.number().int().nonnegative(), endMs: z.number().int().nonnegative(), words: z.array(wordSchema).exactOptional() });
10
+ export const recordingSidecarSchema = z.object({
11
+ kind: z.enum(['site', 'page']),
12
+ source: z.string(),
13
+ width: z.number().int().positive(),
14
+ height: z.number().int().positive(),
15
+ device: z.enum(['desktop', 'phone']),
16
+ scale: z.literal(2),
17
+ durationMs: z.number().int().nonnegative(),
18
+ steps: z.array(stepSchema),
19
+ actions: z.array(actionSchema),
20
+ });
21
+ export const narrationSidecarSchema = z.object({ kind: z.literal('narration'), durationMs: z.number().int().nonnegative(), captions: z.array(sidecarCaptionSchema) });
22
+ export const videoSidecarSchema = z.object({
23
+ kind: z.literal('video'),
24
+ durationMs: z.number().int().nonnegative(),
25
+ width: z.number().int().positive(),
26
+ height: z.number().int().positive(),
27
+ scenes: z.array(z.object({ startMs: z.number().int().nonnegative(), endMs: z.number().int().nonnegative() })),
28
+ captions: z.array(sidecarCaptionSchema),
29
+ });
30
+ const sidecarSchema = z.discriminatedUnion('kind', [recordingSidecarSchema, narrationSidecarSchema, videoSidecarSchema]);
31
+ /** The sidecar's path beside a file. */
32
+ export function sidecarPath(file) {
33
+ return `${file}.kvvideo.json`;
34
+ }
35
+ /** The sidecar beside an output; an existing one is replaced only with `replace` (plan 16 §16.3). */
36
+ export function sidecarOutputPath(output, replace, shown) {
37
+ const beside = sidecarPath(output);
38
+ if (existsSync(beside) && !replace)
39
+ throw invalid(`${sidecarPath(shown)} exists; set replace to true to write over it.`, { path: sidecarPath(shown) });
40
+ return beside;
41
+ }
42
+ function parsed(text) {
43
+ try {
44
+ return JSON.parse(text);
45
+ }
46
+ catch (error) {
47
+ if (error instanceof SyntaxError)
48
+ return undefined;
49
+ throw error;
50
+ }
51
+ }
52
+ /** The sidecar beside `file`, or `undefined` when it is missing or invalid. */
53
+ export function readSidecar(file) {
54
+ const beside = sidecarPath(file);
55
+ if (!existsSync(beside))
56
+ return undefined;
57
+ const result = sidecarSchema.safeParse(parsed(readFileSync(beside, 'utf8')));
58
+ return result.success ? result.data : undefined;
59
+ }
60
+ /** Writes a sidecar into a work folder, to be placed beside its output; answers its path there. */
61
+ export function writeSidecar(folder, sidecar) {
62
+ const made = path.join(folder, 'sidecar.json');
63
+ writeFileSync(made, `${JSON.stringify(sidecar, null, 2)}\n`);
64
+ return made;
65
+ }
66
+ //# sourceMappingURL=sidecar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sidecar.js","sourceRoot":"","sources":["../../src/files/sidecar.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAWtC,YAAY,EAAE,MAAM,UAAU,CAAC;yBAKf,KAAK,GAAG,KAAG,IAAI;AAA/B,wBAUE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AActC,YAAY,EAAE,MAAM,UAAU,CAAC;yBAKf,KAAK,GAAG,KAAG,IAAI;AAA/B,wBAaE"}
package/dist/index.js CHANGED
@@ -1,23 +1,29 @@
1
+ import { registerBrand } from "./brand/brand.js";
1
2
  import { registerCompose } from "./compose/register-compose.js";
2
3
  import { registerFonts } from "./fonts/register-fonts.js";
3
4
  import { registerNarration } from "./narration/register-narration.js";
5
+ import { registerVoice } from "./narration/register-voice.js";
4
6
  import { registerRecord } from "./record/register-record.js";
7
+ import { registerReview } from "./review/register-review.js";
5
8
  import { registerWithKvcoder } from "./register-with-kvcoder.js";
6
9
  import { registerSettings } from "./settings.js";
7
10
  import { registerSetup } from "./setup/register-setup.js";
8
11
  import { registerUi } from "./ui.js";
9
12
  import { registerVideoStart } from "./video-start.js";
10
- // kvvideo (plan 16): makes videos of the person's app, recorded in the installed browser, narrated, and captioned. It
13
+ // kvvideo (plan 16): makes any kind of video, recorded in the installed browser, narrated, and captioned. It
11
14
  // has no loop of its own; it extends kvcoder with the `video` connector and its guide, which a chat has once the
12
15
  // person runs `/video` in it (ADR 0107).
13
16
  export default (ctx) => {
14
17
  registerSettings(ctx);
18
+ registerBrand(ctx);
15
19
  registerUi(ctx);
16
20
  registerSetup(ctx);
17
21
  registerFonts(ctx);
18
22
  registerRecord(ctx);
19
23
  registerNarration(ctx);
24
+ registerVoice(ctx);
20
25
  registerCompose(ctx);
26
+ registerReview(ctx);
21
27
  registerVideoStart(ctx);
22
28
  registerWithKvcoder(ctx);
23
29
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAItD,sHAAsH;AACtH,iHAAiH;AACjH,yCAAyC;AACzC,eAAe,CAAC,GAAQ,EAAQ,EAAE;IAChC,gBAAgB,CAAC,GAAG,CAAC,CAAC;IACtB,UAAU,CAAC,GAAG,CAAC,CAAC;IAChB,aAAa,CAAC,GAAG,CAAC,CAAC;IACnB,aAAa,CAAC,GAAG,CAAC,CAAC;IACnB,cAAc,CAAC,GAAG,CAAC,CAAC;IACpB,iBAAiB,CAAC,GAAG,CAAC,CAAC;IACvB,eAAe,CAAC,GAAG,CAAC,CAAC;IACrB,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACxB,mBAAmB,CAAC,GAAG,CAAC,CAAC;AAC3B,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAItD,6GAA6G;AAC7G,iHAAiH;AACjH,yCAAyC;AACzC,eAAe,CAAC,GAAQ,EAAQ,EAAE;IAChC,gBAAgB,CAAC,GAAG,CAAC,CAAC;IACtB,aAAa,CAAC,GAAG,CAAC,CAAC;IACnB,UAAU,CAAC,GAAG,CAAC,CAAC;IAChB,aAAa,CAAC,GAAG,CAAC,CAAC;IACnB,aAAa,CAAC,GAAG,CAAC,CAAC;IACnB,cAAc,CAAC,GAAG,CAAC,CAAC;IACpB,iBAAiB,CAAC,GAAG,CAAC,CAAC;IACvB,aAAa,CAAC,GAAG,CAAC,CAAC;IACnB,eAAe,CAAC,GAAG,CAAC,CAAC;IACrB,cAAc,CAAC,GAAG,CAAC,CAAC;IACpB,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACxB,mBAAmB,CAAC,GAAG,CAAC,CAAC;AAC3B,CAAC,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { z } from '@kvman/sdk';
2
+ export declare const alignmentSchema: z.ZodObject<{
3
+ startsMs: z.ZodArray<z.ZodNumber>;
4
+ endsMs: z.ZodArray<z.ZodNumber>;
5
+ }, z.core.$strip>;
6
+ /** When each spoken character starts and ends, in ms from the sentence's start. */
7
+ export type Alignment = z.output<typeof alignmentSchema>;
8
+ export declare const elevenLabsAlignmentSchema: z.ZodObject<{
9
+ characters: z.ZodArray<z.ZodString>;
10
+ character_start_times_seconds: z.ZodArray<z.ZodNumber>;
11
+ character_end_times_seconds: z.ZodArray<z.ZodNumber>;
12
+ }, z.core.$strip>;
13
+ /** The alignment of `spoken`; one whose characters aren't the text fails `kvvideo/NARRATION_FAILED`. */
14
+ export declare function alignmentOf(answer: z.output<typeof elevenLabsAlignmentSchema>, spoken: string): Alignment;
15
+ //# sourceMappingURL=alignment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alignment.d.ts","sourceRoot":"","sources":["../../src/narration/alignment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,YAAY,CAAC;AAM/B,eAAO,MAAM,eAAe;;;iBAAmH,CAAC;AAEhJ,mFAAmF;AACnF,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,eAAe,CAAC,CAAC;AAEzD,eAAO,MAAM,yBAAyB;;;;iBAIpC,CAAC;AAIH,wGAAwG;AACxG,wBAAgB,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,yBAAyB,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,CAOzG"}
@@ -0,0 +1,21 @@
1
+ import { z } from '@kvman/sdk';
2
+ import { kvvideoProblem } from "../problems.js";
3
+ // ElevenLabs's character times (plan 16 §16.6; ADR 0115, 17): each character of the text it was sent, by code point,
4
+ // with when it starts and ends, kept in whole milliseconds.
5
+ export const alignmentSchema = z.object({ startsMs: z.array(z.number().int().nonnegative()), endsMs: z.array(z.number().int().nonnegative()) });
6
+ export const elevenLabsAlignmentSchema = z.object({
7
+ characters: z.array(z.string()),
8
+ character_start_times_seconds: z.array(z.number()),
9
+ character_end_times_seconds: z.array(z.number()),
10
+ });
11
+ const ms = (seconds) => Math.max(0, Math.round(seconds * 1000));
12
+ /** The alignment of `spoken`; one whose characters aren't the text fails `kvvideo/NARRATION_FAILED`. */
13
+ export function alignmentOf(answer, spoken) {
14
+ const { characters, character_start_times_seconds: starts, character_end_times_seconds: ends } = answer;
15
+ if (characters.join('') !== spoken || [...spoken].length !== characters.length || starts.length !== characters.length || ends.length !== characters.length) {
16
+ const reason = "ElevenLabs's character times don't match the text it was sent";
17
+ throw kvvideoProblem('NARRATION_FAILED', reason, { service: 'elevenlabs', reason });
18
+ }
19
+ return { startsMs: starts.map(ms), endsMs: ends.map(ms) };
20
+ }
21
+ //# sourceMappingURL=alignment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alignment.js","sourceRoot":"","sources":["../../src/narration/alignment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,YAAY,CAAC;AAC/B,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,qHAAqH;AACrH,4DAA4D;AAE5D,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC;AAKhJ,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChD,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAC/B,6BAA6B,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAClD,2BAA2B,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;CACjD,CAAC,CAAC;AAEH,MAAM,EAAE,GAAG,CAAC,OAAe,EAAU,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC;AAEhF,wGAAwG;AACxG,MAAM,UAAU,WAAW,CAAC,MAAkD,EAAE,MAAc;IAC5F,MAAM,EAAE,UAAU,EAAE,6BAA6B,EAAE,MAAM,EAAE,2BAA2B,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC;IACxG,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,MAAM,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC,MAAM,EAAE,CAAC;QAC3J,MAAM,MAAM,GAAG,+DAA+D,CAAC;QAC/E,MAAM,cAAc,CAAC,kBAAkB,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC;IACtF,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;AAC5D,CAAC"}
@@ -1,10 +1,28 @@
1
+ import type { Alignment } from './alignment.ts';
2
+ import type { Spoken } from './pronunciations.ts';
3
+ export type Word = {
4
+ text: string;
5
+ startMs: number;
6
+ endMs: number;
7
+ };
1
8
  export type Caption = {
2
9
  text: string;
3
10
  startMs: number;
4
11
  endMs: number;
12
+ words?: Word[];
13
+ };
14
+ /** The text's sentences, in order: cut at line breaks and after `.`, `!`, `?`, `؟`, and `…` followed by a space. */
15
+ export declare function sentencesOf(text: string): string[];
16
+ /** A sentence's caption lines: whole words, each line as long as it can be up to 42 characters. */
17
+ export declare function linesOf(sentence: string): string[];
18
+ /** One sentence's place in the narration: its audio from `startMs` for `durationMs`, and its character times. */
19
+ export type PlacedSentence = {
20
+ text: string;
21
+ spoken: Spoken;
22
+ startMs: number;
23
+ durationMs: number;
24
+ alignment: Alignment | null;
5
25
  };
6
- /** The caption lines of a text, in order. */
7
- export declare function captionLines(text: string): string[];
8
- /** The text's captions over a narration of `durationMs`. */
9
- export declare function timedCaptions(text: string, durationMs: number): Caption[];
26
+ /** The captions of placed sentences over a narration of `durationMs`: each line ends where the next starts. */
27
+ export declare function captionsOf(sentences: readonly PlacedSentence[], durationMs: number): Caption[];
10
28
  //# sourceMappingURL=captions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"captions.d.ts","sourceRoot":"","sources":["../../src/narration/captions.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,OAAO,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AA0BvE,6CAA6C;AAC7C,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAGnD;AAED,4DAA4D;AAC5D,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,EAAE,CAUzE"}
1
+ {"version":3,"file":"captions.d.ts","sourceRoot":"","sources":["../../src/narration/captions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAMlD,MAAM,MAAM,IAAI,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpE,MAAM,MAAM,OAAO,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,IAAI,EAAE,CAAA;CAAE,CAAC;AAMvF,oHAAoH;AACpH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAMlD;AAED,mGAAmG;AACnG,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAclD;AAED,iHAAiH;AACjH,MAAM,MAAM,cAAc,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,SAAS,GAAG,IAAI,CAAA;CAAE,CAAC;AAwChI,+GAA+G;AAC/G,wBAAgB,UAAU,CAAC,SAAS,EAAE,SAAS,cAAc,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,EAAE,CAG9F"}
@@ -1,11 +1,15 @@
1
- // A narration's captions (plan 16 §16.6, ADR 0107, 7): lines of whole words, each shown for the share of the
2
- // narration's length that its characters have, one after another from 0 with no gap.
3
1
  const maximumLine = 42;
4
2
  const length = (text) => [...text].length;
5
- function sentencesOf(line) {
6
- return line.split(/(?<=[.!?؟…])\s+/u).filter((sentence) => sentence !== '');
3
+ /** The text's sentences, in order: cut at line breaks and after `.`, `!`, `?`, `؟`, and `…` followed by a space. */
4
+ export function sentencesOf(text) {
5
+ return text
6
+ .split(/\r?\n/u)
7
+ .map((line) => line.replace(/\s+/gu, ' ').trim())
8
+ .flatMap((line) => line.split(/(?<=[.!?؟…])\s+/u))
9
+ .filter((sentence) => sentence !== '');
7
10
  }
8
- function linesOf(sentence) {
11
+ /** A sentence's caption lines: whole words, each line as long as it can be up to 42 characters. */
12
+ export function linesOf(sentence) {
9
13
  const lines = [];
10
14
  let current = '';
11
15
  for (const word of sentence.split(' ')) {
@@ -22,21 +26,45 @@ function linesOf(sentence) {
22
26
  lines.push(current);
23
27
  return lines;
24
28
  }
25
- /** The caption lines of a text, in order. */
26
- export function captionLines(text) {
27
- const textLines = text.split(/\r?\n/u).map((line) => line.replace(/\s+/gu, ' ').trim());
28
- return textLines.flatMap(sentencesOf).flatMap(linesOf);
29
+ // Each line's start, in characters of the sentence, and its words with their starts and ends.
30
+ function lineSpans(sentence) {
31
+ const characters = [...sentence];
32
+ let at = 0;
33
+ return linesOf(sentence).map((line) => {
34
+ while (characters[at] === ' ')
35
+ at += 1;
36
+ const from = at;
37
+ const words = [];
38
+ for (const word of line.split(' ')) {
39
+ words.push({ text: word, from: at, to: at + length(word) - 1 });
40
+ at += length(word) + 1;
41
+ }
42
+ at -= 1;
43
+ return { text: line, from, words };
44
+ });
29
45
  }
30
- /** The text's captions over a narration of `durationMs`. */
31
- export function timedCaptions(text, durationMs) {
32
- const lines = captionLines(text);
46
+ function proportional(sentence) {
47
+ const lines = linesOf(sentence.text);
33
48
  const total = lines.reduce((sum, line) => sum + length(line), 0);
34
49
  let before = 0;
35
- return lines.map((line, index) => {
36
- const startMs = Math.floor((durationMs * before) / total);
50
+ return lines.map((line) => {
51
+ const startMs = sentence.startMs + Math.floor((sentence.durationMs * before) / total);
37
52
  before += length(line);
38
- const endMs = index === lines.length - 1 ? durationMs : Math.floor((durationMs * before) / total);
39
- return { text: line, startMs, endMs };
53
+ return { text: line, startMs, endMs: 0 };
40
54
  });
41
55
  }
56
+ function aligned(sentence, alignment) {
57
+ const at = (index, edge) => sentence.startMs + Math.floor(alignment[edge][sentence.spoken.spokenIndex(index, edge === 'startsMs' ? 'first' : 'last')] ?? 0);
58
+ return lineSpans(sentence.text).map((line) => ({
59
+ text: line.text,
60
+ startMs: at(line.from, 'startsMs'),
61
+ endMs: 0,
62
+ words: line.words.map((word) => ({ text: word.text, startMs: at(word.from, 'startsMs'), endMs: at(word.to, 'endsMs') })),
63
+ }));
64
+ }
65
+ /** The captions of placed sentences over a narration of `durationMs`: each line ends where the next starts. */
66
+ export function captionsOf(sentences, durationMs) {
67
+ const lines = sentences.flatMap((sentence) => (sentence.alignment === null ? proportional(sentence) : aligned(sentence, sentence.alignment)));
68
+ return lines.map((line, index) => ({ ...line, endMs: index === lines.length - 1 ? durationMs : (lines[index + 1]?.startMs ?? durationMs) }));
69
+ }
42
70
  //# sourceMappingURL=captions.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"captions.js","sourceRoot":"","sources":["../../src/narration/captions.ts"],"names":[],"mappings":"AAAA,6GAA6G;AAC7G,qFAAqF;AAIrF,MAAM,WAAW,GAAG,EAAE,CAAC;AAEvB,MAAM,MAAM,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,MAAM,CAAC;AAE1D,SAAS,WAAW,CAAC,IAAY;IAC/B,OAAO,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,KAAK,EAAE,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,OAAO,CAAC,QAAgB;IAC/B,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACvC,MAAM,MAAM,GAAG,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,IAAI,EAAE,CAAC;QAC5D,IAAI,OAAO,KAAK,EAAE,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,WAAW,EAAE,CAAC;YACnD,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACpB,OAAO,GAAG,IAAI,CAAC;QACjB,CAAC;aAAM,CAAC;YACN,OAAO,GAAG,MAAM,CAAC;QACnB,CAAC;IACH,CAAC;IACD,IAAI,OAAO,KAAK,EAAE;QAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACxC,OAAO,KAAK,CAAC;AACf,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACxF,OAAO,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AACzD,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,UAAkB;IAC5D,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACjC,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IACjE,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,UAAU,GAAG,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC;QAC1D,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC;QACvB,MAAM,KAAK,GAAG,KAAK,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,UAAU,GAAG,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC;QAClG,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IACxC,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"captions.js","sourceRoot":"","sources":["../../src/narration/captions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare const sentenceGapMs = 250;
2
+ export declare function joinNarrationArgs(inputs: readonly string[], output: string): string[];
3
+ //# sourceMappingURL=join-args.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"join-args.d.ts","sourceRoot":"","sources":["../../src/narration/join-args.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,aAAa,MAAM,CAAC;AAEjC,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAcrF"}
@@ -0,0 +1,19 @@
1
+ // ffmpeg's arguments to join a narration's sentences (plan 16 §16.6 and §16.7; ADR 0115, 41): each brought to the
2
+ // same sound, 250 ms of silence after every one but the last, joined in order and encoded as MP3 at 192 kb/s.
3
+ export const sentenceGapMs = 250;
4
+ export function joinNarrationArgs(inputs, output) {
5
+ const shaped = inputs.map((_, index) => {
6
+ const pad = index === inputs.length - 1 ? '' : `,apad=pad_dur=${String(sentenceGapMs / 1000)}`;
7
+ return `[${String(index)}:a]aformat=sample_rates=44100:channel_layouts=mono${pad}[s${String(index)}]`;
8
+ });
9
+ const joined = `${inputs.map((_, index) => `[s${String(index)}]`).join('')}concat=n=${String(inputs.length)}:v=0:a=1[out]`;
10
+ return [
11
+ '-hide_banner', '-loglevel', 'error',
12
+ ...inputs.flatMap((input) => ['-i', input]),
13
+ '-filter_complex', [...shaped, joined].join(';'),
14
+ '-map', '[out]',
15
+ '-codec:a', 'libmp3lame', '-b:a', '192k',
16
+ '-y', output,
17
+ ];
18
+ }
19
+ //# sourceMappingURL=join-args.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"join-args.js","sourceRoot":"","sources":["../../src/narration/join-args.ts"],"names":[],"mappings":"AAAA,kHAAkH;AAClH,8GAA8G;AAE9G,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,CAAC;AAEjC,MAAM,UAAU,iBAAiB,CAAC,MAAyB,EAAE,MAAc;IACzE,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE;QACrC,MAAM,GAAG,GAAG,KAAK,KAAK,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,iBAAiB,MAAM,CAAC,aAAa,GAAG,IAAI,CAAC,EAAE,CAAC;QAC/F,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,qDAAqD,GAAG,KAAK,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC;IACxG,CAAC,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,YAAY,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC;IAC3H,OAAO;QACL,cAAc,EAAE,WAAW,EAAE,OAAO;QACpC,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC3C,iBAAiB,EAAE,CAAC,GAAG,MAAM,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;QAChD,MAAM,EAAE,OAAO;QACf,UAAU,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM;QACxC,IAAI,EAAE,MAAM;KACb,CAAC;AACJ,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { type Collection, type Ctx, type Files, type JsonObject } from '@kvman/sdk';
2
+ import { type Alignment } from './alignment.ts';
3
+ /** What makes two sentences sound the same. */
4
+ export type SentenceKey = {
5
+ service: string;
6
+ voice: string | null;
7
+ model: string | null;
8
+ tone: string | null;
9
+ speed: number;
10
+ spoken: string;
11
+ };
12
+ export type CachedSentence = {
13
+ audio: Buffer;
14
+ type: string;
15
+ durationMs: number;
16
+ alignment: Alignment | null;
17
+ };
18
+ export declare function sentenceKey(key: SentenceKey): string;
19
+ export declare function cachedSentence(ctx: Ctx, key: string): Promise<CachedSentence | undefined>;
20
+ export declare function keepSentence(ctx: Ctx, key: string, sentence: CachedSentence): Promise<void>;
21
+ /** Deletes the oldest rows past `limit`, with their files. */
22
+ export declare function trimOldest<Row extends JsonObject & {
23
+ fileId: string;
24
+ }>(collection: Pick<Collection<Row>, 'count' | 'find' | 'delete'>, files: Pick<Files, 'unlink'>, limit: number): Promise<void>;
25
+ //# sourceMappingURL=narration-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"narration-cache.d.ts","sourceRoot":"","sources":["../../src/narration/narration-cache.ts"],"names":[],"mappings":"AACA,OAAO,EAAK,KAAK,UAAU,EAAE,KAAK,GAAG,EAAE,KAAK,KAAK,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AACvF,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAUjE,+CAA+C;AAC/C,MAAM,MAAM,WAAW,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9I,MAAM,MAAM,cAAc,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,SAAS,GAAG,IAAI,CAAA;CAAE,CAAC;AAE9G,wBAAgB,WAAW,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CAEpD;AAID,wBAAsB,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAI/F;AAED,wBAAsB,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAMjG;AAED,8DAA8D;AAC9D,wBAAsB,UAAU,CAAC,GAAG,SAAS,UAAU,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOxM"}
@@ -0,0 +1,36 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { z } from '@kvman/sdk';
3
+ import { alignmentSchema } from "./alignment.js";
4
+ // The narration cache (plan 16 §16.6; ADR 0115, 40): each spoken sentence's audio, kept in the kernel's files with a
5
+ // row in the workspace collection `narrations`, so an unchanged sentence is never paid for twice. Past 2000 rows the
6
+ // oldest go with their files; the collection's ids rise with time, so the oldest come first.
7
+ const kept = 2000;
8
+ const rowSchema = z.object({ key: z.string(), fileId: z.string(), type: z.string(), durationMs: z.number().int().nonnegative(), alignment: alignmentSchema.nullable(), createdAt: z.string() });
9
+ export function sentenceKey(key) {
10
+ return createHash('sha256').update(JSON.stringify([key.service, key.voice, key.model, key.tone, key.speed, key.spoken])).digest('hex');
11
+ }
12
+ const rows = (ctx) => ctx.store.collection('narrations', rowSchema);
13
+ export async function cachedSentence(ctx, key) {
14
+ const [row] = await rows(ctx).find({ key }, { limit: 1 });
15
+ if (row === undefined)
16
+ return undefined;
17
+ return { audio: await ctx.files.read(row.fileId), type: row.type, durationMs: row.durationMs, alignment: row.alignment };
18
+ }
19
+ export async function keepSentence(ctx, key, sentence) {
20
+ const extension = sentence.type === 'audio/wav' ? 'wav' : 'mp3';
21
+ const file = await ctx.files.write(`narration-${key.slice(0, 16)}.${extension}`, sentence.audio, sentence.type);
22
+ const collection = rows(ctx);
23
+ await collection.insert({ key, fileId: file.id, type: sentence.type, durationMs: sentence.durationMs, alignment: sentence.alignment, createdAt: new Date().toISOString() });
24
+ await trimOldest(collection, ctx.files, kept);
25
+ }
26
+ /** Deletes the oldest rows past `limit`, with their files. */
27
+ export async function trimOldest(collection, files, limit) {
28
+ const extra = (await collection.count({})) - limit;
29
+ if (extra <= 0)
30
+ return;
31
+ for (const old of await collection.find({}, { limit: extra, order: 'asc' })) {
32
+ await files.unlink(old.fileId);
33
+ await collection.delete(old.id);
34
+ }
35
+ }
36
+ //# sourceMappingURL=narration-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"narration-cache.js","sourceRoot":"","sources":["../../src/narration/narration-cache.ts"],"names":[],"mappings":"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"}