hyperframes 0.8.107 → 0.8.108
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.
- package/dist/{add-DXZ3HNQI.js → add-OH75E7FX.js} +15 -15
- package/dist/{animatedGifPrep-2IQB4DGE.js → animatedGifPrep-ZDAWSJYL.js} +6 -6
- package/dist/{asset-KZIG3MZN.js → asset-BVDO4DEW.js} +2 -2
- package/dist/{assetCataloger-4GE6PIUA.js → assetCataloger-FXEHOUA3.js} +2 -2
- package/dist/{auth-5IYF3H67.js → auth-K5GUKO5S.js} +2 -2
- package/dist/{autoUpdate-5C3FXM6Y.js → autoUpdate-77ROWK5G.js} +2 -2
- package/dist/{backgroundChecks-75WGW4NB.js → backgroundChecks-3Q3D5WBJ.js} +3 -3
- package/dist/backgroundChecksWorker.js +3 -3
- package/dist/{batchRender-FKKS3YBX.js → batchRender-ZTHFMHZY.js} +3 -3
- package/dist/{beats-ISR36NSK.js → beats-HQZPR6KE.js} +18 -12
- package/dist/{benchmark-U6TQ6DS2.js → benchmark-BQOWARGU.js} +12 -12
- package/dist/{browser-VDS6QAVA.js → browser-45CK7HXI.js} +9 -9
- package/dist/{bundleWithLocalizedFonts-PMWWW5YG.js → bundleWithLocalizedFonts-3M2LKRHK.js} +2 -2
- package/dist/{capture-5KE34KCD.js → capture-6IVZXM7G.js} +2 -2
- package/dist/{capture-BKA3UCZS.js → capture-VGEUOP7N.js} +7 -7
- package/dist/{catalog-ZXOSU27O.js → catalog-VHD7B6FD.js} +15 -15
- package/dist/{check-MZMZCXPN.js → check-UPNZZJXV.js} +30 -29
- package/dist/{checkBrowser-UIZJXYCQ.js → checkBrowser-KWTHKOOP.js} +29 -28
- package/dist/{chunk-L7XDI3DT.js → chunk-5N4KKGSZ.js} +1 -1
- package/dist/{normalize-audio-J2PG6YXH.js → chunk-5ON5GH3X.js} +101 -209
- package/dist/{chunk-HGL4WJDI.js → chunk-5R5UHSXN.js} +9 -9
- package/dist/{chunk-AO4PBESP.js → chunk-AFGDOKRI.js} +7 -7
- package/dist/{chunk-NHTRUAMD.js → chunk-AWUZ3AUD.js} +1 -1
- package/dist/{chunk-VMDEGITC.js → chunk-B25H4M4V.js} +1 -1
- package/dist/{chunk-3WG63KFW.js → chunk-C6XQER6H.js} +25 -11
- package/dist/{chunk-FLUBCMNT.js → chunk-CFC3EEDQ.js} +1 -1
- package/dist/{chunk-6QWHIARJ.js → chunk-D7SCIX4D.js} +1 -1
- package/dist/{chunk-T4Z4UNSX.js → chunk-FZGUZIK5.js} +3 -3
- package/dist/{chunk-73VPF3SS.js → chunk-GYYFNAVA.js} +1 -1
- package/dist/{chunk-BRTGJ73L.js → chunk-HQGJLZB6.js} +2 -2
- package/dist/{chunk-3CYAZWF2.js → chunk-J7XPPADY.js} +3 -3
- package/dist/{chunk-4W4UDPCH.js → chunk-KVOWTRD5.js} +2 -2
- package/dist/{chunk-SKPL32FI.js → chunk-KZ5OSG4G.js} +1 -1
- package/dist/{chunk-TI5Z4SWP.js → chunk-KZJ6V7RT.js} +3 -3
- package/dist/{chunk-P7XRDAWU.js → chunk-LAQEZHOH.js} +1 -1
- package/dist/{chunk-HJCTKNXF.js → chunk-LPXM5L6S.js} +1 -1
- package/dist/{chunk-J6CSEDK7.js → chunk-LTYI4E42.js} +4 -4
- package/dist/{chunk-KTPQ67TX.js → chunk-LZPAZZZP.js} +1 -1
- package/dist/{chunk-GLTHJJIF.js → chunk-MGTECHI3.js} +2 -2
- package/dist/{chunk-ADP6TMYP.js → chunk-NGVH2QYT.js} +8 -8
- package/dist/{chunk-YY5J75H5.js → chunk-NJLFRKHX.js} +3 -3
- package/dist/{chunk-OGTR33KN.js → chunk-NROJESOK.js} +2 -2
- package/dist/{chunk-QM2NUN2B.js → chunk-ONY5CJXS.js} +2 -2
- package/dist/{chunk-PU2IOWX4.js → chunk-OVRFBUXU.js} +2 -2
- package/dist/{chunk-D5EJCP26.js → chunk-QB6OM2BP.js} +79 -64
- package/dist/{chunk-WBVPQC7J.js → chunk-QBHT234I.js} +1 -1
- package/dist/{chunk-3LBFLW7E.js → chunk-QRXICW5Q.js} +1 -1
- package/dist/{chunk-YVEZT6WT.js → chunk-RPMXMOFU.js} +1 -1
- package/dist/{chunk-QH6UFY2O.js → chunk-RSL3XFMO.js} +4 -4
- package/dist/{chunk-C3KEF3UA.js → chunk-SIVCJJHE.js} +1 -1
- package/dist/{chunk-4DJXCVQJ.js → chunk-SQ42NHXP.js} +574 -61
- package/dist/{chunk-SGBOZ2HF.js → chunk-THVNQFYG.js} +1 -1
- package/dist/{chunk-T3BOWXPX.js → chunk-TIZQC44K.js} +1 -1
- package/dist/{chunk-I73Z6OOE.js → chunk-US7SWKGC.js} +1 -1
- package/dist/{chunk-TPPIERG3.js → chunk-VBXJSCHR.js} +3 -3
- package/dist/{chunk-NX6G66F4.js → chunk-VLHN34SB.js} +2 -2
- package/dist/{chunk-R4IB642V.js → chunk-X763EUBO.js} +2 -2
- package/dist/{chunk-Z4UAXNWV.js → chunk-XIGK4LNU.js} +2 -2
- package/dist/{chunk-JNY3VJWB.js → chunk-XYVFPDNU.js} +1 -1
- package/dist/chunk-YLVI7VL5.js +3541 -0
- package/dist/{chunk-7BI5BYMQ.js → chunk-ZFL6FVQZ.js} +5 -5
- package/dist/{clean-46MZVA37.js → clean-LCRWNIWO.js} +15 -14
- package/dist/cli.js +50 -50
- package/dist/{cloud-GAZQGPCW.js → cloud-ITRFE5UN.js} +4 -4
- package/dist/{cloudrun-ZWL7SLDD.js → cloudrun-LVZ4OPPC.js} +3 -3
- package/dist/{compare-66AAJESM.js → compare-NPVMUILH.js} +24 -23
- package/dist/{compiler-3N7XQRH6.js → compiler-YYOV2BJ7.js} +3 -3
- package/dist/{component-3OCOHK2B.js → component-HJFMHPNW.js} +3 -3
- package/dist/{compositions-H2BP4N6F.js → compositions-I34RN5WD.js} +11 -11
- package/dist/{delete-WNJLVPGO.js → delete-WN3J74BD.js} +2 -2
- package/dist/{dist-AY2RBEXL.js → dist-WCMFH74H.js} +1 -1
- package/dist/{dist-HSEMXPG3.js → dist-YUIPB7OX.js} +8 -2
- package/dist/{doctor-IFOZS45N.js → doctor-MYC2S3J3.js} +10 -10
- package/dist/{events-6TH3FU3F.js → events-7JVV4746.js} +9 -9
- package/dist/{events-5EKFJCCZ.js → events-AEUV2JPA.js} +8 -8
- package/dist/{feedback-QRQNMORT.js → feedback-X7DDSZPU.js} +10 -10
- package/dist/{figma-WONEPLUQ.js → figma-ISI4PPTF.js} +3 -3
- package/dist/fontLocalizeCli.js +8 -8
- package/dist/{get-C7FCYNI2.js → get-IYALAE4I.js} +2 -2
- package/dist/{gpuPolicy-BXXQF3VC.js → gpuPolicy-KSWTVU5C.js} +6 -6
- package/dist/{grade-compare-SCCSZ5P3.js → grade-compare-YWPIWQLK.js} +24 -23
- package/dist/{help-FJOUNXVD.js → help-S2KJRMAJ.js} +1 -1
- package/dist/{history-OZY36NEC.js → history-CQDDCY4J.js} +15 -14
- package/dist/hyperframe-runtime.js +54 -54
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +54 -54
- package/dist/hyperframes-player.global.js +3 -3
- package/dist/{info-RG4SZQ2C.js → info-4KFNUWYN.js} +11 -11
- package/dist/{init-YGZCDKSS.js → init-I7GMRHFW.js} +22 -22
- package/dist/{inspect-X547EZ4I.js → inspect-DUCLCHSD.js} +25 -24
- package/dist/{installer-6J24NTIV.js → installer-NBEN3ZIP.js} +4 -4
- package/dist/{keyframes-EIWEION2.js → keyframes-F3VDEN66.js} +12 -12
- package/dist/{lambda-DSZDMP7P.js → lambda-BFHJMMCG.js} +4 -4
- package/dist/{layout-B7KCBLBH.js → layout-RNCXJI6C.js} +25 -24
- package/dist/{lint-RBDG4ERJ.js → lint-3NKKYCMH.js} +12 -12
- package/dist/{lintProject-CMPAR7BS.js → lintProject-F2OTN2IR.js} +1 -1
- package/dist/{list-BPHPHLDJ.js → list-Q7SOE3NF.js} +2 -2
- package/dist/{login-HV7KBW2J.js → login-TGRGWS5E.js} +4 -4
- package/dist/{media-treatment-RS6BZSQC.js → media-treatment-5TUXWHWE.js} +12 -12
- package/dist/{models-K4U7GRXV.js → models-YJUTM6TH.js} +7 -7
- package/dist/{motionShot-5AI2DALY.js → motionShot-5QUMZ7J3.js} +10 -10
- package/dist/normalize-audio-63BI5BPL.js +276 -0
- package/dist/{pipeline-HIUESSET.js → pipeline-4NN5T7Q3.js} +6 -6
- package/dist/{play-TTLQXBAH.js → play-SRDESSZI.js} +20 -19
- package/dist/{preflight-63ODQ625.js → preflight-SVN4PSFO.js} +7 -7
- package/dist/{present-XKGZ26FQ.js → present-TDYR5LRW.js} +16 -15
- package/dist/{preview-O2YEKMYJ.js → preview-Z5MFRZUM.js} +17 -17
- package/dist/{producer-ZTQIJO7E.js → producer-RS7CB3XJ.js} +1 -1
- package/dist/{projectConfig-VVFH7XW5.js → projectConfig-JHEWPAA5.js} +6 -6
- package/dist/{publication-NALPAHDC.js → publication-7XA2H7UB.js} +2 -2
- package/dist/{publish-G7OL45EL.js → publish-2R22XX77.js} +8 -8
- package/dist/{remove-background-LOLKFKLT.js → remove-background-KT2SWYCC.js} +7 -7
- package/dist/{render-I65IU7RM.js → render-4C3YKVZI.js} +3 -3
- package/dist/{render-ULQLUIWD.js → render-7GDLEGXT.js} +12 -12
- package/dist/{render-EXSRG666.js → render-Y2Y7N5WD.js} +21 -21
- package/dist/{render-batch-RSNCREPB.js → render-batch-AFDBPDMM.js} +3 -3
- package/dist/{renderCancellation-2WB4SGXR.js → renderCancellation-RQ3UVNVJ.js} +6 -6
- package/dist/renderSetupWorker.js +1 -1
- package/dist/{resolver-CVN2IM2R.js → resolver-S72XBTEQ.js} +4 -4
- package/dist/{sherpa-OJUI54HG.js → sherpa-PR3I4KGM.js} +7 -7
- package/dist/{skills-CPS5E5YP.js → skills-BEYZZWY6.js} +11 -11
- package/dist/{skillsUpdateCheck-3IT5CJWU.js → skillsUpdateCheck-3USXDPWV.js} +3 -3
- package/dist/{snapshot-MSGC7HTA.js → snapshot-S77MQOV2.js} +25 -24
- package/dist/{src-SV7CNZXN.js → src-6R4DC2YI.js} +5 -5
- package/dist/{src-EZBJT4VH.js → src-IOJXK4VC.js} +7 -7
- package/dist/{staticProjectServer-5JAGMYT7.js → staticProjectServer-RXAFGDK7.js} +14 -13
- package/dist/{status-4W3EJYEH.js → status-CRS7H6FA.js} +6 -6
- package/dist/studio/assets/{hyperframes-player-h4mktSdm.js → hyperframes-player-BakGew45.js} +1 -1
- package/dist/studio/assets/{index-D8GKc2D9.js → index-C5dyUHwk.js} +1 -1
- package/dist/studio/assets/{index-CM1xA_jD.js → index-C842tcVa.js} +165 -165
- package/dist/studio/assets/{index-zoqPmBF6.js → index-CPe7d_wO.js} +1 -1
- package/dist/studio/assets/{index-lrT-gfHa.css → index-ncVJ5IVu.css} +1 -1
- package/dist/studio/chunk-6LUNLTHR.js +611 -0
- package/dist/studio/chunk-6LUNLTHR.js.map +1 -0
- package/dist/studio/{chunk-4OZC426H.js → chunk-AOWVEVEU.js} +3 -503
- package/dist/studio/chunk-AOWVEVEU.js.map +1 -0
- package/dist/studio/{chunk-46XP7J3B.js → chunk-PQFEBX32.js} +5 -3
- package/dist/studio/chunk-PQFEBX32.js.map +1 -0
- package/dist/studio/{domEditingLayers-AQBDFNUC.js → domEditingLayers-JQPQGGT7.js} +3 -3
- package/dist/studio/index.d.ts +11 -2
- package/dist/studio/index.html +2 -2
- package/dist/studio/index.js +12416 -11195
- package/dist/studio/index.js.map +1 -1
- package/dist/studio/player.js +2 -2
- package/dist/studio/styles.css +1 -1
- package/dist/{studio-api-L2TJ2JTK.js → studio-api-3FH7OSSS.js} +8 -7
- package/dist/{studioServer-UV7YRYWN.js → studioServer-4E5RRPU7.js} +44 -38
- package/dist/{system-OL4MXRPK.js → system-YMANAUAM.js} +6 -6
- package/dist/{telemetry-WRUU725E.js → telemetry-46XSB2VN.js} +9 -9
- package/dist/{timeline-P43A53BW.js → timeline-XKLKHGD2.js} +15 -14
- package/dist/{tokens-NUHTJM2V.js → tokens-JCZKPUPT.js} +2 -2
- package/dist/{transcribe-FSVNIFGF.js → transcribe-FIFJ3BBB.js} +12 -12
- package/dist/{transcribe-TRLZJK73.js → transcribe-FQ4YC2AS.js} +7 -7
- package/dist/{updateCheck-33TAG46I.js → updateCheck-PDIH4GZW.js} +2 -2
- package/dist/{upgrade-AJ6QBTH2.js → upgrade-TTGO6JCF.js} +2 -2
- package/dist/{urlDownloader-MP6GJIDV.js → urlDownloader-32JRHOPN.js} +5 -5
- package/dist/{validate-VL3A6VTJ.js → validate-G5F56ONL.js} +15 -15
- package/dist/{video-KO7VT63P.js → video-SGBEMEKA.js} +6 -6
- package/package.json +1 -1
- package/dist/chunk-PMLZPNIB.js +0 -3431
- package/dist/studio/chunk-46XP7J3B.js.map +0 -1
- package/dist/studio/chunk-4OZC426H.js.map +0 -1
- package/dist/studio/chunk-DI4LCJHL.js +0 -102
- package/dist/studio/chunk-DI4LCJHL.js.map +0 -1
- /package/dist/studio/{domEditingLayers-AQBDFNUC.js.map → domEditingLayers-JQPQGGT7.js.map} +0 -0
|
@@ -15,13 +15,20 @@ import {
|
|
|
15
15
|
splitElementInHtml,
|
|
16
16
|
unwrapElementsFromHtml,
|
|
17
17
|
wrapElementsInHtml
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-NJLFRKHX.js";
|
|
19
19
|
import {
|
|
20
20
|
atomicTempPath,
|
|
21
21
|
createFileAtomically,
|
|
22
22
|
isAtomicTempPath,
|
|
23
23
|
replaceFileAtomically
|
|
24
24
|
} from "./chunk-WEATBQTR.js";
|
|
25
|
+
import {
|
|
26
|
+
DEFAULT_TARGET_LUFS,
|
|
27
|
+
absoluteLoudnessPlan,
|
|
28
|
+
measureAudio,
|
|
29
|
+
requiredFfmpeg,
|
|
30
|
+
resolveLocalAudioPath
|
|
31
|
+
} from "./chunk-5ON5GH3X.js";
|
|
25
32
|
import {
|
|
26
33
|
PROXY_PARAMS_VERSION,
|
|
27
34
|
PROXY_PENDING_RETRY_AFTER_SECONDS,
|
|
@@ -47,7 +54,7 @@ import {
|
|
|
47
54
|
shouldPrewarmProxy,
|
|
48
55
|
waitForProxy,
|
|
49
56
|
walkDir
|
|
50
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-OVRFBUXU.js";
|
|
51
58
|
import {
|
|
52
59
|
findTimelineScript,
|
|
53
60
|
parseGsapScriptAcorn
|
|
@@ -66,7 +73,7 @@ import {
|
|
|
66
73
|
formatRenderOutputTimestamp,
|
|
67
74
|
parseFps,
|
|
68
75
|
sameInstant
|
|
69
|
-
} from "./chunk-
|
|
76
|
+
} from "./chunk-B25H4M4V.js";
|
|
70
77
|
import {
|
|
71
78
|
MagicString,
|
|
72
79
|
VALID_CANVAS_RESOLUTIONS,
|
|
@@ -75,15 +82,17 @@ import {
|
|
|
75
82
|
import {
|
|
76
83
|
addScenePartsManifest,
|
|
77
84
|
ensureHfIds
|
|
78
|
-
} from "./chunk-
|
|
85
|
+
} from "./chunk-X763EUBO.js";
|
|
79
86
|
import {
|
|
80
87
|
findStartTags,
|
|
81
88
|
injectScriptsIntoHtml,
|
|
82
89
|
injectTagsAtHeadStart,
|
|
83
90
|
insertBeforeCloseTag,
|
|
84
91
|
isFullHtmlDocument,
|
|
92
|
+
resolveRateSpec,
|
|
93
|
+
sourceTimeAt,
|
|
85
94
|
stripEmbeddedRuntimeScripts
|
|
86
|
-
} from "./chunk-
|
|
95
|
+
} from "./chunk-YLVI7VL5.js";
|
|
87
96
|
import {
|
|
88
97
|
ProjectRootMissingError,
|
|
89
98
|
folderGone,
|
|
@@ -96,12 +105,13 @@ import {
|
|
|
96
105
|
import {
|
|
97
106
|
isWithinProjectRoot,
|
|
98
107
|
readProjectFile
|
|
99
|
-
} from "./chunk-
|
|
108
|
+
} from "./chunk-ONY5CJXS.js";
|
|
100
109
|
import {
|
|
101
110
|
FFPROBE_PATH_ENV,
|
|
102
111
|
findFfBinary
|
|
103
112
|
} from "./chunk-PJ3HDUCY.js";
|
|
104
113
|
import {
|
|
114
|
+
readMediaOffsetSeconds,
|
|
105
115
|
rewriteAssetPaths,
|
|
106
116
|
rewriteCssAssetUrls,
|
|
107
117
|
rewriteInlineStyleAssetUrls
|
|
@@ -5106,16 +5116,25 @@ import { createHash as createHash32, randomUUID as randomUUID22 } from "crypto";
|
|
|
5106
5116
|
import { readFileSync as readFileSync8 } from "fs";
|
|
5107
5117
|
import { existsSync as existsSync7, readFileSync as readFileSync10, statSync as statSync7 } from "fs";
|
|
5108
5118
|
import { join as join12, resolve as resolve52 } from "path";
|
|
5119
|
+
import { execFile } from "child_process";
|
|
5120
|
+
import { existsSync as existsSync8, readFileSync as readFileSync11, statSync as statSync8 } from "fs";
|
|
5121
|
+
import { dirname as dirname52, join as join13, relative as relative4, sep as sep22 } from "path";
|
|
5122
|
+
import { createHash as createHash42, randomBytes } from "crypto";
|
|
5123
|
+
import { existsSync as existsSync9 } from "fs";
|
|
5124
|
+
import { existsSync as existsSync10, readFileSync as readFileSync12, statSync as statSync9 } from "fs";
|
|
5125
|
+
import { join as join14, resolve as resolve6 } from "path";
|
|
5126
|
+
import { execFile as execFile2, spawn as spawn2 } from "child_process";
|
|
5127
|
+
import { promisify } from "util";
|
|
5109
5128
|
import { closeSync as closeSync32, constants as constants3, fstatSync as fstatSync3, openSync as openSync32, readSync } from "fs";
|
|
5110
5129
|
import { streamSSE as streamSSE2 } from "hono/streaming";
|
|
5111
|
-
import { existsSync as
|
|
5112
|
-
import { basename as basename22, dirname as
|
|
5113
|
-
import { existsSync as
|
|
5130
|
+
import { existsSync as existsSync11 } from "fs";
|
|
5131
|
+
import { basename as basename22, dirname as dirname6, extname as extname2, join as join15, posix } from "path";
|
|
5132
|
+
import { existsSync as existsSync12, readFileSync as readFileSync13 } from "fs";
|
|
5114
5133
|
import { homedir as homedir2 } from "os";
|
|
5115
|
-
import { join as
|
|
5116
|
-
import { createHash as
|
|
5117
|
-
import { readFileSync as
|
|
5118
|
-
import { join as
|
|
5134
|
+
import { join as join16 } from "path";
|
|
5135
|
+
import { createHash as createHash5 } from "crypto";
|
|
5136
|
+
import { readFileSync as readFileSync14, readdirSync as readdirSync5, rmSync as rmSync5 } from "fs";
|
|
5137
|
+
import { join as join17 } from "path";
|
|
5119
5138
|
async function filterCompositionFiles(projectDir, files) {
|
|
5120
5139
|
const htmlFiles = files.filter((f) => f.endsWith(".html") && !isInHiddenOrVendorDir(f));
|
|
5121
5140
|
const checks = await Promise.all(
|
|
@@ -6152,7 +6171,7 @@ function bakeGroupTransformIntoMembers(html, groupId, members, groupCenter) {
|
|
|
6152
6171
|
const rad = grot * Math.PI / 180;
|
|
6153
6172
|
const cos = Math.cos(rad);
|
|
6154
6173
|
const sin = Math.sin(rad);
|
|
6155
|
-
const
|
|
6174
|
+
const round32 = (n) => Math.round(n * 1e3) / 1e3;
|
|
6156
6175
|
let script = block.scriptText;
|
|
6157
6176
|
for (const m of members) {
|
|
6158
6177
|
const memberSel = `#${m.id}`;
|
|
@@ -6169,27 +6188,27 @@ function bakeGroupTransformIntoMembers(html, groupId, members, groupCenter) {
|
|
|
6169
6188
|
const visY = groupCenter.cy + gscale * (sin * dx + cos * dy) + gy;
|
|
6170
6189
|
const newProps = {
|
|
6171
6190
|
...mProps,
|
|
6172
|
-
x:
|
|
6173
|
-
y:
|
|
6191
|
+
x: round32(visX - m.cx),
|
|
6192
|
+
y: round32(visY - m.cy)
|
|
6174
6193
|
};
|
|
6175
6194
|
if (gz !== 0) newProps.z = (typeof mProps.z === "number" ? mProps.z : 0) + gz;
|
|
6176
6195
|
if (grot !== 0) {
|
|
6177
|
-
newProps.rotation =
|
|
6196
|
+
newProps.rotation = round32(
|
|
6178
6197
|
(typeof mProps.rotation === "number" ? mProps.rotation : 0) + grot
|
|
6179
6198
|
);
|
|
6180
6199
|
}
|
|
6181
6200
|
if (gscale !== 1) {
|
|
6182
|
-
newProps.scale =
|
|
6201
|
+
newProps.scale = round32((typeof mProps.scale === "number" ? mProps.scale : 1) * gscale);
|
|
6183
6202
|
}
|
|
6184
6203
|
const pivoted = /* @__PURE__ */ new Set(["x", "y", "z", "rotation", "scale"]);
|
|
6185
6204
|
for (const [k, v] of Object.entries(gt)) {
|
|
6186
6205
|
if (pivoted.has(k) || typeof v !== "number") continue;
|
|
6187
6206
|
if (k === "scaleX" || k === "scaleY") {
|
|
6188
|
-
if (v !== 1) newProps[k] =
|
|
6207
|
+
if (v !== 1) newProps[k] = round32((typeof mProps[k] === "number" ? mProps[k] : 1) * v);
|
|
6189
6208
|
} else if (k === "transformPerspective") {
|
|
6190
6209
|
if (typeof mProps[k] !== "number") newProps[k] = v;
|
|
6191
6210
|
} else if (v !== 0) {
|
|
6192
|
-
newProps[k] =
|
|
6211
|
+
newProps[k] = round32((typeof mProps[k] === "number" ? mProps[k] : 0) + v);
|
|
6193
6212
|
}
|
|
6194
6213
|
}
|
|
6195
6214
|
for (const s of [...sets].reverse()) {
|
|
@@ -6360,7 +6379,7 @@ async function prepareGsapMutationScript(c, res, firstMutation) {
|
|
|
6360
6379
|
let block = extractGsapScriptBlock(html);
|
|
6361
6380
|
if (!block && (firstMutation.type === "add" || firstMutation.type === "add-with-keyframes")) {
|
|
6362
6381
|
const compId = html.match(/data-composition-id="([^"]+)"/)?.[1] ?? "main";
|
|
6363
|
-
const { GSAP_CDN } = await import("./dist-
|
|
6382
|
+
const { GSAP_CDN } = await import("./dist-YUIPB7OX.js");
|
|
6364
6383
|
const bootstrap = [
|
|
6365
6384
|
`<script src="${GSAP_CDN}"></script>`,
|
|
6366
6385
|
"<script>",
|
|
@@ -8944,7 +8963,8 @@ function registerRenderRoutes(api, adapter) {
|
|
|
8944
8963
|
progress: current.progress,
|
|
8945
8964
|
status: current.status,
|
|
8946
8965
|
stage: current.stage,
|
|
8947
|
-
error: current.error
|
|
8966
|
+
error: current.error,
|
|
8967
|
+
...current.status === "complete" && current.audioLoweredDb !== void 0 ? { audioLoweredDb: current.audioLoweredDb } : {}
|
|
8948
8968
|
})
|
|
8949
8969
|
});
|
|
8950
8970
|
if (current.status !== "rendering") break;
|
|
@@ -9053,11 +9073,13 @@ function registerRenderRoutes(api, adapter) {
|
|
|
9053
9073
|
const metaPath = join10(rendersDir, `${rid}.meta.json`);
|
|
9054
9074
|
let status = "complete";
|
|
9055
9075
|
let durationMs;
|
|
9076
|
+
let audioLoweredDb;
|
|
9056
9077
|
if (existsSync6(metaPath)) {
|
|
9057
9078
|
try {
|
|
9058
9079
|
const meta = JSON.parse(readFileSync72(metaPath, "utf-8"));
|
|
9059
9080
|
if (meta.status === "failed" && !existsSync6(fp)) status = "failed";
|
|
9060
9081
|
if (meta.durationMs) durationMs = meta.durationMs;
|
|
9082
|
+
if (typeof meta.audioLoweredDb === "number") audioLoweredDb = meta.audioLoweredDb;
|
|
9061
9083
|
} catch {
|
|
9062
9084
|
}
|
|
9063
9085
|
}
|
|
@@ -9067,7 +9089,8 @@ function registerRenderRoutes(api, adapter) {
|
|
|
9067
9089
|
size: stat22.size,
|
|
9068
9090
|
createdAt: stat22.mtimeMs,
|
|
9069
9091
|
status,
|
|
9070
|
-
durationMs
|
|
9092
|
+
durationMs,
|
|
9093
|
+
...audioLoweredDb !== void 0 ? { audioLoweredDb } : {}
|
|
9071
9094
|
};
|
|
9072
9095
|
}).sort((a, b) => b.createdAt - a.createdAt);
|
|
9073
9096
|
for (const file of files) {
|
|
@@ -9100,10 +9123,10 @@ var ThumbnailGenerationCoordinator = class {
|
|
|
9100
9123
|
if (signal.aborted) return Promise.reject(new DOMException("Aborted", "AbortError"));
|
|
9101
9124
|
let entry = this.entries.get(key);
|
|
9102
9125
|
if (!entry) {
|
|
9103
|
-
let
|
|
9126
|
+
let resolve7;
|
|
9104
9127
|
let reject;
|
|
9105
9128
|
const promise = new Promise((resolvePromise, rejectPromise) => {
|
|
9106
|
-
|
|
9129
|
+
resolve7 = resolvePromise;
|
|
9107
9130
|
reject = rejectPromise;
|
|
9108
9131
|
});
|
|
9109
9132
|
entry = {
|
|
@@ -9113,7 +9136,7 @@ var ThumbnailGenerationCoordinator = class {
|
|
|
9113
9136
|
state: "queued",
|
|
9114
9137
|
work,
|
|
9115
9138
|
promise,
|
|
9116
|
-
resolve:
|
|
9139
|
+
resolve: resolve7,
|
|
9117
9140
|
reject
|
|
9118
9141
|
};
|
|
9119
9142
|
this.entries.set(key, entry);
|
|
@@ -9127,7 +9150,7 @@ var ThumbnailGenerationCoordinator = class {
|
|
|
9127
9150
|
return /* @__PURE__ */ new Set([...this.entries.keys(), ...[...this.activeEntries].map((entry) => entry.key)]);
|
|
9128
9151
|
}
|
|
9129
9152
|
lease(entry, signal) {
|
|
9130
|
-
return new Promise((
|
|
9153
|
+
return new Promise((resolve7, reject) => {
|
|
9131
9154
|
let released = false;
|
|
9132
9155
|
const release = () => {
|
|
9133
9156
|
if (released) return;
|
|
@@ -9151,7 +9174,7 @@ var ThumbnailGenerationCoordinator = class {
|
|
|
9151
9174
|
entry.promise.then(
|
|
9152
9175
|
(value) => {
|
|
9153
9176
|
release();
|
|
9154
|
-
|
|
9177
|
+
resolve7(value);
|
|
9155
9178
|
},
|
|
9156
9179
|
(reason) => {
|
|
9157
9180
|
release();
|
|
@@ -9226,14 +9249,14 @@ async function generateThumbnail(path, signal) {
|
|
|
9226
9249
|
async function resolveSource(adapter, id, url) {
|
|
9227
9250
|
const project = await adapter.resolveProject(id);
|
|
9228
9251
|
if (!project) throw new HTTPException(404);
|
|
9229
|
-
let
|
|
9252
|
+
let relative5;
|
|
9230
9253
|
try {
|
|
9231
|
-
|
|
9254
|
+
relative5 = requestSubPath(url, "projects/:id/image-thumbnail");
|
|
9232
9255
|
} catch {
|
|
9233
9256
|
throw new HTTPException(400);
|
|
9234
9257
|
}
|
|
9235
|
-
if (!/\.jpe?g$/i.test(
|
|
9236
|
-
const path = pinWithinProject(project.dir,
|
|
9258
|
+
if (!/\.jpe?g$/i.test(relative5)) throw new HTTPException(415);
|
|
9259
|
+
const path = pinWithinProject(project.dir, relative5);
|
|
9237
9260
|
if (!path) throw new HTTPException(404);
|
|
9238
9261
|
const info = await stat2(path).catch(() => {
|
|
9239
9262
|
throw new HTTPException(404);
|
|
@@ -9574,6 +9597,493 @@ function registerWaveformRoutes(api, adapter) {
|
|
|
9574
9597
|
return c.json({ peaks });
|
|
9575
9598
|
});
|
|
9576
9599
|
}
|
|
9600
|
+
var FREEZE_HOLD_SECONDS = 2;
|
|
9601
|
+
var LINK_ATTR = "data-link";
|
|
9602
|
+
var EPSILON = 1e-3;
|
|
9603
|
+
var round3 = (value) => Math.round(value * 1e3) / 1e3;
|
|
9604
|
+
function numberAttr(el, name) {
|
|
9605
|
+
const raw = el.getAttribute(name);
|
|
9606
|
+
if (raw === null || raw.trim() === "") return null;
|
|
9607
|
+
const value = Number(raw);
|
|
9608
|
+
return Number.isFinite(value) ? value : null;
|
|
9609
|
+
}
|
|
9610
|
+
function trackOf(el) {
|
|
9611
|
+
return numberAttr(el, "data-track-index") ?? numberAttr(el, "data-layer") ?? 0;
|
|
9612
|
+
}
|
|
9613
|
+
function freezeFrameMediaTime(input) {
|
|
9614
|
+
const rate = resolveRateSpec(input.automation, input.playbackRate);
|
|
9615
|
+
return input.mediaStart + sourceTimeAt(rate, Math.max(0, input.playhead - input.clipStart));
|
|
9616
|
+
}
|
|
9617
|
+
function freezeExtractArgs(src, mediaTime, output) {
|
|
9618
|
+
return ["-n", "-ss", String(round3(mediaTime)), "-i", src, "-frames:v", "1", output];
|
|
9619
|
+
}
|
|
9620
|
+
var randomStillToken = () => randomBytes(4).toString("hex");
|
|
9621
|
+
function freezeStillFileName(clipId, playhead, token = randomStillToken()) {
|
|
9622
|
+
const stem = clipId.replace(/[^A-Za-z0-9_-]/g, "_").slice(0, 48) || "clip";
|
|
9623
|
+
const idHash = createHash42("sha256").update(clipId).digest("hex").slice(0, 10);
|
|
9624
|
+
return `${stem}-${idHash}-${Math.round(playhead * 1e3)}-${token}.png`;
|
|
9625
|
+
}
|
|
9626
|
+
function readFreezeSource(html, target, playhead) {
|
|
9627
|
+
const { document: document2 } = parseSourceDocument(html);
|
|
9628
|
+
const el = findTargetElement(document2, target);
|
|
9629
|
+
if (!el || el.tagName.toLowerCase() !== "video") return null;
|
|
9630
|
+
const src = el.getAttribute("src");
|
|
9631
|
+
const start = numberAttr(el, "data-start");
|
|
9632
|
+
const duration = numberAttr(el, "data-duration");
|
|
9633
|
+
if (!src || start === null || duration === null) return null;
|
|
9634
|
+
if (playhead <= start + EPSILON || playhead >= start + duration - EPSILON) return null;
|
|
9635
|
+
return {
|
|
9636
|
+
id: el.getAttribute("id") || "clip",
|
|
9637
|
+
src,
|
|
9638
|
+
mediaTime: freezeFrameMediaTime({
|
|
9639
|
+
clipStart: start,
|
|
9640
|
+
playhead,
|
|
9641
|
+
mediaStart: readMediaOffsetSeconds((name) => el.getAttribute(name)),
|
|
9642
|
+
playbackRate: numberAttr(el, "data-playback-rate") ?? 1,
|
|
9643
|
+
automation: el.getAttribute("data-automation")
|
|
9644
|
+
})
|
|
9645
|
+
};
|
|
9646
|
+
}
|
|
9647
|
+
function targetOf(el) {
|
|
9648
|
+
const hfId = el.getAttribute("data-hf-id");
|
|
9649
|
+
return { ...hfId ? { hfId } : {}, id: el.getAttribute("id") };
|
|
9650
|
+
}
|
|
9651
|
+
function spans(el, time) {
|
|
9652
|
+
const start = numberAttr(el, "data-start");
|
|
9653
|
+
const duration = numberAttr(el, "data-duration");
|
|
9654
|
+
if (start === null || duration === null) return false;
|
|
9655
|
+
return time > start + EPSILON && time < start + duration - EPSILON;
|
|
9656
|
+
}
|
|
9657
|
+
function uniqueId(document2, base) {
|
|
9658
|
+
let id = base;
|
|
9659
|
+
for (let n = 2; document2.getElementById(id); n++) id = `${base}-${n}`;
|
|
9660
|
+
return id;
|
|
9661
|
+
}
|
|
9662
|
+
function shiftTracks(document2, tracks, from, by) {
|
|
9663
|
+
for (const el of document2.querySelectorAll("[data-start]")) {
|
|
9664
|
+
if (el.hasAttribute("data-composition-id") || !tracks.has(trackOf(el))) continue;
|
|
9665
|
+
const start = numberAttr(el, "data-start");
|
|
9666
|
+
if (start === null || start < from - EPSILON) continue;
|
|
9667
|
+
el.setAttribute("data-start", String(round3(start + by)));
|
|
9668
|
+
}
|
|
9669
|
+
}
|
|
9670
|
+
function growRootToFit(document2) {
|
|
9671
|
+
const root = document2.querySelector("[data-composition-id]");
|
|
9672
|
+
const rootDuration = root ? numberAttr(root, "data-duration") : null;
|
|
9673
|
+
if (!root || rootDuration === null) return;
|
|
9674
|
+
let end = rootDuration;
|
|
9675
|
+
for (const el of root.querySelectorAll("[data-start][data-duration]")) {
|
|
9676
|
+
const start = numberAttr(el, "data-start");
|
|
9677
|
+
const duration = numberAttr(el, "data-duration");
|
|
9678
|
+
if (start !== null && duration !== null) end = Math.max(end, start + duration);
|
|
9679
|
+
}
|
|
9680
|
+
if (end > rootDuration + EPSILON) root.setAttribute("data-duration", String(round3(end)));
|
|
9681
|
+
}
|
|
9682
|
+
var COPIED_PICTURE_ATTRS = ["class", "style", "data-color-grading"];
|
|
9683
|
+
function buildStill(document2, video, input) {
|
|
9684
|
+
const img = document2.createElement("img");
|
|
9685
|
+
img.setAttribute("id", input.id);
|
|
9686
|
+
for (const name of COPIED_PICTURE_ATTRS) {
|
|
9687
|
+
const value = video.getAttribute(name);
|
|
9688
|
+
if (value !== null) img.setAttribute(name, value);
|
|
9689
|
+
}
|
|
9690
|
+
if (!img.classList.contains("clip")) img.classList.add("clip");
|
|
9691
|
+
img.setAttribute("src", input.imageSrc);
|
|
9692
|
+
img.setAttribute("alt", "");
|
|
9693
|
+
img.setAttribute("data-start", String(round3(input.playhead)));
|
|
9694
|
+
img.setAttribute("data-duration", String(input.holdSeconds));
|
|
9695
|
+
img.setAttribute("data-track-index", String(trackOf(video)));
|
|
9696
|
+
img.setAttribute("data-timeline-label", "Freeze");
|
|
9697
|
+
return img;
|
|
9698
|
+
}
|
|
9699
|
+
function linkedPartners(document2, video) {
|
|
9700
|
+
const link = video.getAttribute(LINK_ATTR);
|
|
9701
|
+
if (!link) return [];
|
|
9702
|
+
return Array.from(document2.querySelectorAll(`[${LINK_ATTR}]`)).filter(
|
|
9703
|
+
(el) => el !== video && el.getAttribute(LINK_ATTR) === link
|
|
9704
|
+
);
|
|
9705
|
+
}
|
|
9706
|
+
function splitAll(html, elements, time) {
|
|
9707
|
+
const rightHalfIds = [];
|
|
9708
|
+
let next = html;
|
|
9709
|
+
for (const el of elements) {
|
|
9710
|
+
const split = splitElementInHtml(
|
|
9711
|
+
next,
|
|
9712
|
+
targetOf(el),
|
|
9713
|
+
time,
|
|
9714
|
+
`${el.getAttribute("id") || "clip"}-split`,
|
|
9715
|
+
{
|
|
9716
|
+
start: numberAttr(el, "data-start") ?? 0,
|
|
9717
|
+
duration: numberAttr(el, "data-duration") ?? 0,
|
|
9718
|
+
track: trackOf(el)
|
|
9719
|
+
}
|
|
9720
|
+
);
|
|
9721
|
+
if (!split.matched || !split.newId) return null;
|
|
9722
|
+
next = split.html;
|
|
9723
|
+
rightHalfIds.push(split.newId);
|
|
9724
|
+
}
|
|
9725
|
+
return { html: next, rightHalfIds };
|
|
9726
|
+
}
|
|
9727
|
+
function relinkRightHalves(document2, link, ids) {
|
|
9728
|
+
if (!link) return;
|
|
9729
|
+
const rightLink = uniqueLink(document2, link);
|
|
9730
|
+
for (const id of ids) document2.getElementById(id)?.setAttribute(LINK_ATTR, rightLink);
|
|
9731
|
+
}
|
|
9732
|
+
function applyFreezeFrameToHtml(html, input) {
|
|
9733
|
+
const hold = input.holdSeconds ?? FREEZE_HOLD_SECONDS;
|
|
9734
|
+
const { document: before } = parseSourceDocument(html);
|
|
9735
|
+
const video = findTargetElement(before, input.target);
|
|
9736
|
+
if (!video || !isHTMLElement(video) || !spans(video, input.playhead)) return null;
|
|
9737
|
+
const partners = linkedPartners(before, video);
|
|
9738
|
+
const tracks = /* @__PURE__ */ new Set([trackOf(video), ...partners.map(trackOf)]);
|
|
9739
|
+
const cut = splitAll(
|
|
9740
|
+
html,
|
|
9741
|
+
[video, ...partners.filter((el) => spans(el, input.playhead))],
|
|
9742
|
+
input.playhead
|
|
9743
|
+
);
|
|
9744
|
+
if (!cut) return null;
|
|
9745
|
+
const { document: document2, wrappedFragment } = parseSourceDocument(cut.html);
|
|
9746
|
+
relinkRightHalves(document2, video.getAttribute(LINK_ATTR), cut.rightHalfIds);
|
|
9747
|
+
shiftTracks(document2, tracks, input.playhead, hold);
|
|
9748
|
+
const leftHalf = findTargetElement(document2, input.target);
|
|
9749
|
+
if (!leftHalf?.parentElement) return null;
|
|
9750
|
+
const freezeId = uniqueId(document2, `${video.getAttribute("id") || "clip"}-freeze`);
|
|
9751
|
+
const still = buildStill(document2, leftHalf, {
|
|
9752
|
+
id: freezeId,
|
|
9753
|
+
imageSrc: input.imageSrc,
|
|
9754
|
+
playhead: input.playhead,
|
|
9755
|
+
holdSeconds: hold
|
|
9756
|
+
});
|
|
9757
|
+
leftHalf.parentElement.insertBefore(still, leftHalf.nextSibling);
|
|
9758
|
+
growRootToFit(document2);
|
|
9759
|
+
return {
|
|
9760
|
+
html: ensureHfIds(wrappedFragment ? document2.body.innerHTML || "" : document2.toString()),
|
|
9761
|
+
freezeId
|
|
9762
|
+
};
|
|
9763
|
+
}
|
|
9764
|
+
function uniqueLink(document2, base) {
|
|
9765
|
+
const taken = new Set(
|
|
9766
|
+
Array.from(document2.querySelectorAll(`[${LINK_ATTR}]`)).map((el) => el.getAttribute(LINK_ATTR))
|
|
9767
|
+
);
|
|
9768
|
+
let candidate = `${base}-2`;
|
|
9769
|
+
for (let n = 3; taken.has(candidate); n++) candidate = `${base}-${n}`;
|
|
9770
|
+
return candidate;
|
|
9771
|
+
}
|
|
9772
|
+
var EXTRACT_TIMEOUT_MS = 3e4;
|
|
9773
|
+
var ffmpegExtractor = (args) => {
|
|
9774
|
+
const ffmpeg = findFfBinary("ffmpeg", { configuredMustExist: true });
|
|
9775
|
+
if (!ffmpeg) return Promise.resolve({ ok: false, error: "ffmpeg not found" });
|
|
9776
|
+
return new Promise((resolvePromise) => {
|
|
9777
|
+
execFile(
|
|
9778
|
+
ffmpeg,
|
|
9779
|
+
args,
|
|
9780
|
+
{ timeout: EXTRACT_TIMEOUT_MS, windowsHide: true },
|
|
9781
|
+
(error, _o, stderr) => resolvePromise(
|
|
9782
|
+
error ? { ok: false, error: String(stderr || error.message) } : { ok: true }
|
|
9783
|
+
)
|
|
9784
|
+
);
|
|
9785
|
+
});
|
|
9786
|
+
};
|
|
9787
|
+
function isFreezeFrameRequest(value) {
|
|
9788
|
+
if (typeof value !== "object" || value === null) return false;
|
|
9789
|
+
const body = value;
|
|
9790
|
+
return typeof body.path === "string" && body.path.length > 0 && typeof body.expectedVersion === "string" && typeof body.target === "object" && body.target !== null && typeof body.playhead === "number" && Number.isFinite(body.playhead);
|
|
9791
|
+
}
|
|
9792
|
+
var FREEZE_DIR = ["assets", "freeze"];
|
|
9793
|
+
function readExpected(absPath, expectedVersion) {
|
|
9794
|
+
let content;
|
|
9795
|
+
try {
|
|
9796
|
+
content = readFileSync11(absPath, "utf-8");
|
|
9797
|
+
} catch {
|
|
9798
|
+
return { error: "not found", status: 404 };
|
|
9799
|
+
}
|
|
9800
|
+
return fileContentVersion(content) === expectedVersion ? { content } : { error: "file conflict", status: 409 };
|
|
9801
|
+
}
|
|
9802
|
+
async function extractStill(projectDir, absPath, source, playhead, tools) {
|
|
9803
|
+
const fileDir = dirname52(absPath);
|
|
9804
|
+
const mediaPath = pinWithinProject(projectDir, relative4(projectDir, join13(fileDir, source.src)));
|
|
9805
|
+
if (!mediaPath) return { error: `forbidden media path: ${source.src}`, status: 403 };
|
|
9806
|
+
const freezeDir = join13(projectDir, ...FREEZE_DIR);
|
|
9807
|
+
const fileName = freezeStillFileName(source.id, playhead, tools.stillToken());
|
|
9808
|
+
mkdirWithinProject(projectDir, freezeDir);
|
|
9809
|
+
const imagePath = pinWithinProject(projectDir, join13(...FREEZE_DIR, fileName));
|
|
9810
|
+
if (!imagePath || dirname52(imagePath) !== freezeDir) {
|
|
9811
|
+
return { error: `forbidden freeze path: ${fileName}`, status: 403 };
|
|
9812
|
+
}
|
|
9813
|
+
if (existsSync8(imagePath))
|
|
9814
|
+
return { error: `freeze still already exists: ${fileName}`, status: 409 };
|
|
9815
|
+
const extracted = await tools.extract(freezeExtractArgs(mediaPath, source.mediaTime, imagePath));
|
|
9816
|
+
if (!extracted.ok) {
|
|
9817
|
+
return {
|
|
9818
|
+
error: `Could not extract the frame: ${extracted.error ?? "ffmpeg failed"}`,
|
|
9819
|
+
status: 500
|
|
9820
|
+
};
|
|
9821
|
+
}
|
|
9822
|
+
const depth = relative4(projectDir, fileDir).split(sep22).filter(Boolean).length;
|
|
9823
|
+
return { imageSrc: `${"../".repeat(depth)}${FREEZE_DIR.join("/")}/${fileName}` };
|
|
9824
|
+
}
|
|
9825
|
+
function writeFolded(projectDir, absPath, path, before, after, options) {
|
|
9826
|
+
if (readFileSync11(absPath, "utf-8") !== before) {
|
|
9827
|
+
return { error: `file conflict: ${path}`, status: 409 };
|
|
9828
|
+
}
|
|
9829
|
+
const backup = snapshotBeforeWrite(projectDir, absPath);
|
|
9830
|
+
if (backup.error) return { error: `Failed to create backup: ${backup.error}`, status: 500 };
|
|
9831
|
+
const writeToken = createWriteToken(options.token);
|
|
9832
|
+
replaceFileAtomically(absPath, after, statSync8(absPath).mode);
|
|
9833
|
+
const version = fileContentVersion(after);
|
|
9834
|
+
recordFileWriteReceipt(absPath, { path, version, writeToken, overwrote: before });
|
|
9835
|
+
return { version, writeToken, backupPath: backupPathForResponse(projectDir, backup.backupPath) };
|
|
9836
|
+
}
|
|
9837
|
+
function registerFreezeFrameRoutes(api, adapter, extract = ffmpegExtractor, stillToken = randomStillToken) {
|
|
9838
|
+
api.post("/projects/:id/file-mutations/freeze-frame", async (c) => {
|
|
9839
|
+
const body = await c.req.json().catch(() => null);
|
|
9840
|
+
if (!isFreezeFrameRequest(body)) {
|
|
9841
|
+
return c.json({ error: "path, expectedVersion, target and playhead required" }, 400);
|
|
9842
|
+
}
|
|
9843
|
+
const project = await adapter.resolveProject(c.req.param("id"));
|
|
9844
|
+
if (!project) return c.json({ error: "not found" }, 404);
|
|
9845
|
+
const absPath = pinWithinProject(project.dir, body.path);
|
|
9846
|
+
if (!absPath) return c.json({ error: `forbidden path: ${body.path}` }, 403);
|
|
9847
|
+
const read = readExpected(absPath, body.expectedVersion);
|
|
9848
|
+
if ("error" in read) return c.json({ error: `${read.error}: ${body.path}` }, read.status);
|
|
9849
|
+
const before = read.content;
|
|
9850
|
+
const source = readFreezeSource(before, body.target, body.playhead);
|
|
9851
|
+
if (!source) return c.json({ error: "Move the playhead inside a video clip to freeze" }, 400);
|
|
9852
|
+
const still = await extractStill(project.dir, absPath, source, body.playhead, {
|
|
9853
|
+
extract,
|
|
9854
|
+
stillToken
|
|
9855
|
+
});
|
|
9856
|
+
if ("error" in still) return c.json({ error: still.error }, still.status);
|
|
9857
|
+
const { imageSrc } = still;
|
|
9858
|
+
const folded = applyFreezeFrameToHtml(before, {
|
|
9859
|
+
target: body.target,
|
|
9860
|
+
playhead: body.playhead,
|
|
9861
|
+
imageSrc
|
|
9862
|
+
});
|
|
9863
|
+
if (!folded) return c.json({ error: "Freeze target was not found in the file" }, 400);
|
|
9864
|
+
const written = writeFolded(project.dir, absPath, body.path, before, folded.html, {
|
|
9865
|
+
token: body.transactionToken ?? c.req.header("X-Hyperframes-Write-Token")
|
|
9866
|
+
});
|
|
9867
|
+
if ("error" in written) return c.json({ error: written.error }, written.status);
|
|
9868
|
+
const { version, writeToken, backupPath } = written;
|
|
9869
|
+
return c.json({
|
|
9870
|
+
ok: true,
|
|
9871
|
+
path: body.path,
|
|
9872
|
+
before,
|
|
9873
|
+
after: folded.html,
|
|
9874
|
+
version,
|
|
9875
|
+
writeToken,
|
|
9876
|
+
backupPath,
|
|
9877
|
+
freezeId: folded.freezeId,
|
|
9878
|
+
imageSrc
|
|
9879
|
+
});
|
|
9880
|
+
});
|
|
9881
|
+
}
|
|
9882
|
+
var defaultMeasure = (file, window2) => measureAudio(requiredFfmpeg(), file, window2);
|
|
9883
|
+
var InvalidField = class extends Error {
|
|
9884
|
+
};
|
|
9885
|
+
function numberField(body, name, fallback, valid) {
|
|
9886
|
+
const raw = body[name];
|
|
9887
|
+
if (raw === void 0 || raw === null) return fallback;
|
|
9888
|
+
if (typeof raw === "number" && Number.isFinite(raw) && valid(raw)) return raw;
|
|
9889
|
+
throw new InvalidField(`${name} is out of range`);
|
|
9890
|
+
}
|
|
9891
|
+
function readNormalizeRequest(body) {
|
|
9892
|
+
const src = typeof body.src === "string" ? body.src.trim() : "";
|
|
9893
|
+
if (!src) throw new InvalidField("src is required");
|
|
9894
|
+
const duration = numberField(body, "duration", 0, (v) => v > 0);
|
|
9895
|
+
return {
|
|
9896
|
+
id: typeof body.id === "string" && body.id ? body.id : src,
|
|
9897
|
+
src,
|
|
9898
|
+
window: {
|
|
9899
|
+
mediaStart: numberField(body, "mediaStart", 0, (v) => v >= 0),
|
|
9900
|
+
duration: duration > 0 ? duration : null,
|
|
9901
|
+
playbackRate: numberField(body, "playbackRate", 1, (v) => v > 0)
|
|
9902
|
+
},
|
|
9903
|
+
volume: numberField(body, "volume", 1, (v) => v >= 0),
|
|
9904
|
+
targetLufs: numberField(body, "targetLufs", DEFAULT_TARGET_LUFS, (v) => v < 0)
|
|
9905
|
+
};
|
|
9906
|
+
}
|
|
9907
|
+
function parseNormalizeRequest(body) {
|
|
9908
|
+
try {
|
|
9909
|
+
return readNormalizeRequest(body);
|
|
9910
|
+
} catch (error) {
|
|
9911
|
+
if (error instanceof InvalidField) return error.message;
|
|
9912
|
+
throw error;
|
|
9913
|
+
}
|
|
9914
|
+
}
|
|
9915
|
+
function isRecord(value) {
|
|
9916
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9917
|
+
}
|
|
9918
|
+
function registerLoudnessRoutes(api, adapter, measure = defaultMeasure) {
|
|
9919
|
+
api.post("/projects/:id/loudness/normalize", async (c) => {
|
|
9920
|
+
const project = await adapter.resolveProject(c.req.param("id"));
|
|
9921
|
+
if (!project) return c.json({ error: "not found" }, 404);
|
|
9922
|
+
const body = await c.req.json().catch(() => null);
|
|
9923
|
+
if (!isRecord(body)) return c.json({ error: "invalid body" }, 400);
|
|
9924
|
+
const request = parseNormalizeRequest(body);
|
|
9925
|
+
if (typeof request === "string") return c.json({ error: request }, 400);
|
|
9926
|
+
let file;
|
|
9927
|
+
try {
|
|
9928
|
+
file = resolveLocalAudioPath(project.dir, request.src);
|
|
9929
|
+
} catch (error) {
|
|
9930
|
+
return c.json({ error: error instanceof Error ? error.message : String(error) }, 400);
|
|
9931
|
+
}
|
|
9932
|
+
if (!existsSync9(file)) return c.json({ error: "file not found" }, 404);
|
|
9933
|
+
try {
|
|
9934
|
+
const measurement = await measure(file, request.window);
|
|
9935
|
+
const plan = absoluteLoudnessPlan(
|
|
9936
|
+
{ id: request.id, volume: request.volume, ...measurement },
|
|
9937
|
+
request.targetLufs
|
|
9938
|
+
);
|
|
9939
|
+
return c.json({ plan });
|
|
9940
|
+
} catch (error) {
|
|
9941
|
+
return c.json({ error: error instanceof Error ? error.message : String(error) }, 422);
|
|
9942
|
+
}
|
|
9943
|
+
});
|
|
9944
|
+
}
|
|
9945
|
+
var PEAK_BIN_SECONDS = 0.05;
|
|
9946
|
+
var PEAK_SAMPLE_RATE = 48e3;
|
|
9947
|
+
var execFileAsync = promisify(execFile2);
|
|
9948
|
+
var PEAK_MAP_CACHE_VERSION = "peaks-v2";
|
|
9949
|
+
function createPeakAccumulator(sampleRate = PEAK_SAMPLE_RATE, binSeconds = PEAK_BIN_SECONDS, channels = 2) {
|
|
9950
|
+
return {
|
|
9951
|
+
bins: [],
|
|
9952
|
+
frame: 0,
|
|
9953
|
+
carry: Buffer.alloc(0),
|
|
9954
|
+
framesPerBin: Math.max(1, Math.round(sampleRate * binSeconds)),
|
|
9955
|
+
channels: Math.max(1, channels)
|
|
9956
|
+
};
|
|
9957
|
+
}
|
|
9958
|
+
function framePeak(data, offset, channels) {
|
|
9959
|
+
let peak = 0;
|
|
9960
|
+
for (let ch = 0; ch < channels; ch++) {
|
|
9961
|
+
peak = Math.max(peak, Math.abs(data.readFloatLE(offset + ch * 4)));
|
|
9962
|
+
}
|
|
9963
|
+
return peak;
|
|
9964
|
+
}
|
|
9965
|
+
function accumulatePeaks(acc, chunk) {
|
|
9966
|
+
const data = acc.carry.length > 0 ? Buffer.concat([acc.carry, chunk]) : chunk;
|
|
9967
|
+
const frameBytes = 4 * acc.channels;
|
|
9968
|
+
const whole = data.length - data.length % frameBytes;
|
|
9969
|
+
for (let offset = 0; offset < whole; offset += frameBytes) {
|
|
9970
|
+
const peak = framePeak(data, offset, acc.channels);
|
|
9971
|
+
const bin = Math.floor(acc.frame / acc.framesPerBin);
|
|
9972
|
+
if (acc.bins.length <= bin) acc.bins.push(0);
|
|
9973
|
+
if (peak > (acc.bins[bin] ?? 0)) acc.bins[bin] = peak;
|
|
9974
|
+
acc.frame += 1;
|
|
9975
|
+
}
|
|
9976
|
+
acc.carry = Buffer.from(data.subarray(whole));
|
|
9977
|
+
}
|
|
9978
|
+
function finishPeaks(acc) {
|
|
9979
|
+
return acc.bins.map((peak) => Number(peak.toFixed(4)));
|
|
9980
|
+
}
|
|
9981
|
+
async function probeChannels(mediaPath) {
|
|
9982
|
+
const { stdout } = await execFileAsync(
|
|
9983
|
+
findFfBinary("ffprobe") ?? "ffprobe",
|
|
9984
|
+
[
|
|
9985
|
+
"-v",
|
|
9986
|
+
"error",
|
|
9987
|
+
"-select_streams",
|
|
9988
|
+
"a:0",
|
|
9989
|
+
"-show_entries",
|
|
9990
|
+
"stream=channels",
|
|
9991
|
+
"-of",
|
|
9992
|
+
"csv=p=0",
|
|
9993
|
+
"--",
|
|
9994
|
+
mediaPath
|
|
9995
|
+
],
|
|
9996
|
+
{ encoding: "utf8", timeout: 3e4, windowsHide: true }
|
|
9997
|
+
);
|
|
9998
|
+
const channels = Number.parseInt(stdout.trim(), 10);
|
|
9999
|
+
if (!Number.isFinite(channels) || channels < 1) throw new Error("no audio stream");
|
|
10000
|
+
return channels;
|
|
10001
|
+
}
|
|
10002
|
+
async function decodePeakMap(mediaPath) {
|
|
10003
|
+
const channels = await probeChannels(mediaPath);
|
|
10004
|
+
return new Promise((resolvePromise, reject) => {
|
|
10005
|
+
const proc = spawn2(
|
|
10006
|
+
findFfBinary("ffmpeg") ?? "ffmpeg",
|
|
10007
|
+
[
|
|
10008
|
+
"-v",
|
|
10009
|
+
"error",
|
|
10010
|
+
"-i",
|
|
10011
|
+
mediaPath,
|
|
10012
|
+
"-map",
|
|
10013
|
+
"0:a:0",
|
|
10014
|
+
"-vn",
|
|
10015
|
+
"-ar",
|
|
10016
|
+
String(PEAK_SAMPLE_RATE),
|
|
10017
|
+
"-f",
|
|
10018
|
+
"f32le",
|
|
10019
|
+
"pipe:1"
|
|
10020
|
+
],
|
|
10021
|
+
{ stdio: ["ignore", "pipe", "ignore"], windowsHide: true }
|
|
10022
|
+
);
|
|
10023
|
+
const acc = createPeakAccumulator(PEAK_SAMPLE_RATE, PEAK_BIN_SECONDS, channels);
|
|
10024
|
+
proc.stdout?.on("data", (chunk) => accumulatePeaks(acc, chunk));
|
|
10025
|
+
proc.on("close", (code) => {
|
|
10026
|
+
if (code !== 0) {
|
|
10027
|
+
reject(new Error(`ffmpeg failed decoding audio (exit ${code})`));
|
|
10028
|
+
return;
|
|
10029
|
+
}
|
|
10030
|
+
if (acc.frame === 0) {
|
|
10031
|
+
reject(new Error("ffmpeg produced no audio samples"));
|
|
10032
|
+
return;
|
|
10033
|
+
}
|
|
10034
|
+
resolvePromise(finishPeaks(acc));
|
|
10035
|
+
});
|
|
10036
|
+
proc.on("error", reject);
|
|
10037
|
+
});
|
|
10038
|
+
}
|
|
10039
|
+
function buildPeakMapCacheKey(assetPath, fingerprint) {
|
|
10040
|
+
const name = assetPath.replace(/[/\\]/g, "_");
|
|
10041
|
+
return `${PEAK_MAP_CACHE_VERSION}_${name}_${fingerprint.size}-${Math.round(fingerprint.mtimeMs)}.json`;
|
|
10042
|
+
}
|
|
10043
|
+
var decodesInFlight = /* @__PURE__ */ new Map();
|
|
10044
|
+
function decodeOnce(cachePath, mediaPath, decode) {
|
|
10045
|
+
const pending = decodesInFlight.get(cachePath);
|
|
10046
|
+
if (pending) return pending;
|
|
10047
|
+
const started = decode(mediaPath).finally(() => decodesInFlight.delete(cachePath));
|
|
10048
|
+
decodesInFlight.set(cachePath, started);
|
|
10049
|
+
return started;
|
|
10050
|
+
}
|
|
10051
|
+
function readCachedBins(cacheDir, cachePath) {
|
|
10052
|
+
try {
|
|
10053
|
+
if (!isWaveformCacheDirectory(cacheDir) || !existsSync10(cachePath)) return null;
|
|
10054
|
+
const parsed = JSON.parse(readFileSync12(cachePath, "utf-8"));
|
|
10055
|
+
return Array.isArray(parsed) && parsed.every((n) => typeof n === "number") ? parsed : null;
|
|
10056
|
+
} catch {
|
|
10057
|
+
return null;
|
|
10058
|
+
}
|
|
10059
|
+
}
|
|
10060
|
+
function registerPeakRoutes(api, adapter, decode = decodePeakMap) {
|
|
10061
|
+
api.get("/projects/:id/peaks/*", async (c) => {
|
|
10062
|
+
const project = await adapter.resolveProject(c.req.param("id"));
|
|
10063
|
+
if (!project) return c.json({ error: "not found" }, 404);
|
|
10064
|
+
const assetPath = requestSubPath(c.req.url, "projects/:id/peaks");
|
|
10065
|
+
const mediaPath = resolve6(project.dir, assetPath);
|
|
10066
|
+
if (!isWithinProjectRoot(project.dir, mediaPath))
|
|
10067
|
+
return c.json({ error: "file not found" }, 404);
|
|
10068
|
+
const stats = statSync9(mediaPath, { throwIfNoEntry: false });
|
|
10069
|
+
if (!stats?.isFile()) return c.json({ error: "file not found" }, 404);
|
|
10070
|
+
const cacheDir = join14(project.dir, ".waveform-cache");
|
|
10071
|
+
const cachePath = join14(cacheDir, buildPeakMapCacheKey(assetPath, stats));
|
|
10072
|
+
const cached = readCachedBins(cacheDir, cachePath);
|
|
10073
|
+
if (cached) return c.json({ binSeconds: PEAK_BIN_SECONDS, bins: cached });
|
|
10074
|
+
let bins;
|
|
10075
|
+
try {
|
|
10076
|
+
bins = await decodeOnce(cachePath, mediaPath, decode);
|
|
10077
|
+
} catch {
|
|
10078
|
+
return c.json({ error: "failed to decode audio" }, 500);
|
|
10079
|
+
}
|
|
10080
|
+
try {
|
|
10081
|
+
writeWaveformCache(cachePath, bins);
|
|
10082
|
+
} catch {
|
|
10083
|
+
}
|
|
10084
|
+
return c.json({ binSeconds: PEAK_BIN_SECONDS, bins });
|
|
10085
|
+
});
|
|
10086
|
+
}
|
|
9577
10087
|
var MAX_FONT_RESULTS = 2e3;
|
|
9578
10088
|
var GOOGLE_FONTS_METADATA_URL = "https://fonts.google.com/metadata/fonts";
|
|
9579
10089
|
var GOOGLE_FONTS_FETCH_TIMEOUT_MS = 3e3;
|
|
@@ -9601,7 +10111,7 @@ var GOOGLE_FONT_FALLBACKS = [
|
|
|
9601
10111
|
"Outfit",
|
|
9602
10112
|
"JetBrains Mono"
|
|
9603
10113
|
];
|
|
9604
|
-
function
|
|
10114
|
+
function isRecord2(value) {
|
|
9605
10115
|
return typeof value === "object" && value !== null;
|
|
9606
10116
|
}
|
|
9607
10117
|
function collectFontsFromDir(dir) {
|
|
@@ -9625,10 +10135,10 @@ function listInstalledFontFamilies() {
|
|
|
9625
10135
|
return cachedFonts;
|
|
9626
10136
|
}
|
|
9627
10137
|
function parseGoogleFontMetadata(value) {
|
|
9628
|
-
if (!
|
|
10138
|
+
if (!isRecord2(value) || !Array.isArray(value.familyMetadataList)) return [];
|
|
9629
10139
|
const families = [];
|
|
9630
10140
|
for (const entry of value.familyMetadataList) {
|
|
9631
|
-
if (!
|
|
10141
|
+
if (!isRecord2(entry) || typeof entry.family !== "string") continue;
|
|
9632
10142
|
families.push(entry.family);
|
|
9633
10143
|
}
|
|
9634
10144
|
return families;
|
|
@@ -9728,14 +10238,14 @@ function registerRegistryRoutes(api, adapter) {
|
|
|
9728
10238
|
}
|
|
9729
10239
|
});
|
|
9730
10240
|
}
|
|
9731
|
-
function
|
|
10241
|
+
function isRecord3(value) {
|
|
9732
10242
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9733
10243
|
}
|
|
9734
10244
|
function isFiniteNumber(value) {
|
|
9735
10245
|
return typeof value === "number" && Number.isFinite(value);
|
|
9736
10246
|
}
|
|
9737
10247
|
function isStringRecord(value) {
|
|
9738
|
-
return
|
|
10248
|
+
return isRecord3(value) && Object.values(value).every((v) => typeof v === "string");
|
|
9739
10249
|
}
|
|
9740
10250
|
function hasString(value, key) {
|
|
9741
10251
|
return typeof value[key] === "string";
|
|
@@ -9753,20 +10263,20 @@ function hasOptionalNumber(value, key) {
|
|
|
9753
10263
|
return value[key] === void 0 || isFiniteNumber(value[key]);
|
|
9754
10264
|
}
|
|
9755
10265
|
function isBoundingBox(value) {
|
|
9756
|
-
return
|
|
10266
|
+
return isRecord3(value) && ["x", "y", "width", "height"].every((key) => isFiniteNumber(value[key]));
|
|
9757
10267
|
}
|
|
9758
10268
|
function isTarget(value) {
|
|
9759
|
-
if (!
|
|
10269
|
+
if (!isRecord3(value)) return false;
|
|
9760
10270
|
return hasOptionalNullableString(value, "id") && hasOptionalString(value, "hfId") && hasOptionalString(value, "selector") && hasOptionalNumber(value, "selectorIndex");
|
|
9761
10271
|
}
|
|
9762
10272
|
function isTextField(value) {
|
|
9763
|
-
return
|
|
10273
|
+
return isRecord3(value) && hasRequiredStrings(value, ["key", "label", "value", "tagName"]) && ["self", "child", "text-node"].includes(value.source);
|
|
9764
10274
|
}
|
|
9765
10275
|
function isTextFields(value) {
|
|
9766
10276
|
return Array.isArray(value) && value.every(isTextField);
|
|
9767
10277
|
}
|
|
9768
10278
|
function isSelectionSnapshot(value) {
|
|
9769
|
-
if (!
|
|
10279
|
+
if (!isRecord3(value)) return false;
|
|
9770
10280
|
const checks = [
|
|
9771
10281
|
value.schemaVersion === 1 && hasRequiredStrings(value, [
|
|
9772
10282
|
"projectId",
|
|
@@ -9784,7 +10294,7 @@ function isSelectionSnapshot(value) {
|
|
|
9784
10294
|
isStringRecord(value.inlineStyles),
|
|
9785
10295
|
isStringRecord(value.computedStyles),
|
|
9786
10296
|
isTextFields(value.textFields),
|
|
9787
|
-
|
|
10297
|
+
isRecord3(value.capabilities)
|
|
9788
10298
|
];
|
|
9789
10299
|
return checks.every(Boolean);
|
|
9790
10300
|
}
|
|
@@ -9808,7 +10318,7 @@ function registerSelectionRoutes(api, adapter) {
|
|
|
9808
10318
|
} catch {
|
|
9809
10319
|
return c.json({ error: "invalid json" }, 400);
|
|
9810
10320
|
}
|
|
9811
|
-
if (!
|
|
10321
|
+
if (!isRecord3(body) || !("selection" in body)) {
|
|
9812
10322
|
return c.json({ error: "missing selection" }, 400);
|
|
9813
10323
|
}
|
|
9814
10324
|
if (body.selection === null) {
|
|
@@ -9860,7 +10370,7 @@ function uniqueAssetPath(projectDir, assetPath, taken) {
|
|
|
9860
10370
|
const ext = extname2(assetPath);
|
|
9861
10371
|
const withoutExt = assetPath.slice(0, -ext.length);
|
|
9862
10372
|
let candidate = assetPath;
|
|
9863
|
-
for (let index = 2; taken.has(candidate) ||
|
|
10373
|
+
for (let index = 2; taken.has(candidate) || existsSync11(join15(projectDir, candidate)); index++) {
|
|
9864
10374
|
candidate = `${withoutExt}-${index}${ext}`;
|
|
9865
10375
|
}
|
|
9866
10376
|
return candidate;
|
|
@@ -9921,7 +10431,7 @@ function registerMediaRoutes(api, adapter, options = {}) {
|
|
|
9921
10431
|
}
|
|
9922
10432
|
const filePath = resolveWithinProject(project.dir, assetPath);
|
|
9923
10433
|
if (!filePath) return c.json({ error: "forbidden" }, 403);
|
|
9924
|
-
if (!
|
|
10434
|
+
if (!existsSync11(filePath)) return c.json({ error: "media not found" }, 404);
|
|
9925
10435
|
return c.json({ path: assetPath, metadata: await readMediaMetadata(filePath) });
|
|
9926
10436
|
});
|
|
9927
10437
|
api.post(
|
|
@@ -9943,7 +10453,7 @@ function registerMediaRoutes(api, adapter, options = {}) {
|
|
|
9943
10453
|
}
|
|
9944
10454
|
const inputPath = resolveWithinProject(project.dir, inputAssetPath);
|
|
9945
10455
|
if (!inputPath) return c.json({ error: "forbidden" }, 403);
|
|
9946
|
-
if (!
|
|
10456
|
+
if (!existsSync11(inputPath)) return c.json({ error: "input media not found" }, 404);
|
|
9947
10457
|
const inputIsVideo = isVideoPath(inputAssetPath);
|
|
9948
10458
|
const inputIsImage = isImagePath(inputAssetPath);
|
|
9949
10459
|
if (!inputIsVideo && !inputIsImage) {
|
|
@@ -9979,8 +10489,8 @@ function registerMediaRoutes(api, adapter, options = {}) {
|
|
|
9979
10489
|
return c.json({ error: "forbidden" }, 403);
|
|
9980
10490
|
}
|
|
9981
10491
|
}
|
|
9982
|
-
mkdirWithinProject(project.dir,
|
|
9983
|
-
if (backgroundOutputPath) mkdirWithinProject(project.dir,
|
|
10492
|
+
mkdirWithinProject(project.dir, dirname6(outputPath));
|
|
10493
|
+
if (backgroundOutputPath) mkdirWithinProject(project.dir, dirname6(backgroundOutputPath));
|
|
9984
10494
|
const jobId = makeJobId(project.id, mediaJobs);
|
|
9985
10495
|
const state = adapter.startBackgroundRemoval({
|
|
9986
10496
|
project,
|
|
@@ -10036,10 +10546,10 @@ function registerMediaRoutes(api, adapter, options = {}) {
|
|
|
10036
10546
|
});
|
|
10037
10547
|
}
|
|
10038
10548
|
function readGlobalAssets(home = homedir2()) {
|
|
10039
|
-
const manifestPath =
|
|
10040
|
-
if (!
|
|
10549
|
+
const manifestPath = join16(home, ".media", "manifest.jsonl");
|
|
10550
|
+
if (!existsSync12(manifestPath)) return [];
|
|
10041
10551
|
const out = [];
|
|
10042
|
-
for (const line of
|
|
10552
|
+
for (const line of readFileSync13(manifestPath, "utf8").split("\n")) {
|
|
10043
10553
|
if (!line.trim()) continue;
|
|
10044
10554
|
try {
|
|
10045
10555
|
const rec = JSON.parse(line);
|
|
@@ -10222,6 +10732,9 @@ function createStudioApi(adapter) {
|
|
|
10222
10732
|
registerSelectionRoutes(api, adapter);
|
|
10223
10733
|
registerMediaRoutes(api, adapter);
|
|
10224
10734
|
registerWaveformRoutes(api, adapter);
|
|
10735
|
+
registerFreezeFrameRoutes(api, adapter);
|
|
10736
|
+
registerLoudnessRoutes(api, adapter);
|
|
10737
|
+
registerPeakRoutes(api, adapter);
|
|
10225
10738
|
registerFontRoutes(api);
|
|
10226
10739
|
registerRegistryRoutes(api, adapter);
|
|
10227
10740
|
registerGlobalAssetRoutes(api);
|
|
@@ -10237,23 +10750,23 @@ function duplicateElementInHtml(source, target, newId, at) {
|
|
|
10237
10750
|
if (duration === null || numericAttribute(element, "data-start") === null) {
|
|
10238
10751
|
return { html: source, matched: false, newId: null };
|
|
10239
10752
|
}
|
|
10240
|
-
const
|
|
10753
|
+
const uniqueId2 = nextUniqueId(document2, newId);
|
|
10241
10754
|
rippleElements(document2, element, at, duration, track);
|
|
10242
10755
|
const clone = element.cloneNode(true);
|
|
10243
10756
|
if (!isHTMLElement(clone)) return { html: source, matched: false, newId: null };
|
|
10244
|
-
clone.setAttribute("id",
|
|
10757
|
+
clone.setAttribute("id", uniqueId2);
|
|
10245
10758
|
dedupeClonedCompositionId(document2, clone);
|
|
10246
10759
|
stripStableIds(clone);
|
|
10247
10760
|
clone.setAttribute("data-start", String(at));
|
|
10248
10761
|
element.parentElement.insertBefore(clone, element.nextSibling);
|
|
10249
10762
|
const html = wrappedFragment ? document2.body.innerHTML || "" : document2.toString();
|
|
10250
|
-
return { html: ensureHfIds(html), matched: true, newId:
|
|
10763
|
+
return { html: ensureHfIds(html), matched: true, newId: uniqueId2 };
|
|
10251
10764
|
}
|
|
10252
10765
|
function nextUniqueId(document2, newId) {
|
|
10253
|
-
let
|
|
10766
|
+
let uniqueId2 = newId;
|
|
10254
10767
|
let suffix = 2;
|
|
10255
|
-
while (document2.getElementById(
|
|
10256
|
-
return
|
|
10768
|
+
while (document2.getElementById(uniqueId2)) uniqueId2 = `${newId}-${suffix++}`;
|
|
10769
|
+
return uniqueId2;
|
|
10257
10770
|
}
|
|
10258
10771
|
function rippleElements(document2, element, at, duration, track) {
|
|
10259
10772
|
for (const candidate of Array.from(document2.querySelectorAll("[data-start][data-duration]"))) {
|
|
@@ -10278,13 +10791,13 @@ function numericAttribute(element, name) {
|
|
|
10278
10791
|
return Number.isFinite(value) ? value : null;
|
|
10279
10792
|
}
|
|
10280
10793
|
function createPreviewDocumentStore(projectDir, salt) {
|
|
10281
|
-
const dir =
|
|
10282
|
-
const fileFor = (key) =>
|
|
10794
|
+
const dir = join17(projectDir, ".hyperframes", "preview");
|
|
10795
|
+
const fileFor = (key) => join17(dir, `${createHash5("sha256").update(`${salt}
|
|
10283
10796
|
${key}`).digest("hex").slice(0, 32)}.html`);
|
|
10284
10797
|
return {
|
|
10285
10798
|
read(key) {
|
|
10286
10799
|
try {
|
|
10287
|
-
return
|
|
10800
|
+
return readFileSync14(fileFor(key), "utf-8");
|
|
10288
10801
|
} catch {
|
|
10289
10802
|
return null;
|
|
10290
10803
|
}
|
|
@@ -10295,7 +10808,7 @@ ${key}`).digest("hex").slice(0, 32)}.html`);
|
|
|
10295
10808
|
const file = fileFor(key);
|
|
10296
10809
|
replaceFileAtomically(file, html, 420);
|
|
10297
10810
|
for (const name of readdirSync5(dir)) {
|
|
10298
|
-
if (
|
|
10811
|
+
if (join17(dir, name) !== file) rmSync5(join17(dir, name), { force: true });
|
|
10299
10812
|
}
|
|
10300
10813
|
} catch {
|
|
10301
10814
|
}
|