@gentbajko/slopify 2.4.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (469) hide show
  1. package/LICENSE +201 -21
  2. package/NOTICE +12 -0
  3. package/README.md +21 -40
  4. package/SUBTITLES.md +1 -1
  5. package/dist/adapter-registry.js +11 -1
  6. package/dist/adapters/alignment/cache.js +4 -1
  7. package/dist/adapters/alignment/ctc.js +25 -23
  8. package/dist/adapters/alignment/index.js +37 -6
  9. package/dist/adapters/alignment/multilingual.js +267 -0
  10. package/dist/adapters/alignment/protocol.js +11 -0
  11. package/dist/adapters/alignment/quality.js +4 -3
  12. package/dist/adapters/alignment/sentences.js +95 -0
  13. package/dist/adapters/alignment/spec.js +24 -0
  14. package/dist/adapters/alignment/spell.js +769 -0
  15. package/dist/adapters/alignment/text.js +56 -9
  16. package/dist/adapters/alignment/window.js +34 -30
  17. package/dist/adapters/alignment/worker.js +23 -21
  18. package/dist/adapters/explain.js +11 -11
  19. package/dist/adapters/host-cli/index.js +55 -5
  20. package/dist/adapters/host-cli/transport.js +13 -6
  21. package/dist/adapters/image/bytes.js +2 -2
  22. package/dist/adapters/image/codex-output.js +60 -18
  23. package/dist/adapters/image/codex.js +166 -25
  24. package/dist/adapters/image/fal.js +31 -3
  25. package/dist/adapters/image/google.js +17 -2
  26. package/dist/adapters/image/openai.js +45 -16
  27. package/dist/adapters/image/reference.js +41 -0
  28. package/dist/adapters/image/replicate.js +14 -2
  29. package/dist/adapters/image/video.js +2 -2
  30. package/dist/adapters/key-probes.js +36 -0
  31. package/dist/adapters/llm/claude-code.js +168 -32
  32. package/dist/adapters/llm/cli-login-error.js +1 -1
  33. package/dist/adapters/llm/codex-limits.js +157 -0
  34. package/dist/adapters/llm/codex-models.js +2 -1
  35. package/dist/adapters/llm/codex-server-models.js +2 -1
  36. package/dist/adapters/llm/codex.js +99 -12
  37. package/dist/adapters/llm/document-workspace.js +2 -2
  38. package/dist/adapters/llm/gemini-workspace.js +1 -1
  39. package/dist/adapters/llm/gemini.js +16 -3
  40. package/dist/adapters/llm/image-workspace.js +58 -0
  41. package/dist/adapters/llm/openrouter.js +11 -3
  42. package/dist/adapters/llm/run-cli.js +26 -9
  43. package/dist/adapters/tts/cartesia.js +10 -0
  44. package/dist/adapters/tts/elevenlabs.js +31 -9
  45. package/dist/adapters/tts/inworld-async.js +9 -5
  46. package/dist/adapters/tts/inworld.js +17 -3
  47. package/dist/adapters/tts/openai.js +3 -0
  48. package/dist/adapters/tts/voice-languages.js +80 -0
  49. package/dist/assets/fonts/noto/NotoSans-Regular.ttf +0 -0
  50. package/dist/assets/fonts/noto/NotoSansArabic-Regular.ttf +0 -0
  51. package/dist/assets/fonts/noto/NotoSansDevanagari-Regular.ttf +0 -0
  52. package/dist/assets/fonts/noto/NotoSansHebrew-Regular.ttf +0 -0
  53. package/dist/assets/fonts/noto/NotoSansThai-Regular.ttf +0 -0
  54. package/dist/assets/fonts/noto/OFL.txt +93 -0
  55. package/dist/assets/fonts/noto/SOURCE.txt +18 -0
  56. package/dist/assets/models.yaml +7 -0
  57. package/dist/assets/sample/sample-audiobook.tar +0 -0
  58. package/dist/assets/sample/sample-podcast.tar +0 -0
  59. package/dist/assets/sample/sample-project.tar +0 -0
  60. package/dist/catalog/merge.js +132 -0
  61. package/dist/catalog/registry.js +33 -12
  62. package/dist/catalog/runtime-models.js +1 -1
  63. package/dist/catalog/schema.js +12 -1
  64. package/dist/catalog/store.js +147 -8
  65. package/dist/catalog/validate.js +17 -2
  66. package/dist/compose.yaml +71 -0
  67. package/dist/edge/autostart/docker-record.js +32 -0
  68. package/dist/edge/autostart/docker.js +50 -0
  69. package/dist/edge/autostart/index.js +78 -0
  70. package/dist/edge/autostart/launcher.js +176 -0
  71. package/dist/edge/autostart/model.js +3 -0
  72. package/dist/edge/autostart/native.js +210 -0
  73. package/dist/edge/autostart/prompt.js +66 -0
  74. package/dist/edge/autostart/service.js +81 -0
  75. package/dist/edge/cli.js +57 -51
  76. package/dist/edge/docker-install/activation.js +56 -0
  77. package/dist/edge/docker-install/apply.js +458 -0
  78. package/dist/edge/docker-install/engine.js +362 -0
  79. package/dist/edge/docker-install/run.js +154 -0
  80. package/dist/edge/docker-install/state.js +146 -0
  81. package/dist/edge/{docker-projects → docker-install}/volume.js +1 -5
  82. package/dist/edge/docker.js +14 -22
  83. package/dist/edge/events/hub.js +11 -0
  84. package/dist/edge/host-cli.js +1 -1
  85. package/dist/edge/http/actions.js +32 -10
  86. package/dist/edge/http/app.js +60 -2
  87. package/dist/edge/http/auditions.js +70 -0
  88. package/dist/edge/http/autostart.js +37 -0
  89. package/dist/edge/http/backups.js +40 -0
  90. package/dist/edge/http/channel-memory.js +92 -0
  91. package/dist/edge/http/channels.js +128 -0
  92. package/dist/edge/http/entries.js +22 -3
  93. package/dist/edge/http/files.js +1 -1
  94. package/dist/edge/http/folder-location.js +1 -1
  95. package/dist/edge/http/home.js +39 -0
  96. package/dist/edge/http/host-cli.js +45 -6
  97. package/dist/edge/http/narration-peaks.js +76 -0
  98. package/dist/edge/http/onboarding.js +152 -0
  99. package/dist/edge/http/open-folder.js +1 -1
  100. package/dist/edge/http/patch-notes.js +45 -0
  101. package/dist/edge/http/planning.js +4 -2
  102. package/dist/edge/http/problem.js +1 -0
  103. package/dist/edge/http/project-create.js +87 -0
  104. package/dist/edge/http/projects.js +31 -99
  105. package/dist/edge/http/prompts.js +40 -3
  106. package/dist/edge/http/pronunciations.js +23 -4
  107. package/dist/edge/http/providers.js +86 -0
  108. package/dist/edge/http/reviews.js +121 -0
  109. package/dist/edge/http/revision-files.js +1 -1
  110. package/dist/edge/http/revisions.js +1 -1
  111. package/dist/edge/http/run-cost.js +25 -0
  112. package/dist/edge/http/schedules.js +111 -6
  113. package/dist/edge/http/settings.js +128 -6
  114. package/dist/edge/http/storage-files.js +50 -0
  115. package/dist/edge/http/storage.js +29 -2
  116. package/dist/edge/http/studio.js +207 -0
  117. package/dist/edge/http/style-preview.js +100 -0
  118. package/dist/edge/http/subtitles.js +1 -1
  119. package/dist/edge/http/trash.js +69 -0
  120. package/dist/edge/http/update.js +24 -3
  121. package/dist/edge/http/whats-new.js +15 -0
  122. package/dist/edge/http/youtube-edits.js +83 -0
  123. package/dist/edge/native-update.js +62 -0
  124. package/dist/host-cli/open-folder.js +10 -10
  125. package/dist/host-cli/runtime.js +12 -3
  126. package/dist/kernel/db/migrations/0022-drop-duplicate-held-work.sql +56 -0
  127. package/dist/kernel/db/migrations/0024-reference-attachments.sql +18 -0
  128. package/dist/kernel/db/migrations/0025-automatic-reviews.sql +40 -0
  129. package/dist/kernel/db/migrations/0026-schedule-topic-generation.sql +23 -0
  130. package/dist/kernel/db/migrations/0027-run-cost.sql +58 -0
  131. package/dist/kernel/db/migrations/0030-automatic-retries.sql +18 -0
  132. package/dist/kernel/db/migrations/0031-prompt-history-and-description-edits.sql +33 -0
  133. package/dist/kernel/db/migrations/0032-channels.sql +65 -0
  134. package/dist/kernel/db/migrations/0034-script-prompts.sql +23 -0
  135. package/dist/kernel/db/migrations/0035-narration-aliases.sql +13 -0
  136. package/dist/kernel/db/migrations/0037-project-uploads.sql +8 -0
  137. package/dist/kernel/db/migrations/0038-voice-languages.sql +7 -0
  138. package/dist/kernel/db/migrations/0039-channel-essentials.sql +64 -0
  139. package/dist/kernel/db/migrations/0040-standalone-usage.sql +35 -0
  140. package/dist/kernel/paths.js +27 -6
  141. package/dist/kernel/pipeline.js +4 -1
  142. package/dist/kernel/ports/host-cli.js +139 -16
  143. package/dist/kernel/ports/image.js +3 -1
  144. package/dist/kernel/ports/key-probe.js +1 -0
  145. package/dist/kernel/ports/languages.js +157 -0
  146. package/dist/kernel/ports/llm.js +3 -1
  147. package/dist/kernel/ports/model.js +5 -2
  148. package/dist/kernel/ports/narration-aliases.js +60 -0
  149. package/dist/kernel/ports/plan-limits.js +36 -0
  150. package/dist/kernel/runner/attempt.js +18 -9
  151. package/dist/kernel/runner/audition.js +36 -0
  152. package/dist/kernel/runner/graph.js +24 -5
  153. package/dist/kernel/runner/index.js +35 -5
  154. package/dist/kernel/runner/meter.js +1 -0
  155. package/dist/kernel/runner/providers.js +164 -9
  156. package/dist/kernel/runner/retry-policy.js +43 -0
  157. package/dist/kernel/runner/standalone.js +134 -0
  158. package/dist/kernel/runner/work-authority.js +28 -2
  159. package/dist/main.js +321 -20
  160. package/dist/patch-notes/0.4.2-to-1.0.md +93 -0
  161. package/dist/patch-notes/1.0-to-2.0.md +74 -0
  162. package/dist/patch-notes/2.0-to-3.0.md +257 -0
  163. package/dist/patch-notes/3.0.0.md +70 -0
  164. package/dist/patch-notes/index.json +26 -0
  165. package/dist/slices/admission/model.js +35 -0
  166. package/dist/slices/admission/repo.js +24 -4
  167. package/dist/slices/admission/rules.js +126 -1
  168. package/dist/slices/admission/schema.js +68 -1
  169. package/dist/slices/admission/short-mode.js +47 -0
  170. package/dist/slices/admission/start.js +90 -16
  171. package/dist/slices/article/continuation.js +2 -2
  172. package/dist/slices/article/provided-entries.js +2 -2
  173. package/dist/slices/article/run.js +6 -2
  174. package/dist/slices/article/segments.js +3 -3
  175. package/dist/slices/backups/files.js +135 -0
  176. package/dist/slices/backups/folder.js +43 -0
  177. package/dist/slices/backups/model.js +65 -0
  178. package/dist/slices/backups/repo.js +28 -0
  179. package/dist/slices/backups/schedule.js +60 -0
  180. package/dist/slices/backups/service.js +311 -0
  181. package/dist/slices/batch/index.js +9 -2
  182. package/dist/slices/cancel/index.js +1 -1
  183. package/dist/slices/channels/cast-images.js +110 -0
  184. package/dist/slices/channels/cast-match.js +32 -0
  185. package/dist/slices/channels/images.js +19 -0
  186. package/dist/slices/channels/model.js +5 -0
  187. package/dist/slices/channels/rebrand.js +100 -0
  188. package/dist/slices/channels/repo.js +218 -0
  189. package/dist/slices/channels/runs.js +129 -0
  190. package/dist/slices/channels/schema.js +129 -0
  191. package/dist/slices/channels/service.js +180 -0
  192. package/dist/slices/channels/studio-csv.js +110 -0
  193. package/dist/slices/channels/videos.js +120 -0
  194. package/dist/slices/checkpoints/recovery.js +10 -0
  195. package/dist/slices/control/index.js +2 -1
  196. package/dist/slices/document/fonts.js +1 -1
  197. package/dist/slices/document/render.js +1 -1
  198. package/dist/slices/episodes/related.js +90 -0
  199. package/dist/slices/episodes/repo.js +60 -0
  200. package/dist/slices/episodes/service.js +58 -0
  201. package/dist/slices/episodes/summarize.js +170 -0
  202. package/dist/slices/estimate/index.js +113 -24
  203. package/dist/slices/estimate/requests.js +60 -2
  204. package/dist/slices/fixes/rules.js +73 -0
  205. package/dist/slices/fonts/coverage.js +82 -0
  206. package/dist/slices/fonts/sfnt.js +74 -0
  207. package/dist/slices/images/run.js +8 -5
  208. package/dist/slices/images/scale.js +84 -0
  209. package/dist/slices/library/diff.js +122 -0
  210. package/dist/slices/library/history.js +100 -0
  211. package/dist/slices/library/model.js +3 -0
  212. package/dist/slices/library/photorealistic.js +49 -0
  213. package/dist/slices/library/repo.js +19 -14
  214. package/dist/slices/library/save.js +62 -12
  215. package/dist/slices/library/slots.js +15 -3
  216. package/dist/slices/library/snapshot.js +8 -2
  217. package/dist/slices/library/used-by.js +153 -0
  218. package/dist/slices/loudness/level-pieces.js +41 -0
  219. package/dist/slices/loudness/loudnorm.js +164 -0
  220. package/dist/slices/loudness/model.js +153 -0
  221. package/dist/slices/model-upkeep/model.js +10 -0
  222. package/dist/slices/model-upkeep/switch.js +217 -0
  223. package/dist/slices/model-upkeep/usage.js +183 -0
  224. package/dist/slices/narration/aliases-library.js +31 -0
  225. package/dist/slices/narration/aliases-schema.js +53 -0
  226. package/dist/slices/narration/aliases.js +49 -0
  227. package/dist/slices/narration/blocks.js +352 -0
  228. package/dist/slices/narration/chunk.js +19 -7
  229. package/dist/slices/narration/concat.js +2 -2
  230. package/dist/slices/narration/describe.js +45 -0
  231. package/dist/slices/narration/pauses-model.js +63 -0
  232. package/dist/slices/narration/pauses.js +269 -0
  233. package/dist/slices/narration/peaks-model.js +1 -0
  234. package/dist/slices/narration/peaks.js +94 -0
  235. package/dist/slices/narration/preparation.js +21 -3
  236. package/dist/slices/narration/pronunciation-chunks.js +3 -3
  237. package/dist/slices/narration/pronunciation.js +72 -25
  238. package/dist/slices/narration/run.js +6 -6
  239. package/dist/slices/narration/shared-glossary.js +1 -1
  240. package/dist/slices/narration/steering.js +15 -4
  241. package/dist/slices/notifications/notifier.js +94 -0
  242. package/dist/slices/notifications/rules.js +102 -0
  243. package/dist/slices/notifications/send.js +40 -0
  244. package/dist/slices/notifications/settings.js +34 -0
  245. package/dist/slices/onboarding/copy.js +143 -0
  246. package/dist/slices/onboarding/first-run.js +46 -0
  247. package/dist/slices/onboarding/install.js +119 -0
  248. package/dist/slices/onboarding/model.js +64 -0
  249. package/dist/slices/onboarding/packs.js +491 -0
  250. package/dist/slices/onboarding/quick-short.js +129 -0
  251. package/dist/slices/onboarding/sample.js +132 -0
  252. package/dist/slices/onboarding/state.js +68 -0
  253. package/dist/slices/onboarding/template.js +73 -0
  254. package/dist/slices/patch-notes/library.js +73 -0
  255. package/dist/slices/patch-notes/seen.js +77 -0
  256. package/dist/slices/play-drafts/convert.js +160 -9
  257. package/dist/slices/play-drafts/readiness.js +3 -0
  258. package/dist/slices/play-drafts/repo.js +9 -1
  259. package/dist/slices/play-drafts/review-inputs.js +22 -3
  260. package/dist/slices/play-drafts/schema.js +109 -2
  261. package/dist/slices/play-drafts/service.js +10 -1
  262. package/dist/slices/play-drafts/start.js +43 -18
  263. package/dist/slices/play-drafts/uploads.js +2 -1
  264. package/dist/slices/project-templates/from-project.js +70 -4
  265. package/dist/slices/project-templates/one-off.js +26 -0
  266. package/dist/slices/project-templates/repo.js +2 -1
  267. package/dist/slices/project-templates/service.js +15 -4
  268. package/dist/slices/project-templates/setup.js +29 -2
  269. package/dist/slices/rebuild/admission-repo.js +1 -1
  270. package/dist/slices/rebuild/model.js +6 -0
  271. package/dist/slices/rebuild/preview-details.js +67 -2
  272. package/dist/slices/rebuild/preview-plan.js +13 -6
  273. package/dist/slices/rebuild/recipe-audio-parts.js +40 -7
  274. package/dist/slices/rebuild/recipe-audio.js +66 -12
  275. package/dist/slices/rebuild/recipe-build.js +15 -5
  276. package/dist/slices/rebuild/recipe-cast.js +18 -0
  277. package/dist/slices/rebuild/recipe-checkpoints.js +11 -9
  278. package/dist/slices/rebuild/recipe-describe.js +93 -0
  279. package/dist/slices/rebuild/recipe-edit.js +13 -1
  280. package/dist/slices/rebuild/recipe-exports.js +62 -8
  281. package/dist/slices/rebuild/recipe-input-schema.js +43 -1
  282. package/dist/slices/rebuild/recipe-legacy.js +12 -0
  283. package/dist/slices/rebuild/recipe-loudness.js +45 -0
  284. package/dist/slices/rebuild/recipe-model.js +25 -6
  285. package/dist/slices/rebuild/recipe-pauses.js +7 -0
  286. package/dist/slices/rebuild/recipe-preparation.js +3 -3
  287. package/dist/slices/rebuild/recipe-provider-choice.js +11 -1
  288. package/dist/slices/rebuild/recipe-reference.js +58 -0
  289. package/dist/slices/rebuild/recipe-reviews.js +117 -0
  290. package/dist/slices/rebuild/recipe-save.js +4 -1
  291. package/dist/slices/rebuild/recipe-shorts.js +32 -5
  292. package/dist/slices/rebuild/recipe-text.js +114 -19
  293. package/dist/slices/rebuild/recipe-validation.js +29 -3
  294. package/dist/slices/rebuild/recipe-visual.js +104 -29
  295. package/dist/slices/rebuild/recipe-voices.js +286 -0
  296. package/dist/slices/rebuild/recipe-work.js +77 -6
  297. package/dist/slices/rebuild/recipe-youtube.js +2 -0
  298. package/dist/slices/rebuild/recovery-conflict.js +7 -3
  299. package/dist/slices/rebuild/recovery-model.js +3 -0
  300. package/dist/slices/rebuild/recovery-selection.js +28 -2
  301. package/dist/slices/rebuild/recovery.js +35 -17
  302. package/dist/slices/rebuild/repo.js +3 -3
  303. package/dist/slices/rebuild/retry.js +18 -0
  304. package/dist/slices/rebuild/review-redo.js +110 -0
  305. package/dist/slices/rebuild/runtime-actions.js +14 -2
  306. package/dist/slices/rebuild/runtime-admission.js +4 -1
  307. package/dist/slices/rebuild/runtime-animate.js +4 -4
  308. package/dist/slices/rebuild/runtime-article.js +5 -5
  309. package/dist/slices/rebuild/runtime-document.js +4 -4
  310. package/dist/slices/rebuild/runtime-export-bed.js +43 -0
  311. package/dist/slices/rebuild/runtime-export-edit.js +70 -11
  312. package/dist/slices/rebuild/runtime-export-inputs.js +52 -10
  313. package/dist/slices/rebuild/runtime-export-short.js +85 -0
  314. package/dist/slices/rebuild/runtime-export.js +84 -19
  315. package/dist/slices/rebuild/runtime-figure-card.js +87 -0
  316. package/dist/slices/rebuild/runtime-image.js +69 -0
  317. package/dist/slices/rebuild/runtime-local.js +154 -27
  318. package/dist/slices/rebuild/runtime-materialize.js +8 -0
  319. package/dist/slices/rebuild/runtime-narration-reuse.js +2 -1
  320. package/dist/slices/rebuild/runtime-narration-text.js +7 -7
  321. package/dist/slices/rebuild/runtime-pictures.js +28 -0
  322. package/dist/slices/rebuild/runtime-piece-label.js +29 -0
  323. package/dist/slices/rebuild/runtime-provider.js +134 -19
  324. package/dist/slices/rebuild/runtime-publication.js +21 -5
  325. package/dist/slices/rebuild/runtime-review.js +237 -0
  326. package/dist/slices/rebuild/runtime-run.js +17 -11
  327. package/dist/slices/rebuild/runtime-shorts.js +48 -23
  328. package/dist/slices/rebuild/runtime-store.js +39 -10
  329. package/dist/slices/rebuild/runtime-subtitles.js +72 -19
  330. package/dist/slices/rebuild/runtime-voices.js +103 -0
  331. package/dist/slices/rebuild/runtime-youtube.js +7 -6
  332. package/dist/slices/rebuild/service-readiness.js +15 -1
  333. package/dist/slices/rebuild/soften.js +49 -0
  334. package/dist/slices/rebuild/transition-repo.js +10 -3
  335. package/dist/slices/research/run.js +4 -4
  336. package/dist/slices/research/synthesis.js +2 -2
  337. package/dist/slices/reviews/model.js +105 -0
  338. package/dist/slices/reviews/outcome.js +22 -0
  339. package/dist/slices/reviews/repo.js +106 -0
  340. package/dist/slices/reviews/rules.js +63 -0
  341. package/dist/slices/reviews/verdict.js +71 -0
  342. package/dist/slices/reviews/view.js +30 -0
  343. package/dist/slices/revisions/adopt-content.js +12 -2
  344. package/dist/slices/revisions/adopt.js +9 -2
  345. package/dist/slices/revisions/downloads.js +7 -1
  346. package/dist/slices/revisions/image-plan.js +183 -0
  347. package/dist/slices/revisions/mutation-assets.js +43 -9
  348. package/dist/slices/revisions/mutation-cues.js +71 -0
  349. package/dist/slices/revisions/mutation-prepare.js +8 -10
  350. package/dist/slices/revisions/mutation-request.js +2 -1
  351. package/dist/slices/revisions/mutations.js +97 -3
  352. package/dist/slices/revisions/schema.js +16 -2
  353. package/dist/slices/run-cost/limits.js +128 -0
  354. package/dist/slices/run-cost/meter.js +47 -0
  355. package/dist/slices/run-cost/panel.js +234 -0
  356. package/dist/slices/run-cost/pricing.js +92 -0
  357. package/dist/slices/run-cost/week.js +108 -0
  358. package/dist/slices/schedules/agenda.js +158 -0
  359. package/dist/slices/schedules/repo.js +58 -18
  360. package/dist/slices/schedules/scheduler.js +67 -16
  361. package/dist/slices/schedules/schema.js +138 -1
  362. package/dist/slices/schedules/service.js +48 -4
  363. package/dist/slices/schedules/similar.js +90 -0
  364. package/dist/slices/schedules/topic-list.js +163 -0
  365. package/dist/slices/schedules/topics.js +422 -0
  366. package/dist/slices/settings/first-run.js +102 -0
  367. package/dist/slices/settings/health.js +190 -0
  368. package/dist/slices/settings/key-guides.js +128 -0
  369. package/dist/slices/settings/key-test.js +85 -0
  370. package/dist/slices/settings/model.js +11 -1
  371. package/dist/slices/settings/playback.js +15 -0
  372. package/dist/slices/settings/repo.js +17 -3
  373. package/dist/slices/settings/voices.js +64 -4
  374. package/dist/slices/settings/whats-new.js +64 -0
  375. package/dist/slices/shorts/captions.js +9 -0
  376. package/dist/slices/shorts/pick.js +3 -3
  377. package/dist/slices/shorts/prompts.js +1 -1
  378. package/dist/slices/shorts/render.js +54 -5
  379. package/dist/slices/storage/asset-name.js +3 -0
  380. package/dist/slices/storage/backup-export.js +48 -9
  381. package/dist/slices/storage/backup-format.js +38 -1
  382. package/dist/slices/storage/backup-import.js +191 -19
  383. package/dist/slices/storage/delete-project.js +7 -4
  384. package/dist/slices/storage/documents.js +79 -0
  385. package/dist/slices/storage/files-location.js +531 -0
  386. package/dist/slices/storage/layout.js +20 -0
  387. package/dist/slices/storage/model.js +14 -0
  388. package/dist/slices/storage/portable.js +95 -12
  389. package/dist/slices/storage/reconcile.js +19 -2
  390. package/dist/slices/storage/repo.js +4 -1
  391. package/dist/slices/storage/schema.js +11 -0
  392. package/dist/slices/storage/trim.js +146 -0
  393. package/dist/slices/studio/disclosure.js +74 -0
  394. package/dist/slices/studio/model.js +28 -0
  395. package/dist/slices/studio/pack.js +209 -0
  396. package/dist/slices/studio/settings.js +133 -0
  397. package/dist/slices/style-preview/images.js +61 -0
  398. package/dist/slices/style-preview/render.js +161 -0
  399. package/dist/slices/style-preview/schema.js +45 -0
  400. package/dist/slices/style-preview/service.js +93 -0
  401. package/dist/slices/style-preview/settings.js +89 -0
  402. package/dist/slices/subtitles/captions.js +42 -9
  403. package/dist/slices/subtitles/model.js +22 -0
  404. package/dist/slices/subtitles/prepare.js +27 -16
  405. package/dist/slices/subtitles/transcript.js +1 -1
  406. package/dist/slices/thumbnail/run.js +7 -7
  407. package/dist/slices/trash/model.js +25 -0
  408. package/dist/slices/trash/service.js +273 -0
  409. package/dist/slices/uploads/repo.js +20 -0
  410. package/dist/slices/video/ambient-bed-schema.js +15 -0
  411. package/dist/slices/video/ambient-bed.js +95 -0
  412. package/dist/slices/video/ambient-mix.js +72 -0
  413. package/dist/slices/video/audio-inputs.js +2 -2
  414. package/dist/slices/video/cards.js +5 -2
  415. package/dist/slices/video/edit-list.js +23 -2
  416. package/dist/slices/video/edit-settings.js +13 -3
  417. package/dist/slices/video/ffmpeg.js +63 -9
  418. package/dist/slices/video/figure-card.js +492 -0
  419. package/dist/slices/video/figure-spans.js +51 -0
  420. package/dist/slices/video/plan.js +125 -13
  421. package/dist/slices/video/run.js +14 -12
  422. package/dist/slices/video/slideshow.js +39 -4
  423. package/dist/slices/voices/attribution.js +69 -0
  424. package/dist/slices/voices/audio-files.js +82 -0
  425. package/dist/slices/voices/audition.js +25 -0
  426. package/dist/slices/voices/cast.js +56 -0
  427. package/dist/slices/voices/grouping.js +49 -0
  428. package/dist/slices/voices/join.js +35 -0
  429. package/dist/slices/voices/languages.js +25 -0
  430. package/dist/slices/voices/model.js +179 -0
  431. package/dist/slices/voices/palette.js +26 -0
  432. package/dist/slices/voices/panel.js +91 -0
  433. package/dist/slices/voices/portraits.js +55 -0
  434. package/dist/slices/voices/script.js +136 -0
  435. package/dist/slices/voices/timing.js +58 -0
  436. package/dist/slices/youtube/answer.js +1 -1
  437. package/dist/slices/youtube/chapters.js +126 -0
  438. package/dist/slices/youtube/edits-repo.js +69 -0
  439. package/dist/slices/youtube/edits.js +89 -0
  440. package/dist/slices/youtube/placeholders.js +98 -0
  441. package/dist/slices/youtube/transcript.js +11 -4
  442. package/dist/updater/service.js +66 -21
  443. package/dist/web/assets/index-CUA2sUxU.css +1 -0
  444. package/dist/web/assets/index-CX590kE-.js +303 -0
  445. package/dist/web/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
  446. package/dist/web/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
  447. package/dist/web/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
  448. package/dist/web/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
  449. package/dist/web/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
  450. package/dist/web/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
  451. package/dist/web/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
  452. package/dist/web/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
  453. package/dist/web/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
  454. package/dist/web/assets/{pdf-CAJNT254.js → pdf-BG8n_uc5.js} +1 -1
  455. package/dist/web/index.html +2 -2
  456. package/package.json +4 -4
  457. package/dist/edge/docker-launch.js +0 -81
  458. package/dist/edge/docker-projects/activation.js +0 -35
  459. package/dist/edge/docker-projects/claims.js +0 -85
  460. package/dist/edge/docker-projects/committed.js +0 -40
  461. package/dist/edge/docker-projects/engine.js +0 -461
  462. package/dist/edge/docker-projects/install.js +0 -254
  463. package/dist/edge/docker-projects/prune.js +0 -66
  464. package/dist/edge/docker-projects/recover.js +0 -100
  465. package/dist/edge/docker-projects/state.js +0 -225
  466. package/dist/web/assets/index-BGgYMm2u.css +0 -1
  467. package/dist/web/assets/index-BVVgtntL.js +0 -171
  468. package/scripts/docker-run.sh +0 -3
  469. /package/dist/edge/{docker-projects → docker-install}/tree.js +0 -0
@@ -0,0 +1,769 @@
1
+ // Number words for the languages the multilingual model times, so a numeral in the article
2
+ // matches what the voice said. Lower case, words separated by spaces (hyphens are spaces to
3
+ // the aligner anyway). Each speller covers 0 to 999,999,999,999; the aligner reads longer
4
+ // numbers digit by digit, as it does in English.
5
+ const split = (value, size) => [
6
+ Math.floor(value / size),
7
+ value % size,
8
+ ];
9
+ const join = (...parts) => parts.filter((part) => part !== "").join(" ");
10
+ // Spanish.
11
+ const esSmall = [
12
+ "cero",
13
+ "uno",
14
+ "dos",
15
+ "tres",
16
+ "cuatro",
17
+ "cinco",
18
+ "seis",
19
+ "siete",
20
+ "ocho",
21
+ "nueve",
22
+ "diez",
23
+ "once",
24
+ "doce",
25
+ "trece",
26
+ "catorce",
27
+ "quince",
28
+ "dieciséis",
29
+ "diecisiete",
30
+ "dieciocho",
31
+ "diecinueve",
32
+ "veinte",
33
+ "veintiuno",
34
+ "veintidós",
35
+ "veintitrés",
36
+ "veinticuatro",
37
+ "veinticinco",
38
+ "veintiséis",
39
+ "veintisiete",
40
+ "veintiocho",
41
+ "veintinueve",
42
+ ];
43
+ const esTens = [
44
+ "",
45
+ "",
46
+ "",
47
+ "treinta",
48
+ "cuarenta",
49
+ "cincuenta",
50
+ "sesenta",
51
+ "setenta",
52
+ "ochenta",
53
+ "noventa",
54
+ ];
55
+ const esHundreds = [
56
+ "",
57
+ "ciento",
58
+ "doscientos",
59
+ "trescientos",
60
+ "cuatrocientos",
61
+ "quinientos",
62
+ "seiscientos",
63
+ "setecientos",
64
+ "ochocientos",
65
+ "novecientos",
66
+ ];
67
+ // "uno" shortens before a noun: veintiún mil, treinta y un millones.
68
+ const esApocope = (words) => words.replace(/veintiuno$/, "veintiún").replace(/(^|\s)uno$/, "$1un");
69
+ function es(value) {
70
+ if (value < 30)
71
+ return esSmall[value] ?? "";
72
+ if (value < 100) {
73
+ const [tens, unit] = split(value, 10);
74
+ return unit === 0 ? (esTens[tens] ?? "") : `${esTens[tens]} y ${esSmall[unit]}`;
75
+ }
76
+ if (value < 1000) {
77
+ if (value === 100)
78
+ return "cien";
79
+ const [hundreds, rest] = split(value, 100);
80
+ return join(esHundreds[hundreds] ?? "", rest === 0 ? "" : es(rest));
81
+ }
82
+ if (value < 1_000_000) {
83
+ const [thousands, rest] = split(value, 1000);
84
+ return join(thousands === 1 ? "mil" : `${esApocope(es(thousands))} mil`, rest === 0 ? "" : es(rest));
85
+ }
86
+ const [millions, rest] = split(value, 1_000_000);
87
+ return join(millions === 1 ? "un millón" : `${esApocope(es(millions))} millones`, rest === 0 ? "" : es(rest));
88
+ }
89
+ // German: one word below a million.
90
+ const deSmall = [
91
+ "null",
92
+ "eins",
93
+ "zwei",
94
+ "drei",
95
+ "vier",
96
+ "fünf",
97
+ "sechs",
98
+ "sieben",
99
+ "acht",
100
+ "neun",
101
+ "zehn",
102
+ "elf",
103
+ "zwölf",
104
+ "dreizehn",
105
+ "vierzehn",
106
+ "fünfzehn",
107
+ "sechzehn",
108
+ "siebzehn",
109
+ "achtzehn",
110
+ "neunzehn",
111
+ ];
112
+ const deTens = [
113
+ "",
114
+ "",
115
+ "zwanzig",
116
+ "dreißig",
117
+ "vierzig",
118
+ "fünfzig",
119
+ "sechzig",
120
+ "siebzig",
121
+ "achtzig",
122
+ "neunzig",
123
+ ];
124
+ const deCompound = (value) => (value === 1 ? "ein" : de(value));
125
+ function deUnder100(value) {
126
+ if (value < 20)
127
+ return deSmall[value] ?? "";
128
+ const [tens, unit] = split(value, 10);
129
+ return `${unit === 0 ? "" : `${deCompound(unit)}und`}${deTens[tens]}`;
130
+ }
131
+ function de(value, one = "ein") {
132
+ if (value < 100)
133
+ return deUnder100(value);
134
+ if (value < 1000) {
135
+ const [hundreds, rest] = split(value, 100);
136
+ return `${hundreds === 1 ? one : deSmall[hundreds]}hundert${rest === 0 ? "" : deUnder100(rest)}`;
137
+ }
138
+ if (value < 1_000_000) {
139
+ const [thousands, rest] = split(value, 1000);
140
+ return `${thousands === 1 ? one : deCompound(thousands)}tausend${rest === 0 ? "" : de(rest)}`;
141
+ }
142
+ const [millions, rest] = split(value, 1_000_000);
143
+ return join(millions === 1 ? "eine million" : `${de(millions)} millionen`, rest === 0 ? "" : de(rest));
144
+ }
145
+ function deYear(value) {
146
+ if (value < 1100 || value >= 2000)
147
+ return undefined;
148
+ const [hundreds, rest] = split(value, 100);
149
+ return `${deUnder100(hundreds)}hundert${rest === 0 ? "" : deUnder100(rest)}`;
150
+ }
151
+ function deAlternatives(value) {
152
+ // "hundert" and "tausend" without the "ein".
153
+ const plain = de(value, "");
154
+ return plain === de(value) ? [] : [plain];
155
+ }
156
+ // French.
157
+ const frSmall = [
158
+ "zéro",
159
+ "un",
160
+ "deux",
161
+ "trois",
162
+ "quatre",
163
+ "cinq",
164
+ "six",
165
+ "sept",
166
+ "huit",
167
+ "neuf",
168
+ "dix",
169
+ "onze",
170
+ "douze",
171
+ "treize",
172
+ "quatorze",
173
+ "quinze",
174
+ "seize",
175
+ ];
176
+ const frTens = ["", "", "vingt", "trente", "quarante", "cinquante", "soixante"];
177
+ function frUnder100(value) {
178
+ if (value <= 16)
179
+ return frSmall[value] ?? "";
180
+ if (value < 20)
181
+ return `dix ${frSmall[value - 10]}`;
182
+ if (value < 70) {
183
+ const [tens, unit] = split(value, 10);
184
+ if (unit === 0)
185
+ return frTens[tens] ?? "";
186
+ return unit === 1 ? `${frTens[tens]} et un` : `${frTens[tens]} ${frSmall[unit]}`;
187
+ }
188
+ if (value < 80)
189
+ return value === 71 ? "soixante et onze" : `soixante ${frUnder100(value - 60)}`;
190
+ if (value === 80)
191
+ return "quatre vingts";
192
+ return `quatre vingt ${frUnder100(value - 80)}`;
193
+ }
194
+ function fr(value) {
195
+ if (value < 100)
196
+ return frUnder100(value);
197
+ if (value < 1000) {
198
+ const [hundreds, rest] = split(value, 100);
199
+ const head = hundreds === 1 ? "cent" : `${frSmall[hundreds]} cent${rest === 0 ? "s" : ""}`;
200
+ return join(head, rest === 0 ? "" : frUnder100(rest));
201
+ }
202
+ // "vingts" and "cents" lose their s before mille.
203
+ const plain = (words) => words.replace(/(vingt|cent)s$/, "$1");
204
+ if (value < 1_000_000) {
205
+ const [thousands, rest] = split(value, 1000);
206
+ return join(thousands === 1 ? "mille" : `${plain(fr(thousands))} mille`, rest === 0 ? "" : fr(rest));
207
+ }
208
+ const [millions, rest] = split(value, 1_000_000);
209
+ return join(millions === 1 ? "un million" : `${fr(millions)} millions`, rest === 0 ? "" : fr(rest));
210
+ }
211
+ function frYear(value) {
212
+ // Old-fashioned but still heard: "dix-neuf cent quatre-vingt-dix".
213
+ if (value < 1100 || value >= 2000)
214
+ return undefined;
215
+ const [hundreds, rest] = split(value, 100);
216
+ return join(`${frUnder100(hundreds)} cent`, rest === 0 ? "" : frUnder100(rest));
217
+ }
218
+ // Italian: one word below a million; the tens drop their vowel before uno and otto.
219
+ const itSmall = [
220
+ "zero",
221
+ "uno",
222
+ "due",
223
+ "tre",
224
+ "quattro",
225
+ "cinque",
226
+ "sei",
227
+ "sette",
228
+ "otto",
229
+ "nove",
230
+ "dieci",
231
+ "undici",
232
+ "dodici",
233
+ "tredici",
234
+ "quattordici",
235
+ "quindici",
236
+ "sedici",
237
+ "diciassette",
238
+ "diciotto",
239
+ "diciannove",
240
+ ];
241
+ const itTens = [
242
+ "",
243
+ "",
244
+ "venti",
245
+ "trenta",
246
+ "quaranta",
247
+ "cinquanta",
248
+ "sessanta",
249
+ "settanta",
250
+ "ottanta",
251
+ "novanta",
252
+ ];
253
+ function itUnder1000(value) {
254
+ if (value < 20)
255
+ return itSmall[value] ?? "";
256
+ if (value < 100) {
257
+ const [tens, unit] = split(value, 10);
258
+ const head = itTens[tens] ?? "";
259
+ if (unit === 0)
260
+ return head;
261
+ return `${unit === 1 || unit === 8 ? head.slice(0, -1) : head}${itSmall[unit]}`;
262
+ }
263
+ const [hundreds, rest] = split(value, 100);
264
+ const head = hundreds === 1 ? "cento" : `${itSmall[hundreds]}cento`;
265
+ if (rest === 0)
266
+ return head;
267
+ return `${Math.floor(rest / 10) === 8 ? head.slice(0, -1) : head}${itUnder1000(rest)}`;
268
+ }
269
+ function it(value) {
270
+ // A compound ending in tre is written tré: ventitré, centotré.
271
+ const accent = (words) => (value > 3 ? words.replace(/tre$/, "tré") : words);
272
+ if (value < 1000)
273
+ return accent(itUnder1000(value));
274
+ if (value < 1_000_000) {
275
+ const [thousands, rest] = split(value, 1000);
276
+ return accent(`${thousands === 1 ? "mille" : `${itUnder1000(thousands)}mila`}${rest === 0 ? "" : itUnder1000(rest)}`);
277
+ }
278
+ const [millions, rest] = split(value, 1_000_000);
279
+ return join(millions === 1 ? "un milione" : `${it(millions)} milioni`, rest === 0 ? "" : it(rest));
280
+ }
281
+ // Portuguese: Brazilian spelling first, European second where they differ.
282
+ const ptSmall = [
283
+ "zero",
284
+ "um",
285
+ "dois",
286
+ "três",
287
+ "quatro",
288
+ "cinco",
289
+ "seis",
290
+ "sete",
291
+ "oito",
292
+ "nove",
293
+ "dez",
294
+ "onze",
295
+ "doze",
296
+ "treze",
297
+ "catorze",
298
+ "quinze",
299
+ "dezesseis",
300
+ "dezessete",
301
+ "dezoito",
302
+ "dezenove",
303
+ ];
304
+ const ptTens = [
305
+ "",
306
+ "",
307
+ "vinte",
308
+ "trinta",
309
+ "quarenta",
310
+ "cinquenta",
311
+ "sessenta",
312
+ "setenta",
313
+ "oitenta",
314
+ "noventa",
315
+ ];
316
+ const ptHundreds = [
317
+ "",
318
+ "cento",
319
+ "duzentos",
320
+ "trezentos",
321
+ "quatrocentos",
322
+ "quinhentos",
323
+ "seiscentos",
324
+ "setecentos",
325
+ "oitocentos",
326
+ "novecentos",
327
+ ];
328
+ function ptUnder1000(value) {
329
+ if (value < 20)
330
+ return ptSmall[value] ?? "";
331
+ if (value < 100) {
332
+ const [tens, unit] = split(value, 10);
333
+ return unit === 0 ? (ptTens[tens] ?? "") : `${ptTens[tens]} e ${ptSmall[unit]}`;
334
+ }
335
+ if (value === 100)
336
+ return "cem";
337
+ const [hundreds, rest] = split(value, 100);
338
+ return rest === 0
339
+ ? (ptHundreds[hundreds] ?? "")
340
+ : `${ptHundreds[hundreds]} e ${ptUnder1000(rest)}`;
341
+ }
342
+ // "e" joins a thousand to what follows only when that is below a hundred or a round hundred.
343
+ const ptRest = (rest) => rest === 0 ? "" : rest < 100 || rest % 100 === 0 ? `e ${ptUnder1000(rest)}` : ptUnder1000(rest);
344
+ function pt(value) {
345
+ if (value < 1000)
346
+ return ptUnder1000(value);
347
+ if (value < 1_000_000) {
348
+ const [thousands, rest] = split(value, 1000);
349
+ return join(thousands === 1 ? "mil" : `${ptUnder1000(thousands)} mil`, ptRest(rest));
350
+ }
351
+ const [millions, rest] = split(value, 1_000_000);
352
+ return join(millions === 1 ? "um milhão" : `${pt(millions)} milhões`, rest === 0 ? "" : rest < 1000 ? ptRest(rest) : pt(rest));
353
+ }
354
+ function ptAlternatives(value) {
355
+ const european = pt(value)
356
+ .replaceAll("dezesseis", "dezasseis")
357
+ .replaceAll("dezessete", "dezassete")
358
+ .replaceAll("dezenove", "dezanove");
359
+ return european === pt(value) ? [] : [european];
360
+ }
361
+ // Catalan.
362
+ const caSmall = [
363
+ "zero",
364
+ "u",
365
+ "dos",
366
+ "tres",
367
+ "quatre",
368
+ "cinc",
369
+ "sis",
370
+ "set",
371
+ "vuit",
372
+ "nou",
373
+ "deu",
374
+ "onze",
375
+ "dotze",
376
+ "tretze",
377
+ "catorze",
378
+ "quinze",
379
+ "setze",
380
+ "disset",
381
+ "divuit",
382
+ "dinou",
383
+ ];
384
+ const caTens = [
385
+ "",
386
+ "",
387
+ "vint",
388
+ "trenta",
389
+ "quaranta",
390
+ "cinquanta",
391
+ "seixanta",
392
+ "setanta",
393
+ "vuitanta",
394
+ "noranta",
395
+ ];
396
+ function caUnder1000(value) {
397
+ if (value < 20)
398
+ return caSmall[value] ?? "";
399
+ if (value < 100) {
400
+ const [tens, unit] = split(value, 10);
401
+ if (unit === 0)
402
+ return caTens[tens] ?? "";
403
+ return tens === 2 ? `vint i ${caSmall[unit]}` : `${caTens[tens]} ${caSmall[unit]}`;
404
+ }
405
+ const [hundreds, rest] = split(value, 100);
406
+ return join(hundreds === 1 ? "cent" : `${caSmall[hundreds]} cents`, rest === 0 ? "" : caUnder1000(rest));
407
+ }
408
+ const caOne = (words) => words.replace(/(^|\s)u$/, "$1un");
409
+ function ca(value) {
410
+ if (value < 1000)
411
+ return caUnder1000(value);
412
+ if (value < 1_000_000) {
413
+ const [thousands, rest] = split(value, 1000);
414
+ return join(thousands === 1 ? "mil" : `${caOne(caUnder1000(thousands))} mil`, rest === 0 ? "" : caUnder1000(rest));
415
+ }
416
+ const [millions, rest] = split(value, 1_000_000);
417
+ return join(millions === 1 ? "un milió" : `${caOne(ca(millions))} milions`, rest === 0 ? "" : ca(rest));
418
+ }
419
+ // Dutch: one word below a million; "ën" after a vowel it would merge with.
420
+ const nlSmall = [
421
+ "nul",
422
+ "een",
423
+ "twee",
424
+ "drie",
425
+ "vier",
426
+ "vijf",
427
+ "zes",
428
+ "zeven",
429
+ "acht",
430
+ "negen",
431
+ "tien",
432
+ "elf",
433
+ "twaalf",
434
+ "dertien",
435
+ "veertien",
436
+ "vijftien",
437
+ "zestien",
438
+ "zeventien",
439
+ "achttien",
440
+ "negentien",
441
+ ];
442
+ const nlTens = [
443
+ "",
444
+ "",
445
+ "twintig",
446
+ "dertig",
447
+ "veertig",
448
+ "vijftig",
449
+ "zestig",
450
+ "zeventig",
451
+ "tachtig",
452
+ "negentig",
453
+ ];
454
+ function nlUnder100(value) {
455
+ if (value < 20)
456
+ return nlSmall[value] ?? "";
457
+ const [tens, unit] = split(value, 10);
458
+ if (unit === 0)
459
+ return nlTens[tens] ?? "";
460
+ return `${nlSmall[unit]}${unit === 2 || unit === 3 ? "ën" : "en"}${nlTens[tens]}`;
461
+ }
462
+ function nlUnder1000(value) {
463
+ if (value < 100)
464
+ return nlUnder100(value);
465
+ const [hundreds, rest] = split(value, 100);
466
+ return `${hundreds === 1 ? "" : nlSmall[hundreds]}honderd${rest === 0 ? "" : nlUnder100(rest)}`;
467
+ }
468
+ function nl(value) {
469
+ if (value < 1000)
470
+ return nlUnder1000(value);
471
+ if (value < 1_000_000) {
472
+ const [thousands, rest] = split(value, 1000);
473
+ return join(`${thousands === 1 ? "" : nlUnder1000(thousands)}duizend`, rest === 0 ? "" : nlUnder1000(rest));
474
+ }
475
+ const [millions, rest] = split(value, 1_000_000);
476
+ return join(`${nl(millions)} miljoen`, rest === 0 ? "" : nl(rest));
477
+ }
478
+ function nlYear(value) {
479
+ if (value < 1100 || value >= 2000)
480
+ return undefined;
481
+ const [hundreds, rest] = split(value, 100);
482
+ return `${nlUnder100(hundreds)}honderd${rest === 0 ? "" : nlUnder100(rest)}`;
483
+ }
484
+ function nlAlternatives(value) {
485
+ // Written as one word too: "duizendtweehonderd".
486
+ const joined = value >= 1000 && value < 1_000_000 ? nl(value).replace(" ", "") : nl(value);
487
+ return joined === nl(value) ? [] : [joined];
488
+ }
489
+ // Polish and Czech pick the noun's form by the count.
490
+ const slavicPlural = (count, one, few, many) => {
491
+ if (count === 1)
492
+ return one;
493
+ const unit = count % 10;
494
+ const teen = count % 100 >= 12 && count % 100 <= 14;
495
+ return unit >= 2 && unit <= 4 && !teen ? few : many;
496
+ };
497
+ const plSmall = [
498
+ "zero",
499
+ "jeden",
500
+ "dwa",
501
+ "trzy",
502
+ "cztery",
503
+ "pięć",
504
+ "sześć",
505
+ "siedem",
506
+ "osiem",
507
+ "dziewięć",
508
+ "dziesięć",
509
+ "jedenaście",
510
+ "dwanaście",
511
+ "trzynaście",
512
+ "czternaście",
513
+ "piętnaście",
514
+ "szesnaście",
515
+ "siedemnaście",
516
+ "osiemnaście",
517
+ "dziewiętnaście",
518
+ ];
519
+ const plTens = [
520
+ "",
521
+ "",
522
+ "dwadzieścia",
523
+ "trzydzieści",
524
+ "czterdzieści",
525
+ "pięćdziesiąt",
526
+ "sześćdziesiąt",
527
+ "siedemdziesiąt",
528
+ "osiemdziesiąt",
529
+ "dziewięćdziesiąt",
530
+ ];
531
+ const plHundreds = [
532
+ "",
533
+ "sto",
534
+ "dwieście",
535
+ "trzysta",
536
+ "czterysta",
537
+ "pięćset",
538
+ "sześćset",
539
+ "siedemset",
540
+ "osiemset",
541
+ "dziewięćset",
542
+ ];
543
+ function plUnder1000(value) {
544
+ if (value < 20)
545
+ return plSmall[value] ?? "";
546
+ if (value < 100) {
547
+ const [tens, unit] = split(value, 10);
548
+ return join(plTens[tens] ?? "", unit === 0 ? "" : (plSmall[unit] ?? ""));
549
+ }
550
+ const [hundreds, rest] = split(value, 100);
551
+ return join(plHundreds[hundreds] ?? "", rest === 0 ? "" : plUnder1000(rest));
552
+ }
553
+ function pl(value) {
554
+ if (value < 1000)
555
+ return plUnder1000(value);
556
+ if (value < 1_000_000) {
557
+ const [thousands, rest] = split(value, 1000);
558
+ const head = thousands === 1
559
+ ? "tysiąc"
560
+ : `${plUnder1000(thousands)} ${slavicPlural(thousands, "tysiąc", "tysiące", "tysięcy")}`;
561
+ return join(head, rest === 0 ? "" : plUnder1000(rest));
562
+ }
563
+ const [millions, rest] = split(value, 1_000_000);
564
+ const head = millions === 1
565
+ ? "milion"
566
+ : `${pl(millions)} ${slavicPlural(millions, "milion", "miliony", "milionów")}`;
567
+ return join(head, rest === 0 ? "" : pl(rest));
568
+ }
569
+ const csSmall = [
570
+ "nula",
571
+ "jedna",
572
+ "dva",
573
+ "tři",
574
+ "čtyři",
575
+ "pět",
576
+ "šest",
577
+ "sedm",
578
+ "osm",
579
+ "devět",
580
+ "deset",
581
+ "jedenáct",
582
+ "dvanáct",
583
+ "třináct",
584
+ "čtrnáct",
585
+ "patnáct",
586
+ "šestnáct",
587
+ "sedmnáct",
588
+ "osmnáct",
589
+ "devatenáct",
590
+ ];
591
+ const csTens = [
592
+ "",
593
+ "",
594
+ "dvacet",
595
+ "třicet",
596
+ "čtyřicet",
597
+ "padesát",
598
+ "šedesát",
599
+ "sedmdesát",
600
+ "osmdesát",
601
+ "devadesát",
602
+ ];
603
+ function csUnder1000(value) {
604
+ if (value < 20)
605
+ return csSmall[value] ?? "";
606
+ if (value < 100) {
607
+ const [tens, unit] = split(value, 10);
608
+ return join(csTens[tens] ?? "", unit === 0 ? "" : (csSmall[unit] ?? ""));
609
+ }
610
+ const [hundreds, rest] = split(value, 100);
611
+ const head = hundreds === 1
612
+ ? "sto"
613
+ : hundreds === 2
614
+ ? "dvě stě"
615
+ : hundreds <= 4
616
+ ? `${csSmall[hundreds]} sta`
617
+ : `${csSmall[hundreds]} set`;
618
+ return join(head, rest === 0 ? "" : csUnder1000(rest));
619
+ }
620
+ // Czech uses the "few" form only for exactly two to four.
621
+ const csPlural = (count, one, few, many) => count === 1 ? one : count >= 2 && count <= 4 ? few : many;
622
+ function cs(value) {
623
+ if (value < 1000)
624
+ return csUnder1000(value);
625
+ if (value < 1_000_000) {
626
+ const [thousands, rest] = split(value, 1000);
627
+ const count = thousands === 2 ? "dva" : csUnder1000(thousands);
628
+ const head = thousands === 1 ? "tisíc" : `${count} ${csPlural(thousands, "tisíc", "tisíce", "tisíc")}`;
629
+ return join(head, rest === 0 ? "" : csUnder1000(rest));
630
+ }
631
+ const [millions, rest] = split(value, 1_000_000);
632
+ const head = millions === 1
633
+ ? "milion"
634
+ : `${millions === 2 ? "dva" : cs(millions)} ${csPlural(millions, "milion", "miliony", "milionů")}`;
635
+ return join(head, rest === 0 ? "" : cs(rest));
636
+ }
637
+ function csAlternatives(value) {
638
+ // Counting reads one as "jedna"; before a masculine noun and in "jeden tisíc" it is "jeden".
639
+ const masculine = cs(value).replace(/(^|\s)jedna(?=\s|$)/g, "$1jeden");
640
+ return masculine === cs(value) ? [] : [masculine];
641
+ }
642
+ export const spellers = {
643
+ es: {
644
+ cardinal: es,
645
+ decimal: "coma",
646
+ percent: "por ciento",
647
+ euro: "euros",
648
+ dollar: "dólares",
649
+ pound: "libras",
650
+ and: "y",
651
+ },
652
+ de: {
653
+ cardinal: de,
654
+ year: deYear,
655
+ alternatives: deAlternatives,
656
+ decimal: "komma",
657
+ percent: "prozent",
658
+ euro: "euro",
659
+ dollar: "dollar",
660
+ pound: "pfund",
661
+ and: "und",
662
+ },
663
+ fr: {
664
+ cardinal: fr,
665
+ year: frYear,
666
+ decimal: "virgule",
667
+ percent: "pour cent",
668
+ euro: "euros",
669
+ dollar: "dollars",
670
+ pound: "livres",
671
+ and: "et",
672
+ },
673
+ it: {
674
+ cardinal: it,
675
+ decimal: "virgola",
676
+ percent: "per cento",
677
+ euro: "euro",
678
+ dollar: "dollari",
679
+ pound: "sterline",
680
+ and: "e",
681
+ },
682
+ pt: {
683
+ cardinal: pt,
684
+ alternatives: ptAlternatives,
685
+ decimal: "vírgula",
686
+ percent: "por cento",
687
+ euro: "euros",
688
+ dollar: "dólares",
689
+ pound: "libras",
690
+ and: "e",
691
+ },
692
+ ca: {
693
+ cardinal: ca,
694
+ decimal: "coma",
695
+ percent: "per cent",
696
+ euro: "euros",
697
+ dollar: "dòlars",
698
+ pound: "lliures",
699
+ and: "i",
700
+ },
701
+ nl: {
702
+ cardinal: nl,
703
+ year: nlYear,
704
+ alternatives: nlAlternatives,
705
+ decimal: "komma",
706
+ percent: "procent",
707
+ euro: "euro",
708
+ dollar: "dollar",
709
+ pound: "pond",
710
+ and: "en",
711
+ },
712
+ pl: {
713
+ cardinal: pl,
714
+ decimal: "przecinek",
715
+ percent: "procent",
716
+ euro: "euro",
717
+ dollar: "dolarów",
718
+ pound: "funtów",
719
+ and: "i",
720
+ },
721
+ cs: {
722
+ cardinal: cs,
723
+ alternatives: csAlternatives,
724
+ decimal: "celá",
725
+ percent: "procent",
726
+ euro: "eur",
727
+ dollar: "dolarů",
728
+ pound: "liber",
729
+ and: "a",
730
+ },
731
+ };
732
+ // Every way a numeral may have been read: "1.000" is a thousand in most of these languages,
733
+ // "3,5" is three point five, "1,000" could be either. Digits beyond the spellers' range are
734
+ // read one by one.
735
+ export function spokenNumber(raw, speller) {
736
+ const digitsAlone = (digits) => digits
737
+ .split("")
738
+ .map((digit) => speller.cardinal(Number(digit)))
739
+ .join(" ");
740
+ const whole = (digits) => {
741
+ const value = Number(digits);
742
+ if (!Number.isSafeInteger(value) || value >= 1_000_000_000_000)
743
+ return [digitsAlone(digits)];
744
+ const year = speller.year?.(value);
745
+ return [
746
+ ...(year === undefined ? [] : [year]),
747
+ speller.cardinal(value),
748
+ ...(speller.alternatives?.(value) ?? []),
749
+ ];
750
+ };
751
+ const grouped = /^\d{1,3}(?:[. {2}]\d{3})+$/.test(raw);
752
+ const forms = [];
753
+ if (/^\d+$/.test(raw))
754
+ forms.push(...whole(raw));
755
+ else if (grouped)
756
+ forms.push(...whole(raw.replace(/[. {2}]/g, "")));
757
+ const fraction = /^(\d+)[.,](\d+)$/.exec(raw);
758
+ if (fraction !== null && !grouped) {
759
+ const [, integer = "", decimals = ""] = fraction;
760
+ if (/^\d{1,3},\d{3}$/.test(raw))
761
+ forms.push(...whole(`${integer}${decimals}`));
762
+ const head = whole(integer)[0] ?? "";
763
+ forms.push(`${head} ${speller.decimal} ${whole(decimals.replace(/^0+(?=\d)/, ""))[0]}`);
764
+ forms.push(`${head} ${speller.decimal} ${digitsAlone(decimals)}`);
765
+ }
766
+ if (forms.length === 0)
767
+ forms.push(digitsAlone(raw.replace(/\D/g, "")));
768
+ return [...new Set(forms)];
769
+ }