hyperframes 0.8.191 → 0.8.193

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 (213) hide show
  1. package/dist/{add-S2ZQYG52.js → add-JC6DKZKC.js} +17 -17
  2. package/dist/{animatedGifPrep-3JA2CQ3U.js → animatedGifPrep-S6KXJGEL.js} +11 -10
  3. package/dist/api.js +24 -23
  4. package/dist/{appHistory-TH3TL6N6.js → appHistory-QVCSAOI4.js} +1 -1
  5. package/dist/{asset-2CNTAPOC.js → asset-XITFIFE6.js} +2 -2
  6. package/dist/{assetCataloger-5HXLXL7C.js → assetCataloger-K5FNKG35.js} +13 -12
  7. package/dist/{audio-DZTSYHXS.js → audio-364UHTY4.js} +22 -21
  8. package/dist/{auth-GX3M6TJ4.js → auth-5JEESRE6.js} +4 -4
  9. package/dist/{autoUpdate-EDIWE4Z5.js → autoUpdate-RVVYEHAA.js} +5 -5
  10. package/dist/{backgroundChecks-VPUPJ7UI.js → backgroundChecks-DCBIYWIQ.js} +5 -5
  11. package/dist/backgroundChecksWorker.js +5 -5
  12. package/dist/{batchRender-JHIIDBJR.js → batchRender-ZZ4QMBAA.js} +14 -7
  13. package/dist/{beats-PZRVTRYW.js → beats-YEL65M6G.js} +53 -15
  14. package/dist/{benchmark-22UFDW2N.js → benchmark-RBTRPA76.js} +18 -14
  15. package/dist/{browser-VRDWYIUM.js → browser-BVAYXT4R.js} +7 -7
  16. package/dist/{bundleWithLocalizedFonts-23QDKFSN.js → bundleWithLocalizedFonts-JLB2OYMT.js} +3 -3
  17. package/dist/{capture-TOCLXYMJ.js → capture-GBXTMYLZ.js} +76 -68
  18. package/dist/{capture-NFCBXHDE.js → capture-NIFX6IRS.js} +3 -3
  19. package/dist/{captureCompositionFrame-BEM6MF7F.js → captureCompositionFrame-ATNNKUL5.js} +17 -16
  20. package/dist/{catalog-NXS35KM7.js → catalog-AGIF5SM5.js} +18 -18
  21. package/dist/{catch-up-6WJBUI2C.js → catch-up-SZ3ULDTI.js} +7 -7
  22. package/dist/{check-WVEBMWN5.js → check-YLQS3TF4.js} +43 -42
  23. package/dist/{checkBrowser-RT45HJ36.js → checkBrowser-QH4FMCBO.js} +38 -37
  24. package/dist/{chunk-JOLZ3BSL.js → chunk-2LSCYS2H.js} +2 -2
  25. package/dist/{chunk-B2A56S5C.js → chunk-2MCXIY4B.js} +13 -10
  26. package/dist/{chunk-TADJOIFW.js → chunk-2NERNYCJ.js} +4 -4
  27. package/dist/{chunk-KGMHMYWI.js → chunk-2SFDWMSW.js} +2 -2
  28. package/dist/{chunk-DCAI5DBR.js → chunk-2ST4WAFY.js} +9 -1
  29. package/dist/{chunk-3NRB7YXW.js → chunk-2VXY3PEF.js} +96 -67
  30. package/dist/{chunk-IXLUTE6N.js → chunk-3422KMTD.js} +5 -1
  31. package/dist/{chunk-VYQYVYQ5.js → chunk-3W4B6G7Y.js} +83 -45
  32. package/dist/{chunk-JYSSPQDT.js → chunk-4LXZJIVY.js} +11 -11
  33. package/dist/{chunk-WHAEJX26.js → chunk-4PPWAQYV.js} +17 -12
  34. package/dist/{chunk-COWQITWP.js → chunk-4TKJWWPL.js} +1 -1
  35. package/dist/{chunk-NXMYHJAL.js → chunk-4VYPICIA.js} +29 -1
  36. package/dist/{chunk-RE3EEBWC.js → chunk-5J6TWLFG.js} +4 -4
  37. package/dist/{chunk-TFMZ4RKM.js → chunk-6DLCOQR4.js} +474 -429
  38. package/dist/{chunk-KV72BP7O.js → chunk-6LWUPIKD.js} +11 -11
  39. package/dist/{chunk-HRPWRZGF.js → chunk-6N65ZMC5.js} +1 -1
  40. package/dist/{chunk-XUXGIA7H.js → chunk-6NLPPKBO.js} +1 -2
  41. package/dist/{chunk-JJJCFKMF.js → chunk-6XUJVEY2.js} +17 -6
  42. package/dist/{chunk-GM3WIOO6.js → chunk-7HTH5PFK.js} +2 -2
  43. package/dist/{chunk-LBNEH6IQ.js → chunk-7QNIXBQD.js} +1 -1
  44. package/dist/{chunk-OV6KHXLX.js → chunk-7YKJF5JV.js} +1 -1
  45. package/dist/{chunk-COETAXRN.js → chunk-7YSFE4SZ.js} +2 -2
  46. package/dist/{chunk-3WJT2JCX.js → chunk-AR3DQYRR.js} +52 -23
  47. package/dist/{chunk-HYW6HTAK.js → chunk-BJAS2JLW.js} +2 -2
  48. package/dist/{chunk-RWYUK7LM.js → chunk-BP4EMEGH.js} +2 -2
  49. package/dist/{chunk-XGHHVYC7.js → chunk-BY6OQ6XP.js} +2 -2
  50. package/dist/{chunk-TMBUBLZB.js → chunk-C4Y3ZREE.js} +185 -46
  51. package/dist/{chunk-JQYJXUJW.js → chunk-C6KE4AFW.js} +1 -1
  52. package/dist/{chunk-TMK4Q7JA.js → chunk-CFUCHO4T.js} +20 -5
  53. package/dist/{chunk-JGTRVG32.js → chunk-CGTZOY53.js} +1 -1
  54. package/dist/chunk-CZGHFATT.js +31 -0
  55. package/dist/{chunk-NJGTNWQY.js → chunk-D625D4TV.js} +6 -6
  56. package/dist/{chunk-CYBXXSC4.js → chunk-DIKAPMMF.js} +2 -2
  57. package/dist/{chunk-CXMXJEVY.js → chunk-DSQ72G5I.js} +1 -1
  58. package/dist/{chunk-GLG5JWLI.js → chunk-DYNHVCBF.js} +2 -2
  59. package/dist/{chunk-7L37AB57.js → chunk-E3P3LJG6.js} +9 -9
  60. package/dist/{chunk-EFCKV7MY.js → chunk-E77ALFLW.js} +1 -1
  61. package/dist/{chunk-WQ3X5OH4.js → chunk-EFXMETRK.js} +2 -2
  62. package/dist/{chunk-7KVVNF7B.js → chunk-ELP5QZWL.js} +1 -1
  63. package/dist/{chunk-QH3T4WI2.js → chunk-EXAX37XR.js} +8 -2
  64. package/dist/{chunk-7A65UCMI.js → chunk-F5LLORBP.js} +2 -2
  65. package/dist/{chunk-EI7FP7F3.js → chunk-FBVUAH7N.js} +12 -2
  66. package/dist/{chunk-XWOCXIKR.js → chunk-GKHMSSGY.js} +1 -1
  67. package/dist/{chunk-DOOSC34Z.js → chunk-GR5DQKDR.js} +8 -8
  68. package/dist/{chunk-W64L7IFS.js → chunk-IW5G323T.js} +1 -1
  69. package/dist/{chunk-NAUKCKCJ.js → chunk-KU3UFQN7.js} +9 -12
  70. package/dist/{chunk-NMDUSCCE.js → chunk-L4JB7LI4.js} +478 -129
  71. package/dist/{chunk-ALEF2F5N.js → chunk-L5YLA54L.js} +2 -2
  72. package/dist/{chunk-MSM6VRQ4.js → chunk-LFUVTS6V.js} +2 -2
  73. package/dist/{chunk-7ZJEQY7Q.js → chunk-LMNZLZMJ.js} +23 -3
  74. package/dist/{chunk-AQB5M53R.js → chunk-M3KZBDPB.js} +3 -3
  75. package/dist/{chunk-BFFLKQVB.js → chunk-MFUNDJEV.js} +4 -4
  76. package/dist/{chunk-7NKJS5KM.js → chunk-OFV3WSOE.js} +1 -1
  77. package/dist/{chunk-CINKQY6M.js → chunk-OFYW4J7Y.js} +3 -3
  78. package/dist/{chunk-5C7R55BJ.js → chunk-P2I4RLJE.js} +1 -1
  79. package/dist/{chunk-RUOG4VB7.js → chunk-PKZ7RK5N.js} +5 -4
  80. package/dist/{chunk-LLFQA7XF.js → chunk-QFPBRZJD.js} +1 -1
  81. package/dist/{chunk-TRZVS6TL.js → chunk-QKX7ITER.js} +3 -3
  82. package/dist/{chunk-46HEFGXJ.js → chunk-REUL2KH2.js} +1 -1
  83. package/dist/{chunk-TFGO5YMI.js → chunk-RTLPWOO6.js} +2 -2
  84. package/dist/{chunk-DYAPHNV6.js → chunk-RWGASWT7.js} +1 -1
  85. package/dist/chunk-RXATE6FZ.js +385 -0
  86. package/dist/{chunk-U5GTDAQL.js → chunk-SOY2FPOR.js} +7 -7
  87. package/dist/{chunk-KNU5COPB.js → chunk-T2EUWCJE.js} +1 -1
  88. package/dist/{chunk-RQBB7PYT.js → chunk-TY3LDJA3.js} +5 -12
  89. package/dist/{chunk-KAC2WR7P.js → chunk-TZEKVLPV.js} +3 -3
  90. package/dist/{chunk-TJKE4EYX.js → chunk-UB7BIDBS.js} +3 -3
  91. package/dist/{chunk-WY3TQ2PT.js → chunk-UIC7B5KW.js} +2 -2
  92. package/dist/{chunk-2WNVHZHA.js → chunk-UNATIAOT.js} +13 -13
  93. package/dist/chunk-USWPZXEA.js +3897 -0
  94. package/dist/{chunk-FBDOHH3Q.js → chunk-V7ZA2BNW.js} +29 -59
  95. package/dist/{chunk-7LUJE3II.js → chunk-VLLFORE2.js} +1 -1
  96. package/dist/{chunk-T5YF32WV.js → chunk-VPC4XIVI.js} +6 -5
  97. package/dist/{chunk-7FF36MAD.js → chunk-VW63MHQU.js} +9 -6
  98. package/dist/{chunk-ZHKUIC7X.js → chunk-WFS6S65A.js} +21 -14
  99. package/dist/{chunk-UNR3P7IF.js → chunk-WIVOXGEP.js} +3 -3
  100. package/dist/{chunk-3XI7MIZB.js → chunk-X5CECNCK.js} +1 -1
  101. package/dist/{chunk-KHCTBZGJ.js → chunk-XQPA4W3M.js} +4 -4
  102. package/dist/{chunk-XMSQRDAK.js → chunk-YS4JUGNI.js} +2 -2
  103. package/dist/{chunk-SMEF3TRJ.js → chunk-ZH7J2ZUL.js} +15 -15
  104. package/dist/{chunk-WJEVUPVD.js → chunk-ZT45TCY3.js} +1 -1
  105. package/dist/{chunk-JTPHFYZI.js → chunk-ZTKFRXJB.js} +68 -7
  106. package/dist/{chunk-W3CS2KFV.js → chunk-ZZPBXRYQ.js} +2 -2
  107. package/dist/{clean-3VIU2BSK.js → clean-5HGESK5A.js} +40 -27
  108. package/dist/cli.js +70 -68
  109. package/dist/{cloud-NA3J4XW2.js → cloud-746PHS32.js} +4 -4
  110. package/dist/{cloudrun-4MHOF7UT.js → cloudrun-DO7WFLSM.js} +9 -9
  111. package/dist/commands/contrast-audit.browser.js +1 -1
  112. package/dist/{compare-ZR7XRPPT.js → compare-66YPRNG2.js} +76 -47
  113. package/dist/{compiler-MA2ELZPG.js → compiler-R4UYDWXO.js} +8 -7
  114. package/dist/{component-ZJSOPUAM.js → component-EQ3H6RFP.js} +3 -3
  115. package/dist/{compositions-WA5V2SHF.js → compositions-ZZ7P5HT2.js} +19 -17
  116. package/dist/{contactSheet-CAGMKI3E.js → contactSheet-SZBJDOMT.js} +2 -2
  117. package/dist/{delete-UC427UEA.js → delete-Z5MSLJSR.js} +7 -7
  118. package/dist/{deploy-B5UO4UIK.js → deploy-RGSAC2K5.js} +1 -1
  119. package/dist/{deterministicFonts-EGAAE7QL.js → deterministicFonts-RO2TCMLZ.js} +3 -3
  120. package/dist/{dist-XGPSPKKP.js → dist-QQ26RUDV.js} +5 -4
  121. package/dist/{dist-BPK37SAB.js → dist-RKK4YLAD.js} +5 -5
  122. package/dist/{doctor-ZERCTKEK.js → doctor-W4ZZDRTU.js} +20 -19
  123. package/dist/{events-DCOZQERS.js → events-BSSL4A4W.js} +4 -4
  124. package/dist/{events-CNIXB2QK.js → events-UACT7PX3.js} +5 -5
  125. package/dist/{feedback-YBD5ITTY.js → feedback-47ILDLQG.js} +16 -16
  126. package/dist/{ffmpeg-V4BBFDTG.js → ffmpeg-IEHSUNUT.js} +13 -12
  127. package/dist/{figma-Z45ZYVGE.js → figma-PLFIIYRU.js} +3 -3
  128. package/dist/fontLocalizeCli.js +14 -13
  129. package/dist/{get-23NXQWCD.js → get-PDWGJYNL.js} +7 -7
  130. package/dist/{gpuPolicy-H6ABHVEB.js → gpuPolicy-6UBXO6ME.js} +11 -10
  131. package/dist/{grade-compare-ZPX2G3UV.js → grade-compare-5VWLQGM7.js} +38 -37
  132. package/dist/{gsapParserAcorn-SKODXC2N.js → gsapParserAcorn-OOTY2MVN.js} +2 -2
  133. package/dist/{help-EP4CDPLO.js → help-DS3KMWYO.js} +1 -1
  134. package/dist/{history-E5OSXO74.js → history-OC326NVZ.js} +41 -17
  135. package/dist/hyperframe.manifest.json +1 -1
  136. package/dist/hyperframe.runtime.iife.js +62 -62
  137. package/dist/hyperframes-player.global.js +3 -3
  138. package/dist/hyperframes-slideshow.global.js +1 -1
  139. package/dist/{info-2HHGSW5H.js → info-AUIFV6MX.js} +56 -22
  140. package/dist/{init-ENEG6RZT.js → init-MRTWWDFW.js} +38 -45
  141. package/dist/{inspect-PVQK4E2A.js → inspect-55NOAXI2.js} +36 -35
  142. package/dist/{installer-YGGLEOSF.js → installer-YSFFGBBV.js} +8 -8
  143. package/dist/{keyframes-UWSYS2SL.js → keyframes-OO2BX2IB.js} +13 -14
  144. package/dist/{lambda-L3LPXC2M.js → lambda-CXXY6QT3.js} +11 -11
  145. package/dist/{layout-JVL4QREC.js → layout-57GJXKDK.js} +36 -35
  146. package/dist/{lint-JXQ72DDB.js → lint-J4FK3Z6G.js} +23 -16
  147. package/dist/{lintProject-F7IC7WY4.js → lintProject-52SLJPRC.js} +5 -4
  148. package/dist/{list-UFMLM3VV.js → list-VDQUJ76B.js} +7 -7
  149. package/dist/{login-CKGMWQJN.js → login-TJSEALWW.js} +7 -7
  150. package/dist/{logout-DDC4QLVK.js → logout-JYFWWUGK.js} +3 -3
  151. package/dist/{manager-U6OP3EXB.js → manager-4PLYEEWP.js} +14 -13
  152. package/dist/{manager-UHWEKPXC.js → manager-MZIJY73J.js} +3 -3
  153. package/dist/{media-treatment-MFMEWCDY.js → media-treatment-GXP4PMJH.js} +20 -19
  154. package/dist/{models-QA3TJ75Y.js → models-HQQQKEEP.js} +18 -17
  155. package/dist/{motionShot-NV2OPJHD.js → motionShot-2BT5D7DC.js} +21 -20
  156. package/dist/{normalize-3AYFSN2F.js → normalize-FASIPBUM.js} +1 -1
  157. package/dist/{normalize-audio-JWJRUKK2.js → normalize-audio-SOLFMHNP.js} +12 -8
  158. package/dist/{open-PTJNDRER.js → open-KHEUODFQ.js} +18 -18
  159. package/dist/{parakeetRunner-B5FCWWOO.js → parakeetRunner-BHU5NCAX.js} +20 -19
  160. package/dist/{pipeline-N26NA6ZG.js → pipeline-WFV5HDTD.js} +15 -14
  161. package/dist/{play-45D6X6TV.js → play-GB34CANJ.js} +27 -26
  162. package/dist/{policies-MBWGLMWB.js → policies-GHVXA5PE.js} +1 -1
  163. package/dist/{preflight-MFOHPUOI.js → preflight-REF3VSJ7.js} +15 -14
  164. package/dist/{present-IFBUDI4D.js → present-SIUTA7TD.js} +24 -23
  165. package/dist/{preview-MQRLXQOV.js → preview-T2GE7Z4A.js} +27 -26
  166. package/dist/{producer-2QG7HLAW.js → producer-23KVQZAB.js} +1 -1
  167. package/dist/{projectConfig-I4FTZXHB.js → projectConfig-DBSNBPNP.js} +10 -10
  168. package/dist/{publication-3GOFXCGU.js → publication-IXPUKYWJ.js} +5 -5
  169. package/dist/{publish-3B2TZCFH.js → publish-3BA5VHXJ.js} +18 -17
  170. package/dist/{refresh-RXTOPRBB.js → refresh-USSFPJAU.js} +3 -3
  171. package/dist/{remove-background-RK4BJDBF.js → remove-background-RMSCJVVQ.js} +16 -15
  172. package/dist/{render-SJ4HFPFU.js → render-6RNE2MLU.js} +26 -25
  173. package/dist/{render-PW3XGS7B.js → render-XGOZMMWX.js} +42 -41
  174. package/dist/{render-BV6FWFX3.js → render-Y6CTQ3YW.js} +8 -8
  175. package/dist/{render-batch-GKX54O6N.js → render-batch-VUR6N6EY.js} +9 -9
  176. package/dist/renderSetupWorker.js +9 -8
  177. package/dist/{resolver-RQJ7CNXD.js → resolver-GJCUH57W.js} +7 -7
  178. package/dist/{screenshotCapture-UBY6TT75.js → screenshotCapture-I5EDCITF.js} +6 -3
  179. package/dist/{sherpa-XZPG7QFF.js → sherpa-VVAKRCPL.js} +19 -18
  180. package/dist/skills/hyperframes/references/format.md +1 -0
  181. package/dist/skills/hyperframes/references/skill-lifecycle.md +8 -4
  182. package/dist/skills/hyperframes-cli/references/init-and-scaffold.md +1 -1
  183. package/dist/{skills-EYLB2V6F.js → skills-ZHBURVQG.js} +13 -75
  184. package/dist/{skillsUpdateCheck-TE6K5ROM.js → skillsUpdateCheck-VMDAL2O2.js} +5 -5
  185. package/dist/{slideshow-YTWATJRT.js → slideshow-SJGK4RQS.js} +1 -1
  186. package/dist/{snapshot-FE4T3SCN.js → snapshot-KEOG56SL.js} +61 -53
  187. package/dist/{src-ZOXSEJCD.js → src-BH5NICGQ.js} +24 -9
  188. package/dist/{src-SEJ7LNNB.js → src-TZLGFRRX.js} +13 -12
  189. package/dist/{staticProjectServer-LSVIRDRO.js → staticProjectServer-BKXL5CXB.js} +22 -21
  190. package/dist/{status-CM7IQTU2.js → status-H5WLKQDS.js} +3 -3
  191. package/dist/studio/assets/{hyperframes-player-Bv9hQ3v7.js → hyperframes-player-BMcUdmDb.js} +3 -3
  192. package/dist/studio/assets/{index-CBO8uz7-.css → index-CYbvOVp-.css} +1 -1
  193. package/dist/studio/assets/{index-D_QqfWhx.js → index-Ca-mgTnS.js} +122 -122
  194. package/dist/studio/assets/{index-Df14bh-L.js → index-Ci6GuloR.js} +1 -1
  195. package/dist/studio/index.html +2 -2
  196. package/dist/{studio-api-SL2Z76NU.js → studio-api-A5U6QAMC.js} +19 -14
  197. package/dist/{studioServer-BADWVIHU.js → studioServer-5EC5CP4W.js} +60 -59
  198. package/dist/{telemetry-QG5AANZ4.js → telemetry-4K6CPMNT.js} +2 -2
  199. package/dist/{telemetry-RN6VYEID.js → telemetry-BCKJXDSW.js} +5 -5
  200. package/dist/{timeline-JBTCIPLU.js → timeline-AZWAXTAY.js} +65 -43
  201. package/dist/{tokens-A7V7UHNK.js → tokens-X7NC3V7C.js} +2 -2
  202. package/dist/{transcribe-E4BOSNM4.js → transcribe-7NCY7QZ2.js} +17 -16
  203. package/dist/{transcribe-NTUCJGFI.js → transcribe-SH26H755.js} +26 -25
  204. package/dist/{tts-A2WILYGN.js → tts-5I2AJNLM.js} +1 -1
  205. package/dist/{updateCheck-M7UAYLUR.js → updateCheck-Y7FUWQM4.js} +4 -4
  206. package/dist/{upgrade-A2COSIMB.js → upgrade-ZHGEVL65.js} +4 -4
  207. package/dist/{urlDownloader-MBSQYART.js → urlDownloader-FPILIT7M.js} +10 -9
  208. package/dist/{validate-NODZYBHY.js → validate-KQOZR4F6.js} +30 -29
  209. package/dist/{video-LBCUUYK7.js → video-N2QAETFB.js} +12 -11
  210. package/dist/warmCheck.js +43 -42
  211. package/package.json +2 -1
  212. package/dist/chunk-I5JRXMCV.js +0 -6077
  213. package/dist/chunk-LM265QNK.js +0 -3896
@@ -26,7 +26,7 @@ import {
26
26
  renderFrameIdForRenderId,
27
27
  resolveAuthoredTimingWindow,
28
28
  toFps
29
- } from "./chunk-GM3WIOO6.js";
29
+ } from "./chunk-7HTH5PFK.js";
30
30
  import {
31
31
  AUDIO_GROUP_RENDER_ID_ATTR,
32
32
  COLOR_GRADING_SOURCE_HIDDEN_ATTR,
@@ -63,7 +63,7 @@ import {
63
63
  sourceTimeAt,
64
64
  timeAtSourceTime,
65
65
  volumeSegmentSampleCount
66
- } from "./chunk-LM265QNK.js";
66
+ } from "./chunk-USWPZXEA.js";
67
67
  import {
68
68
  clampAudioGain,
69
69
  clipGain,
@@ -83,7 +83,7 @@ import {
83
83
  } from "./chunk-4UMPIPCQ.js";
84
84
  import {
85
85
  resolveReferencedStart
86
- } from "./chunk-3NRB7YXW.js";
86
+ } from "./chunk-2VXY3PEF.js";
87
87
  import {
88
88
  FFMPEG_PATH_ENV,
89
89
  FFPROBE_PATH_ENV,
@@ -1477,6 +1477,7 @@ function getLowMemoryFlags() {
1477
1477
  }
1478
1478
  var CANVAS_DRAW_ELEMENT_FEATURE_FLAG = "--enable-features=CanvasDrawElement";
1479
1479
  var WEBGPU_FLAG = "--enable-unsafe-webgpu";
1480
+ var DISABLE_DXC_FLAG = "--disable-dawn-features=use_dxc";
1480
1481
  function usesSoftwareWebGpu(requiresWebGpu, config) {
1481
1482
  return !!requiresWebGpu && !!config?.allowSoftwareWebGpu && !(config.disableGpu ?? DEFAULT_CONFIG.disableGpu) && (config.browserGpuMode ?? DEFAULT_CONFIG.browserGpuMode) === "software";
1482
1483
  }
@@ -1532,6 +1533,9 @@ function buildChromeArgs(options, config) {
1532
1533
  ];
1533
1534
  if (browserGpuMode !== "software" || options.requiresWebGpu) {
1534
1535
  chromeArgs.push(WEBGPU_FLAG);
1536
+ if (platform === "win32") {
1537
+ chromeArgs.push(DISABLE_DXC_FLAG);
1538
+ }
1535
1539
  }
1536
1540
  if (softwareWebGpu) chromeArgs.push("--use-vulkan=swiftshader");
1537
1541
  if (browserGpuMode === "software" && !softwareWebGpu) {
@@ -4778,8 +4782,11 @@ async function sampleProcessRss(pids, exec = defaultExec(), platform = process.p
4778
4782
  if (platform === "win32") {
4779
4783
  const results = [];
4780
4784
  for (const pid of unique) {
4781
- const { stdout: stdout2 } = await exec("tasklist", ["/FO", "CSV", "/NH", "/FI", `PID eq ${pid}`]);
4782
- results.push(...parseTasklistCsv(pid, stdout2));
4785
+ try {
4786
+ const { stdout: stdout2 } = await exec("tasklist", ["/FO", "CSV", "/NH", "/FI", `PID eq ${pid}`]);
4787
+ results.push(...parseTasklistCsv(pid, stdout2));
4788
+ } catch {
4789
+ }
4783
4790
  }
4784
4791
  return results;
4785
4792
  }
@@ -4795,6 +4802,7 @@ var CaptureFailure = class extends Error {
4795
4802
  kind;
4796
4803
  cause;
4797
4804
  workerDiagnostics;
4805
+ pageErrorLines;
4798
4806
  constructor(input) {
4799
4807
  super(input.message);
4800
4808
  this.name = "CaptureFailure";
@@ -4805,6 +4813,7 @@ var CaptureFailure = class extends Error {
4805
4813
  (diagnostic) => Object.freeze({ ...diagnostic, lines: Object.freeze([...diagnostic.lines]) })
4806
4814
  )
4807
4815
  );
4816
+ this.pageErrorLines = Object.freeze([...input.pageErrorLines ?? []]);
4808
4817
  if (input.cause instanceof Error && input.cause.stack) this.stack = input.cause.stack;
4809
4818
  }
4810
4819
  };
@@ -4890,32 +4899,37 @@ function ioError(error, message) {
4890
4899
  )
4891
4900
  ) || BROKEN_PIPE_MESSAGE.test(message) || hasIoOperationFailure(message);
4892
4901
  }
4902
+ var ORDERED_KIND_RULES = [
4903
+ [
4904
+ "memory_exhaustion",
4905
+ (message) => BUN_MEMORY_EXHAUSTION_EXACT_MESSAGE.test(message.trim()) || BUN_MEMORY_EXHAUSTION_WRAPPED_WORKER_MESSAGE.test(message) || matchesAny(message, MEMORY_EXHAUSTION_ERROR_PATTERNS)
4906
+ ],
4907
+ ["verification", (message) => matchesAny(message, VERIFICATION_ERROR_PATTERNS)],
4908
+ ["protocol_timeout", (message) => matchesAny(message, PROTOCOL_TIMEOUT_PATTERNS)],
4909
+ ["transient_browser", (message) => matchesAny(message, TRANSIENT_BROWSER_ERROR_PATTERNS)],
4910
+ ["authoring", (message) => matchesAny(message, AUTHORING_ERROR_PATTERNS)]
4911
+ ];
4912
+ function classifyKind(error, message, signal) {
4913
+ if (signal?.aborted || /(?:render|capture)?_?cancelled|AbortError/i.test(message)) {
4914
+ return "cancelled";
4915
+ }
4916
+ const rule = ORDERED_KIND_RULES.find(([, matches]) => matches(message));
4917
+ if (rule) return rule[0];
4918
+ return ioError(error, message) ? "io" : "authoring";
4919
+ }
4893
4920
  function classifyCaptureFailure(error, options = {}) {
4894
- if (error instanceof CaptureFailure && !options.workerDiagnostics && !options.signal?.aborted) {
4895
- return error;
4921
+ const prior = error instanceof CaptureFailure ? error : void 0;
4922
+ if (prior && !(options.workerDiagnostics || options.pageErrorLines || options.signal?.aborted)) {
4923
+ return prior;
4896
4924
  }
4897
4925
  const message = messageOf(error);
4898
- let kind;
4899
- if (options.signal?.aborted || /(?:render|capture)?_?cancelled|AbortError/i.test(message)) {
4900
- kind = "cancelled";
4901
- } else if (BUN_MEMORY_EXHAUSTION_EXACT_MESSAGE.test(message.trim()) || BUN_MEMORY_EXHAUSTION_WRAPPED_WORKER_MESSAGE.test(message) || matchesAny(message, MEMORY_EXHAUSTION_ERROR_PATTERNS)) {
4902
- kind = "memory_exhaustion";
4903
- } else if (matchesAny(message, VERIFICATION_ERROR_PATTERNS)) {
4904
- kind = "verification";
4905
- } else if (matchesAny(message, PROTOCOL_TIMEOUT_PATTERNS)) {
4906
- kind = "protocol_timeout";
4907
- } else if (matchesAny(message, TRANSIENT_BROWSER_ERROR_PATTERNS)) {
4908
- kind = "transient_browser";
4909
- } else if (matchesAny(message, AUTHORING_ERROR_PATTERNS)) {
4910
- kind = "authoring";
4911
- } else {
4912
- kind = ioError(error, message) ? "io" : "authoring";
4913
- }
4926
+ const kind = classifyKind(error, message, options.signal);
4914
4927
  return new CaptureFailure({
4915
4928
  kind,
4916
4929
  message,
4917
4930
  cause: error,
4918
- workerDiagnostics: options.workerDiagnostics ?? (error instanceof CaptureFailure ? error.workerDiagnostics : void 0)
4931
+ workerDiagnostics: options.workerDiagnostics ?? prior?.workerDiagnostics,
4932
+ pageErrorLines: options.pageErrorLines ?? prior?.pageErrorLines
4919
4933
  });
4920
4934
  }
4921
4935
  function isTransientBrowserError(error) {
@@ -5200,12 +5214,14 @@ async function driveWarmupTicks(options, state) {
5200
5214
  } else {
5201
5215
  if (!state.running) return;
5202
5216
  }
5217
+ let ticked = false;
5203
5218
  try {
5204
5219
  await options.tick(state.ticks * options.intervalMs, options.intervalMs);
5205
5220
  state.ticks += 1;
5221
+ ticked = true;
5206
5222
  } catch {
5207
5223
  }
5208
- await sleep(options.intervalMs);
5224
+ if (!(options.lockWarmupTicks && !state.running && ticked)) await sleep(options.intervalMs);
5209
5225
  }
5210
5226
  }
5211
5227
  function resolveCaptureSessionOptions(options, browserVersion, platform = process.platform) {
@@ -8544,6 +8560,7 @@ var videoMetadataCache = /* @__PURE__ */ new Map();
8544
8560
  var finalVideoFrameTimestampCache = /* @__PURE__ */ new Map();
8545
8561
  var finalVideoFrameTimestampSignalCaches = /* @__PURE__ */ new WeakMap();
8546
8562
  var audioMetadataCache = /* @__PURE__ */ new Map();
8563
+ var audioMetadataSignalCaches = /* @__PURE__ */ new WeakMap();
8547
8564
  var mediaProbeOutputCache = /* @__PURE__ */ new Map();
8548
8565
  var mediaProbeOutputSignalCaches = /* @__PURE__ */ new WeakMap();
8549
8566
  var MEDIA_PROBE_OUTPUT_CACHE_MAX_ENTRIES = 128;
@@ -8599,7 +8616,20 @@ function isPngImageProbe(output) {
8599
8616
  (stream) => stream.codec_type === "video" && stream.codec_name?.toLowerCase() === "png"
8600
8617
  );
8601
8618
  }
8619
+ var contentAddressedUrls = /* @__PURE__ */ new Map();
8620
+ var withoutQuery = (url) => url.split(/[?#]/, 1)[0] ?? url;
8621
+ function declareContentAddressedUrl(url, sha256) {
8622
+ contentAddressedUrls.set(withoutQuery(url), sha256);
8623
+ }
8624
+ var probeFactsUrls = /* @__PURE__ */ new Map();
8625
+ function declareProbeFactsUrl(url, factsUrl) {
8626
+ probeFactsUrls.set(withoutQuery(url), factsUrl);
8627
+ }
8602
8628
  function mediaFileIdentity(filePath) {
8629
+ if (/^https?:\/\//i.test(filePath)) {
8630
+ const sha256 = contentAddressedUrls.get(withoutQuery(filePath));
8631
+ return sha256 ? `sha256:${sha256}` : null;
8632
+ }
8603
8633
  try {
8604
8634
  const stat = statSync2(filePath, { bigint: true });
8605
8635
  return [stat.dev, stat.ino, stat.size, stat.mtimeNs, stat.ctimeNs].join(":");
@@ -8623,6 +8653,75 @@ function writeMetadataCache(cache, key, identity, promise) {
8623
8653
  }
8624
8654
  );
8625
8655
  }
8656
+ var PROBE_FACTS_VERSION = "v2";
8657
+ var PROBE_JSON_ARGS = ["-print_format", "json", "-show_format", "-show_streams"];
8658
+ var storedFacts = /* @__PURE__ */ new Map();
8659
+ function readStoredFacts(filePath) {
8660
+ if (!/^https?:\/\//i.test(filePath)) return void 0;
8661
+ const factsUrl = probeFactsUrls.get(withoutQuery(filePath));
8662
+ if (!factsUrl) return void 0;
8663
+ let facts = storedFacts.get(factsUrl);
8664
+ if (!facts) {
8665
+ facts = (async () => {
8666
+ try {
8667
+ const response = await fetch(factsUrl, { signal: AbortSignal.timeout(1e4) });
8668
+ if (!response.ok) return null;
8669
+ const parsed = JSON.parse(await response.text());
8670
+ return Array.isArray(parsed.ffprobe?.streams) ? parsed : null;
8671
+ } catch {
8672
+ return null;
8673
+ }
8674
+ })();
8675
+ storedFacts.set(factsUrl, facts);
8676
+ }
8677
+ return facts;
8678
+ }
8679
+ function readProbeJson(filePath, signal) {
8680
+ const pending = readStoredFacts(filePath);
8681
+ if (!pending) return runFfprobe(filePath, PROBE_JSON_ARGS, signal);
8682
+ return pending.then(
8683
+ (stored) => stored ? JSON.stringify(stored.ffprobe) : runFfprobe(filePath, PROBE_JSON_ARGS, signal)
8684
+ );
8685
+ }
8686
+ var runtimeFfprobeMajor;
8687
+ function ffprobeMajor() {
8688
+ runtimeFfprobeMajor ??= new Promise((resolve) => {
8689
+ let out = "";
8690
+ const binary = getFfprobeBinary();
8691
+ const proc = spawn3(binary, ["-version"], { stdio: ["ignore", "pipe", "ignore"] });
8692
+ proc.stdout.on("data", (chunk) => out += String(chunk));
8693
+ proc.on("error", () => resolve(void 0));
8694
+ proc.on("close", () => resolve(Number(/version n?(\d+)/.exec(out)?.[1]) || void 0));
8695
+ });
8696
+ return runtimeFfprobeMajor;
8697
+ }
8698
+ async function buildProbeFactsText(filePath, signal) {
8699
+ const facts = {
8700
+ ffprobe: parseProbeJson(await runFfprobe(filePath, PROBE_JSON_ARGS, signal)),
8701
+ ffprobeMajor: await ffprobeMajor()
8702
+ };
8703
+ try {
8704
+ const metadata = await extractMediaMetadata(filePath);
8705
+ const window2 = resolveStreamWindow(filePath, {
8706
+ videoStreamStartSeconds: metadata.videoStreamStartSeconds,
8707
+ videoStreamDurationSeconds: resolvePlayableVideoDuration(metadata) - (metadata.videoStreamLeadSeconds ?? 0)
8708
+ });
8709
+ if (window2.videoStreamDurationSeconds > 0) {
8710
+ facts.finalFrame = {
8711
+ streamStart: window2.videoStreamStartSeconds,
8712
+ streamDuration: window2.videoStreamDurationSeconds,
8713
+ seconds: await extractFinalVideoFrameTimestamp(filePath, window2, signal),
8714
+ lastPacketSeconds: await extractFinalPacketDuration(filePath, window2, signal)
8715
+ };
8716
+ }
8717
+ } catch {
8718
+ if (signal?.aborted) throw signal.reason;
8719
+ }
8720
+ return JSON.stringify(facts);
8721
+ }
8722
+ function resolvePlayableVideoDuration(metadata) {
8723
+ return Number.isFinite(metadata.videoStreamDurationSeconds) && metadata.videoStreamDurationSeconds > 0 ? (metadata.videoStreamLeadSeconds ?? 0) + metadata.videoStreamDurationSeconds : metadata.durationSeconds;
8724
+ }
8626
8725
  async function probeMediaOutput(filePath, signal) {
8627
8726
  let cache = mediaProbeOutputCache;
8628
8727
  if (signal) {
@@ -8638,11 +8737,7 @@ async function probeMediaOutput(filePath, signal) {
8638
8737
  }
8639
8738
  return cached.promise;
8640
8739
  }
8641
- const promise = runFfprobe(
8642
- filePath,
8643
- ["-print_format", "json", "-show_format", "-show_streams"],
8644
- signal
8645
- ).then(parseProbeJson);
8740
+ const promise = readProbeJson(filePath, signal).then(parseProbeJson);
8646
8741
  if (identity !== null) {
8647
8742
  cache.set(filePath, { identity, promise });
8648
8743
  if (!signal && cache.size > MEDIA_PROBE_OUTPUT_CACHE_MAX_ENTRIES) {
@@ -8898,6 +8993,43 @@ function resolveStreamWindow(filePath, metadata) {
8898
8993
  const cacheKey = `${filePath}\0${String(videoStreamStartSeconds)}\0${String(videoStreamDurationSeconds)}`;
8899
8994
  return { videoStreamStartSeconds, videoStreamDurationSeconds, cacheKey };
8900
8995
  }
8996
+ function readStoredFinalFrame(filePath, metadata) {
8997
+ const { videoStreamStartSeconds, videoStreamDurationSeconds } = resolveStreamWindow(
8998
+ filePath,
8999
+ metadata
9000
+ );
9001
+ return readStoredFacts(filePath)?.then(async (facts) => {
9002
+ const stored = facts?.finalFrame;
9003
+ if (facts?.ffprobeMajor !== void 0 && facts.ffprobeMajor !== await ffprobeMajor())
9004
+ return void 0;
9005
+ return stored && stored.streamStart === videoStreamStartSeconds && stored.streamDuration === videoStreamDurationSeconds ? stored : void 0;
9006
+ });
9007
+ }
9008
+ async function extractFinalPacketDuration(filePath, window2, signal) {
9009
+ const streamEnd = window2.videoStreamStartSeconds + window2.videoStreamDurationSeconds;
9010
+ const intervalStart = Math.max(window2.videoStreamStartSeconds, streamEnd - 1);
9011
+ const stdout = await runFfprobe(
9012
+ filePath,
9013
+ [
9014
+ "-select_streams",
9015
+ "v:0",
9016
+ "-read_intervals",
9017
+ `${intervalStart}%${streamEnd}`,
9018
+ "-show_entries",
9019
+ "packet=pts_time,duration_time",
9020
+ "-of",
9021
+ "csv=p=0"
9022
+ ],
9023
+ signal,
9024
+ { retainTail: true, maxChars: 64 * 1024 }
9025
+ );
9026
+ const packets = stdout.split("\n").map((line) => line.trim().split(",").map(Number)).filter(([pts, duration]) => Number.isFinite(pts) && Number.isFinite(duration));
9027
+ const last = packets.reduce(
9028
+ (best, packet) => !best || packet[0] > best[0] ? packet : best,
9029
+ void 0
9030
+ );
9031
+ return last?.[1];
9032
+ }
8901
9033
  async function extractFinalVideoFrameTimestamp(filePath, metadata, signal) {
8902
9034
  const {
8903
9035
  videoStreamStartSeconds,
@@ -8913,6 +9045,9 @@ async function extractFinalVideoFrameTimestamp(filePath, metadata, signal) {
8913
9045
  const cached = readMetadataCache(probeCache, cacheKey, identity);
8914
9046
  if (cached) return cached;
8915
9047
  const probePromise = (async () => {
9048
+ const pendingStored = readStoredFinalFrame(filePath, metadata);
9049
+ const stored = pendingStored && await pendingStored;
9050
+ if (stored) return stored.seconds;
8916
9051
  if (!(videoDurationSeconds > 0) || !Number.isFinite(videoDurationSeconds)) {
8917
9052
  throw new Error(
8918
9053
  `[FFmpeg] Cannot locate final video frame for invalid duration ${String(videoDurationSeconds)}`
@@ -8951,44 +9086,51 @@ async function extractFinalVideoFrameTimestamp(filePath, metadata, signal) {
8951
9086
  var extractVideoMetadata = extractMediaMetadata;
8952
9087
  async function extractAudioMetadata(filePath, options) {
8953
9088
  const identity = mediaFileIdentity(filePath);
8954
- const cached = options?.signal ? void 0 : readMetadataCache(audioMetadataCache, filePath, identity);
9089
+ const signal = options?.signal;
9090
+ if (signal && identity === null) return probeAudioMetadata(filePath, signal);
9091
+ let cache = audioMetadataCache;
9092
+ if (signal) {
9093
+ cache = audioMetadataSignalCaches.get(signal) ?? /* @__PURE__ */ new Map();
9094
+ audioMetadataSignalCaches.set(signal, cache);
9095
+ }
9096
+ const cached = readMetadataCache(cache, filePath, identity);
8955
9097
  if (cached) return cached;
8956
- const probePromise = (async () => {
8957
- const output = await probeMediaOutput(filePath, options?.signal);
8958
- const audioStream = output.streams.find((s) => s.codec_type === "audio");
8959
- if (!audioStream) throw new Error("[FFmpeg] No audio stream found");
8960
- let durationSeconds = output.format.duration ? parseFloat(output.format.duration) : 0;
8961
- const streamDuration = audioStream.duration ? parseFloat(audioStream.duration) : void 0;
8962
- const sampleRate = audioStream.sample_rate ? parseInt(audioStream.sample_rate) : 44100;
8963
- const audioCodec = audioStream.codec_name || "unknown";
8964
- if (sampleRate > 0) {
8965
- const decoded = await probeDecodedAudioDuration(
8966
- filePath,
8967
- sampleRate,
8968
- audioStartSeconds(audioStream, output.format),
8969
- durationSeconds,
8970
- options?.signal
8971
- );
8972
- if (decoded !== null) {
8973
- durationSeconds = reconcileAudioDuration(durationSeconds, decoded, output.format);
8974
- }
8975
- }
8976
- return {
8977
- durationSeconds,
8978
- streamDurationSeconds: streamDuration && streamDuration > 0 ? streamDuration : void 0,
8979
- sampleRate,
8980
- channels: audioStream.channels || 2,
8981
- audioCodec,
8982
- bitrate: output.format.bit_rate ? parseInt(output.format.bit_rate) : void 0,
8983
- latestStreamLeadSeconds: latestStreamLeadSeconds(output),
8984
- audioStreamLeadSeconds: streamLeadSeconds(output, audioStream),
8985
- audioStreamCount: output.streams.filter((s) => s.codec_type === "audio").length
8986
- };
8987
- })();
8988
- if (options?.signal) return probePromise;
8989
- writeMetadataCache(audioMetadataCache, filePath, identity, probePromise);
9098
+ const probePromise = probeAudioMetadata(filePath, signal);
9099
+ writeMetadataCache(cache, filePath, identity, probePromise);
8990
9100
  return probePromise;
8991
9101
  }
9102
+ async function probeAudioMetadata(filePath, signal) {
9103
+ const output = await probeMediaOutput(filePath, signal);
9104
+ const audioStream = output.streams.find((s) => s.codec_type === "audio");
9105
+ if (!audioStream) throw new Error("[FFmpeg] No audio stream found");
9106
+ let durationSeconds = output.format.duration ? parseFloat(output.format.duration) : 0;
9107
+ const streamDuration = audioStream.duration ? parseFloat(audioStream.duration) : void 0;
9108
+ const sampleRate = audioStream.sample_rate ? parseInt(audioStream.sample_rate) : 44100;
9109
+ const audioCodec = audioStream.codec_name || "unknown";
9110
+ if (sampleRate > 0) {
9111
+ const decoded = await probeDecodedAudioDuration(
9112
+ filePath,
9113
+ sampleRate,
9114
+ audioStartSeconds(audioStream, output.format),
9115
+ durationSeconds,
9116
+ signal
9117
+ );
9118
+ if (decoded !== null) {
9119
+ durationSeconds = reconcileAudioDuration(durationSeconds, decoded, output.format);
9120
+ }
9121
+ }
9122
+ return {
9123
+ durationSeconds,
9124
+ streamDurationSeconds: streamDuration && streamDuration > 0 ? streamDuration : void 0,
9125
+ sampleRate,
9126
+ channels: audioStream.channels || 2,
9127
+ audioCodec,
9128
+ bitrate: output.format.bit_rate ? parseInt(output.format.bit_rate) : void 0,
9129
+ latestStreamLeadSeconds: latestStreamLeadSeconds(output),
9130
+ audioStreamLeadSeconds: streamLeadSeconds(output, audioStream),
9131
+ audioStreamCount: output.streams.filter((s) => s.codec_type === "audio").length
9132
+ };
9133
+ }
8992
9134
  function audioVideoStreamStarts(output) {
8993
9135
  return (output?.streams ?? []).filter(
8994
9136
  (s) => (s.codec_type === "audio" || s.codec_type === "video") && s.disposition?.attached_pic !== 1
@@ -9124,8 +9266,10 @@ async function analyzeKeyframeIntervalsUncached(filePath, videoStreamStartSecond
9124
9266
 
9125
9267
  // ../engine/src/services/softwareEncoderThreads.ts
9126
9268
  import { availableParallelism } from "os";
9127
- function appendSoftwareEncoderThreadsArg(args, parallelism = availableParallelism()) {
9128
- args.push("-threads", String(Math.max(1, Math.floor(parallelism))));
9269
+ var X265_MAX_THREADS = 16;
9270
+ function appendSoftwareEncoderThreadsArg(args, encoder, parallelism = availableParallelism()) {
9271
+ const cap = encoder === "libx265" ? X265_MAX_THREADS : Infinity;
9272
+ args.push("-threads", String(Math.min(cap, Math.max(1, Math.floor(parallelism)))));
9129
9273
  }
9130
9274
 
9131
9275
  // ../engine/src/utils/renderProvenance.ts
@@ -9352,7 +9496,7 @@ function buildEncoderArgs(options, inputArgs, outputPath, gpuEncoder = null) {
9352
9496
  } else {
9353
9497
  const encoderName = codec === "h264" ? "libx264" : "libx265";
9354
9498
  args.push("-c:v", encoderName, "-preset", preset);
9355
- appendSoftwareEncoderThreadsArg(args);
9499
+ appendSoftwareEncoderThreadsArg(args, encoderName);
9356
9500
  if (bitrate) args.push("-b:v", bitrate);
9357
9501
  else args.push("-crf", String(quality));
9358
9502
  const gop = resolveLockedGopSize(options);
@@ -10057,7 +10201,7 @@ function buildStreamingArgs(options, outputPath, gpuEncoder = null) {
10057
10201
  } else {
10058
10202
  const encoderName = codec === "h264" ? "libx264" : "libx265";
10059
10203
  args.push("-c:v", encoderName, "-preset", preset);
10060
- appendSoftwareEncoderThreadsArg(args);
10204
+ appendSoftwareEncoderThreadsArg(args, encoderName);
10061
10205
  if (bitrate) args.push("-b:v", bitrate);
10062
10206
  else args.push("-crf", String(quality));
10063
10207
  const lockedGop = resolveLockedGopSize(options);
@@ -11481,7 +11625,7 @@ function getSingleMeaningfulChild(container) {
11481
11625
  }
11482
11626
  function unwrapTemplate(html) {
11483
11627
  const lowered = html.toLowerCase();
11484
- if (!lowered.includes("<template") || !lowered.includes("</template>")) {
11628
+ if (!lowered.includes("<template") || !/<\/template[ \t\n\r\f]*>/.test(lowered)) {
11485
11629
  return html;
11486
11630
  }
11487
11631
  const { body } = parseHTMLContent(html);
@@ -11506,12 +11650,52 @@ import {
11506
11650
  lstatSync as lstatSync2,
11507
11651
  mkdirSync as mkdirSync5,
11508
11652
  readdirSync as readdirSync5,
11509
- renameSync,
11510
11653
  rmSync as rmSync3,
11511
11654
  statSync as statSync6,
11512
11655
  utimesSync,
11513
11656
  writeFileSync as writeFileSync3
11514
11657
  } from "fs";
11658
+
11659
+ // ../engine/src/utils/renameWithRetry.ts
11660
+ import { renameSync } from "fs";
11661
+ import { rename } from "fs/promises";
11662
+ var RETRYABLE = /* @__PURE__ */ new Set(["EPERM", "EACCES", "EBUSY"]);
11663
+ var BACKOFF_MS = [10, 20, 40, 80, 160, 320, 640];
11664
+ function isRetryable(error, platform) {
11665
+ if (platform !== "win32") return false;
11666
+ return RETRYABLE.has(error?.code ?? "");
11667
+ }
11668
+ function sleepSync(ms) {
11669
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
11670
+ }
11671
+ function renameWithRetry(from, to, options = {}) {
11672
+ const doRename = options.rename ?? renameSync;
11673
+ const platform = options.platform ?? process.platform;
11674
+ for (let attempt = 0; ; attempt++) {
11675
+ try {
11676
+ doRename(from, to);
11677
+ return;
11678
+ } catch (error) {
11679
+ if (attempt >= BACKOFF_MS.length || !isRetryable(error, platform)) throw error;
11680
+ sleepSync(BACKOFF_MS[attempt]);
11681
+ }
11682
+ }
11683
+ }
11684
+ async function renameWithRetryAsync(from, to, options = {}) {
11685
+ const doRename = options.rename ?? rename;
11686
+ const platform = options.platform ?? process.platform;
11687
+ for (let attempt = 0; ; attempt++) {
11688
+ try {
11689
+ await doRename(from, to);
11690
+ return;
11691
+ } catch (error) {
11692
+ if (attempt >= BACKOFF_MS.length || !isRetryable(error, platform)) throw error;
11693
+ await new Promise((resolve) => setTimeout(resolve, BACKOFF_MS[attempt]));
11694
+ }
11695
+ }
11696
+ }
11697
+
11698
+ // ../engine/src/services/extractionCache.ts
11515
11699
  import { join as join9 } from "path";
11516
11700
  var COMPLETE_SENTINEL = ".hf-complete";
11517
11701
  var GC_MARKER = ".hf-last-gc";
@@ -11575,7 +11759,7 @@ function isTargetExistsRenameError(err) {
11575
11759
  return code === "EEXIST" || code === "ENOTEMPTY" || code === "EPERM";
11576
11760
  }
11577
11761
  function adoptPublishedWinner(entry, partialDir) {
11578
- if (!existsSync8(join9(entry.dir, COMPLETE_SENTINEL))) return null;
11762
+ if (!existsSync8(join9(entry.dir, COMPLETE_SENTINEL)) || !hasFrameFiles(entry.dir)) return null;
11579
11763
  removeDir(partialDir);
11580
11764
  return { dir: entry.dir, published: true };
11581
11765
  }
@@ -11586,7 +11770,7 @@ function publishCacheEntry(entry, partialDir) {
11586
11770
  return { dir: partialDir, published: false };
11587
11771
  }
11588
11772
  try {
11589
- renameSync(partialDir, entry.dir);
11773
+ renameWithRetry(partialDir, entry.dir);
11590
11774
  return { dir: entry.dir, published: true };
11591
11775
  } catch (err) {
11592
11776
  if (!isTargetExistsRenameError(err)) return { dir: partialDir, published: false };
@@ -11599,7 +11783,7 @@ function publishCacheEntry(entry, partialDir) {
11599
11783
  return { dir: partialDir, published: false };
11600
11784
  }
11601
11785
  try {
11602
- renameSync(partialDir, entry.dir);
11786
+ renameWithRetry(partialDir, entry.dir);
11603
11787
  return { dir: entry.dir, published: true };
11604
11788
  } catch {
11605
11789
  return adoptPublishedWinner(entry, partialDir) ?? { dir: partialDir, published: false };
@@ -11784,6 +11968,24 @@ function extractionFrameCountForDuration(durationSeconds, fps, isVFR) {
11784
11968
  const frames = Number(frameCount);
11785
11969
  return Math.max(1, Number.isSafeInteger(frames) ? frames : Number.MAX_SAFE_INTEGER);
11786
11970
  }
11971
+ function exactSourceRate(probed) {
11972
+ const nominal = Math.round(probed * 1.001);
11973
+ return [nominal, nominal * 1e3 / 1001].find((rate) => Math.abs(rate - probed) <= 5e-3 + 1e-9) ?? null;
11974
+ }
11975
+ function tailFramesFromFinalFrame(input) {
11976
+ const sourceRate = exactSourceRate(input.sourceFps);
11977
+ if (!sourceRate || !(input.outputFps > 0)) return null;
11978
+ const lead = input.streamLeadSeconds;
11979
+ if (lead !== 0 && !(Math.abs((input.lastPacketSeconds ?? NaN) - 1 / sourceRate) <= 1e-4)) {
11980
+ return null;
11981
+ }
11982
+ const seek = input.startTime + input.firstFrame / input.outputFps;
11983
+ const slots = (lead + input.finalFrameSeconds + 1 / sourceRate - seek) * input.outputFps;
11984
+ const distanceToSlot = Math.abs(slots - Math.round(slots));
11985
+ if (distanceToSlot >= 5e-5 && distanceToSlot < 5e-4) return null;
11986
+ const count = Math.min(input.tailFrames, Math.ceil(slots - 5e-5));
11987
+ return count > 0 ? count : null;
11988
+ }
11787
11989
  var DOWNLOAD_SUBDIR = "_downloads";
11788
11990
  var EXTRACT_CACHE_MIN_AGE_MS = 60 * 60 * 1e3;
11789
11991
  var GC_STALENESS_MS = 24 * 60 * 60 * 1e3;
@@ -12158,6 +12360,8 @@ function undoTickRoundingOnTheSourceFrameGrid(seek, lead) {
12158
12360
  }
12159
12361
  var EXTRACTION_SLOTS = Math.max(1, Math.floor(cpus().length / 2));
12160
12362
  var inExtractionSlot = createConcurrencyLimit(EXTRACTION_SLOTS);
12363
+ var TAIL_PROBE_SLOTS = Math.max(1, Number(process.env.HF_TAIL_PROBE_SLOTS) || 16);
12364
+ var inTailProbeSlot = createConcurrencyLimit(TAIL_PROBE_SLOTS);
12161
12365
  function splitFrameRanges(ranges, segmentFrames) {
12162
12366
  const segments = [];
12163
12367
  for (const range of ranges) {
@@ -12171,7 +12375,7 @@ function splitFrameRanges(ranges, segmentFrames) {
12171
12375
  return segments;
12172
12376
  }
12173
12377
  async function runSegmentedExtraction(job) {
12174
- const { decodeArgs, filterAndEncodeArgs, videoPath, startTime, fps, segments } = job;
12378
+ const { decodeArgs, filterAndEncodeArgs, videoPath, startTime, fps, segments, gate } = job;
12175
12379
  const segmentCount = segments.length;
12176
12380
  const failed = new AbortController();
12177
12381
  const signal = job.runOptions.signal ? AbortSignal.any([job.runOptions.signal, failed.signal]) : failed.signal;
@@ -12182,7 +12386,7 @@ async function runSegmentedExtraction(job) {
12182
12386
  const index = next++;
12183
12387
  const { firstFrame, frames } = segments[index];
12184
12388
  const seek = startTime + firstFrame / fps;
12185
- const result = await inExtractionSlot(
12389
+ const result = await gate(
12186
12390
  () => runFfmpeg(
12187
12391
  [
12188
12392
  ...decodeArgs,
@@ -12333,6 +12537,7 @@ async function extractVideoFramesRangeUnredacted(videoPath, videoId, startTime,
12333
12537
  videoPath,
12334
12538
  startTime,
12335
12539
  fps,
12540
+ gate: options.tailProbe ? inTailProbeSlot : inExtractionSlot,
12336
12541
  segments: splitFrameRanges(
12337
12542
  options.frameRanges ?? [{ firstFrame: 0, frames: totalFrames }],
12338
12543
  segmentFrames
@@ -12433,9 +12638,6 @@ function resolveSegmentDuration(requested, mediaStart, sourceDuration) {
12433
12638
  const sourceRemaining = sourceDuration - mediaStart;
12434
12639
  return sourceRemaining > 0 ? sourceRemaining : sourceDuration;
12435
12640
  }
12436
- function resolvePlayableVideoDuration(metadata) {
12437
- return Number.isFinite(metadata.videoStreamDurationSeconds) && metadata.videoStreamDurationSeconds > 0 ? (metadata.videoStreamLeadSeconds ?? 0) + metadata.videoStreamDurationSeconds : metadata.durationSeconds;
12438
- }
12439
12641
  function canHoldFinalFramePastEof(video) {
12440
12642
  const timelineDuration = video.end - video.start;
12441
12643
  return !video.loop && Number.isFinite(timelineDuration) && timelineDuration > 0;
@@ -13114,23 +13316,7 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config, c
13114
13316
  );
13115
13317
  const tailFrames = Math.min(expectedFrames, Math.ceil(fps));
13116
13318
  if (expectedFrames <= tailFrames) return null;
13117
- const probeDir = join10(options.outputDir, `${work.video.id}.tail-probe`);
13118
- try {
13119
- const tail = await extractVideoFramesRange(
13120
- work.videoPath,
13121
- work.video.id,
13122
- work.extractionMediaStart,
13123
- work.videoDuration,
13124
- {
13125
- ...scopedExtractionOptions(work),
13126
- frameRanges: [{ firstFrame: expectedFrames - tailFrames, frames: tailFrames }]
13127
- },
13128
- signal,
13129
- config,
13130
- probeDir
13131
- );
13132
- const totalFrames = expectedFrames - tailFrames + tail.totalFrames;
13133
- if (totalFrames <= expectedFrames * 0.6) return null;
13319
+ const deferred = (totalFrames) => {
13134
13320
  const outputDir = join10(options.outputDir, work.video.id);
13135
13321
  mkdirSync6(outputDir, { recursive: true });
13136
13322
  return {
@@ -13148,6 +13334,45 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config, c
13148
13334
  format: work.format
13149
13335
  }
13150
13336
  };
13337
+ };
13338
+ if (work.extractionMediaStart + work.videoDuration + 1 <= resolvePlayableVideoDuration(work.metadata)) {
13339
+ return deferred(expectedFrames);
13340
+ }
13341
+ const firstTailFrame = expectedFrames - tailFrames;
13342
+ const storedFinalFrame = await readStoredFinalFrame(work.videoPath, work.metadata);
13343
+ const storedTailFrames = storedFinalFrame === void 0 ? null : tailFramesFromFinalFrame({
13344
+ startTime: work.extractionMediaStart,
13345
+ firstFrame: firstTailFrame,
13346
+ tailFrames,
13347
+ outputFps: fps,
13348
+ sourceFps: work.metadata.fps,
13349
+ finalFrameSeconds: storedFinalFrame.seconds,
13350
+ lastPacketSeconds: storedFinalFrame.lastPacketSeconds,
13351
+ streamLeadSeconds: work.metadata.videoStreamLeadSeconds ?? 0
13352
+ });
13353
+ if (storedTailFrames !== null) {
13354
+ const totalFrames = firstTailFrame + storedTailFrames;
13355
+ return totalFrames <= expectedFrames * 0.6 ? null : deferred(totalFrames);
13356
+ }
13357
+ const probeDir = join10(options.outputDir, `${work.video.id}.tail-probe`);
13358
+ try {
13359
+ const tail = await extractVideoFramesRange(
13360
+ work.videoPath,
13361
+ work.video.id,
13362
+ work.extractionMediaStart,
13363
+ work.videoDuration,
13364
+ {
13365
+ ...scopedExtractionOptions(work),
13366
+ frameRanges: [{ firstFrame: firstTailFrame, frames: tailFrames }],
13367
+ tailProbe: isHttpUrl(work.videoPath)
13368
+ },
13369
+ signal,
13370
+ config,
13371
+ probeDir
13372
+ );
13373
+ const totalFrames = firstTailFrame + tail.totalFrames;
13374
+ if (totalFrames <= expectedFrames * 0.6) return null;
13375
+ return deferred(totalFrames);
13151
13376
  } catch {
13152
13377
  return null;
13153
13378
  } finally {
@@ -14026,16 +14251,7 @@ async function queryElementStacking(page, nativeHdrIds) {
14026
14251
  }
14027
14252
 
14028
14253
  // ../engine/src/services/audioMixer.ts
14029
- import {
14030
- closeSync as closeSync4,
14031
- existsSync as existsSync11,
14032
- mkdirSync as mkdirSync7,
14033
- mkdtempSync as mkdtempSync7,
14034
- openSync as openSync4,
14035
- renameSync as renameSync3,
14036
- rmSync as rmSync8,
14037
- writeFileSync as writeFileSync7
14038
- } from "fs";
14254
+ import { closeSync as closeSync4, existsSync as existsSync11, mkdirSync as mkdirSync7, mkdtempSync as mkdtempSync7, openSync as openSync4, rmSync as rmSync8, writeFileSync as writeFileSync7 } from "fs";
14039
14255
  import { join as join14, dirname as dirname7, isAbsolute, relative } from "path";
14040
14256
 
14041
14257
  // ../engine/src/utils/notMediaPayload.ts
@@ -14154,6 +14370,7 @@ function clampFadesToDuration(fades, duration) {
14154
14370
  import { cpus as cpus2 } from "os";
14155
14371
 
14156
14372
  // ../engine/src/services/aacEncode.ts
14373
+ import { execFile as execFile3 } from "child_process";
14157
14374
  import { mkdtempSync as mkdtempSync4, readFileSync as readFileSync5, rmSync as rmSync5, writeFileSync as writeFileSync4 } from "fs";
14158
14375
  import { dirname as dirname5, join as join11 } from "path";
14159
14376
  var SAMPLE_RATE = 48e3;
@@ -14189,12 +14406,35 @@ function planSegments(totalDuration, count) {
14189
14406
  return { trim, keepFrom: cut - firstFrame, keepTo: next - firstFrame };
14190
14407
  });
14191
14408
  }
14409
+ var settsDurationSupport = /* @__PURE__ */ new Map();
14410
+ function supportsSettsDuration(binary = getFfmpegBinary()) {
14411
+ let supported = settsDurationSupport.get(binary);
14412
+ if (!supported) {
14413
+ supported = new Promise((resolve) => {
14414
+ execFile3(binary, ["-hide_banner", "-h", "bsf=setts"], (error, stdout) => {
14415
+ resolve(error !== null || stdout.includes("duration"));
14416
+ });
14417
+ });
14418
+ settsDurationSupport.set(binary, supported);
14419
+ }
14420
+ return supported;
14421
+ }
14422
+ function encodeInOnePass(input, outputPath, { signal, timeout, filter }) {
14423
+ const filters = [filter, `aresample=${SAMPLE_RATE}`].filter(Boolean).join(",");
14424
+ return runFfmpeg(["-i", input, "-af", filters, ...AAC_ARGS, "-y", outputPath], {
14425
+ signal,
14426
+ timeout
14427
+ });
14428
+ }
14192
14429
  async function encodeAac(input, outputPath, totalDuration, {
14193
14430
  signal,
14194
14431
  timeout,
14195
14432
  filter,
14196
14433
  segments: count = aacSegmentCount(totalDuration)
14197
14434
  }) {
14435
+ if (!await supportsSettsDuration()) {
14436
+ return encodeInOnePass(input, outputPath, { signal, timeout, filter });
14437
+ }
14198
14438
  const dir = mkdtempSync4(join11(dirname5(outputPath), ".aac-segments-"));
14199
14439
  try {
14200
14440
  const segments = planSegments(totalDuration, count).map((segment, k) => ({
@@ -14360,7 +14600,7 @@ function audioFailureDiagnostics(values) {
14360
14600
  }
14361
14601
 
14362
14602
  // ../engine/src/services/audioVolumeEnvelope.ts
14363
- import { mkdtempSync as mkdtempSync5, readFileSync as readFileSync6, renameSync as renameSync2, rmSync as rmSync6, writeFileSync as writeFileSync5 } from "fs";
14603
+ import { mkdtempSync as mkdtempSync5, readFileSync as readFileSync6, rmSync as rmSync6, writeFileSync as writeFileSync5 } from "fs";
14364
14604
  import { dirname as dirname6, join as join12 } from "path";
14365
14605
 
14366
14606
  // ../core/dist/runtime/mediaVolumeEnvelope.js
@@ -14490,7 +14730,7 @@ function applyVolumeEnvelopeToWav(wavPath, keyframes, trackStart, baseVolume) {
14490
14730
  stagingDir = mkdtempSync5(join12(dirname6(wavPath), ".hf-volume-"));
14491
14731
  const tempPath = join12(stagingDir, "audio.wav");
14492
14732
  writeFileSync5(tempPath, buffer, { flag: "wx" });
14493
- renameSync2(tempPath, wavPath);
14733
+ renameWithRetry(tempPath, wavPath);
14494
14734
  return true;
14495
14735
  } catch {
14496
14736
  return false;
@@ -15269,6 +15509,7 @@ function legacyFilterScriptOptionIsUnsupported(stderr) {
15269
15509
  return /filter_complex_script/i.test(stderr) && /(?:unrecognized option|option (?:was )?not found)/i.test(stderr);
15270
15510
  }
15271
15511
  var inPrepareSlot = createConcurrencyLimit(Math.max(2, Math.floor(cpus2().length / 2)));
15512
+ var inRemotePrepareSlot = createConcurrencyLimit(16);
15272
15513
  var MAX_VOLUME_SEGMENTS = 32;
15273
15514
  var VOLUME_SIMPLIFY_EPSILON = 5e-3;
15274
15515
  var STEREO_CHANNEL_FILTER = "pan=stereo|FL=FL+FC|FR=FR+FC";
@@ -15485,8 +15726,11 @@ function parseAudioElements(html) {
15485
15726
  const startCache = /* @__PURE__ */ new Map();
15486
15727
  const visiting = /* @__PURE__ */ new Set();
15487
15728
  const resolveStart = (el) => el.getAttribute("data-start") ? resolveReferencedStart(document2, el, startCache, visiting) : 0;
15488
- const parseEnd = (raw) => {
15489
- return parseStrictFiniteTimingNumber(raw) ?? 0;
15729
+ const resolveEnd = (el) => {
15730
+ const end = parseStrictFiniteTimingNumber(el.getAttribute("data-end"));
15731
+ if (end != null) return end;
15732
+ const duration = parseStrictFiniteTimingNumber(el.getAttribute("data-duration"));
15733
+ return duration != null && duration > 0 ? resolveStart(el) + duration : 0;
15490
15734
  };
15491
15735
  const isHidden = isSelfOrAncestorHidden;
15492
15736
  const groupsById = new Map(
@@ -15505,9 +15749,10 @@ function parseAudioElements(html) {
15505
15749
  id,
15506
15750
  src,
15507
15751
  start: resolveStart(el),
15508
- end: parseEnd(el.getAttribute("data-end")),
15752
+ end: resolveEnd(el),
15509
15753
  mediaStart: readMediaStart(el),
15510
15754
  playbackRate: readElementRateSpec(el),
15755
+ loop: el.getAttribute("loop") !== null,
15511
15756
  layer: layerAttr ? parseInt(layerAttr) : 0,
15512
15757
  volume: volumeAttr ? parseFloat(volumeAttr) : 1,
15513
15758
  ...fades.fadeIn > 0 ? { fadeIn: fades.fadeIn } : {},
@@ -15543,7 +15788,7 @@ function parseAudioElements(html) {
15543
15788
  }
15544
15789
  var FAIL_ON_READ_ERROR_INSTEAD_OF_ENDING_THERE = ["-xerror"];
15545
15790
  var SIDECAR_WARM_UP_SECONDS = 1;
15546
- async function extractAudioSegment(srcPath, outputPath, stage, mediaStart, duration, playbackRate = 1, signal, config, audioSidecarUrl) {
15791
+ async function extractAudioSegment(srcPath, outputPath, stage, mediaStart, duration, playbackRate = 1, signal, config, audioSidecarUrl, options) {
15547
15792
  const ffmpegProcessTimeout = config?.ffmpegProcessTimeout ?? DEFAULT_CONFIG.ffmpegProcessTimeout;
15548
15793
  const outputDir = dirname7(outputPath);
15549
15794
  if (!existsSync11(outputDir)) mkdirSync7(outputDir, { recursive: true });
@@ -15553,7 +15798,62 @@ async function extractAudioSegment(srcPath, outputPath, stage, mediaStart, durat
15553
15798
  const metadata = readsUrl ? await extractAudioMetadata(srcPath, { signal }).catch((error) => {
15554
15799
  if (signal?.aborted) throw error;
15555
15800
  return extractAudioMetadata(srcPath, { signal });
15556
- }) : await extractAudioMetadata(srcPath).catch(() => null);
15801
+ }) : await extractAudioMetadata(srcPath).catch((error) => {
15802
+ if (options?.loop) throw error;
15803
+ return null;
15804
+ });
15805
+ const loopDuration = (metadata?.durationSeconds ?? 0) - mediaStart;
15806
+ if (options?.loop && loopDuration > 0 && sourceDuration > loopDuration) {
15807
+ const cycleDir = mkdtempSync7(join14(outputDir, ".audio-loop-"));
15808
+ const cyclePath = join14(cycleDir, "cycle.wav");
15809
+ try {
15810
+ const cycle = await extractAudioSegment(
15811
+ srcPath,
15812
+ cyclePath,
15813
+ stage,
15814
+ mediaStart,
15815
+ loopDuration,
15816
+ 1,
15817
+ signal,
15818
+ config,
15819
+ audioSidecarUrl,
15820
+ { padToDuration: true }
15821
+ );
15822
+ if (!cycle.success) return { ...cycle, outputPath };
15823
+ const outputArgs2 = preparedAudioOutputArgs(metadata, normalizedPlaybackRate, duration, null);
15824
+ const result2 = await runFfmpeg(
15825
+ [
15826
+ "-stream_loop",
15827
+ "-1",
15828
+ "-t",
15829
+ String(sourceDuration),
15830
+ "-i",
15831
+ cyclePath,
15832
+ "-vn",
15833
+ "-acodec",
15834
+ "pcm_s16le",
15835
+ "-ar",
15836
+ "48000",
15837
+ ...outputArgs2,
15838
+ "-t",
15839
+ String(duration),
15840
+ "-y",
15841
+ outputPath
15842
+ ],
15843
+ { signal, timeout: ffmpegProcessTimeout }
15844
+ );
15845
+ const failure2 = result2.success ? void 0 : ffmpegFailure(stage, result2, ffmpegProcessTimeout);
15846
+ return {
15847
+ success: result2.success,
15848
+ outputPath,
15849
+ durationMs: cycle.durationMs + result2.durationMs,
15850
+ error: failure2?.detail,
15851
+ failure: failure2
15852
+ };
15853
+ } finally {
15854
+ rmSync8(cycleDir, { recursive: true, force: true });
15855
+ }
15856
+ }
15557
15857
  const inputSeek = mediaStart >= (metadata?.latestStreamLeadSeconds ?? 0);
15558
15858
  const start = formatFilterNumber(mediaStart);
15559
15859
  const timestampTrim = inputSeek ? null : `atrim=start=${start}:end=${formatFilterNumber(mediaStart + sourceDuration)},asetpts=PTS-${start}/TB,aresample=async=1:first_pts=0`;
@@ -15563,7 +15863,10 @@ async function extractAudioSegment(srcPath, outputPath, stage, mediaStart, durat
15563
15863
  metadata,
15564
15864
  normalizedPlaybackRate,
15565
15865
  duration,
15566
- warmUp > 0 ? `atrim=start=${warmUp},asetpts=PTS-STARTPTS` : timestampTrim
15866
+ [
15867
+ warmUp > 0 ? `atrim=start=${warmUp},asetpts=PTS-STARTPTS` : timestampTrim,
15868
+ ...options?.padToDuration ? ["apad"] : []
15869
+ ].filter(Boolean).join(",") || null
15567
15870
  );
15568
15871
  const readFrom = fromSidecar ? audioSidecarUrl : srcPath;
15569
15872
  const args = [
@@ -15574,7 +15877,7 @@ async function extractAudioSegment(srcPath, outputPath, stage, mediaStart, durat
15574
15877
  readFrom
15575
15878
  ];
15576
15879
  args.push("-vn", "-acodec", "pcm_s16le", "-ar", "48000", ...outputArgs);
15577
- if (normalizedPlaybackRate !== 1) args.push("-t", String(duration));
15880
+ if (normalizedPlaybackRate !== 1 || options?.padToDuration) args.push("-t", String(duration));
15578
15881
  args.push("-y", outputPath);
15579
15882
  const result = await runFfmpeg(args, { signal, timeout: ffmpegProcessTimeout });
15580
15883
  if (signal?.aborted) {
@@ -15606,6 +15909,17 @@ async function extractAudioSegment(srcPath, outputPath, stage, mediaStart, durat
15606
15909
  failure
15607
15910
  };
15608
15911
  }
15912
+ function isRemoteElement(element, baseDir, compiledDir, config) {
15913
+ if (isHttpUrl(element.src)) return true;
15914
+ if (!config?.urlByAbsentLocalPath?.size) return false;
15915
+ try {
15916
+ return config.urlByAbsentLocalPath.has(
15917
+ resolveProjectRelativeSrc(element.src, baseDir, compiledDir)
15918
+ );
15919
+ } catch {
15920
+ return false;
15921
+ }
15922
+ }
15609
15923
  async function generateSilence(outputPath, duration, signal, config) {
15610
15924
  const ffmpegProcessTimeout = config?.ffmpegProcessTimeout ?? DEFAULT_CONFIG.ffmpegProcessTimeout;
15611
15925
  const outputDir = dirname7(outputPath);
@@ -15914,7 +16228,7 @@ async function mixGroupMembers(memberTracks, outputPath, totalDuration, signal,
15914
16228
  try {
15915
16229
  const summed = await sumInSlices(memberTracks, scratchDir, totalDuration, signal, config);
15916
16230
  if (!summed.success) return summed;
15917
- renameSync3(summed.track.srcPath, outputPath);
16231
+ renameWithRetry(summed.track.srcPath, outputPath);
15918
16232
  return { success: true, degradedAutomation: summed.degradedAutomation };
15919
16233
  } finally {
15920
16234
  rmSync8(scratchDir, { recursive: true, force: true });
@@ -15956,12 +16270,15 @@ async function mixAudioTracks(tracks, outputPath, totalDuration, signal, config)
15956
16270
  }
15957
16271
  async function mixThroughFloatSum(tracks, masterChain, outputPath, workDir, totalDuration, signal, config) {
15958
16272
  const sumPath = join14(workDir, "master-sum.wav");
16273
+ const mixStart = Date.now();
15959
16274
  const sum = await mixAudioTracks(tracks, sumPath, totalDuration, signal, config);
15960
16275
  if (!sum.success) return { ...sum, outputPath };
16276
+ const masterStart = Date.now();
15961
16277
  const encoderInput = masterChain ? (await applyAudioFxChain(sumPath, masterChain, join14(workDir, "master-fx.wav"), {
15962
16278
  trackId: "master",
15963
16279
  signal
15964
16280
  })).path : sumPath;
16281
+ const encodeStart = Date.now();
15965
16282
  const encoded = await encodeAac(encoderInput, outputPath, totalDuration, {
15966
16283
  signal,
15967
16284
  timeout: config?.ffmpegProcessTimeout ?? DEFAULT_CONFIG.ffmpegProcessTimeout
@@ -15981,8 +16298,17 @@ async function mixThroughFloatSum(tracks, masterChain, outputPath, workDir, tota
15981
16298
  failures: [failure]
15982
16299
  };
15983
16300
  }
15984
- if (config?.keepEncoderInputAt) renameSync3(encoderInput, config.keepEncoderInputAt);
15985
- return { ...sum, outputPath, durationMs: sum.durationMs + encoded.durationMs };
16301
+ if (config?.keepEncoderInputAt) renameWithRetry(encoderInput, config.keepEncoderInputAt);
16302
+ return {
16303
+ ...sum,
16304
+ outputPath,
16305
+ durationMs: sum.durationMs + encoded.durationMs,
16306
+ phaseMs: {
16307
+ mix: masterStart - mixStart,
16308
+ master: encodeStart - masterStart,
16309
+ encode: Date.now() - encodeStart
16310
+ }
16311
+ };
15986
16312
  }
15987
16313
  async function processCompositionAudio(elements, baseDir, workDir, outputPath, totalDuration, signal, config, compiledDir) {
15988
16314
  const startMs = Date.now();
@@ -16000,7 +16326,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
16000
16326
  }
16001
16327
  await Promise.all(
16002
16328
  elements.map(
16003
- (element, index) => inPrepareSlot(async () => {
16329
+ (element, index) => (isRemoteElement(element, baseDir, compiledDir, config) ? inRemotePrepareSlot : inPrepareSlot)(async () => {
16004
16330
  if (effectiveSignal.aborted) {
16005
16331
  failures.push({
16006
16332
  stage: "cancelled",
@@ -16069,6 +16395,9 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
16069
16395
  return;
16070
16396
  }
16071
16397
  if (element.end - element.start <= 0) {
16398
+ console.warn(
16399
+ `[audioMixer] ${element.id} has no data-duration or data-end; its length is unknown, so it plays to the end of its source`
16400
+ );
16072
16401
  let metadata;
16073
16402
  try {
16074
16403
  metadata = await extractAudioMetadata(
@@ -16099,7 +16428,8 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
16099
16428
  element.playbackRate,
16100
16429
  effectiveSignal,
16101
16430
  config,
16102
- audioSidecarUrl
16431
+ audioSidecarUrl,
16432
+ { loop: element.loop }
16103
16433
  );
16104
16434
  if (!extractResult.success) {
16105
16435
  failures.push(
@@ -16125,7 +16455,9 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
16125
16455
  element.end - element.start,
16126
16456
  element.playbackRate,
16127
16457
  effectiveSignal,
16128
- config
16458
+ config,
16459
+ void 0,
16460
+ { loop: element.loop }
16129
16461
  );
16130
16462
  if (!prepResult.success) {
16131
16463
  failures.push(
@@ -16261,6 +16593,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
16261
16593
  failures
16262
16594
  };
16263
16595
  };
16596
+ const prepareMs = Date.now() - startMs;
16264
16597
  if (failures.length > 0) return bail();
16265
16598
  let masterChain;
16266
16599
  const masterFxJson = config?.masterFxChain;
@@ -16371,6 +16704,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
16371
16704
  }
16372
16705
  }
16373
16706
  if (failures.length > 0) return bail();
16707
+ const groupsMs = Date.now() - startMs - prepareMs;
16374
16708
  let mixResult;
16375
16709
  try {
16376
16710
  mixResult = tracks.length > 0 ? await mixThroughFloatSum(
@@ -16389,6 +16723,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
16389
16723
  return {
16390
16724
  ...mixResult,
16391
16725
  durationMs: Date.now() - startMs,
16726
+ phaseMs: { prepare: prepareMs, groups: groupsMs, ...mixResult.phaseMs },
16392
16727
  // Both, when both degraded. `mixResult.error ?? degradedNote` reported only
16393
16728
  // the outer mix and dropped the one that names which GROUPS lost their
16394
16729
  // members' automation — two different losses, and the operator needs to
@@ -16400,18 +16735,18 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
16400
16735
  // ../engine/src/services/parallelCoordinator.ts
16401
16736
  import { cpus as cpus3, freemem } from "os";
16402
16737
  import { existsSync as existsSync12, mkdirSync as mkdirSync8, readdirSync as readdirSync6 } from "fs";
16403
- import { copyFile, readFile as readFile2, rename } from "fs/promises";
16738
+ import { copyFile, readFile as readFile2 } from "fs/promises";
16404
16739
  import { join as join16 } from "path";
16405
16740
  import { getHeapStatistics } from "v8";
16406
16741
 
16407
16742
  // ../engine/src/utils/psnr.ts
16408
- import { execFile as execFile3 } from "child_process";
16743
+ import { execFile as execFile4 } from "child_process";
16409
16744
  import { mkdtemp, rm, writeFile } from "fs/promises";
16410
16745
  import { tmpdir as tmpdir4 } from "os";
16411
16746
  import { join as join15 } from "path";
16412
16747
  import { promisify as promisify3 } from "util";
16413
16748
  async function psnrDb(a, b) {
16414
- const execFileP = promisify3(execFile3);
16749
+ const execFileP = promisify3(execFile4);
16415
16750
  const dir = await mkdtemp(join15(tmpdir4(), "hf-de-verify-"));
16416
16751
  try {
16417
16752
  const pa = join15(dir, "a.jpg");
@@ -16945,7 +17280,8 @@ async function executeWorkerTask(task, serverUrl, captureOptions, createBeforeCa
16945
17280
  endFrame: task.endFrame,
16946
17281
  frameStride: task.frameStride,
16947
17282
  durationMs: Date.now() - startTime,
16948
- perf
17283
+ perf,
17284
+ pageErrorLines: pageErrorLinesOf(activeSession)
16949
17285
  };
16950
17286
  } catch (error) {
16951
17287
  const diagnostics = session ? selectWorkerDiagnostics(session.browserConsoleBuffer) : [];
@@ -16958,7 +17294,8 @@ async function executeWorkerTask(task, serverUrl, captureOptions, createBeforeCa
16958
17294
  };
16959
17295
  const failure = classifyCaptureFailure(error, {
16960
17296
  signal,
16961
- workerDiagnostics: [workerDiagnostic]
17297
+ workerDiagnostics: [workerDiagnostic],
17298
+ pageErrorLines: session ? pageErrorLinesOf(session) : void 0
16962
17299
  });
16963
17300
  onFailure?.(failure);
16964
17301
  return {
@@ -16971,6 +17308,7 @@ async function executeWorkerTask(task, serverUrl, captureOptions, createBeforeCa
16971
17308
  perf,
16972
17309
  error: failure.message,
16973
17310
  diagnostics: diagnostics.length > 0 ? diagnostics : void 0,
17311
+ pageErrorLines: session ? pageErrorLinesOf(session) : void 0,
16974
17312
  failure
16975
17313
  };
16976
17314
  } finally {
@@ -16987,6 +17325,9 @@ function isPoolFatalWorkerFailure(failure, streaming) {
16987
17325
  if (streaming) return failure.kind !== "cancelled";
16988
17326
  return isFatalCaptureFailure(failure);
16989
17327
  }
17328
+ function pageErrorLinesOf(session) {
17329
+ return session.browserConsoleBuffer.filter((line) => line.includes("PAGEERROR"));
17330
+ }
16990
17331
  function createPoolFailureHandler(args) {
16991
17332
  let firstFatalFailure;
16992
17333
  return {
@@ -17078,7 +17419,8 @@ async function executeParallelCapture(serverUrl, workDir, tasks, captureOptions,
17078
17419
  kind: representative?.kind ?? "io",
17079
17420
  message: `[Parallel] Capture failed: ${errorMessages}`,
17080
17421
  cause: representative,
17081
- workerDiagnostics
17422
+ workerDiagnostics,
17423
+ pageErrorLines: [...new Set(results.flatMap((result) => result.pageErrorLines ?? []))]
17082
17424
  });
17083
17425
  }
17084
17426
  return results;
@@ -17096,7 +17438,7 @@ async function mergeWorkerFrames(workDir, tasks, outputDir) {
17096
17438
  const sourcePath = join16(task.outputDir, file);
17097
17439
  const targetPath = join16(outputDir, file);
17098
17440
  try {
17099
- await rename(sourcePath, targetPath);
17441
+ await renameWithRetryAsync(sourcePath, targetPath);
17100
17442
  } catch {
17101
17443
  await copyFile(sourcePath, targetPath);
17102
17444
  }
@@ -17644,6 +17986,11 @@ export {
17644
17986
  formatFfmpegError,
17645
17987
  describeFfmpegFailure,
17646
17988
  runFfmpeg,
17989
+ declareContentAddressedUrl,
17990
+ declareProbeFactsUrl,
17991
+ PROBE_FACTS_VERSION,
17992
+ buildProbeFactsText,
17993
+ resolvePlayableVideoDuration,
17647
17994
  probeMediaProfile,
17648
17995
  extractMediaMetadata,
17649
17996
  extractFinalVideoFrameTimestamp,
@@ -17682,6 +18029,8 @@ export {
17682
18029
  fetchPublicHttpsText,
17683
18030
  downloadToTemp,
17684
18031
  isHttpUrl,
18032
+ renameWithRetry,
18033
+ renameWithRetryAsync,
17685
18034
  directorySizeBytes,
17686
18035
  gcExtractionCache,
17687
18036
  VIDEO_FRAME_FORMATS,
@@ -17696,8 +18045,8 @@ export {
17696
18045
  parseVideoElements,
17697
18046
  parseImageElements,
17698
18047
  extractVideoFramesRange,
17699
- resolvePlayableVideoDuration,
17700
18048
  isVideoPastTimelineEnd,
18049
+ rebaseVideoToWindow,
17701
18050
  resolveTimelineExtractionWindow,
17702
18051
  resolveFinalFrameExtractionWindow,
17703
18052
  resolveVideoExtractionWindow,