@tikagent/video-editor-cli 1.5.0-preview.1 → 1.5.0-preview.3

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 (39) hide show
  1. package/dist/bin/tik-video-editor-cli.js +1 -1
  2. package/dist/lib/asr.js +1 -1
  3. package/dist/lib/auth.js +1 -1
  4. package/dist/lib/browser.js +1 -1
  5. package/dist/lib/cli.js +1 -1
  6. package/dist/lib/export-progress.js +1 -1
  7. package/dist/lib/import-video.js +1 -1
  8. package/dist/lib/media.js +1 -1
  9. package/dist/lib/otlp.js +1 -0
  10. package/dist/lib/storage.js +1 -1
  11. package/dist/lib/telemetry.js +1 -0
  12. package/dist/runtime/app.js +1 -1
  13. package/dist/runtime/cli/lib/browser.js +1 -1
  14. package/dist/runtime/cli/lib/otlp.js +1 -0
  15. package/dist/runtime/cli/lib/telemetry.js +1 -0
  16. package/dist/runtime/delivery.js +1 -0
  17. package/dist/runtime/encode-profiles.js +1 -0
  18. package/dist/runtime/encoding-profiles.json +284 -0
  19. package/dist/runtime/export-audio.js +1 -1
  20. package/dist/runtime/export-cache.js +1 -1
  21. package/dist/runtime/export-decode.js +1 -0
  22. package/dist/runtime/export-delivery.js +1 -0
  23. package/dist/runtime/export-pipeline.js +1 -0
  24. package/dist/runtime/export-worker.js +1 -1
  25. package/dist/runtime/i18n.js +1 -1
  26. package/dist/runtime/index.html +49 -1
  27. package/dist/runtime/mp4-demux.js +1 -0
  28. package/dist/runtime/optimized-encoder-worker.js +1 -1
  29. package/dist/runtime/optimized-export.js +1 -1
  30. package/dist/runtime/project-store.js +1 -1
  31. package/dist/runtime/server.js +1 -1
  32. package/dist/runtime/style.css +45 -0
  33. package/dist/runtime/timeline.js +1 -1
  34. package/dist/runtime/webcodecs-export.js +1 -0
  35. package/package.json +2 -3
  36. package/scripts/build-package.js +0 -69
  37. package/scripts/next-version.js +0 -56
  38. package/scripts/pack-runtime.js +0 -26
  39. package/scripts/release-channel.js +0 -115
@@ -1 +1 @@
1
- "use strict";const e=require("fs"),r=require("os"),o=require("path"),t=require("http"),n=require("https"),{spawn:s}=require("./processes"),{Transform:i}=require("stream"),{pipeline:a}=require("stream/promises"),{extractZip:c}=require("./browser-zip"),l="153.0.8010.52";function m(e=process.platform,r=process.arch){return{"darwin-arm64":"mac-arm64","darwin-x64":"mac-x64","linux-x64":"linux64","linux-arm64":"linux-arm64","win32-x64":"win64","win32-ia32":"win32"}[`${e}-${r}`]}function u(e){return o.join("chrome-"+e,e.startsWith("mac-")?"Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing":e.startsWith("win")?"chrome.exe":"chrome")}function w(r){try{return!!e.statSync(r).isFile()&&(e.accessSync(r,"win32"===process.platform?e.constants.F_OK:e.constants.X_OK),!0)}catch{return!1}}function d(e){if(o.isAbsolute(e)||/[/\\]/.test(e))return w(o.resolve(e))?o.resolve(e):null;for(const r of(process.env.PATH||"").split(o.delimiter).filter(Boolean))for(const t of"win32"===process.platform?["",".exe"]:[""]){const n=o.resolve(r,e+t);if(w(n))return n}return null}function p(){return["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome","/Applications/Chromium.app/Contents/MacOS/Chromium",...[process.env.PROGRAMFILES,process.env["PROGRAMFILES(X86)"],process.env.LOCALAPPDATA].filter(Boolean).map(e=>o.join(e,"Google/Chrome/Application/chrome.exe")),"google-chrome","google-chrome-stable","chromium","chromium-browser","chrome"]}async function h(r,o,t){const s=new AbortController,c=setTimeout(()=>s.abort(),9e5);try{const c=await async function e(r,o=0){const t=new URL(r);if("https:"!==t.protocol||t.username||t.password)throw new Error("Browser downloads require an HTTPS URL without credentials");return new Promise((r,i)=>{const a=n.get(t,{signal:s.signal,timeout:3e4},n=>{if(n.on("error",i),[301,302,303,307,308].includes(n.statusCode)){if(n.resume(),!n.headers.location||o>=5)return i(new Error("Too many browser download redirects"));try{r(e(new URL(n.headers.location,t),o+1))}catch(e){i(e)}}else 200!==n.statusCode?(n.resume(),i(new Error(`Browser download returned HTTP ${n.statusCode}`))):r(n)});a.on("timeout",()=>a.destroy(new Error("Browser download timed out"))),a.on("error",i)})}(r),l=Number(c.headers["content-length"]||0);let m=0,u=Date.now();const w=new i({transform(e,r,o){if(m+=e.length,m>536870912)return o(new Error("Browser download exceeds 512 MiB"));Date.now()-u>2e3&&(t(`Downloading browser: ${Math.round(m/1048576)}${l?"/"+Math.round(l/1048576):""} MiB`),u=Date.now()),o(null,e)}});if(await a(c,w,e.createWriteStream(o,{flags:"wx"}),{signal:s.signal}),!m||l&&m!==l)throw new Error("Incomplete browser download")}finally{clearTimeout(c),s.abort()}}async function f(n){const i=e.mkdtempSync(o.join(r.tmpdir(),"tik-browser-check-")),a=require("crypto").randomBytes(16).toString("hex");let c,l,m,u,w="";const d=new Promise(e=>{u=e}),p=t.createServer((e,r)=>{e.url==="/"+a?(r.writeHead(200,{"Content-Type":"text/html"}),r.end(`<script>fetch("/${a}/ready")<\/script>`)):e.url===`/${a}/ready`?(r.end("ok"),u()):(r.writeHead(404),r.end())});try{await new Promise((e,r)=>{p.once("error",r),p.listen(0,"127.0.0.1",e)}),c=s(n,["--headless=new","--no-first-run","--no-default-browser-check",..."darwin"===process.platform?["--use-mock-keychain"]:[],"--user-data-dir="+i,`http://127.0.0.1:${p.address().port}/${a}`],{stdio:["ignore","ignore","pipe"],windowsHide:!0}),l=new Promise(e=>c.once("close",e)),c.stderr.on("data",e=>{w=(w+e).slice(-600)}),await Promise.race([d,new Promise((e,r)=>{c.once("error",r),c.once("close",e=>r(new Error(`Chrome exited (${e})`))),m=setTimeout(()=>r(new Error("Chrome startup timed out")),3e4)})])}catch(e){throw new Error(`Downloaded Chrome could not run: ${e.message}. Check OS compatibility and, on Linux, required system libraries. ${w}`)}finally{if(clearTimeout(m),c&&null===c.exitCode&&null===c.signalCode){c.kill();const e=setTimeout(()=>c.kill("SIGKILL"),3e3);await l,clearTimeout(e)}p.closeAllConnections?.(),await new Promise(e=>p.close(e)),e.rmSync(i,{recursive:!0,force:!0})}}module.exports={ensureBrowser:async function(t,{cacheRoot:n=o.join(r.homedir(),".tik-video-editor-cli","browsers"),env:s=process.env,platform:i=process.platform,arch:a=process.arch,candidates:y=p(),download:g=h,verify:C=f,log:b=e=>process.stderr.write(e+"\n")}={}){const x=t||s.CHROME_PATH;if(x){const e=d(x);if(!e)throw new Error("Browser is not executable: "+x+"; fix --browser / CHROME_PATH or unset it for automatic setup");return e}const E=m(i,a),A=E&&o.join(n,l,E),T=E&&o.join(A,u(E)),$=()=>{try{return w(T)&&e.readFileSync(o.join(A,".complete"),"utf8")===l}catch{return!1}};if(E&&$())return T;for(const e of y){const r=d(e);if(r)return r}if(!E)throw new Error(`Automatic browser setup is unavailable on ${i}/${a}; pass --browser <path> or set CHROME_PATH`);const S=`${(s.FABLECUT_BROWSER_DOWNLOAD_BASE_URL||"https://cdn.npmmirror.com/binaries/chrome-for-testing").replace(/\/+$/,"")}/${l}/${E}/chrome-${E}.zip`,v=o.dirname(A);await e.promises.mkdir(v,{recursive:!0});const B=await e.promises.mkdtemp(o.join(v,".install-"));try{b(`Preparing Chrome for Testing ${l} (${E}); this download is cached for future exports.`);const r=o.join(B,"browser.zip"),t=o.join(B,"unpacked");await g(S,r,b),await e.promises.mkdir(t),b("Extracting browser…"),await c(r,t);const n=o.join(t,u(E));if(!w(n))throw new Error("Browser archive is missing its executable");if(await C(n),await e.promises.writeFile(o.join(t,".complete"),l),!$())try{await e.promises.rename(t,A)}catch(e){if(!$())throw new Error(`${e.message}; remove the incomplete cache at ${A} and retry`)}return b("Browser ready."),T}catch(e){throw new Error(`Automatic browser setup failed: ${e.message}. Retry export, set FABLECUT_BROWSER_DOWNLOAD_BASE_URL to a trusted HTTPS mirror, or use --browser <path>.`)}finally{await e.promises.rm(B,{recursive:!0,force:!0})}},downloadArchive:h,verifyBrowser:f,platformKey:m,executable:u,VERSION:l};
1
+ "use strict";const e=require("fs"),r=require("os"),o=require("path"),t=require("http"),n=require("https"),{spawn:s}=require("./processes"),{Transform:i}=require("stream"),{pipeline:a}=require("stream/promises"),{extractZip:c}=require("./browser-zip"),l="153.0.8010.52";function m(e=process.platform,r=process.arch){return{"darwin-arm64":"mac-arm64","darwin-x64":"mac-x64","linux-x64":"linux64","linux-arm64":"linux-arm64","win32-x64":"win64","win32-ia32":"win32"}[`${e}-${r}`]}function u(e){return o.join("chrome-"+e,e.startsWith("mac-")?"Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing":e.startsWith("win")?"chrome.exe":"chrome")}function w(r){try{return!!e.statSync(r).isFile()&&(e.accessSync(r,"win32"===process.platform?e.constants.F_OK:e.constants.X_OK),!0)}catch{return!1}}function d(e){if(o.isAbsolute(e)||/[/\\]/.test(e))return w(o.resolve(e))?o.resolve(e):null;for(const r of(process.env.PATH||"").split(o.delimiter).filter(Boolean))for(const t of"win32"===process.platform?["",".exe"]:[""]){const n=o.resolve(r,e+t);if(w(n))return n}return null}function p(){return["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome","/Applications/Chromium.app/Contents/MacOS/Chromium",...[process.env.PROGRAMFILES,process.env["PROGRAMFILES(X86)"],process.env.LOCALAPPDATA].filter(Boolean).map(e=>o.join(e,"Google/Chrome/Application/chrome.exe")),"google-chrome","google-chrome-stable","chromium","chromium-browser","chrome"]}async function h(r,o,t){const s=new AbortController,c=setTimeout(()=>s.abort(),9e5);try{const c=await async function e(r,o=0){const t=new URL(r);if("https:"!==t.protocol||t.username||t.password)throw new Error("Browser downloads require an HTTPS URL without credentials");return new Promise((r,i)=>{const a=n.get(t,{signal:s.signal,timeout:3e4},n=>{if(n.on("error",i),[301,302,303,307,308].includes(n.statusCode)){if(n.resume(),!n.headers.location||o>=5)return i(new Error("Too many browser download redirects"));try{r(e(new URL(n.headers.location,t),o+1))}catch(e){i(e)}}else 200!==n.statusCode?(n.resume(),i(new Error(`Browser download returned HTTP ${n.statusCode}`))):r(n)});a.on("timeout",()=>a.destroy(new Error("Browser download timed out"))),a.on("error",i)})}(r),l=Number(c.headers["content-length"]||0);let m=0,u=Date.now();const w=new i({transform(e,r,o){if(m+=e.length,m>536870912)return o(new Error("Browser download exceeds 512 MiB"));Date.now()-u>2e3&&(t(`Downloading browser: ${Math.round(m/1048576)}${l?"/"+Math.round(l/1048576):""} MiB`),u=Date.now()),o(null,e)}});if(await a(c,w,e.createWriteStream(o,{flags:"wx"}),{signal:s.signal}),!m||l&&m!==l)throw new Error("Incomplete browser download")}finally{clearTimeout(c),s.abort()}}async function f(n){const i=e.mkdtempSync(o.join(r.tmpdir(),"tik-browser-check-")),a=require("crypto").randomBytes(16).toString("hex");let c,l,m,u,w="";const d=new Promise(e=>{u=e}),p=t.createServer((e,r)=>{e.url==="/"+a?(r.writeHead(200,{"Content-Type":"text/html"}),r.end(`<script>fetch("/${a}/ready")<\/script>`)):e.url===`/${a}/ready`?(r.end("ok"),u()):(r.writeHead(404),r.end())});try{await new Promise((e,r)=>{p.once("error",r),p.listen(0,"127.0.0.1",e)}),c=s(n,["--headless=new","--no-first-run","--no-default-browser-check",..."darwin"===process.platform?["--use-mock-keychain"]:[],"--user-data-dir="+i,`http://127.0.0.1:${p.address().port}/${a}`],{stdio:["ignore","ignore","pipe"],windowsHide:!0}),l=new Promise(e=>c.once("close",e)),c.stderr.on("data",e=>{w=(w+e).slice(-600)}),await Promise.race([d,new Promise((e,r)=>{c.once("error",r),c.once("close",e=>r(new Error(`Chrome exited (${e})`))),m=setTimeout(()=>r(new Error("Chrome startup timed out")),3e4)})])}catch(e){throw new Error(`Downloaded Chrome could not run: ${e.message}. Check OS compatibility and, on Linux, required system libraries. ${w}`)}finally{if(clearTimeout(m),c&&null===c.exitCode&&null===c.signalCode){c.kill();const e=setTimeout(()=>c.kill("SIGKILL"),3e3);await l,clearTimeout(e)}p.closeAllConnections?.(),await new Promise(e=>p.close(e)),e.rmSync(i,{recursive:!0,force:!0})}}function y(e,r){try{require("./telemetry").reportError("BrowserSetupFailed",e,r)}catch{}}module.exports={ensureBrowser:async function(t,{cacheRoot:n=o.join(r.homedir(),".tik-video-editor-cli","browsers"),env:s=process.env,platform:i=process.platform,arch:a=process.arch,candidates:g=p(),download:C=h,verify:b=f,log:x=e=>process.stderr.write(e+"\n")}={}){const E=t||s.CHROME_PATH;if(E){const e=d(E);if(!e){const e=new Error("Browser is not executable: "+E+"; fix --browser / CHROME_PATH or unset it for automatic setup");throw y(e,{source:"explicit"}),e}return e}const A=m(i,a),T=A&&o.join(n,l,A),$=A&&o.join(T,u(A)),S=()=>{try{return w($)&&e.readFileSync(o.join(T,".complete"),"utf8")===l}catch{return!1}};if(A&&S())return $;for(const e of g){const r=d(e);if(r)return r}if(!A)throw new Error(`Automatic browser setup is unavailable on ${i}/${a}; pass --browser <path> or set CHROME_PATH`);const B=`${(s.FABLECUT_BROWSER_DOWNLOAD_BASE_URL||"https://cdn.npmmirror.com/binaries/chrome-for-testing").replace(/\/+$/,"")}/${l}/${A}/chrome-${A}.zip`,v=o.dirname(T);await e.promises.mkdir(v,{recursive:!0});const O=await e.promises.mkdtemp(o.join(v,".install-"));try{x(`Preparing Chrome for Testing ${l} (${A}); this download is cached for future exports.`);const r=o.join(O,"browser.zip"),t=o.join(O,"unpacked");await C(B,r,x),await e.promises.mkdir(t),x("Extracting browser…"),await c(r,t);const n=o.join(t,u(A));if(!w(n))throw new Error("Browser archive is missing its executable");if(await b(n),await e.promises.writeFile(o.join(t,".complete"),l),!S())try{await e.promises.rename(t,T)}catch(e){if(!S())throw new Error(`${e.message}; remove the incomplete cache at ${T} and retry`)}return x("Browser ready."),$}catch(e){throw y(e,{source:"download",platform:A}),new Error(`Automatic browser setup failed: ${e.message}. Retry export, set FABLECUT_BROWSER_DOWNLOAD_BASE_URL to a trusted HTTPS mirror, or use --browser <path>.`)}finally{await e.promises.rm(O,{recursive:!0,force:!0})}},downloadArchive:h,verifyBrowser:f,platformKey:m,executable:u,VERSION:l};
@@ -0,0 +1 @@
1
+ "use strict";function e(e){return"boolean"==typeof e?{boolValue:e}:"number"==typeof e&&Number.isFinite(e)?Number.isSafeInteger(e)?{intValue:String(e)}:{doubleValue:e}:"string"==typeof e&&e?{stringValue:e}:null}function t(t){const n=[];if(!t||"object"!=typeof t||Array.isArray(t))return n;for(const o of Object.keys(t)){const a=e(t[o]);a&&n.push({key:String(o),value:a})}return n}function n(e){const n={traceId:e.traceId,spanId:e.spanId,name:e.name,kind:e.kind||1,startTimeUnixNano:String(e.startTimeUnixNano),endTimeUnixNano:String(e.endTimeUnixNano||e.startTimeUnixNano),attributes:t(e.attributes),flags:null==e.flags?1:e.flags,status:e.status||{code:0}};return e.parentSpanId&&(n.parentSpanId=e.parentSpanId),e.events?.length&&(n.events=e.events.map(e=>({timeUnixNano:String(e.timeUnixNano),name:e.name,attributes:t(e.attributes)}))),n}function o(e,o,a={name:"tik-video-editor-cli"}){return{resourceSpans:[{resource:{attributes:t(e)},scopeSpans:[{scope:{name:a.name||"tik-video-editor-cli",...a.version?{version:a.version}:{}},spans:o.map(n)}]}]}}async function a(e,t,n,{fetchImpl:o,signal:a}={}){const r=o||globalThis.fetch;if("function"!=typeof r)throw new Error("fetch unavailable");const i=await r(e,{method:"POST",headers:{"Content-Type":"application/json",...t||{}},body:JSON.stringify(n),signal:a||AbortSignal.timeout(2500)});if(!i.ok)throw new Error("HTTP "+i.status);try{await(i.body?.cancel?.())}catch{}return i}module.exports={attributeValue:e,toAttributes:t,toOtlpSpan:n,encodeExport:o,postExport:a,createTraceExporter:function(e){const t=e.batchSize||64,n=null==e.delayMs?1e3:e.delayMs;let r=[],i=null,s=Promise.resolve(),u=null;function c(){i&&(clearTimeout(i),i=null)}function l(){if(!r.length)return null;const t=r.splice(0,r.length),n="function"==typeof e.scope?e.scope():e.scope;return o(e.resource(),t,n)}function p(t){const n=s.then(async()=>{c();const n=l();if(n){u={document:n,done:!1,queued:!1};try{const o="function"==typeof e.fetchImpl?e.fetchImpl():e.fetchImpl;await a(e.endpoint(),e.headers(),n,{fetchImpl:o,signal:t}),u.done=!0}catch(t){u&&(u.done=!0),u?.queued||(u&&(u.queued=!0),e.onFailure(n,t))}finally{u=null}}});return s=n.catch(()=>{}),n}return{add:e=>(r.push(e),r.length>=t?p():(i||n<0||(i=setTimeout(()=>{i=null,p().catch(()=>{})},n),i.unref?.()),Promise.resolve())),flush:p,salvage(){c(),u&&!u.queued&&(u.queued=!0,e.onFailure(u.document));const t=l();t&&e.onFailure(t)},stop(){c(),r=[]},pending:()=>r.length}}};
@@ -0,0 +1 @@
1
+ "use strict";const e=require("node:crypto"),{execFile:t}=require("node:child_process"),r=require("node:fs"),n=require("node:os"),o=require("node:path"),s=require("./otlp"),i="https://proj-xtrace-1e4934416a1cedff5956b1291b66128-cn-hangzhou.cn-hangzhou.log.aliyuncs.com/apm/trace/opentelemetry/v1/traces",a={"x-arms-license-key":"dw8wc4ogzr@98f7fc56a7038eb","x-arms-project":"proj-xtrace-1e4934416a1cedff5956b1291b66128-cn-hangzhou","x-cms-workspace":"default-cms-1411252257529863-cn-hangzhou"},c=a["x-cms-workspace"],u=2e3,d=4096,l=72e5,p=5e3,m=4e3,f=new Set(["preparing-browser","preparing-media","rendering","finalizing"]),g={queued:6e4,starting:45e3,"preparing-browser":45e3,"preparing-media":45e3,rendering:3e4,finalizing:6e4},h=["wait","stats","stderr","activity","browserGpu","detail","metrics","stack","clipIds","timeSec","browser","exitCode","project","engine"],b=/^00-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})$/;let y={},k={},S=!1,v=null,I=null,j=null,w={},x=Promise.resolve(),E="",T=null,_=null,A=!1;function N(){return y.env||process.env}function M(){return o.join(y.home||n.homedir(),".tik-video-editor-cli")}function O(){return o.join(M(),"telemetry-state.json")}function F(){return o.join(M(),"telemetry-queue")}function C(e){try{const t=JSON.parse(r.readFileSync(e,"utf8").replace(/^\uFEFF/,""));return t&&"object"==typeof t&&!Array.isArray(t)?t:{}}catch{return{}}}function P(){return C(O())}function R(e){try{r.mkdirSync(M(),{recursive:!0,mode:448});const t={...P(),...e},n=O(),o=n+"."+process.pid+".tmp";r.writeFileSync(o,JSON.stringify(t)+"\n",{mode:384}),r.renameSync(o,n)}catch{}}function D(e){const t=String(e||"").trim();if(!t)return"";try{const e=new URL(t);return!["https:","http:"].includes(e.protocol)||e.username||e.password?"":e.href}catch{return""}}function L(e){const t={};for(const r of String(e||"").split(",")){const e=r.indexOf("=");if(!(e<=0))try{const n=decodeURIComponent(r.slice(0,e).trim()),o=decodeURIComponent(r.slice(e+1).trim());n&&(t[n]=o)}catch{}}return t}function U(e=N(),t=function(){return C(o.join(M(),"telemetry.json"))}()){const r={...a};if(t.headers&&"object"==typeof t.headers&&!Array.isArray(t.headers))for(const e of Object.keys(t.headers))r[e]=String(t.headers[e]);if(Object.assign(r,L(e.OTEL_EXPORTER_OTLP_TRACES_HEADERS)),"true"===String(e.OTEL_SDK_DISABLED||"").trim().toLowerCase()||!1===t.enabled)return{disabled:!0,endpoint:"",headers:r};let n=D(i);return null!=t.endpoint&&String(t.endpoint).trim()&&(n=D(t.endpoint),!n)||String(e.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT||"").trim()&&(n=D(e.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT),!n)?{disabled:!0,endpoint:"",headers:r}:{disabled:!1,endpoint:n,headers:r}}function $(){if((null!=N().NODE_TEST_CONTEXT||process.execArgv.includes("--test"))&&!y.env)return!1;const e=U();return!e.disabled&&""!==e.endpoint}function B(e){let t=String(e??"");const r=N();for(const e of[r.TIK_API_KEY,r.FABLECUT_TOKEN]){const r=String(e||"").trim();r&&(t=t.split(r).join("[redacted]"))}t=t.replace(/\bhttps?:\/\/[^\s]+/gi,e=>{try{const t=new URL(e);return t.username="",t.password="",t.search="",t.hash="",t.href}catch{return"[redacted-url]"}}),t=t.replace(/\bBearer\s+\S+/gi,"Bearer [redacted]"),t=t.replace(/\bsk-[A-Za-z0-9-]{8,}/g,"[redacted]"),t=t.replace(/\b[a-fA-F0-9]{64}\b/g,"[redacted]");const o=y.home||n.homedir();return o&&(t=t.split(o).join("~"),"win32"===process.platform&&(t=t.split(o.toLowerCase()).join("~"))),t}function z(e){if(!Array.isArray(e))return"";const t=[];for(const r of e){const e=String(r);e.startsWith("-")?t.push(e.split("=")[0]):t.length||t.push(e)}return t.join(" ").slice(0,500)}function J(e){if(!Array.isArray(e))return{command:"",subcommand:"",projectId:"",check:!1,help:!1};const t=[];let r="",n=!1,o=!1,s=!1;for(let i=0;i<e.length;i++){const a=String(e[i]??"");a&&("--check"===a?n=!0:"--help"===a||"-h"===a?o=!0:"--version"===a||"-v"===a?s=!0:"--project-id"===a&&i+1<e.length?r=String(e[++i]??"").trim():a.startsWith("--project-id=")?r=a.slice(13).trim():a.startsWith("-")||t.push(a))}return{command:t[0]||(s?"version":o?"help":""),subcommand:t[1]||"",projectId:r,check:n,help:o}}function V(e=k.command,t=k.rawArgv){const r=J(t),n=e||r.command;return!(n&&"version"!==n&&"help"!==n&&!r.help)||!("status"!==n||!r.check)||"storage"===n&&"info"===r.subcommand||"list-projects"===n||"auth"===n&&"status"===r.subcommand}function q(e){const t={};if(!e||"object"!=typeof e||Array.isArray(e))return t;for(const r of Object.keys(e)){if(Object.keys(t).length>=20)break;const n=String(r).slice(0,50),o=e[r];if("number"==typeof o&&Number.isFinite(o))t[n]=o;else if("boolean"==typeof o)t[n]=o?1:0;else if("string"==typeof o&&o)t[n]=B(o).slice(0,u);else{if(null==o||""===o)continue;try{t[n]=B(JSON.stringify(o)).slice(0,u)}catch{}}}return t}function G(e){if("string"==typeof e)return B(e).slice(0,d);if("number"==typeof e||"boolean"==typeof e||null==e)return e;if(Array.isArray(e))return e.slice(0,40).map(G);if("object"==typeof e){const t={};for(const r of Object.keys(e).slice(0,40))t[r]=G(e[r]);return t}return B(e)}function W(e){let t="";try{t=JSON.stringify(G(e))}catch{t=""}if(t&&"{}"!==t&&"null"!==t)return t.length>d?t.slice(0,d):t}function K(e){const t=b.exec(String(e||"").trim().toLowerCase());return t?/^0+$/.test(t[1])||/^0+$/.test(t[2])?null:{traceId:t[1],spanId:t[2],sampled:!(1&~Number.parseInt(t[3],16))}:null}function H(){return"function"==typeof y.now?y.now():Date.now()}function X(){return String(1000000n*BigInt(Math.trunc(H())))}function Q(e){const t=String(e||"").trim().slice(0,80);return!t||/[/\\]|\.\.|\s/.test(t)?"":t}function Y(e=k.projectId){const t=Q(e);if(!t)return null;const r=P().projectTraces;if(!r||"object"!=typeof r||Array.isArray(r))return null;const n=r[t];if(!n||"object"!=typeof n)return null;const o=String(n.traceId||"").toLowerCase(),s=String(n.spanId||"").toLowerCase();if(!/^[0-9a-f]{32}$/.test(o)||!/^[0-9a-f]{16}$/.test(s))return null;const i=Number(n.updatedAt)||0;return H()-i>l?null:{traceId:o,spanId:s,linked:!1!==n.linked}}function Z(e,t){const r=Q(e);if(!r||!t?.traceId||!t?.spanId)return;const n=P(),o=n.projectTraces&&"object"==typeof n.projectTraces&&!Array.isArray(n.projectTraces)?{...n.projectTraces}:{},s=H();for(const e of Object.keys(o))(!o[e]||s-(Number(o[e].updatedAt)||0)>l)&&delete o[e];o[r]={traceId:t.traceId,spanId:t.spanId,linked:!1!==t.linked,updatedAt:s};const i=Object.keys(o).sort((e,t)=>(Number(o[e]?.updatedAt)||0)-(Number(o[t]?.updatedAt)||0));for(;i.length>20;)delete o[i.shift()];R({projectTraces:o})}function ee(e){const t=String(e||"").trim().toLowerCase();return"x86_64"===t||"amd64"===t?"x64":"aarch64"===t?"arm64":String(e||"").trim()}function te(e,t,r){const n=ee(e);if(!n)return"";const o=ee(t),s=ee(r);return o&&o!==n?`${n}(rosetta:${o})`:s&&s!==n?`${n}(proc:${s})`:n}function re(){try{return String(n.cpus()?.[0]?.model||"").trim().slice(0,80)}catch{return""}}function ne(e=process.platform){return{darwin:"macOS",win32:"Windows",linux:"Linux"}[e]||e}function oe(e,t){if(!t)return"";const r=Number(t.bsize||t.frsize),n=Number(t.blocks)*r,o=Number(t.bavail)*r;if(!Number.isFinite(n)||n<=0)return"";const s=Math.max(0,Math.min(100,Math.round((n-o)/n*100)));return`${e}:${Math.round(n/1024**3)}G/${s}%`}function se(){const e=y.statfs||r.statfsSync;if("function"!=typeof e)return"";const t=[],s=function(){try{const e=require("./storage");return e.readRoot(e.configDir(y.home||n.homedir()))}catch{return o.join(M(),"storage")}}();let i=null;try{i=e(s);const r=oe("st",i);r&&t.push(r)}catch{i=null}const a=n.tmpdir();try{if(!i||!function(e,t,n=process.platform){try{return o.resolve(e)===o.resolve(t)||("win32"===n?o.parse(e).root.toLowerCase()===o.parse(t).root.toLowerCase():r.statSync(e).dev===r.statSync(t).dev)}catch{return!1}}(s,a)){const r=oe("tmp",e(a));r&&t.push(r)}}catch{}return t.join(";")}function ie(){if(y.channel)return y.channel;const e=L(N().OTEL_RESOURCE_ATTRIBUTES);if("managed"===e["tik.channel"]||"desktop"===e["tik.launcher"])return"managed";if(E)return E;const t=[o.join(__dirname,"..","package.json"),o.join(__dirname,"..","..","package.json"),o.join(__dirname,"..","..","..","package.json")];for(const e of t)try{if("@tikagent/video-editor-cli"!==JSON.parse(r.readFileSync(e,"utf8")).name)continue;let t=o.dirname(e);for(let e=0;e<4;e++){t=o.dirname(t);try{if("tikagent-managed-tik-video-editor-cli"===JSON.parse(r.readFileSync(o.join(t,"package.json"),"utf8")).name)return E="managed",E}catch{}}return E="standalone",E}catch{}return E="standalone",E}function ae(){const e=L(N().OTEL_RESOURCE_ATTRIBUTES)["tik.launcher"];return"desktop"===e||"standalone"===e?e:"managed"===ie()?"desktop":"standalone"}function ce(){const e=L(N().OTEL_RESOURCE_ATTRIBUTES),t=String(e["user.id"]||e["enduser.id"]||"").trim().slice(0,80);return t&&!/sk-|api[_-]?key|token/i.test(t)?(P().userName!==t&&R({userName:t}),t):String(P().userName||"").trim()}function ue(e=N()){return L(e.OTEL_RESOURCE_ATTRIBUTES)["deployment.environment"]||("test"===String(e.TIK_ENV||"").trim().toLowerCase()?"test":function(){if(null!=T)return T;let e=__dirname;for(let t=0;t<6;t++){try{if("fablecut"===JSON.parse(r.readFileSync(o.join(e,"package.json"),"utf8")).name)return T=!0,!0}catch{}const t=o.dirname(e);if(t===e)break;e=t}return T=!1,!1}()?"dev":"prod")}function de(){const e=String(N().FABLECUT_VERSION||"").trim();if(e)return e;const t=[o.join(__dirname,"..","package.json"),o.join(__dirname,"..","..","package.json"),o.join(__dirname,"..","..","..","package.json")];for(const e of t)try{const t=JSON.parse(r.readFileSync(e,"utf8"));if("@tikagent/video-editor-cli"===t.name&&t.version)return String(t.version)}catch{}return""}function le(){const t=P();if("string"==typeof t.deviceId&&t.deviceId.startsWith("uid_"))return t.deviceId;const r="uid_"+e.randomBytes(12).toString("hex");return R({deviceId:r}),r}function pe(e){const t=P()[e];return t&&"number"==typeof t.at?Date.now()-t.at>=(t.value||t.version||t.encoders?6048e5:864e5)?{}:t:{}}function me(){const e=N(),t=function(){if(j){try{j.memFreeMb=Math.round(n.freemem()/1048576)}catch{}return j.disk=se(),j}const e=(()=>{try{return n.cpus()||[]}catch{return[]}})();let t="";try{t="function"==typeof n.machine?n.machine():""}catch{t=""}const r=Number(e[0]?.speed);return j={cpuArch:te(n.arch(),t,process.arch),cpuCores:e.length||"",cpuMhz:r>0?r:"",cpuModel:re(),memTotalMb:Math.round(n.totalmem()/1048576)||"",memFreeMb:Math.round(n.freemem()/1048576)||"",disk:se(),locale:(()=>{try{return Intl.DateTimeFormat().resolvedOptions().locale||""}catch{return""}})()},j}(),r=U(),o=w.ffmpegVer?w:pe("ffmpeg"),s=w.gpu||pe("gpu").value||"",i=ce();return{"service.name":"tik-video-editor-cli","service.version":de(),"deployment.environment":ue(e),"acs.cms.workspace":r.headers["x-cms-workspace"]||c,"tik.role":k.role||"","tik.device_id":le(),"enduser.id":i,"user.id":i,"tik.channel":ie(),"tik.launcher":ae(),"tik.cpu.arch":t.cpuArch,"tik.cpu.cores":t.cpuCores,"tik.cpu.mhz":t.cpuMhz,"tik.cpu.model":t.cpuModel,"tik.mem.total_mb":t.memTotalMb,"tik.mem.free_mb":t.memFreeMb,"tik.disk":t.disk,"tik.locale":t.locale,"tik.gpu":s,"tik.ffmpeg.version":o.version||o.ffmpegVer||"","tik.ffprobe.version":o.probe||o.ffprobeVer||"","tik.hw.encoders":o.encoders||o.hwEncoders||"","tik.browser.gpu":w.browserGpu||k.browserGpu||"","tik.os":ne(),"tik.os.version":n.release(),"process.runtime.version":process.version,...L(e.OTEL_RESOURCE_ATTRIBUTES)}}function fe(e){return(String(e||"").split(/\r?\n/).find(Boolean)||"").replace(/\s+Copyright\b[\s\S]*$/i,"").trim().slice(0,160)}function ge(e){const t=["h264_nvenc","h264_qsv","h264_amf","h264_videotoolbox"].filter(t=>new RegExp("\\b"+t+"\\b").test(String(e||"")));return t.length?t.map(e=>e.replace(/^h264_/,"")).join(","):"none"}function he(e){const t=String(e||"").search(/[\[{]/);if(t<0)return null;try{return JSON.parse(String(e).slice(t))}catch{return null}}function be(e,r,n){const o=y.execFile||t;return new Promise(t=>{try{o(e,r,{encoding:"utf8",timeout:n,windowsHide:!0,maxBuffer:1048576},(e,r,n)=>{t({status:e?1:0,stdout:String(r||""),stderr:String(n||e?.message||"")})})}catch(e){t({status:1,stdout:"",stderr:e.message})}})}function ye(e){return(Array.isArray(e)?e:e?[e]:[]).slice(0,2).map(e=>{const t=String(e.Name||e.sppci_model||"").trim(),r=String(e.DriverVersion||"").trim();return t?r?`${t}(${r})`:t:""}).filter(Boolean).join(";").slice(0,200)}async function ke(e=process.platform){if("win32"===e){const e=o.join(process.env.SystemRoot||"C:\\Windows","System32","WindowsPowerShell","v1.0","powershell.exe"),t="Get-CimInstance Win32_VideoController | Select-Object Name,DriverVersion | ConvertTo-Json -Compress";return ye(he((await be(e,["-NoProfile","-NonInteractive","-Command",t],p)).stdout))}if("darwin"===e){const e=await be("system_profiler",["SPDisplaysDataType","-json"],p);return ye(he(e.stdout)?.SPDisplaysDataType)}const t=await be("lspci",["-mm"],p);return String(t.stdout||"").split(/\r?\n/).filter(e=>/VGA|3D|Display/i.test(e)).slice(0,2).map(e=>{const t=[...e.matchAll(/"([^"]*)"/g)].map(e=>e[1]);return[t[2],t[3]].filter(Boolean).join(" ")}).filter(Boolean).join(";").slice(0,200)}async function Se(){const e=await be("ffmpeg",["-version"],m),t=await be("ffprobe",["-version"],m),r=await be("ffmpeg",["-hide_banner","-encoders"],m),n=0===e.status&&e.stdout;return{version:n?fe(e.stdout):"",probe:0===t.status?fe(t.stdout):"",encoders:n?ge(r.stdout):""}}async function ve(e,t){const r=pe(e);if(r.at)return r;const n={...await t(),at:Date.now()};return R({[e]:n}),n}function Ie(e){e.attributes["tik.launcher"]=ae(),e.attributes["tik.trace.linked"]=e.linked?1:0;const t=ce();t&&(e.attributes["user.id"]=t),k.projectId&&!e.attributes["tik.project.id"]&&(e.attributes["tik.project.id"]=k.projectId),k.role&&(e.attributes["tik.role"]=k.role),k.command&&(e.attributes["tik.command"]=k.command),k.argvSummary&&(e.attributes["tik.argv"]=k.argvSummary)}function je(t,r={}){const n=r.parent||null,o={traceId:n?.traceId||e.randomBytes(16).toString("hex"),spanId:e.randomBytes(8).toString("hex"),parentSpanId:n?.spanId||"",name:String(t||"span").slice(0,120),kind:1,flags:1,startTimeUnixNano:X(),attributes:{...r.attributes||{}},events:[],linked:null!=r.linked?!!r.linked:!(!n||!n.linked),ended:!1};return Ie(o),o}function we(e){const t=e instanceof Error?e:new Error(B(e||"Error"));return{timeUnixNano:X(),name:"exception",attributes:{"exception.type":String(t.name||"Error").slice(0,120),"exception.message":B(t.message||"").slice(0,u),"exception.stacktrace":B(t.stack||"").slice(0,d)}}}function xe(e,t={}){if(!e||e.ended)return Promise.resolve(!1);if(e.ended=!0,e.endTimeUnixNano=X(),t.attributes&&Object.assign(e.attributes,t.attributes),t.events&&e.events.push(...t.events),t.error){const r=t.error instanceof Error?t.error:new Error(B(t.error));e.status={code:2,message:B(r.message||"").slice(0,u)},e.events.push(we(r))}else e.status=t.status||{code:1};return Ie(e),$()?((I||(I=s.createTraceExporter({resource:me,scope:()=>({name:"tik-video-editor-cli",version:de()}),endpoint:()=>U().endpoint,headers:()=>U().headers,fetchImpl:()=>y.fetch||globalThis.fetch,onFailure:e=>Ae(e)})),I).add(e),Promise.resolve(!0)):Promise.resolve(!1)}function Ee(){return v&&!v.ended?{traceId:v.traceId,spanId:v.spanId,linked:v.linked}:null}function Te(){if(v)return k.command&&"cli"===v.name&&(v.name=`cli ${k.command}`.slice(0,120)),Ie(v),v;const e=function(){const e=K(N().TRACEPARENT);return e?{traceId:e.traceId,spanId:e.spanId,linked:!0}:null}(),t=!e&&k.projectId?Y(k.projectId):null,r=e||t;return v=je(k.command?`cli ${k.command}`:"cli",{parent:r,linked:!!r,attributes:{"tik.trace.linked":r?1:0,...k.projectId?{"tik.project.id":k.projectId}:{}}}),k.projectId&&Z(k.projectId,e?{traceId:v.traceId,spanId:v.spanId,linked:!0}:t||{traceId:v.traceId,spanId:v.spanId,linked:!0}),v}function _e(e={}){if(!e.name)return Promise.resolve(!1);const t=process.memoryUsage(),r=je(e.name,{parent:Ee(),attributes:q({role:k.role,command:k.command,...e.group?{group:e.group}:{},...Number.isFinite(e.value)?{value:e.value}:{},...e.properties})}),n=W({rssMb:Math.round(t.rss/1048576),heapUsedMb:Math.round(t.heapUsed/1048576),...e.snapshots});return n&&(r.attributes["tik.snapshot"]=n),xe(r,{status:{code:1}}).then(()=>!0,()=>!1)}function Ae(t){try{r.mkdirSync(F(),{recursive:!0,mode:448});const n=r.readdirSync(F()).filter(e=>e.endsWith(".json")||e.includes(".sending-")).sort();for(;n.length>=50;)r.rmSync(o.join(F(),n.shift()),{force:!0});const s=o.join(F(),Date.now()+"-"+e.randomBytes(4).toString("hex")+".json");return r.writeFileSync(s,JSON.stringify(t),{mode:384,flag:"wx"}),s}catch{return""}}function Ne(e){const t=Number(String(e).split("-")[0]);return Number.isFinite(t)?t:0}function Me(e,t=process.pid,n=Date.now()){const s=o.basename(e),i=/\.sending-\d+$/.test(s);if(!i&&!s.endsWith(".json"))return"";if(i){let t=0;try{t=r.statSync(e).mtimeMs}catch{return""}if(n-t<6e5)return""}const a=s.replace(/\.json$/,"").replace(/\.sending-\d+$/,""),c=o.join(o.dirname(e),a+".sending-"+t);try{return r.renameSync(e,c),c}catch{return""}}async function Oe(e,t){const r=U(),n=y.fetch||globalThis.fetch;await s.postExport(r.endpoint,r.headers,e,{fetchImpl:n,signal:t})}function Fe(e){return _||(_=async function(e){if(!$())return;let t=[];try{t=r.readdirSync(F()).sort()}catch{return}let n=0;for(const s of t){if(e?.aborted||n>=10)return;const t=o.join(F(),s),i=Ne(s);if(!i||Date.now()-i>6048e5){r.rmSync(t,{force:!0});continue}const a=Me(t);if(!a)continue;let c;try{c=JSON.parse(r.readFileSync(a,"utf8"))}catch{r.rmSync(a,{force:!0});continue}try{await Oe(c,e),r.rmSync(a,{force:!0}),n+=1}catch{const e=a.replace(/\.sending-\d+$/,".json");try{e!==a&&r.renameSync(a,e)}catch{}return}}}(e)),_}function Ce(e,t){if(!e||e.done)return null;const r=g[e.state];if(!r)return null;const n=e.lastProgressAt??e.startedAt??t,o=Math.max(0,t-n);if(o<r)return null;const s="rendering"===e.state?o>=12e4:o>=2*r;return{state:e.state,idleMs:o,severe:s,threshold:r}}function Pe(e,t){if(!e||e.done)return!1;if(e.wait&&e.wait.reason)return!0;const r=e.lastProgressAt??e.startedAt??t,n=Math.max(0,t-r);return"rendering"===e.state?n>=1e4:n>=15e3&&Object.prototype.hasOwnProperty.call(g,e.state)}function Re(e){I&&I.stop(),y={...e},k={},S=!1,v=null,I=null,j=null,w={},x=Promise.resolve(),E="",T=null,_=null,A=!1}module.exports={EXPORT_WAIT_REASONS:["source-block","video-seek","source-image","frame-assets","audio-mix","encoder"],DEFAULT_ENDPOINT:i,DEFAULT_HEADERS:a,initTelemetry:function(e={}){if(k={...k,...e},Array.isArray(k.argv)){k.rawArgv=k.argv.slice();const e=J(k.argv);!k.command&&e.command&&(k.command=e.command),!k.projectId&&e.projectId&&(k.projectId=Q(e.projectId)),k.argvSummary=z(k.argv),delete k.argv}return!!$()&&(S||(S=!0,le(),ce(),function(){if(A||"cli"!==k.role||"managed"===ie())return;if(P().noticeShown)return void(A=!0);A=!0;const e=y.stderr||process.stderr;try{e.write('tik-video-editor-cli 会向阿里云 ARMS 上报命令名、导出摘要和机器信息,不含参数值与工程内容。关闭:设置 OTEL_SDK_DISABLED=true,或在 ~/.tik-video-editor-cli/telemetry.json 写入 {"enabled":false}。\n')}catch{}R({noticeShown:!0})}(),"server"===k.role&&("server"===k.role&&(x=Promise.allSettled([(async()=>{const e=await ve("gpu",async()=>({value:await ke()}));w.gpu=e.value||""})(),(async()=>{const e=await ve("ffmpeg",Se);w.ffmpegVer=e.version||"",w.ffprobeVer=e.probe||"",w.hwEncoders=e.encoders||""})()]).then(()=>{})),Fe())),"cli"===k.role&&k.command&&!V()&&Te(),!0)},isTelemetryEnabled:$,rememberUser:function(e){const t=String(e??"").trim().slice(0,80);t&&!/sk-|api[_-]?key|token/i.test(t)&&R({userName:t})},noteBrowserGpu:function(e){const t=B(e).trim().slice(0,180);t&&(w.browserGpu=t,k.browserGpu=t)},reportError:function(e,t,r,n){const o=t instanceof Error?t:new Error(B(t||e)),s=process.memoryUsage(),i=je(String(e||o.name||"Error"),{parent:Ee(),attributes:q({role:k.role,command:k.command,...r})}),a=W({rssMb:Math.round(s.rss/1048576),heapUsedMb:Math.round(s.heapUsed/1048576),...n});return a&&(i.attributes["tik.snapshot"]=a),xe(i,{error:o})},reportCustom:_e,reportFatalSync:function(e,t,r,n){if(!$())return!1;const o=t instanceof Error?t:new Error(B(t||e)),i=je(String(e||"Error"),{parent:Ee(),attributes:q({role:k.role,command:k.command,...r})});i.ended=!0,i.endTimeUnixNano=X(),i.status={code:2,message:B(o.message||"").slice(0,u)},i.events.push(we(o));const a=W(n);return a&&(i.attributes["tik.snapshot"]=a),Ie(i),Ae(s.encodeExport(me(),[i],{name:"tik-video-editor-cli",version:de()})),!0},flushTelemetry:async function(e=500){if(!$())return!1;const t=new AbortController;let r;const n=new Promise(n=>{r=setTimeout(()=>{t.abort(),n("timeout")},Math.max(0,e)),r.unref?.()}),o=(async()=>(I&&await I.flush(t.signal),await Fe(t.signal),"done"))();return await Promise.race([o,n]),clearTimeout(r),I&&I.salvage(),!0},finishCommand:function(e){if(!$())return Promise.resolve(!1);const t=e?Number.isInteger(e.exitCode)?e.exitCode:1:Number(process.exitCode)||0;if(!e&&!t&&V())return v&&(v.ended=!0),Promise.resolve(!1);if(Te(),!v||v.ended)return Promise.resolve(!1);if(e||t){const r=e instanceof Error?e:new Error(t?"exit "+t:"command failed");return xe(v,{error:r,attributes:{"tik.exit.code":t||1}})}return xe(v,{status:{code:1},attributes:{"tik.exit.code":0}})},startSpan:je,endSpan:xe,currentParent:Ee,bindProjectTrace:function(e){const t=Q(e);if(!t)return null;if(k.projectId=t,!$())return null;if(Te(),!v)return null;v.attributes["tik.project.id"]=t;const r=Y(t);if(r&&r.traceId===v.traceId)return Z(t,r),r;const n={traceId:v.traceId,spanId:v.spanId,linked:!0};return Z(t,n),n},resolveProjectTrace:Y,isQuietSuccessCommand:V,traceparent:function(){return v?`00-${v.traceId}-${v.spanId}-01`:""},createExportMonitor:function(e={}){if(!e.report&&!$())return{stop(){},upsert(){},note(){},cancel:()=>!1,fail(){},complete(){},scan(){}};const t=new Map,r=e.now||Date.now;function n(t,r){try{if(e.report)return void e.report(r.error?"exception":"custom",{name:t.name,status:r.error?2:r.status?.code??1,attributes:t.attributes,events:t.events,error:r.error,properties:t.attributes});xe(t,r)}catch{}}function o(e,t={}){for(const r of h)void 0!==t[r]&&(e[r]=t[r])}function s(t,r){!e.report&&f.has(r)&&(t.stageSpan=je(`export.${r}`,{parent:{traceId:t.span.traceId,spanId:t.span.spanId,linked:t.span.linked},linked:t.span.linked,attributes:{"tik.export.id":t.id,"tik.export.engine":t.engine||"","tik.export.stage":r,...t.projectId?{"tik.project.id":t.projectId}:{}}}))}function i(e,t={}){if(!e?.stageSpan)return;const r=e.stageSpan;e.stageSpan=null,xe(r,{status:t.error?void 0:{code:1},error:t.error,attributes:{"tik.export.id":e.id,"tik.export.engine":e.engine||"","tik.export.frames":e.frames||0,...e.totalFrames?{"tik.export.total_frames":e.totalFrames}:{}}})}function a(e,n){let o=t.get(e);if(!o){const i=Q(n.projectId),a=K(n.traceparent),c=a?{traceId:a.traceId,spanId:a.spanId,linked:!0}:i?Y(i):null,u=n.state||"queued";o={id:e,projectId:i,engine:n.engine||"",state:u,startedAt:n.startedAt??r(),lastProgressAt:n.startedAt??r(),frames:0,reported:new Set,stalled:!1,maxStallMs:0,done:!1,stageSpan:null,span:je("export",{parent:c,linked:!!c,attributes:{"tik.export.id":e,"tik.export.engine":n.engine||"",...i?{"tik.project.id":i}:{}}})},s(o,u),t.set(e,o)}return n.projectId&&!o.projectId&&(o.projectId=Q(n.projectId),o.projectId&&(o.span.attributes["tik.project.id"]=o.projectId)),n.traceparent&&function(e,t){const r=K(t);r&&!e.span.parentSpanId&&(e.span.traceId=r.traceId,e.span.parentSpanId=r.spanId,e.span.linked=!0,e.span.attributes["tik.trace.linked"]=1,e.stageSpan&&(e.stageSpan.traceId=r.traceId,e.stageSpan.linked=!0,e.stageSpan.attributes["tik.trace.linked"]=1))}(o,n.traceparent),o}function c(e){return W({project:e.project,wait:e.wait,stats:e.stats,stderr:e.stderr,activity:e.activity,detail:e.detail,browser:e.browser,browserGpu:e.browserGpu,stack:e.stack,clipIds:e.clipIds,metrics:e.metrics,timeSec:e.timeSec})}function u(t){try{const r=e.enrich?.(t.id,t);r&&"object"==typeof r&&o(t,r)}catch{}}function d(e,r){if(!e||e.done)return;i(e,r);const o=c(e);o&&(e.span.attributes["tik.snapshot"]=o),Object.assign(e.span.attributes,{"tik.export.id":e.id,"tik.export.engine":e.engine||"","tik.export.frames":e.frames||0,"tik.export.total_frames":e.totalFrames||0,"tik.export.state":e.state||"",...e.projectId?{"tik.project.id":e.projectId}:{},...r.attributes||{}}),e.done=!0,n(e.span,r),t.delete(e.id)}function l(){const o=r();for(const r of t.values()){if(r.done)continue;u(r);const t=Ce(r,o);if(!t)continue;r.maxStallMs=Math.max(r.maxStallMs,t.idleMs);const s=t.severe?"severe":"warn";if(r.reported.has(s))continue;r.reported.add(s),r.stalled=!0;const i={stage:r.state||"",stallMs:t.idleMs,frames:r.frames||0,totalFrames:r.totalFrames||0,waitReason:r.wait?.reason||"",engine:r.engine||"",severe:t.severe?1:0,"tik.export.id":r.id};if(r.span.events.push({timeUnixNano:X(),name:"export_stall",attributes:i}),e.report&&e.report("custom",{name:"export_stall",properties:i,severe:i.severe}),!t.severe)continue;const a=je("ExportStalled",{parent:{traceId:r.span.traceId,spanId:r.span.spanId,linked:r.span.linked},linked:r.span.linked,attributes:i}),d=c(r);d&&(a.attributes["tik.snapshot"]=d),n(a,{error:new Error(`导出在 ${r.state} 停滞 ${Math.round(t.idleMs/1e3)} 秒`)})}}const p=setInterval(l,e.interval||5e3);return p.unref?.(),{stop(){clearInterval(p)},upsert:function(t,n={}){if(!t)return null;const c=r(),u=a(t,n);n.engine&&(u.engine=n.engine);const d=n.state||u.state,l=d!==u.state,p=Number.isFinite(n.frames)&&n.frames>(u.frames||0),m="string"==typeof n.detail&&n.detail&&n.detail!==u.detail;if(l||p||m){const t=c-u.lastProgressAt;u.stalled&&(u.maxStallMs=Math.max(u.maxStallMs,t),u.span.events.push({timeUnixNano:X(),name:"export_stall_recovered",attributes:{stage:u.state,maxStallMs:u.maxStallMs,engine:u.engine||""}}),e.report&&e.report("custom",{name:"export_stall_recovered",properties:{stage:u.state,maxStallMs:u.maxStallMs}}),u.stalled=!1,u.reported.clear()),u.lastProgressAt=c}return p&&(u.frames=n.frames),Number.isFinite(n.totalFrames)&&(u.totalFrames=n.totalFrames),l&&(i(u),u.state=d,s(u,d)),o(u,n),u},note:function(e,r){const n=t.get(e);n&&o(n,r)},scan:l,cancel:function(e){const n=t.get(e);if(!n||n.done)return!1;u(n);const o=Pe(n,r()),s=Math.max(0,r()-n.lastProgressAt);return o?(d(n,{error:new Error(`导出在 ${n.state} 等待 ${Math.round(s/1e3)} 秒后被取消`),attributes:{"tik.export.outcome":"cancelled-stalled",stallMs:s,waitReason:n.wait?.reason||""}}),!0):(d(n,{status:{code:1},attributes:{"tik.export.outcome":"cancelled",stallMs:s}}),!1)},fail:function(e,r,n={}){const s=t.get(e)||a(e,{state:n.stage||"starting"});s&&!s.done&&(o(s,n),u(s),d(s,{error:r instanceof Error?r:new Error(String(r||"export failed")),attributes:{"tik.export.outcome":"failed",stage:n.stage||s.state||"",origin:n.origin||"server"}}))},complete:function(e,r={}){const n=t.get(e)||a(e,{});if(!n||n.done)return;o(n,r),Number.isFinite(r.frames)&&(n.frames=r.frames),Number.isFinite(r.totalFrames)&&(n.totalFrames=r.totalFrames);const s=r.metrics||n.metrics;d(n,{status:{code:1},attributes:{"tik.export.outcome":"complete",...Number.isFinite(Number(s?.totalMs))?{"tik.export.elapsed_ms":Number(s.totalMs)}:{}}});const i=s?.fallbacks||s?.cache?.fallbacks;i&&"object"==typeof i&&Object.keys(i).length&&_e({name:"export_cache_fallback",type:"export",properties:{engine:n.engine||"",count:Object.keys(i).length},snapshots:{fallbacks:i}})}}},summarizeExportProject:function(e,t={}){const r=Array.isArray(e?.clips)?e.clips:[],n=Array.isArray(e?.media)?e.media:[],o={};let s=0,i=0,a=0,c=0,u=0;for(const e of r){const t=e?.kind||"unknown";o[t]=(o[t]||0)+1;const r=e?.props||{};r.bgRemove&&(s+=1),r.chromaKey&&(i+=1),(r.filterPreset&&"none"!==r.filterPreset||r.shake||r.rgbSplit||r.grain)&&(a+=1),(Number(r.speed)&&1!==Number(r.speed)||e?.keyframes?.speed)&&(c+=1),(e?.transitionIn||e?.transitionOut)&&(u+=1)}const d=r.reduce((e,t)=>Math.max(e,(Number(t?.start)||0)+(Number(t?.duration)||0)),0),l=Number(e?.fps)||0;return{width:e?.width,height:e?.height,fps:l,revision:e?.revision,durationSec:Math.round(1e3*d)/1e3,totalFrames:l>0&&d>0?Math.max(1,Math.round(d*l)):void 0,clips:r.length,kinds:o,tracks:Array.isArray(e?.tracks)?e.tracks.length:void 0,bgRemove:s,chroma:i,effects:a,speed:c,transitions:u,media:n.length,...Number.isFinite(t.mediaBytes)?{mediaBytes:t.mediaBytes}:{}}},resolveTelemetryConfig:U,parseTraceparent:K,summarizeArgv:z,sanitizeTelemetryText:B,clipTelemetryProperties:q,evaluateExportHealth:Ce,isExportCancelStalled:Pe,formatCpuArch:te,formatDiskSegment:oe,parseFfmpegVersionLine:fe,parseHardwareEncoders:ge,tryClaimQueueFile:Me,setTelemetryDeps:Re,resetTelemetryForTests:function(){Re({})}};
@@ -0,0 +1 @@
1
+ !function(e){const t="object"==typeof module&&module.exports,a=function(){"use strict";const e=(e,t,a)=>Math.min(a,Math.max(t,e)),t=(e,t)=>null!=e&&""!==e&&Number.isFinite(+e)?+e:t,a=e=>Math.max(2,2*Math.round(e/2)),o="object"==typeof process&&process&&"darwin"===process.platform&&"function"==typeof require?parseInt(require("os").release(),10)||22:null,r="object"==typeof process&&process&&"darwin"===process.platform?process.arch:null,n={mp4:{label:"MP4",ext:".mp4",mov:!0},mov:{label:"QuickTime MOV",ext:".mov",mov:!0},mkv:{label:"Matroska MKV",ext:".mkv"},webm:{label:"WebM",ext:".webm"},mxf:{label:"MXF (OP1a)",ext:".mxf"}},s={h264:{label:"H.264",encoders:["libx264","h264_videotoolbox","h264_nvenc","h264_qsv","h264_amf"],containers:["mp4","mov","mkv"],rate:["crf","vbr","cbr"],crf:[0,51,18],pixFmts:["yuv420p","yuv422p","yuv444p","yuv420p10le","yuv422p10le"]},hevc:{label:"H.265 / HEVC",encoders:["libx265","hevc_videotoolbox","hevc_nvenc","hevc_qsv","hevc_amf"],containers:["mp4","mov","mkv"],rate:["crf","vbr","cbr"],crf:[0,51,22],pixFmts:["yuv420p","yuv420p10le","yuv422p10le","yuv444p"]},av1:{label:"AV1",encoders:["libsvtav1","libaom-av1","av1_nvenc","av1_qsv","av1_amf"],containers:["mp4","mkv","webm"],rate:["crf","vbr","cbr"],crf:[0,63,30],pixFmts:["yuv420p","yuv420p10le"]},vp9:{label:"VP9",encoders:["libvpx-vp9"],containers:["webm","mkv","mp4"],rate:["crf","vbr","cbr"],crf:[0,63,31],pixFmts:["yuv420p","yuv420p10le"]},prores:{label:"Apple ProRes",encoders:["prores_ks"],containers:["mov"],rate:["fixed"],profiles:{proxy:"Proxy",lt:"LT",standard:"422",hq:"422 HQ",4444:"4444","4444xq":"4444 XQ"},defaultProfile:"hq",pixFmts:["yuv422p10le","yuv444p10le"]},dnxhr:{label:"Avid DNxHR",encoders:["dnxhd"],containers:["mov","mxf"],rate:["fixed"],profiles:{lb:"LB",sq:"SQ",hq:"HQ",hqx:"HQX 10-bit",444:"444 10-bit"},defaultProfile:"hq",pixFmts:["yuv422p","yuv422p10le","yuv444p10le"]},mpeg2:{label:"XDCAM HD422 (MPEG-2 50 Mb/s)",encoders:["mpeg2video"],containers:["mxf","mov"],rate:["fixed"],pixFmts:["yuv422p"]},ffv1:{label:"FFV1 (lossless)",encoders:["ffv1"],containers:["mkv"],rate:["fixed"],pixFmts:["yuv422p10le","yuv444p10le","yuv420p"]}},i={yuv420p:"nv12",yuv420p10le:"p010le",yuv444p:"yuv444p"},l={libx264:{label:"x264 (software)"},h264_videotoolbox:{label:"Apple Silicon VideoToolbox",hw:"videotoolbox",pix:["yuv420p"]},h264_nvenc:{label:"NVIDIA NVENC",hw:"nvenc",pix:["yuv420p","yuv444p","yuv420p10le"]},h264_qsv:{label:"Intel Quick Sync",hw:"qsv",pix:["yuv420p"]},h264_amf:{label:"AMD AMF",hw:"amf",pix:["yuv420p"]},libx265:{label:"x265 (software)"},hevc_videotoolbox:{label:"Apple Silicon VideoToolbox",hw:"videotoolbox",pix:["yuv420p","yuv420p10le"]},hevc_nvenc:{label:"NVIDIA NVENC",hw:"nvenc",pix:["yuv420p","yuv420p10le","yuv444p"]},hevc_qsv:{label:"Intel Quick Sync",hw:"qsv",pix:["yuv420p","yuv420p10le"]},hevc_amf:{label:"AMD AMF",hw:"amf",pix:["yuv420p","yuv420p10le"]},libsvtav1:{label:"SVT-AV1 (software)"},"libaom-av1":{label:"libaom (software, slow)"},av1_nvenc:{label:"NVIDIA NVENC",hw:"nvenc",pix:["yuv420p","yuv420p10le"]},av1_qsv:{label:"Intel Quick Sync",hw:"qsv",pix:["yuv420p","yuv420p10le"]},av1_amf:{label:"AMD AMF",hw:"amf",pix:["yuv420p"]},"libvpx-vp9":{label:"libvpx (software)"},prores_ks:{label:"prores_ks"},dnxhd:{label:"dnxhd"},mpeg2video:{label:"mpeg2video"},ffv1:{label:"ffv1"}},c={aac:{label:"AAC",encoder:"aac",bitrate:[64,512,320],containers:["mp4","mov","mkv"]},opus:{label:"Opus",encoder:"libopus",bitrate:[32,512,192],containers:["webm","mkv","mp4"]},mp3:{label:"MP3",encoder:"libmp3lame",bitrate:[64,320,320],containers:["mp4","mov","mkv"]},pcm16:{label:"PCM 16-bit",encoder:"pcm_s16le",containers:["mov","mkv","mxf"]},pcm24:{label:"PCM 24-bit",encoder:"pcm_s24le",containers:["mov","mkv","mxf"]},flac:{label:"FLAC (lossless)",encoder:"flac",containers:["mkv"]},none:{label:"No audio",containers:["mp4","mov","mkv","webm","mxf"]}},p=[44100,48e3],u={bt709:{label:"Rec. 709 (limited)",matrix:"bt709",primaries:"bt709",trc:"bt709",range:"tv",scale:"bt709"},"bt709-full":{label:"Rec. 709 (full range)",matrix:"bt709",primaries:"bt709",trc:"bt709",range:"pc",scale:"bt709"},"bt601-625":{label:"Rec. 601 PAL (limited)",matrix:"bt470bg",primaries:"bt470bg",trc:"smpte170m",range:"tv",scale:"bt470"},"bt601-525":{label:"Rec. 601 NTSC (limited)",matrix:"smpte170m",primaries:"smpte170m",trc:"smpte170m",range:"tv",scale:"smpte170m"}},d=[23.976,24,25,29.97,30,48,50,59.94,60];function h(e){const t=+e;for(const e of[24,30,60,120])if(Math.abs(t-1e3*e/1001)<.01)return 1e3*e+"/1001";return String(Math.round(1e3*t)/1e3)}const m=["fast","balanced","best"],f=(e,t)=>({codec:"h264",rate:"crf",crf:e,keyint:2,pixFmt:"yuv420p",speed:"balanced",...t}),b={youtube:{label:"YouTube",group:"Platforms",width:1920,height:1080,container:"mp4",video:f(18,{keyint:.5}),audio:{codec:"aac",bitrate:384,sampleRate:48e3,channels:2},filename:"{project}_youtube_{res}",note:"16:9 · H.264 High · CRF 18 · AAC 384k"},"youtube-shorts":{label:"YouTube Shorts",group:"Platforms",width:1080,height:1920,container:"mp4",video:f(18,{keyint:.5}),audio:{codec:"aac",bitrate:384,sampleRate:48e3,channels:2},filename:"{project}_shorts_{res}",limits:{duration:180,vertical:!0},note:"9:16 · up to 3 min"},"instagram-reels":{label:"Instagram Reels",group:"Platforms",width:1080,height:1920,container:"mp4",video:f(19,{maxrate:25e3,keyint:1}),audio:{codec:"aac",bitrate:256,sampleRate:48e3,channels:2},filename:"{project}_reel_{res}",limits:{duration:180,vertical:!0,fps:60},note:"9:16 · ≤ 60 fps · capped at 25 Mb/s"},tiktok:{label:"TikTok",group:"Platforms",width:1080,height:1920,container:"mp4",video:f(19,{maxrate:2e4,keyint:1}),audio:{codec:"aac",bitrate:256,sampleRate:48e3,channels:2},filename:"{project}_tiktok_{res}",limits:{duration:600,vertical:!0,fps:60},note:"9:16 · ≤ 60 fps"},x:{label:"X (Twitter)",group:"Platforms",width:1920,height:1080,container:"mp4",video:f(20,{maxrate:25e3,keyint:1}),audio:{codec:"aac",bitrate:192,sampleRate:48e3,channels:2},filename:"{project}_x_{res}",limits:{duration:140,size:536870912,fps:60},note:"≤ 2 min 20 s and 512 MB on a free account"},linkedin:{label:"LinkedIn",group:"Platforms",width:1920,height:1080,container:"mp4",video:f(20,{maxrate:2e4,keyint:1}),audio:{codec:"aac",bitrate:192,sampleRate:48e3,channels:2},filename:"{project}_linkedin_{res}",limits:{duration:900,size:5*1024**3,fps:60},note:"≤ 15 min and 5 GB"},master:{label:"Master",group:"Delivery",width:null,height:null,container:"mp4",video:f(16,{speed:"best",keyint:2}),audio:{codec:"aac",bitrate:320,sampleRate:48e3,channels:2},filename:"{project}_master_{res}",note:"Project size · H.264 CRF 16 · AAC 320k"},broadcast:{label:"Broadcast",group:"Delivery",width:1920,height:1080,container:"mov",video:{codec:"prores",profile:"hq",pixFmt:"yuv422p10le"},audio:{codec:"pcm24",sampleRate:48e3,channels:2,loudness:-23,truePeak:-1},filename:"{project}_broadcast_{res}_{fps}",limits:{fpsList:[25,29.97,50,59.94]},note:"ProRes 422 HQ · PCM 24-bit 48 kHz · Rec. 709 · −23 LUFS (EBU R128)"},web:{label:"Web",group:"Delivery",width:1280,height:720,container:"mp4",video:f(23,{speed:"balanced"}),audio:{codec:"aac",bitrate:128,sampleRate:48e3,channels:2},filename:"{project}_web_{res}",note:"Small, plays everywhere · fast start"},archive:{label:"Archive",group:"Delivery",width:null,height:null,container:"mkv",video:{codec:"ffv1",pixFmt:"yuv422p10le"},audio:{codec:"pcm24",sampleRate:48e3,channels:2},filename:"{project}_archive_{date}",note:"Lossless FFV1 · PCM 24-bit · source resolution"},custom:{label:"Custom",group:"Custom",width:null,height:null,container:"mp4",video:f(18),audio:{codec:"aac",bitrate:320,sampleRate:48e3,channels:2},filename:"{project}_{res}",note:"Your own settings"}},v=Object.keys(b),x={youtube:-14,"youtube-shorts":-14,"instagram-reels":-14,tiktok:-14,x:-14,linkedin:-14,broadcast:-23};function g(e,t,a){return e.includes(t)?t:a}function $(e,t){return String(e??"").replace(/[\u0000-\u001f\u007f]+/g," ").trim().slice(0,t)}function _(e,t){const a=(s[e]||s.h264).encoders;return t?a.filter(e=>t.has(e)):a.slice()}function y(n,i={}){const h=[],f=i.presets||{};let v=n;"string"==typeof v&&(v={preset:v}),v=v&&"object"==typeof v?v:{};const x="string"==typeof v.preset?v.preset:null,y=x&&(b[x]||f[x])||null;x&&!y&&h.push(`unknown preset "${x}" — using Custom`);const k=y||b.custom,M=v.video&&"object"==typeof v.video?v.video:{},S={...k.video||{}};if(M.codec&&M.codec!==S.codec)for(const e of["crf","pixFmt","profile","encoder","rate"])delete S[e];const F={...S,...M},R={...k.audio||{},...v.audio||{}},A=e=>Object.prototype.hasOwnProperty.call(v,e),P={preset:y?x:"custom"};let q=A("width")?v.width:k.width,j=A("height")?v.height:k.height;if(q=null==q||""===q?null:t(q,null),j=null==j||""===j?null:t(j,null),null==q!=(null==j)&&(h.push("width and height go together — using the picture's own size"),q=j=null),null!=q){const t=a(e(q,16,8192)),o=a(e(j,16,8192));t===q&&o===j||h.push(`resolution ${q}×${j} → ${t}×${o} (even, 16…8192)`),q=t,j=o}P.width=q,P.height=j;let C=A("fps")?v.fps:k.fps;if(C=null==C||""===C||"project"===C?null:t(C,null),null!=C){const t=e(C,1,120),a=d.find(e=>Math.abs(e-t)<.02);P.fps=a??Math.round(1e3*t)/1e3}else P.fps=null;P.reframe=g(["fill","fit","stretch"],A("reframe")?v.reframe:k.reframe,"fill");const L=s[F.codec]?F.codec:"h264";F.codec&&!s[F.codec]&&h.push(`unknown codec "${F.codec}" — using H.264`);const H=s[L],E=_(L,i.available);let T=F.encoder&&H.encoders.includes(F.encoder)?F.encoder:null;F.encoder&&!T&&h.push(`encoder "${F.encoder}" does not make ${H.label}`),T&&i.available&&!i.available.has(T)&&(h.push(`this ffmpeg has no ${T}`),T=null),T||(T=E[0]||H.encoders[0]),i.available&&!E.length&&h.push(`this ffmpeg has no ${H.label} encoder — the export will fail`);const D=l[T]||{};let z=A("container")?v.container:k.container;H.containers.includes(z)||(z&&h.push(`${H.label} does not go in ${String(z).toUpperCase()} — using ${H.containers[0].toUpperCase()}`),z=H.containers[0]),P.container=z;const N={codec:L,encoder:T};if(N.rate=H.rate.includes(F.rate)?F.rate:H.rate[0],F.rate&&F.rate!==N.rate&&"fixed"!==H.rate[0]&&h.push(`rate "${F.rate}" is not offered for ${H.label}`),"fixed"!==N.rate){const[a,n,s]=H.crf;if(N.crf=Math.round(e(t(F.crf,s),a,n)),N.bitrate=Math.round(e(t(F.bitrate,12e3),100,4e5)),N.maxrate=+F.maxrate>0?Math.round(e(+F.maxrate,100,8e5)):null,N.keyint=Math.round(100*e(t(F.keyint,2),0,20))/100,N.speed=g(m,F.speed,"balanced"),"libsvtav1"===T&&"cbr"===N.rate&&(N.rate="vbr",h.push("SVT-AV1 has no CBR here — using VBR")),"videotoolbox"===D.hw){const e=i.arch||r||"arm64",t=i.darwin??o??22;"crf"===N.rate&&"arm64"!==e?(N.rate="vbr",h.push("VideoToolbox constant quality (-q:v) needs Apple Silicon — using VBR")):"cbr"===N.rate&&("arm64"!==e||t<22)&&(N.rate="vbr",h.push("VideoToolbox CBR needs macOS 13+ on Apple Silicon — using VBR"))}}H.profiles&&(N.profile=H.profiles[F.profile]?String(F.profile):H.defaultProfile);let O=H.pixFmts.includes(F.pixFmt)?F.pixFmt:H.pixFmts[0];"prores"===L&&(O=/^4444/.test(N.profile)?"yuv444p10le":"yuv422p10le"),"dnxhr"===L&&(O="444"===N.profile?"yuv444p10le":"hqx"===N.profile?"yuv422p10le":"yuv422p"),D.pix&&!D.pix.includes(O)&&(h.push(`${D.label} cannot encode ${O} — using ${D.pix[0]}`),O=D.pix[0]),M.pixFmt&&M.pixFmt!==O&&!h.some(e=>e.includes(O))&&h.push(`pixel format ${M.pixFmt} → ${O} for ${H.label}${N.profile?" "+H.profiles[N.profile]:""}`),N.pixFmt=O,P.video=N;let U=c[R.codec]?R.codec:"aac";if(!c[U].containers.includes(z)){const e=Object.keys(c).find(e=>"none"!==e&&c[e].containers.includes(z))||"none";h.push(`${c[U].label} audio does not go in ${z.toUpperCase()} — using ${c[e].label}`),U=e}const V=c[U],B={codec:U};if("none"!==U){V.bitrate&&(B.bitrate=Math.round(e(t(R.bitrate,V.bitrate[2]),V.bitrate[0],V.bitrate[1]))),B.sampleRate=g(p,+R.sampleRate,48e3),"opus"===U&&(B.sampleRate=48e3),B.channels=1===+R.channels?1:2;const a=null==R.loudness||""===R.loudness||"off"===R.loudness?null:+R.loudness;B.loudness=Number.isFinite(a)?Math.round(10*e(a,-36,-5))/10:null,null!=B.loudness&&(B.truePeak=Math.round(10*e(t(R.truePeak,-1),-9,0))/10)}P.audio=B,P.color=u[A("color")?v.color:k.color]?A("color")?v.color:k.color:"bt709",P.filename=$(A("filename")?v.filename:k.filename,160)||"{project}_{res}";const I=v.metadata&&"object"==typeof v.metadata?v.metadata:{};P.metadata={};for(const e of w){const t=$(I[e],"description"===e?2e3:300);t&&(P.metadata[e]=t)}return{spec:P,notes:h}}const w=["title","artist","description","copyright","date","keywords"];function k(e,t,o,r){const n={x:0,y:0,w:0|t,h:0|o};let s=r&&r.w>0&&r.h>0?{x:0|r.x,y:0|r.y,w:0|r.w,h:0|r.h}:n;s!==n&&e.width&&Math.abs(e.width/e.height-s.w/s.h)>.01&&(s=n);const i=e.width||Math.max(2,s.w-(1&s.w)),l=e.height||Math.max(2,s.h-(1&s.h));let c={...s},p=i,u=l,d=0,h=0;const m=i/l,f=s.w/s.h;return e.width&&Math.abs(m-f)>.002&&("fill"===e.reframe?f>m?(c.w=Math.round(s.h*m),c.x=s.x+Math.round((s.w-c.w)/2)):(c.h=Math.round(s.w/m),c.y=s.y+Math.round((s.h-c.h)/2)):"fit"===e.reframe&&(f>m?u=a(i/f):p=a(l*f),d=i-p>>1,h=l-u>>1,d-=1&d,h-=1&h)),c.w=Math.max(2,c.w-(1&c.w)),c.h=Math.max(2,c.h-(1&c.h)),{crop:0===c.x&&0===c.y&&c.w===t&&c.h===o?null:c,scaleW:p,scaleH:u,outW:i,outH:l,padX:d,padY:h,upscale:p>1.01*c.w||u>1.01*c.h,from:{w:c.w,h:c.h}}}const M={libx264:{fast:["-preset","veryfast"],balanced:["-preset","medium"],best:["-preset","slow"]},libx265:{fast:["-preset","fast"],balanced:["-preset","medium"],best:["-preset","slow"]},videotoolbox:{fast:["-prio_speed","1"],balanced:[],best:["-prio_speed","0"]},nvenc:{fast:["-preset","p3"],balanced:["-preset","p5"],best:["-preset","p7"]},qsv:{fast:["-preset","veryfast"],balanced:["-preset","medium"],best:["-preset","veryslow"]},amf:{fast:["-quality","speed"],balanced:["-quality","balanced"],best:["-quality","quality"]},"libvpx-vp9":{fast:["-deadline","good","-cpu-used","4"],balanced:["-deadline","good","-cpu-used","2"],best:["-deadline","good","-cpu-used","1"]},"libaom-av1":{fast:["-cpu-used","8"],balanced:["-cpu-used","6"],best:["-cpu-used","4"]},libsvtav1:{fast:["-preset","10"],balanced:["-preset","8"],best:["-preset","5"]}},S={proxy:"0",lt:"1",standard:"2",hq:"3",4444:"4","4444xq":"5"};function F(e,t,a){const o=u[e.color]||u.bt709,r=[];return t.crop&&r.push(`crop=${t.crop.w}:${t.crop.h}:${t.crop.x}:${t.crop.y}`),r.push(`scale=${t.scaleW}:${t.scaleH}:flags=lanczos:in_range=full:in_color_matrix=${a}:out_range=${o.range}:out_color_matrix=${o.scale}`),r.push(`setparams=color_primaries=${o.primaries}:color_trc=${o.trc}:colorspace=${o.matrix}:range=${"pc"===o.range?"pc":"tv"}`),(t.padX||t.padY||t.scaleW!==t.outW||t.scaleH!==t.outH)&&r.push(`pad=${t.outW}:${t.outH}:${t.padX}:${t.padY}:color=black`),r.join(",")}function R(e,t){const a=e.audio;if(null==a.loudness||!t)return"";const o=Math.min(20,Math.max(11,Math.ceil(t.input_lra+1)));return`loudnorm=I=${a.loudness}:TP=${a.truePeak??-1}:LRA=${o}:measured_I=${t.input_i}:measured_TP=${t.input_tp}:measured_LRA=${t.input_lra}:measured_thresh=${t.input_thresh}:offset=${t.target_offset}:linear=true`}function A(e){const t=Math.floor(e/60),a=e-60*t;return`${t}:${a<10?"0":""}${a.toFixed(2)}`}function P(e){return String(e).padStart(2,"0")}function q(e,t,a={}){const o=a.date instanceof Date?a.date:new Date,r=a.width||t.width||0,n=a.height||t.height||0,s=a.fps||t.fps||0,i=r&&n?r>n?`${n}p`:r===n?`${r}sq`:`${r}x${n}`:"source",l={project:a.project||"export",preset:t.preset||"custom",w:r,h:n,width:r,height:n,res:i,fps:s?String(Math.round(100*s)/100).replace(".","_"):"",codec:t.video.codec,date:`${o.getFullYear()}-${P(o.getMonth()+1)}-${P(o.getDate())}`,time:`${P(o.getHours())}${P(o.getMinutes())}`,range:"in-out"===a.range?"inout":"full",n:null!=a.index?String(a.index):"1"};let c=String(e||"{project}").replace(/\{(\w+)\}/g,(e,t)=>t in l?String(l[t]):e);return c=c.replace(/[\\/:*?"<>|\u0000-\u001f]+/g,"_").replace(/\s+/g," ").trim().replace(/^\.+/,""),c.slice(0,120)||"export"}function j(e){return e>=1e3?Math.round(e/100)/10+" Mb/s":`${e} kb/s`}function C(e,t={}){const a=e.video,o=e.audio,r=s[a.codec],n=e.width||t.width,i=e.height||t.height,l=[n&&i?`${n}×${i}`:"source size",`${e.fps||t.fps||"project"} fps`];let p=r.label.replace(/ \(.+\)$/,"");return a.profile&&r.profiles&&(p+=" "+r.profiles[a.profile]),"crf"===a.rate?p+=` CRF ${a.crf}`+(a.maxrate?` ≤ ${j(a.maxrate)}`:""):"vbr"===a.rate?p+=` VBR ${j(a.bitrate)}`:"cbr"===a.rate&&(p+=` CBR ${j(a.bitrate)}`),l.push(p),l.push("none"===o.codec?"no audio":`${c[o.codec].label}${o.bitrate?" "+o.bitrate+"k":""}${null!=o.loudness?` · ${o.loudness} LUFS`:""}`),l.push(e.container.toUpperCase()),l.join(" · ")}const L={prores:{proxy:45,lt:102,standard:147,hq:220,4444:330,"4444xq":500},dnxhr:{lb:45,sq:145,hq:220,hqx:220,444:440}};function H(e,t){const a=e.video,o=e.audio,r=t.duration||0,n=e.width||t.width||1920,s=e.height||t.height||1080,i=e.fps||t.fps||30;let l=null;if("vbr"===a.rate||"cbr"===a.rate?l=a.bitrate:"mpeg2"===a.codec?l=5e4:L[a.codec]&&(l=1e3*L[a.codec][a.profile]*(n*s*i)/62208e3),null==l)return null;const c="none"===o.codec?0:o.bitrate||("pcm24"===o.codec?24:16)*o.sampleRate*o.channels/1e3;return Math.round(1e3*(l+c)/8*r)}function E(e){e=Math.round(e);const t=Math.floor(e/60);return t?`${t} min${e%60?` ${e%60} s`:""}`:`${e} s`}function T(e){return e>=1024**3?`${(e/1024**3).toFixed(1)} GB`:e>=1048576?`${(e/1048576).toFixed(e>=104857600?0:1)} MB`:`${Math.max(1,Math.round(e/1024))} KB`}function D(e){return String(e||"").toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,40)}return{CONTAINERS:n,CODECS:s,ENCODERS:l,AUDIO:c,COLORS:u,PRESETS:b,PRESET_IDS:v,DEFAULT_PRESET:"master",FPS_CHOICES:d,RESOLUTIONS:[[3840,2160,"4K UHD"],[2560,1440,"1440p"],[1920,1080,"1080p"],[1280,720,"720p"],[854,480,"480p"],[4096,2160,"DCI 4K"],[2160,3840,"4K vertical"],[1080,1920,"9:16 vertical"],[720,1280,"9:16 720"],[1080,1350,"4:5 portrait"],[1080,1080,"1:1 square"]],SPEEDS:m,SAMPLE_RATES:p,META_KEYS:w,FILENAME_TOKENS:["project","preset","res","w","h","fps","codec","date","time","range","n"],normalize:y,encodersFor:_,reframe:k,ffmpegArgs:function(e,t){const a=h(t.fps),o=["-y","-hide_banner"],r="rgba"===t.input;t.dry?o.push("-f","lavfi","-i",`color=c=black:s=${t.canvasW}x${t.canvasH}:r=${a}:d=0.1,format=${r?"rgba":"yuvj420p"}`):r?o.push("-thread_queue_size","8","-f","rawvideo","-pix_fmt","rgba","-s",`${t.canvasW}x${t.canvasH}`,"-framerate",a,"-i","-"):o.push("-thread_queue_size","64","-f","image2pipe","-framerate",a,"-c:v","mjpeg","-i","-");const s="none"!==e.audio.codec&&(t.dry?!1!==t.hasAudio:!!t.wavPath);s&&(t.dry?o.push("-f","lavfi","-i","anullsrc=r=48000:cl=stereo"):o.push("-i",t.wavPath)),o.push("-map","0:v:0"),s&&o.push("-map","1:a:0"),o.push("-vf",F(e,t.frame,r?"bt709":"bt601")),o.push(...function(e,t){const a=e.video,o=a.encoder,r=l[o]||{},n=["-c:v",o],s=e=>`${Math.round(e)}k`;if("prores"===a.codec)return n.concat(["-profile:v",S[a.profile]||"3","-vendor","apl0","-pix_fmt",a.pixFmt]);if("dnxhr"===a.codec)return n.concat(["-profile:v",`dnxhr_${a.profile}`,"-pix_fmt",a.pixFmt]);if("ffv1"===a.codec)return n.concat(["-level","3","-g","1","-slices","16","-slicecrc","1","-coder","1","-context","1","-pix_fmt",a.pixFmt]);if("mpeg2"===a.codec)return n.concat(["-pix_fmt","yuv422p","-b:v","50M","-minrate","50M","-maxrate","50M","-bufsize","17825792","-rc_init_occupancy","17825792","-g","12","-bf","2","-intra_vlc","1","-non_linear_quant","1","-dc","10","-qmin","1","-qmax","12","-lmin","1*QP2LAMBDA","-rc_max_vbv_use","1","-rc_min_vbv_use","1"]);n.push(...(M[r.hw||o]||{})[a.speed]||[]);const c=a.bitrate,p=a.maxrate;if("crf"===a.rate)"libx264"===o||"libx265"===o||"libsvtav1"===o?n.push("-crf",String(a.crf)):"libvpx-vp9"===o||"libaom-av1"===o?n.push("-crf",String(a.crf),"-b:v","0"):"nvenc"===r.hw?n.push("-rc","vbr","-cq",String(a.crf),"-b:v","0"):"videotoolbox"===r.hw?n.push("-q:v",String(Math.max(1,Math.min(100,Math.round(100*(51-a.crf)/51))))):"qsv"===r.hw?n.push("-global_quality",String(a.crf)):"amf"===r.hw&&n.push("-rc","cqp","-qp_i",String(a.crf),"-qp_p",String(a.crf),..."h264"===a.codec?["-qp_b",String(a.crf)]:[]),p&&"amf"!==r.hw&&("libsvtav1"===o?n.push("-svtav1-params",`mbr=${p}`):n.push("-maxrate",s(p),"-bufsize",s(2*p)));else if("vbr"===a.rate){const e=p||Math.round(1.5*c);"nvenc"===r.hw&&n.push("-rc","vbr"),"amf"===r.hw&&n.push("-rc","vbr_peak"),n.push("-b:v",s(c),"-maxrate",s(e),"-bufsize",s(2*e))}else"cbr"===a.rate&&("nvenc"===r.hw&&n.push("-rc","cbr"),"amf"===r.hw&&n.push("-rc","cbr"),"videotoolbox"===r.hw&&n.push("-constant_bit_rate","1"),n.push("-b:v",s(c),"-minrate",s(c),"-maxrate",s(c),"-bufsize",s(c)),"libx264"===o&&n.push("-x264-params","nal-hrd=cbr"));if(a.keyint>0){const e=Math.max(1,Math.round(a.keyint*t));n.push("-g",String(e)),"libx264"!==o&&"libx265"!==o||n.push("-keyint_min",String(Math.min(e,Math.max(1,Math.round(t/2)))))}return"libvpx-vp9"!==o&&"libaom-av1"!==o||n.push("-row-mt","1"),"libx265"===o&&n.push("-x265-params","log-level=error"),"hevc"!==a.codec||"mp4"!==e.container&&"mov"!==e.container||n.push("-tag:v","hvc1"),n.push("-pix_fmt",r.hw&&i[a.pixFmt]||a.pixFmt),n}(e,+t.fps));const p=u[e.color]||u.bt709;o.push("-colorspace",p.matrix,"-color_primaries",p.primaries,"-color_trc",p.trc,"-color_range",p.range);const d=+t.duration>0?(+t.duration).toFixed(6):null;s&&!t.dry&&o.push("-af",[t.loudnorm?R(e,t.loudnorm):"",d?`apad=whole_dur=${d},atrim=0:${d}`:"apad"].filter(Boolean).join(",")),o.push(...s?function(e){const t=e.audio;if("none"===t.codec)return["-an"];const a=["-c:a",c[t.codec].encoder];return t.bitrate&&a.push("-b:a",`${t.bitrate}k`),a.push("-ar",String(t.sampleRate),"-ac",String(t.channels)),a}(e):["-an"]);for(const[t,a]of Object.entries(e.metadata||{}))"description"===t?o.push("-metadata",`description=${a}`,"-metadata",`comment=${a}`):o.push("-metadata",`${t}=${a}`);return n[e.container].mov&&o.push("-movflags","+faststart"+(e.metadata&&e.metadata.keywords?"+use_metadata_tags":"")),t.dry?o.push("-t","0.1"):s&&!d&&o.push("-shortest"),o.push(t.outPath),o},videoFilter:F,frameInput:function(e){const t=e.video;return"ffv1"===t.codec||/422|444|10le/.test(t.pixFmt)?"rgba":"jpeg"},jpegQuality:function(e){const t=e.video;return"crf"===t.rate?t.crf<=16?.98:t.crf<=20?.95:.9:.95},fpsRational:h,renderFilename:q,projectFilename:function(e,t={}){const a=k(e,t.width||1920,t.height||1080,t.exportFrame||null);return q(e.filename,e,{project:t.name,width:a.outW,height:a.outH,fps:e.fps||t.fps})},describe:C,estimateSize:H,checks:function(e,t={}){const a=[],o=b[e.preset],r=o&&o.limits||{},n=k(e,t.canvasW||1920,t.canvasH||1080,t.region),s=e.fps||t.fps||30;n.upscale&&a.push(`Upscaled: the part of the picture used is ${n.from.w}×${n.from.h} and the output ${n.outW}×${n.outH} — a larger${e.width&&e.height>e.width?" or vertical":""} project size keeps it sharp`),e.width&&"fill"===e.reframe&&n.crop&&t.canvasW&&(n.crop.w<(t.region?t.region.w:t.canvasW)-2||n.crop.h<(t.region?t.region.h:t.canvasH)-2)&&a.push(`Cropped to ${n.crop.w}×${n.crop.h} from the middle of the picture — set an export frame (⬒ Frame) to choose the part, or use Fit to keep everything`),r.vertical&&e.width&&e.width>e.height&&a.push(`${o.label} expects a vertical picture; this output is landscape`),r.duration&&t.duration>r.duration+.05&&a.push(`${o.label}: ${E(t.duration)} is longer than ${E(r.duration)} — check the platform's current limit`),r.fps&&s>r.fps+.01&&a.push(`${o.label} takes up to ${r.fps} fps; this output is ${s}`),r.fpsList&&!r.fpsList.some(e=>Math.abs(e-s)<.02)&&a.push(`Broadcast usually wants ${r.fpsList.join(" / ")} fps; this output is ${s}`);const i=H(e,{duration:t.duration,width:n.outW,height:n.outH,fps:s});return r.size&&i&&i>r.size&&a.push(`${o.label} takes files up to ${T(r.size)}; this one will be about ${T(i)}`),"mpeg2"!==e.video.codec||1920===n.outW&&1080===n.outH||a.push("XDCAM HD422 is 1920×1080 — other sizes may be refused by playout servers"),a},presetGroups:function(e={}){const t=[],a=(e,a,o)=>{let r=t.find(t=>t.group===e);r||t.push(r={group:e,items:[]}),r.items.push({id:a,label:o.label||a,note:o.note||""})};for(const e of v)"Custom"!==b[e].group&&a(b[e].group,e,b[e]);for(const[t,o]of Object.entries(e))a("Saved",t,o);return a("Custom","custom",b.custom),t},presetId:D,savedPresets:function(e){const t={};for(const{file:a,data:o}of e||[]){if(!o||"object"!=typeof o)continue;const e=D(o.id||String(a||"").replace(/\.json$/i,""));if(!e||b[e])continue;const{spec:r}=y({...o,preset:"custom"});t[e]={...r,preset:e,label:$(o.label||e,60),note:C(r)}}return t},parseEncoders:function(e){const t=new Set;for(const a of String(e||"").split(/\r?\n/)){const e=/^\s*[VAS][.A-Z]{5}\s+(\S+)/.exec(a);e&&"="!==e[1]&&t.add(e[1])}return t},PLATFORM_LOUDNESS:x,LOUDNESS_TARGETS:[[-14,"−14 LUFS · streaming and social"],[-16,"−16 LUFS · podcast, dialogue"],[-23,"−23 LUFS · broadcast (EBU R128)"],[-24,"−24 LUFS · broadcast (ATSC A/85)"]],LOUDNESS_ARGS:e=>["-hide_banner","-nostats","-i",e,"-map","0:a:0","-af","ebur128=peak=true:framelog=quiet","-f","null","-"],LOUDNORM_ARGS:(e,t)=>["-hide_banner","-nostats","-i",e,"-map","0:a:0","-af",`loudnorm=I=${t.audio.loudness}:TP=${t.audio.truePeak??-1}:LRA=11:print_format=json`,"-f","null","-"],parseLoudnorm:function(e){const t=/\{[^{}]*"input_i"[^{}]*\}/.exec(String(e||"").split(/Parsed_loudnorm/).pop()||"");if(!t)return null;try{const e=JSON.parse(t[0]),a={};for(const t of["input_i","input_tp","input_lra","input_thresh","target_offset"])a[t]=Number(e[t]);return Object.values(a).every(Number.isFinite)&&a.input_i>-70?a:null}catch{return null}},loudnormFilter:R,parseEbur128:function(e){const t=String(e||""),a=[...t.matchAll(/\bI:\s+(-?[\d.]+|-inf)\s+LUFS/g)].pop(),o=[...t.matchAll(/True peak:\s*[\r\n]+\s*Peak:\s+(-?[\d.]+|-inf)\s+dBFS/g)].pop(),r=e=>e&&"-inf"!==e[1]?+e[1]:null,n={lufs:r(a),truePeak:r(o)};return a&&("-inf"===a[1]||+a[1]<=-69.95)&&(n.lufs=null,n.silent=!0),n},verify:function(e,t,a={}){const o=[],r=(e,t)=>o.push({ok:!!e,text:t}),n=t&&t.streams||[],s=n.find(e=>"video"===e.codec_type),i=n.find(e=>"audio"===e.codec_type),l=a.frame||{},p=(e,t,a)=>Math.abs(e-t)<=a,d=e=>{const[t,a]=String(e||"0/1").split("/").map(Number);return a?t/a:0},h={h264:"h264",hevc:"hevc",av1:"av1",vp9:"vp9",prores:"prores",dnxhr:"dnxhd",mpeg2:"mpeg2video",ffv1:"ffv1"};if(s){l.outW&&r(s.width===l.outW&&s.height===l.outH,`${s.width}×${s.height}${s.width===l.outW&&s.height===l.outH?"":` (asked ${l.outW}×${l.outH})`}`);const t=d(s.avg_frame_rate)||d(s.r_frame_rate);a.fps&&r(p(t,a.fps,.01),`${Math.round(1e3*t)/1e3} fps${p(t,a.fps,.01)?"":` (asked ${a.fps})`}`);const o=+s.nb_frames;a.frames&&Number.isFinite(o)&&o>0&&r(o===a.frames,`${o} frames${o===a.frames?"":` (rendered ${a.frames})`}`),r(s.codec_name===h[e.video.codec],`${s.codec_name}${s.codec_name===h[e.video.codec]?"":` (asked ${e.video.codec})`}`);const n=u[e.color];n&&s.color_space&&"unknown"!==s.color_space&&r(s.color_space===n.matrix,`color ${s.color_space}${s.color_space===n.matrix?"":` (asked ${n.matrix})`}`)}else r(!1,"no video stream in the file");if("none"===e.audio.codec)r(!i,i?"has an audio stream (asked none)":"no audio");else if(i){const t=c[e.audio.codec];r(i.codec_name===t.encoder||"libopus"===t.encoder&&"opus"===i.codec_name||"libmp3lame"===t.encoder&&"mp3"===i.codec_name,`${i.codec_name} ${Math.round(+i.sample_rate/100)/10} kHz ${1===+i.channels?"mono":2===+i.channels?"stereo":i.channels+" ch"}`),+i.sample_rate!==e.audio.sampleRate&&r(!1,`sample rate ${i.sample_rate} (asked ${e.audio.sampleRate})`),+i.channels!==e.audio.channels&&r(!1,`${i.channels} channel${1===+i.channels?"":"s"} (asked ${e.audio.channels})`)}else r(!a.hasAudio,a.hasAudio?"no audio stream":"no audio (the timeline is silent)");const m=+(t&&t.format&&t.format.duration);a.duration&&Number.isFinite(m)&&r(p(m,a.duration,Math.max(.05,1.5/(a.fps||30))),`${A(m)}${p(m,a.duration,Math.max(.05,1.5/(a.fps||30)))?"":` (timeline ${A(a.duration)})`}`);const f=a.loud;if(!a.loudWanted||!i||f&&null!=f.lufs||f&&f.silent||r(!1,"loudness could not be measured"),f&&f.silent&&i&&r(null==e.audio.loudness,"silent"+(null!=e.audio.loudness?` (target ${e.audio.loudness} LUFS)`:"")),f&&null!=f.lufs){const t=e.audio.loudness,a=f.truePeak;if(null!=t)r(p(f.lufs,t,1),`${f.lufs.toFixed(1)} LUFS${p(f.lufs,t,1)?"":` (target ${t})`}`),null!=a&&r(a<=(e.audio.truePeak??-1)+.5,`${a.toFixed(1)} dBTP${a<=(e.audio.truePeak??-1)+.5?"":` (ceiling ${e.audio.truePeak??-1})`}`);else{const t=x[e.preset],o=null!=t&&f.lufs>t+1?` — ${b[e.preset].label} plays it ${(f.lufs-t).toFixed(1)} dB quieter (set Loudness to ${t} LUFS to match)`:"";r(!0,`${f.lufs.toFixed(1)} LUFS${null!=a?` · ${a.toFixed(1)} dBTP`:""}${o}`),null!=a&&a>0&&r(!1,`true peak ${a.toFixed(1)} dBTP — over 0, it will clip after encoding`)}}const v=b[e.preset]&&b[e.preset].limits||{};return a.size&&r(!(v.size&&a.size>v.size),`${T(a.size)}${v.size&&a.size>v.size?` (over ${b[e.preset].label}'s ${T(v.size)})`:""}`),{ok:!o.filter(e=>!e.ok).length,checks:o,line:o.map(e=>(e.ok?"":"⚠ ")+e.text).join(" · ")}},fmtBytes:T,fmtDur:E}}();t?module.exports=a:e.FableCutDelivery=a}("undefined"!=typeof self?self:this);
@@ -0,0 +1 @@
1
+ "use strict";const e=require("fs"),r=require("os"),t=require("path"),{spawn:i}=require("./cli/lib/processes"),o=t.join(__dirname,"encoding-profiles.json"),n="delivery",s={matrix:"bt709",primaries:"bt709",trc:"bt709",range:"tv"},a={label:"Delivery · H.264 balanced",description:"Built-in fallback — good quality and compatibility.",jpegQuality:.95,extension:".mp4",color:{...s},args:["-c:v","libx264","-preset","fast","-crf","18","-pix_fmt","yuv420p","-c:a","aac","-b:a","192k","-movflags","+faststart","-shortest"]},l=new Set(["-colorspace","-color_primaries","-color_trc","-color_range"]);let c=null,u=-1;function f(e){const r=e&&"object"==typeof e?e:{},t=(e,r)=>{const t=String(e??"").trim().toLowerCase();return/^[a-z0-9._-]+$/.test(t)?t:r};let i=t(r.range,s.range);"full"===i&&(i="pc"),"limited"===i&&(i="tv"),"tv"!==i&&"pc"!==i&&(i=s.range);const o=t(r.matrix??r.colorspace,s.matrix);return{matrix:o,primaries:t(r.primaries,o),trc:t(r.trc??r.transfer,o),range:i}}function p(e,r){const t=r&&"object"==typeof r?r:{},i=Array.isArray(t.args)?t.args.map(String):String(t.args||"").split(/\s+/).filter(Boolean);let o=String(t.extension||a.extension).trim().toLowerCase();o&&!o.startsWith(".")&&(o=`.${o}`),/^\.[a-z0-9]+$/.test(o)||(o=a.extension);const n=Number(t.jpegQuality);return{id:e,label:String(t.label||e),description:String(t.description||t.desc||""),jpegQuality:n>=.1&&n<=1?n:a.jpegQuality,extension:o,color:f(t.color),args:i}}function g(r){const i=function(){try{return e.statSync(o).mtimeMs}catch{return 0}}();if(c&&!r&&i===u)return c;let s=null;const l=[];try{e.existsSync(o)?s=JSON.parse(e.readFileSync(o,"utf8").replace(/^\uFEFF/,"")):l.push(`${t.basename(o)} not found — using the built-in profile`)}catch(e){l.push(`${t.basename(o)} could not be parsed (${e.message}) — using the built-in profile`)}const f={};if(s?.profiles&&"object"==typeof s.profiles)for(const[e,r]of Object.entries(s.profiles))f[e]=p(e,r);for(const[e,r]of Object.entries(f))r.args.length||l.push(`profile "${e}" has no args — ffmpeg will pick its own defaults`);Object.keys(f).length||(f[n]=p(n,a));let g="string"==typeof s?.default?s.default:n;if(!f[g]){const e=Object.keys(f)[0];s?.default&&l.push(`default "${s.default}" is not a defined profile — using ${e}`),g=e}return c={default:g,profiles:f,issues:l},u=i,c}function m(e,r=120){const t=(e.args||[]).join(" ")||"(no args — ffmpeg defaults)";return t.length>r?t.slice(0,r-1)+"…":t}function d(e,r){const t=e.color||s,i=function(e,r){const t=e||s;return`scale=in_range=full:in_color_matrix=${"bt601"===r?"bt601":"bt709"}:out_range=${t.range}:out_color_matrix=${t.matrix},setparams=color_primaries=${t.primaries}:color_trc=${t.trc}`}(t,r),o=function(e){const r=[];for(let t=0;t<e.length;t++)l.has(e[t])?t++:r.push(e[t]);return r}((e.args||[]).slice()),n=o.indexOf("-vf");return n>=0&&null!=o[n+1]?o[n+1]=`${i},${o[n+1]}`:o.unshift("-vf",i),o.push(...function(e){const r=e||s;return["-colorspace",r.matrix,"-color_primaries",r.primaries,"-color_trc",r.trc,"-color_range",r.range]}(t)),o}module.exports={PROFILES_FILE:o,DEFAULT_COLOR:s,loadEncodeProfiles:g,invalidateEncodeProfiles:function(){c=null,u=-1},resolveProfile:function(e){const r=g(),t=e||r.default,i=r.profiles[t];if(!i)throw new Error(`Unknown encoding profile "${t}"`);return i},listProfilesPublic:function(e){const r=g(),i={default:r.default,profiles:{},file:t.basename(o),issues:r.issues||[]};for(const[t,o]of Object.entries(r.profiles)){const r={label:o.label,description:o.description,jpegQuality:o.jpegQuality,extension:o.extension,color:o.color,summary:m(o)};i.profiles[t]=e?{...r,args:o.args}:r}return i},profileSummary:m,buildExportArgs:function(e,{fps:r,wavPath:t,outPath:i,pixelFormat:o,width:n,height:s}={}){const a=["-y","-hide_banner"],l="rgba"===o;if(l){const e=Math.max(2,0|n),t=Math.max(2,0|s);a.push("-thread_queue_size","8","-f","rawvideo","-pix_fmt","rgba","-s",`${e}x${t}`,"-framerate",String(r),"-i","-")}else a.push("-thread_queue_size","64","-f","image2pipe","-framerate",String(r),"-c:v","mjpeg","-i","-");return t&&a.push("-i",t),a.push(...d(e,l?"bt709":"bt601"),i),a},dryRunProfile:function(o,{fps:n=30,hasAudio:s=!0}={}){const a=e.mkdtempSync(t.join(r.tmpdir(),"fablecut-dry-")),l=t.join(a,`probe${o.extension}`),c=["-y","-hide_banner","-f","lavfi","-i",`color=c=black:s=256x144:r=${n}:d=0.1`];return s&&c.push("-f","lavfi","-i","anullsrc=r=48000:cl=stereo"),c.push("-t","0.1",...d(o,"bt709"),l),new Promise(r=>{let t,o,n="",s=!1,l=!1;const u=t=>{if(!s){s=!0,clearTimeout(o);try{e.rmSync(a,{recursive:!0,force:!0})}catch{}r(t)}};try{t=i("ffmpeg",c,{stdio:["ignore","ignore","pipe"]})}catch(e){return void u({ok:!1,error:e.message||String(e)})}o=setTimeout(()=>{l=!0;try{t.kill("SIGKILL")}catch{}},15e3),t.on("error",e=>u({ok:!1,error:e.message||String(e)})),t.stderr.on("data",e=>{n=(n+e).slice(-4e3)}),t.on("close",e=>{if(l)return void u({ok:!1,error:"ffmpeg dry-run timed out"});if(0===e)return void u({ok:!0});const r=n.trim().split("\n").map(e=>e.trim()).filter(Boolean),t=r.filter(e=>/error|invalid|unknown|not found|unrecognized|failed|minimum|unsupported|no such/i.test(e)&&!/^Conversion failed/i.test(e)),i=t.length?t.slice(0,2).concat(r.slice(-1)):r.slice(-3);u({ok:!1,error:[...new Set(i)].join(" · ")||`ffmpeg exited ${e}`})})})}};
@@ -0,0 +1,284 @@
1
+ {
2
+ "default": "delivery",
3
+ "profiles": {
4
+ "draft": {
5
+ "label": "草稿 · H.264 快速",
6
+ "description": "快速预览:较小文件,较快编码。",
7
+ "jpegQuality": 0.85,
8
+ "extension": ".mp4",
9
+ "color": {
10
+ "matrix": "bt709",
11
+ "primaries": "bt709",
12
+ "trc": "bt709",
13
+ "range": "tv"
14
+ },
15
+ "args": [
16
+ "-c:v",
17
+ "libx264",
18
+ "-preset",
19
+ "veryfast",
20
+ "-crf",
21
+ "23",
22
+ "-pix_fmt",
23
+ "yuv420p",
24
+ "-c:a",
25
+ "aac",
26
+ "-b:a",
27
+ "128k",
28
+ "-movflags",
29
+ "+faststart",
30
+ "-shortest"
31
+ ]
32
+ },
33
+ "delivery": {
34
+ "label": "交付 · H.264 均衡",
35
+ "description": "默认软件编码,兼顾画质、大小与兼容性。",
36
+ "jpegQuality": 0.95,
37
+ "extension": ".mp4",
38
+ "color": {
39
+ "matrix": "bt709",
40
+ "primaries": "bt709",
41
+ "trc": "bt709",
42
+ "range": "tv"
43
+ },
44
+ "args": [
45
+ "-c:v",
46
+ "libx264",
47
+ "-preset",
48
+ "fast",
49
+ "-crf",
50
+ "18",
51
+ "-pix_fmt",
52
+ "yuv420p",
53
+ "-c:a",
54
+ "aac",
55
+ "-b:a",
56
+ "192k",
57
+ "-movflags",
58
+ "+faststart",
59
+ "-shortest"
60
+ ]
61
+ },
62
+ "hq": {
63
+ "label": "高质量 · H.264 4:2:2 10-bit",
64
+ "description": "用于中间母版及调色交换,编码较慢、文件较大;部分浏览器和 QuickTime 无法播放。",
65
+ "jpegQuality": 0.98,
66
+ "extension": ".mp4",
67
+ "color": {
68
+ "matrix": "bt709",
69
+ "primaries": "bt709",
70
+ "trc": "bt709",
71
+ "range": "tv"
72
+ },
73
+ "args": [
74
+ "-c:v",
75
+ "libx264",
76
+ "-preset",
77
+ "slow",
78
+ "-crf",
79
+ "16",
80
+ "-pix_fmt",
81
+ "yuv422p10le",
82
+ "-c:a",
83
+ "aac",
84
+ "-b:a",
85
+ "256k",
86
+ "-movflags",
87
+ "+faststart",
88
+ "-shortest"
89
+ ]
90
+ },
91
+ "broadcast1080i50": {
92
+ "label": "广播 · 1080i50 MOV",
93
+ "description": "工程使用 1920×1080、25 fps,滤镜生成广播交付所需的隔行输出。",
94
+ "jpegQuality": 0.98,
95
+ "extension": ".mov",
96
+ "color": {
97
+ "matrix": "bt709",
98
+ "primaries": "bt709",
99
+ "trc": "bt709",
100
+ "range": "tv"
101
+ },
102
+ "args": [
103
+ "-c:v",
104
+ "libx264",
105
+ "-preset",
106
+ "fast",
107
+ "-crf",
108
+ "18",
109
+ "-pix_fmt",
110
+ "yuv420p",
111
+ "-g",
112
+ "10",
113
+ "-maxrate",
114
+ "60M",
115
+ "-bufsize",
116
+ "70M",
117
+ "-x264opts",
118
+ "open_gop=0:interlaced=1:me=hex:subme=2:cabac=1:no-deblock:analyse=all:8x8dct=1:bframes=2:weightp=0:sliced-threads:level=41",
119
+ "-vf",
120
+ "scale=1920:1080:interl=-1,fps=50,tinterlace=interleave_top:bypass_il",
121
+ "-c:a",
122
+ "aac",
123
+ "-b:a",
124
+ "384k",
125
+ "-ar",
126
+ "48000",
127
+ "-strict",
128
+ "-2",
129
+ "-shortest"
130
+ ]
131
+ },
132
+ "prores422": {
133
+ "label": "ProRes 422 HQ · MOV",
134
+ "description": "用于中间母版和剪辑交换,文件较大。",
135
+ "jpegQuality": 1,
136
+ "extension": ".mov",
137
+ "color": {
138
+ "matrix": "bt709",
139
+ "primaries": "bt709",
140
+ "trc": "bt709",
141
+ "range": "tv"
142
+ },
143
+ "args": [
144
+ "-c:v",
145
+ "prores_ks",
146
+ "-profile:v",
147
+ "3",
148
+ "-pix_fmt",
149
+ "yuv422p10le",
150
+ "-c:a",
151
+ "pcm_s16le",
152
+ "-shortest"
153
+ ]
154
+ },
155
+ "nvenc-h264": {
156
+ "label": "NVIDIA · H.264",
157
+ "description": "使用 NVIDIA NVENC 编码,需可用显卡及包含 NVENC 的 ffmpeg。",
158
+ "jpegQuality": 0.95,
159
+ "extension": ".mp4",
160
+ "color": {
161
+ "matrix": "bt709",
162
+ "primaries": "bt709",
163
+ "trc": "bt709",
164
+ "range": "tv"
165
+ },
166
+ "args": [
167
+ "-c:v",
168
+ "h264_nvenc",
169
+ "-preset",
170
+ "p5",
171
+ "-tune",
172
+ "hq",
173
+ "-rc",
174
+ "vbr",
175
+ "-cq",
176
+ "19",
177
+ "-b:v",
178
+ "0",
179
+ "-pix_fmt",
180
+ "yuv420p",
181
+ "-c:a",
182
+ "aac",
183
+ "-b:a",
184
+ "192k",
185
+ "-movflags",
186
+ "+faststart",
187
+ "-shortest"
188
+ ]
189
+ },
190
+ "nvenc-hevc": {
191
+ "label": "NVIDIA · HEVC",
192
+ "description": "使用 NVIDIA NVENC 编码 HEVC,需可用显卡及包含 NVENC 的 ffmpeg。",
193
+ "jpegQuality": 0.95,
194
+ "extension": ".mp4",
195
+ "color": {
196
+ "matrix": "bt709",
197
+ "primaries": "bt709",
198
+ "trc": "bt709",
199
+ "range": "tv"
200
+ },
201
+ "args": [
202
+ "-c:v",
203
+ "hevc_nvenc",
204
+ "-preset",
205
+ "p5",
206
+ "-tune",
207
+ "hq",
208
+ "-rc",
209
+ "vbr",
210
+ "-cq",
211
+ "21",
212
+ "-b:v",
213
+ "0",
214
+ "-pix_fmt",
215
+ "yuv420p",
216
+ "-tag:v",
217
+ "hvc1",
218
+ "-c:a",
219
+ "aac",
220
+ "-b:a",
221
+ "192k",
222
+ "-movflags",
223
+ "+faststart",
224
+ "-shortest"
225
+ ]
226
+ },
227
+ "videotoolbox-h264": {
228
+ "label": "Apple Silicon · H.264",
229
+ "description": "使用 VideoToolbox 硬件编码,需 Apple Silicon、macOS 及包含 VideoToolbox 的 ffmpeg。",
230
+ "jpegQuality": 0.95,
231
+ "extension": ".mp4",
232
+ "color": {
233
+ "matrix": "bt709",
234
+ "primaries": "bt709",
235
+ "trc": "bt709",
236
+ "range": "tv"
237
+ },
238
+ "args": [
239
+ "-c:v",
240
+ "h264_videotoolbox",
241
+ "-q:v",
242
+ "65",
243
+ "-pix_fmt",
244
+ "yuv420p",
245
+ "-c:a",
246
+ "aac",
247
+ "-b:a",
248
+ "192k",
249
+ "-movflags",
250
+ "+faststart",
251
+ "-shortest"
252
+ ]
253
+ },
254
+ "videotoolbox-hevc": {
255
+ "label": "Apple Silicon · HEVC",
256
+ "description": "使用 VideoToolbox 硬件编码 HEVC,需 Apple Silicon、macOS 及包含 VideoToolbox 的 ffmpeg。",
257
+ "jpegQuality": 0.95,
258
+ "extension": ".mp4",
259
+ "color": {
260
+ "matrix": "bt709",
261
+ "primaries": "bt709",
262
+ "trc": "bt709",
263
+ "range": "tv"
264
+ },
265
+ "args": [
266
+ "-c:v",
267
+ "hevc_videotoolbox",
268
+ "-q:v",
269
+ "58",
270
+ "-pix_fmt",
271
+ "yuv420p",
272
+ "-tag:v",
273
+ "hvc1",
274
+ "-c:a",
275
+ "aac",
276
+ "-b:a",
277
+ "192k",
278
+ "-movflags",
279
+ "+faststart",
280
+ "-shortest"
281
+ ]
282
+ }
283
+ }
284
+ }
@@ -1 +1 @@
1
- "use strict";const e=require("node:fs/promises"),r=require("node:os"),t=require("node:path"),{localMedia:o}=require("./export-cache"),{run:a}=require("./export-encoder");module.exports={ExportAudio:class{constructor({libraryDir:e}){this.libraryDir=e,this.queue=Promise.resolve()}async prepare(i,n,s){const c=await o(i,this.libraryDir,n),u=this.queue.then(async()=>{if(s?.aborted)throw new Error("export cancelled");const o=await e.mkdtemp(t.join(r.tmpdir(),"fablecut-export-audio-")),i=t.join(o,"source.wav"),n=()=>e.rm(o,{recursive:!0,force:!0}),u=new AbortController,l=()=>u.abort();s?.addEventListener("abort",l,{once:!0}),s?.aborted&&l();const d=setTimeout(l,6e5);try{return await a("ffmpeg",["-nostdin","-v","error","-y","-i",c,"-map","0:a:0?","-vn","-af","aresample=48000:async=1:first_pts=0","-c:a","pcm_f32le","-rf64","auto",i],u.signal),{file:i,cleanup:n}}catch(e){if(await n(),!u.signal.aborted&&/does not contain any stream/i.test(e.message))return null;throw e}finally{clearTimeout(d),s?.removeEventListener("abort",l)}});return this.queue=u.catch(()=>{}),u}}};
1
+ "use strict";const e=require("node:fs/promises"),r=require("node:os"),t=require("node:path"),{localMedia:a}=require("./export-cache"),{run:o}=require("./export-encoder");module.exports={ExportAudio:class{constructor({libraryDir:e}){this.libraryDir=e,this.queue=Promise.resolve()}async prepare(i,s,n){const c=await a(i,this.libraryDir,s),u=this.queue.then(async()=>{if(n?.aborted)throw new Error("export cancelled");const a=await e.mkdtemp(t.join(r.tmpdir(),"fablecut-export-audio-")),i=t.join(a,"source.wav"),s=()=>e.rm(a,{recursive:!0,force:!0}),u=new AbortController,l=()=>u.abort();n?.addEventListener("abort",l,{once:!0}),n?.aborted&&l();const d=setTimeout(l,6e5);try{return await o("ffmpeg",["-nostdin","-v","error","-y","-i",c,"-map","0:a:0?","-vn","-af","aresample=48000:async=1:first_pts=0","-c:a","pcm_f32le","-rf64","auto",i],u.signal),{file:i,cleanup:s}}catch(r){if(await s(),!u.signal.aborted&&/does not contain any stream/i.test(r.message))return null;let t="";try{t=" size="+(await e.stat(c)).size}catch{}throw t&&(r.message+=t),r}finally{clearTimeout(d),n?.removeEventListener("abort",l)}});return this.queue=u.catch(()=>{}),u}}};
@@ -1 +1 @@
1
- "use strict";const e=require("node:fs"),t=e.promises,s=require("node:path"),r=require("node:crypto"),{spawn:i}=require("./cli/lib/processes"),a=require("node:os"),n=Math.min(2,a.availableParallelism?.()||a.cpus().length||1),o=e=>{const[t,s=1]=String(e).split("/").map(Number);return t/s};function c(e,t,s,r){return new Promise((a,n)=>{if(s?.aborted)return n(new Error("cancelled"));const o=i(e,t,{stdio:["ignore","pipe","pipe"]});let c,l="",d="";const h=()=>{c=new Error("cancelled"),o.kill("SIGKILL")},p=setTimeout(()=>{c=new Error(e+" timed out"),o.kill("SIGKILL")},12e4);s?.addEventListener("abort",h,{once:!0}),o.stdout.on("data",e=>{l+=e,l.length>16777216&&(c=new Error("probe output too large"),o.kill("SIGKILL"))}),o.stderr.on("data",e=>{r?.(String(e)),d=(d+e).slice(-4e3)}),o.on("error",e=>{c=e}),o.on("close",t=>{clearTimeout(p),s?.removeEventListener("abort",h),c||0!==t?n(c||new Error(d||e+" failed")):a(l)})})}function l(e){const t=/ffmpeg version\s+n?(\d+)\.(\d+)/.exec(e);if(t){const e=Number(t[1]),s=Number(t[2]);return e>5||5===e&&s>=1?["-fps_mode","passthrough"]:["-vsync","0"]}return/(?:^|[\r\n])\s*-fps_mode\b/.test(e)?["-fps_mode","passthrough"]:/(?:^|[\r\n])\s*-vsync\b/.test(e)?["-vsync","0"]:null}let d;function h(e){const t=o(e.r_frame_rate),s=o(e.avg_frame_rate);return Number.isFinite(t)&&t>0&&t<=120&&Math.abs(t-s)<1e-4&&0===Number(e.start_time||0)&&["1:1","0:1",void 0].includes(e.sample_aspect_ratio)&&!e.tags?.rotate&&!e.side_data_list?.some(e=>e.rotation)&&["yuv420p","yuvj420p"].includes(e.pix_fmt)&&["bt709","smpte170m","bt470bg"].includes(e.color_space)&&[void 0,"unknown","bt709","smpte170m","bt470bg"].includes(e.color_primaries)&&[void 0,"unknown","bt709","smpte170m","gamma22","gamma28"].includes(e.color_transfer)&&e.width>0&&e.height>0}function p(e,t){const s=1/t,r=Math.max(.002,.1*s);return e.length>0&&e.every((t,i)=>Number.isFinite(t)&&(!i||t>e[i-1]&&Math.abs(t-e[i-1]-s)<=r))}async function m(e,r,i){const a=`/projects/${e.id}/media/`;let n,o;if(i?.startsWith(a))n=e.mediaDir,o=i.slice(a.length);else if("default"===e.id&&i?.startsWith("/media/"))n=e.mediaDir,o=i.slice(7);else{if(!i?.startsWith("/library/"))throw new Error("non-local or cross-project source");n=r,o=i.slice(9)}n=await t.realpath(n);const c=await t.realpath(s.resolve(n,decodeURIComponent(o)));if(!c.startsWith(n+s.sep))throw new Error("source escapes media directory");return c}class u{constructor(e=((a.availableParallelism?.()||a.cpus().length||1)>=8?2:1)){this.concurrency=e,this.pending=[],this.active=new Set,this.lastOwner=new Map}enqueue(e,t,s,r,i="default"){let a,n;const o={run:e,priority:t,neededAt:s,signal:r,owner:i,enqueuedAt:Date.now(),promise:new Promise((e,t)=>{a=e,n=t}),resolve:a,reject:n},c=()=>{const e=this.pending.indexOf(o);e>=0&&(this.pending.splice(e,1),o.cleanup(),n(new Error("cancelled")),this.pump())};return o.cleanup=()=>r.removeEventListener("abort",c),r.addEventListener("abort",c,{once:!0}),this.pending.push(o),queueMicrotask(()=>this.pump()),o}promote(e,t,s){"demand"===t&&(e.priority="demand"),e.neededAt=Math.min(e.neededAt,s),this.pump()}pump(){for(;this.active.size<this.concurrency;){const e=[...this.active].some(e=>"prefetch"===e.priority),t=this.pending.some(e=>"demand"===e.priority)?"demand":"prefetch";if("prefetch"===t&&e)return;const s=this.pending.filter(e=>e.priority===t);if(!s.length)return;const r=[...new Set(s.map(e=>e.owner))],i=r.indexOf(this.lastOwner.get(t)),a=r[(i+1)%r.length],n=s.filter(e=>e.owner===a).sort((e,t)=>e.neededAt-t.neededAt)[0];this.pending.splice(this.pending.indexOf(n),1),n.cleanup(),this.active.add(n),this.lastOwner.set(t,a),n.startedAt=Date.now(),Promise.resolve().then(()=>{if(n.signal.aborted)throw new Error("cancelled");return n.run(n.startedAt-n.enqueuedAt)}).then(n.resolve,n.reject).finally(()=>{this.active.delete(n),this.pump()})}}}module.exports={ExportCache:class{constructor({libraryDir:e,limit:t=2147483648,ttl:s=9e4,concurrency:r}={}){this.libraryDir=e,this.limit=t,this.ttl=s,this.queue=new u(r),this.sessions=new Map,this.jobs=new Map,this.pins=new Map,this.roots=new Map,this.releases=new Map,this.timer=setInterval(()=>{for(const e of this.sessions.values())!e.managed&&Date.now()-e.touched>s&&this.release(e.id,e.pp.id)},Math.min(s,15e3)),this.timer.unref()}get(e,t){const s=this.sessions.get(e);if(!s||s.pp.id!==t)throw new Error("no such cache session");return s.touched=Date.now(),s}create(t,s,i,{managed:a=!1}={}){const n=i||JSON.parse(e.readFileSync(t.projectFile,"utf8").replace(/^\uFEFF/,""));if(n.revision!==s)throw new Error("Project changed; save/reload before exporting");const o={id:r.randomBytes(16).toString("hex"),pp:t,project:n,managed:a,touched:Date.now(),operations:new Set,controller:new AbortController,sources:new Map,blocks:new Map,leases:new Map,pins:new Set,prefetchSequence:-1,prefetchPlan:null,waitSequence:-1,state:"preparing",stats:{hits:0,misses:0,fallbacks:{},extractionMs:0,queueWaitMs:0,decodeMs:0,publishMs:0,prefetchSkipped:0,capacityFallbacks:0,peakDiskBytes:0}};return this.sessions.set(o.id,o),o.ready=this.prepare(o).then(()=>{o.state="ready"}).catch(e=>{o.state="error",o.error=e.message}),o.id}async prepare(s){const i=new Set(s.project.disabledTracks||[]),a=new Map;for(const n of s.project.clips)if("video"===n.kind&&!i.has(n.track)){if(s.controller.signal.aborted)throw new Error("cancelled");try{if(n.keyframes?.speed?.length)throw new Error("speed ramp");const i=Math.max(.1,Math.min(8,Number(n.props?.speed)||1));if(![n.in,n.duration,i].every(Number.isFinite)||n.in<0||n.duration<=0)throw new Error("invalid source interval");const l=s.project.media.find(e=>e.id===n.mediaId);a.has(n.mediaId)||a.set(n.mediaId,(async()=>{const i=await m(s.pp,this.libraryDir,l?.src),a=await t.stat(i),n=JSON.parse(await c("ffprobe",["-v","error","-select_streams","v:0","-show_streams","-of","json",i],s.controller.signal)),d=n.streams?.[0];if(!d||!h(d))throw new Error("unsupported/uncertain video metadata");const p=r.createHash("sha256");for await(const t of e.createReadStream(i)){if(s.controller.signal.aborted)throw new Error("cancelled");p.update(t)}return{file:i,stamp:`${a.size}:${a.mtimeMs}`,hash:p.digest("hex"),fps:o(d.r_frame_rate),width:d.width,height:d.height,duration:Number(d.duration)}})());const d=await a.get(n.mediaId);s.sources.set(n.id,{...d,start:n.in,end:n.in+n.duration*i})}catch(e){s.stats.fallbacks[n.id]=e.message}}}status(e,t){const s=this.get(e,t);return{id:e,state:s.state,error:s.error,clips:[...s.sources.keys()],stats:s.stats}}pin(e,t){e.pins.has(t)||(e.pins.add(t),this.pins.set(t,(this.pins.get(t)||0)+1))}unpin(e,t){if(!e.pins.delete(t))return;const s=(this.pins.get(t)||1)-1;s?this.pins.set(t,s):this.pins.delete(t)}async rootIndex(e){if(!this.roots.has(e)){const s=(async()=>{await t.mkdir(e,{recursive:!0});const s={entries:new Map,partials:new Map,lock:Promise.resolve()};return await this.scan(e,s),s})();this.roots.set(e,s),s.catch(()=>this.roots.delete(e))}return this.roots.get(e)}async scan(e,r){const i=new Map;for(const a of await t.readdir(e)){const n=s.join(e,a);if(/^[a-f0-9]{64}$/.test(a))try{const e=JSON.parse(await t.readFile(s.join(n,"manifest.json"))),r=await t.stat(n);if(!Number.isFinite(e.bytes)||e.bytes<0)throw new Error("invalid cache manifest");i.set(n,{dir:n,bytes:e.bytes,time:r.mtimeMs,manifest:e})}catch(e){if("ENOENT"!==e.code)throw e}else if(/^[a-f0-9]{64}\.partial-[a-f0-9]+$/.test(a)&&!this.jobs.has(n.slice(0,n.lastIndexOf(".partial-")))){const e=await t.stat(n);if(Date.now()-e.mtimeMs>12e4)await t.rm(n,{recursive:!0,force:!0}),r.partials.delete(n);else{const e=await Promise.all((await t.readdir(n)).map(e=>t.stat(s.join(n,e))));r.partials.set(n,e.reduce((e,t)=>e+t.size,0))}}}r.entries=i}async locked(e,t){const s=await this.rootIndex(e),r=s.lock.then(()=>t(s));return s.lock=r.catch(()=>{}),r}async makeRoom(e,s,r=0,i=!0){let a=[...s.entries.values()].reduce((e,t)=>e+t.bytes,0)+[...s.partials.values()].reduce((e,t)=>e+t,0)+r;for(const r of[...s.entries.values()].sort((e,t)=>e.time-t.time)){if(a<=this.limit)break;if(!this.pins.has(r.dir)&&!this.jobs.has(r.dir)){try{await t.rm(r.dir,{recursive:!0,force:!0})}catch(t){throw await this.scan(e,s),t}s.entries.delete(r.dir),a-=r.bytes}}if(a>this.limit&&i)return await this.scan(e,s),this.makeRoom(e,s,r,!1);if(a>this.limit)throw new Error("frame cache capacity exceeded");return a}async room(e,t=0,r){const i=()=>this.locked(e,async s=>(r&&s.partials.set(r,t),this.makeRoom(e,s,r?0:t)));try{return await i()}catch(t){const a=r&&this.jobs.get(r.slice(0,r.lastIndexOf(".partial-")));if(!/capacity/.test(t.message)||"demand"!==a?.queued.priority)throw t;const n=new Set,o=new Set;for(const t of this.sessions.values())for(const r of t.leases.values())s.dirname(r.dir)===e&&("demand"===r.priority?o:n).add(r.dir);for(const e of o)n.delete(e);for(const e of n)"demand"===this.jobs.get(e)?.queued.priority&&n.delete(e);if(!n.size)throw t;const c=[...n].map(e=>this.jobs.get(e)).filter(Boolean);for(const e of this.sessions.values())for(const[t,s]of e.leases)n.has(s.dir)&&this.removeLease(e,t);return await Promise.allSettled(c.map(e=>e.promise)),i()}}async build(e,i,a,o,h,m={}){const u=i+".partial-"+r.randomBytes(6).toString("hex");await t.mkdir(u,{recursive:!0});const f=[];let w="";const b=Math.max(0,5*o-2/a.fps),g=5*(o+1)+1/a.fps,y=await(d||(d=(async()=>{const e=l(await c("ffmpeg",["-version"]));if(e)return e;const t=l(await c("ffmpeg",["-hide_banner","-h","full"]));if(!t)throw new Error("ffmpeg 缺少 -fps_mode 和 -vsync");return t})().catch(e=>{throw d=void 0,e})),d),v=["-hide_banner","-loglevel","info","-nostdin","-y","-copyts","-ss",String(Math.max(0,b-2)),"-t",String(g-Math.max(0,b-2)+1),"-i",a.file,"-map","0:v:0","-an","-vf",`select='gte(t,${b-1e-5})*lt(t,${g})',showinfo`,...y,"-threads",String(n),"-compression_level","1",s.join(u,"%06d.png")];let k,E,S=Promise.resolve(),M=!1;const j=new AbortController,I=()=>j.abort();h.addEventListener("abort",I,{once:!0});try{await this.room(e,0,u),k=setInterval(()=>{M||(M=!0,S=(async()=>{const r=await t.readdir(u),i=await Promise.all(r.map(e=>t.stat(s.join(u,e))));await this.room(e,i.reduce((e,t)=>e+t.size,0),u)})().catch(e=>{E=e,j.abort()}).finally(()=>{M=!1}))},250),h.aborted&&j.abort();const r=Date.now();try{await c("ffmpeg",v,j.signal,e=>{w+=e;const t=w.split(/[\r\n]/);w=t.pop();for(const e of t){const t=/\bn:\s*\d+.*?pts_time:([\d.e+\-]+)/.exec(e);t&&f.push(Number(t[1]))}})}finally{m.decodeMs=Date.now()-r}const n=Date.now();if(clearInterval(k),await S,E)throw E;if(!p(f,a.fps))throw new Error("variable or invalid frame timestamps");const o=(await t.readdir(u)).filter(e=>e.endsWith(".png"));if(o.length!==f.length)throw new Error("incomplete extracted frames");const l=(await Promise.all(o.map(e=>t.stat(s.join(u,e))))).reduce((e,t)=>e+t.size,0);await this.room(e,l,u);const d={times:f,bytes:l,width:a.width,height:a.height};if(await t.writeFile(s.join(u,"manifest.json"),JSON.stringify(d)),h.aborted)throw new Error("cancelled");return await this.locked(e,async s=>{await this.makeRoom(e,s),await t.rename(u,i),s.partials.delete(u),s.entries.set(i,{dir:i,bytes:l,time:Date.now(),manifest:d})}),m.publishMs=Date.now()-n,d}catch(e){if(E)throw E;throw e}finally{clearInterval(k),await S,h.removeEventListener("abort",I),await this.locked(e,async e=>{await t.rm(u,{recursive:!0,force:!0}),e.partials.delete(u)})}}async block(e,t,s,r,i={}){const a=this.get(e,t),n=this.loadBlock(a,s,r,i);a.operations.add(n);try{return await n}finally{a.operations.delete(n)}}async loadBlock(e,i,a,{priority:n="demand",neededAt:o=0,sequence:c}={}){if(!["demand","prefetch"].includes(n)||!Number.isFinite(o)||o<0)throw new Error("invalid cache priority");await e.ready;const l=e.sources.get(i);if(!l||e.stats.fallbacks[i])return{fallback:e.stats.fallbacks[i]||"source unavailable"};if(!Number.isInteger(a)||a<Math.floor(l.start/5)||a>Math.floor(l.end/5))throw new Error("block outside clip interval");const d=i+":"+a,h=()=>"demand"===n||"demand"===e.leases.get(d)?.priority||null===e.prefetchPlan||c<=e.prefetchSequence&&e.prefetchPlan.has(d);let p,m;try{if(!h())return{skipped:"obsolete prefetch"};const c=await t.stat(l.file);if(`${c.size}:${c.mtimeMs}`!==l.stamp)throw new Error("source changed during export");const f=s.join(e.pp.dir,".export-cache"),w=await this.rootIndex(f),b=(u=JSON.stringify([2,l.hash,a,l.fps,"png-1"]),r.createHash("sha256").update(u).digest("hex"));if(p=s.join(f,b),e.controller.signal.aborted)throw new Error("cancelled");if(!h())return{skipped:"obsolete prefetch"};this.pin(e,p),m={clipId:i,block:a,key:b,dir:p,priority:"demand"===e.leases.get(d)?.priority?"demand":n},e.leases.set(d,m);for(const[t,s]of e.leases)"demand"===n&&s.clipId===i&&s.block<a-1&&(e.leases.delete(t),[...e.leases.values()].some(e=>e.dir===s.dir)||(e.blocks.delete(s.key),this.unpin(e,s.dir)));let g;try{g=await this.locked(f,async e=>{try{await t.access(s.join(p,"manifest.json"));const r=e.entries.get(p)?.manifest;if(!r)throw new Error("cache block not indexed");return r}catch(t){throw e.entries.delete(p),t}}),e.stats.hits++}catch{if(e.controller.signal.aborted)throw new Error("cancelled");e.stats.misses++;const t=this.jobs.get(p);if(t?.controller.signal.aborted&&await t.promise.catch(()=>{}),e.controller.signal.aborted)throw new Error("cancelled");if(!this.jobs.has(p)){const t=new AbortController,s=Date.now(),r={},i=this.queue.enqueue(async s=>{e.stats.queueWaitMs+=s;try{return await this.build(f,p,l,a,t.signal,r)}finally{e.stats.decodeMs+=r.decodeMs||0,e.stats.publishMs+=r.publishMs||0}},n,o,t.signal,e.id),c=i.promise;this.jobs.set(p,{controller:t,promise:c,queued:i}),c.finally(()=>{this.jobs.delete(p),e.stats.extractionMs+=Date.now()-s}).catch(()=>{})}const s=this.jobs.get(p);this.queue.promote(s.queued,n,o),g=await s.promise}if(e.controller.signal.aborted)throw new Error("cancelled");if(!h()||!e.leases.has(d))return{skipped:"obsolete prefetch"};const y=new Date;return await t.utimes(p,y,y),w.entries.has(p)&&(w.entries.get(p).time=y.getTime()),e.blocks.set(b,{clipId:i,block:a,dir:p,manifest:g}),e.stats.peakDiskBytes=Math.max(e.stats.peakDiskBytes,[...w.entries.values()].reduce((e,t)=>e+t.bytes,0)+[...w.partials.values()].reduce((e,t)=>e+t,0)),{key:b,...g}}catch(t){if("prefetch"===n&&!/variable or invalid frame timestamps|incomplete extracted frames/.test(t.message))return e.stats.prefetchSkipped++,e.leases.get(d)===m&&"prefetch"===m?.priority&&this.removeLease(e,d),{skipped:t.message};/capacity/.test(t.message)&&e.stats.capacityFallbacks++;const s=new Set(/variable or invalid frame timestamps|incomplete extracted frames/.test(t.message)?[...e.sources].filter(([,e])=>e.hash===l.hash).map(([e])=>e):[i]);for(const r of s)e.stats.fallbacks[r]=t.message;for(const[t,r]of e.leases)s.has(r.clipId)&&(e.leases.delete(t),[...e.leases.values()].some(e=>e.dir===r.dir)||(e.blocks.delete(r.key),this.unpin(e,r.dir)));return{fallback:t.message}}var u}removeLease(e,t){const s=e.leases.get(t);s&&(e.leases.delete(t),[...e.leases.values()].some(e=>e.dir===s.dir)||(e.blocks.delete(s.key),this.unpin(e,s.dir),this.pins.has(s.dir)||this.jobs.get(s.dir)?.controller.abort()))}retain(e,t,s,r,i=[]){const a=this.get(e,t);if(!Number.isSafeInteger(s)||s<0||!Array.isArray(r)||r.length>3||r.some(e=>"string"!=typeof e.clipId||!Number.isSafeInteger(e.block)||e.block<0))throw new Error("invalid prefetch plan");if(!Array.isArray(i)||i.length>a.project.clips.length||i.some(e=>!a.sources.has(e.clipId)||!Number.isSafeInteger(e.block)||e.block<0))throw new Error("invalid current blocks");if(!(s<=a.prefetchSequence)){a.prefetchSequence=s,a.prefetchPlan=new Set(r.map(e=>e.clipId+":"+e.block));for(const e of i){const t=a.leases.get(e.clipId+":"+e.block);if(t){t.priority="demand";const e=this.jobs.get(t.dir);e&&this.queue.promote(e.queued,"demand",0)}}for(const[e,t]of a.leases)"prefetch"!==t.priority||a.prefetchPlan.has(e)||this.removeLease(a,e)}}reportWait(e,t,{sequence:s,reason:r,elapsedMs:i=0}){const a=this.get(e,t);if(!Number.isSafeInteger(s)||s<0||![null,"source-block","source-image","encoder"].includes(r)||!Number.isFinite(i)||i<0||i>864e5)throw new Error("invalid export wait");s<=a.waitSequence||(a.waitSequence=s,a.wait=r?{reason:r,since:Date.now()-i}:null)}drop(e,t,s){const r=this.get(e,t);if(!Array.isArray(s)||s.length>r.project.clips.length)throw new Error("invalid clip list");const i=new Set(s);for(const[e,t]of r.leases)i.has(t.clipId)&&(r.leases.delete(e),[...r.leases.values()].some(e=>e.dir===t.dir)||(r.blocks.delete(t.key),this.unpin(r,t.dir),this.pins.has(t.dir)||this.jobs.get(t.dir)?.controller.abort()))}frame(e,t,r,i){const a=this.get(e,t).blocks.get(r);if(!a||!Number.isInteger(i)||i<0||i>=a.manifest.times.length)throw new Error("unknown cache frame");return s.join(a.dir,String(i+1).padStart(6,"0")+".png")}release(e,t){const s=this.sessions.get(e);if(!s)return this.releases.get(e)?.projectId===t?this.releases.get(e).done:void 0;if(s.pp.id!==t)return;this.sessions.delete(e),s.controller.abort();const r=[s.ready,...s.operations];for(const e of[...s.pins])if(this.unpin(s,e),!this.pins.has(e)){const t=this.jobs.get(e);t&&(t.controller.abort(),r.push(t.promise))}const i=Promise.allSettled(r).finally(()=>this.releases.delete(e));return this.releases.set(e,{projectId:t,done:i}),i}close(){clearInterval(this.timer);for(const e of this.sessions.values())this.release(e.id,e.pp.id)}},ExtractionQueue:u,frameIndex:function(e,t){let s=0,r=e.length;for(;s<r;){const i=s+r>>>1;e[i]<=t+1e-5?s=i+1:r=i}return s-1},frameSyncArgs:l,supported:h,validFrameTimes:p,localMedia:m,command:c,BLOCK_SECONDS:5};
1
+ "use strict";const e=require("node:fs"),t=e.promises,s=require("node:path"),r=require("node:crypto"),{spawn:i}=require("./cli/lib/processes"),a=require("node:os"),n=Math.min(2,a.availableParallelism?.()||a.cpus().length||1),o=e=>{const[t,s=1]=String(e).split("/").map(Number);return t/s};function c(e,t,s,r){return new Promise((a,n)=>{if(s?.aborted)return n(new Error("cancelled"));const o=i(e,t,{stdio:["ignore","pipe","pipe"]});let c,l="",d="";const h=()=>{c=new Error("cancelled"),o.kill("SIGKILL")},p=setTimeout(()=>{c=new Error(e+" timed out"),o.kill("SIGKILL")},12e4);s?.addEventListener("abort",h,{once:!0}),o.stdout.on("data",e=>{l+=e,l.length>16777216&&(c=new Error("probe output too large"),o.kill("SIGKILL"))}),o.stderr.on("data",e=>{r?.(String(e)),d=(d+e).slice(-4e3)}),o.on("error",e=>{c=e}),o.on("close",t=>{clearTimeout(p),s?.removeEventListener("abort",h),c||0!==t?n(c||new Error(d||e+" failed")):a(l)})})}function l(e){const t=/ffmpeg version\s+n?(\d+)\.(\d+)/.exec(e);if(t){const e=Number(t[1]),s=Number(t[2]);return e>5||5===e&&s>=1?["-fps_mode","passthrough"]:["-vsync","0"]}return/(?:^|[\r\n])\s*-fps_mode\b/.test(e)?["-fps_mode","passthrough"]:/(?:^|[\r\n])\s*-vsync\b/.test(e)?["-vsync","0"]:null}let d;function h(e){const t=o(e.r_frame_rate),s=o(e.avg_frame_rate);return Number.isFinite(t)&&t>0&&t<=120&&Math.abs(t-s)<1e-4&&0===Number(e.start_time||0)&&["1:1","0:1",void 0].includes(e.sample_aspect_ratio)&&!e.tags?.rotate&&!e.side_data_list?.some(e=>e.rotation)&&["yuv420p","yuvj420p"].includes(e.pix_fmt)&&["bt709","smpte170m","bt470bg"].includes(e.color_space)&&[void 0,"unknown","bt709","smpte170m","bt470bg"].includes(e.color_primaries)&&[void 0,"unknown","bt709","smpte170m","gamma22","gamma28"].includes(e.color_transfer)&&e.width>0&&e.height>0}function p(e,t){const s=1/t,r=Math.max(.002,.1*s);return e.length>0&&e.every((t,i)=>Number.isFinite(t)&&(!i||t>e[i-1]&&Math.abs(t-e[i-1]-s)<=r))}async function m(e,r,i){const a=`/projects/${e.id}/media/`;let n,o;if(i?.startsWith(a))n=e.mediaDir,o=i.slice(a.length);else if("default"===e.id&&i?.startsWith("/media/"))n=e.mediaDir,o=i.slice(7);else{if(!i?.startsWith("/library/"))throw new Error("non-local or cross-project source");n=r,o=i.slice(9)}n=await t.realpath(n);const c=await t.realpath(s.resolve(n,decodeURIComponent(o)));if(!c.startsWith(n+s.sep))throw new Error("source escapes media directory");return c}class u{constructor(e=((a.availableParallelism?.()||a.cpus().length||1)>=8?2:1)){this.concurrency=e,this.pending=[],this.active=new Set,this.lastOwner=new Map}enqueue(e,t,s,r,i="default"){let a,n;const o={run:e,priority:t,neededAt:s,signal:r,owner:i,enqueuedAt:Date.now(),promise:new Promise((e,t)=>{a=e,n=t}),resolve:a,reject:n},c=()=>{const e=this.pending.indexOf(o);e>=0&&(this.pending.splice(e,1),o.cleanup(),n(new Error("cancelled")),this.pump())};return o.cleanup=()=>r.removeEventListener("abort",c),r.addEventListener("abort",c,{once:!0}),this.pending.push(o),queueMicrotask(()=>this.pump()),o}promote(e,t,s){"demand"===t&&(e.priority="demand"),e.neededAt=Math.min(e.neededAt,s),this.pump()}pump(){for(;this.active.size<this.concurrency;){const e=[...this.active].some(e=>"prefetch"===e.priority),t=this.pending.some(e=>"demand"===e.priority)?"demand":"prefetch";if("prefetch"===t&&e)return;const s=this.pending.filter(e=>e.priority===t);if(!s.length)return;const r=[...new Set(s.map(e=>e.owner))],i=r.indexOf(this.lastOwner.get(t)),a=r[(i+1)%r.length],n=s.filter(e=>e.owner===a).sort((e,t)=>e.neededAt-t.neededAt)[0];this.pending.splice(this.pending.indexOf(n),1),n.cleanup(),this.active.add(n),this.lastOwner.set(t,a),n.startedAt=Date.now(),Promise.resolve().then(()=>{if(n.signal.aborted)throw new Error("cancelled");return n.run(n.startedAt-n.enqueuedAt)}).then(n.resolve,n.reject).finally(()=>{this.active.delete(n),this.pump()})}}}module.exports={ExportCache:class{constructor({libraryDir:e,limit:t=2147483648,ttl:s=9e4,concurrency:r}={}){this.libraryDir=e,this.limit=t,this.ttl=s,this.queue=new u(r),this.sessions=new Map,this.jobs=new Map,this.pins=new Map,this.roots=new Map,this.releases=new Map,this.timer=setInterval(()=>{for(const e of this.sessions.values())!e.managed&&Date.now()-e.touched>s&&this.release(e.id,e.pp.id)},Math.min(s,15e3)),this.timer.unref()}get(e,t){const s=this.sessions.get(e);if(!s||s.pp.id!==t)throw new Error("no such cache session");return s.touched=Date.now(),s}create(t,s,i,{managed:a=!1}={}){const n=i||JSON.parse(e.readFileSync(t.projectFile,"utf8").replace(/^\uFEFF/,""));if(n.revision!==s)throw new Error("Project changed; save/reload before exporting");const o={id:r.randomBytes(16).toString("hex"),pp:t,project:n,managed:a,touched:Date.now(),operations:new Set,controller:new AbortController,sources:new Map,blocks:new Map,leases:new Map,pins:new Set,prefetchSequence:-1,prefetchPlan:null,waitSequence:-1,state:"preparing",stats:{hits:0,misses:0,fallbacks:{},extractionMs:0,queueWaitMs:0,decodeMs:0,publishMs:0,prefetchSkipped:0,capacityFallbacks:0,peakDiskBytes:0}};return this.sessions.set(o.id,o),o.ready=this.prepare(o).then(()=>{o.state="ready"}).catch(e=>{o.state="error",o.error=e.message}),o.id}async prepare(s){const i=new Set(s.project.disabledTracks||[]),a=new Map;for(const n of s.project.clips)if("video"===n.kind&&!i.has(n.track)){if(s.controller.signal.aborted)throw new Error("cancelled");try{if(n.keyframes?.speed?.length)throw new Error("speed ramp");const i=Math.max(.1,Math.min(8,Number(n.props?.speed)||1));if(![n.in,n.duration,i].every(Number.isFinite)||n.in<0||n.duration<=0)throw new Error("invalid source interval");const l=s.project.media.find(e=>e.id===n.mediaId);a.has(n.mediaId)||(s.activity={mediaId:n.mediaId,phase:"probe"},a.set(n.mediaId,(async()=>{const i=await m(s.pp,this.libraryDir,l?.src),a=await t.stat(i),d=JSON.parse(await c("ffprobe",["-v","error","-select_streams","v:0","-show_streams","-of","json",i],s.controller.signal)),p=d.streams?.[0];if(!p||!h(p))throw new Error("unsupported/uncertain video metadata");const u=r.createHash("sha256");s.activity={mediaId:n.mediaId,phase:"hash",bytes:a.size};for await(const t of e.createReadStream(i)){if(s.controller.signal.aborted)throw new Error("cancelled");u.update(t)}return{file:i,stamp:`${a.size}:${a.mtimeMs}`,hash:u.digest("hex"),fps:o(p.r_frame_rate),width:p.width,height:p.height,duration:Number(p.duration)}})()));const d=await a.get(n.mediaId);s.sources.set(n.id,{...d,start:n.in,end:n.in+n.duration*i})}catch(e){s.stats.fallbacks[n.id]=e.message}}s.activity=null}status(e,t){const s=this.get(e,t);return{id:e,state:s.state,error:s.error,clips:[...s.sources.keys()],stats:s.stats}}pin(e,t){e.pins.has(t)||(e.pins.add(t),this.pins.set(t,(this.pins.get(t)||0)+1))}unpin(e,t){if(!e.pins.delete(t))return;const s=(this.pins.get(t)||1)-1;s?this.pins.set(t,s):this.pins.delete(t)}async rootIndex(e){if(!this.roots.has(e)){const s=(async()=>{await t.mkdir(e,{recursive:!0});const s={entries:new Map,partials:new Map,lock:Promise.resolve()};return await this.scan(e,s),s})();this.roots.set(e,s),s.catch(()=>this.roots.delete(e))}return this.roots.get(e)}async scan(e,r){const i=new Map;for(const a of await t.readdir(e)){const n=s.join(e,a);if(/^[a-f0-9]{64}$/.test(a))try{const e=JSON.parse(await t.readFile(s.join(n,"manifest.json"))),r=await t.stat(n);if(!Number.isFinite(e.bytes)||e.bytes<0)throw new Error("invalid cache manifest");i.set(n,{dir:n,bytes:e.bytes,time:r.mtimeMs,manifest:e})}catch(e){if("ENOENT"!==e.code)throw e}else if(/^[a-f0-9]{64}\.partial-[a-f0-9]+$/.test(a)&&!this.jobs.has(n.slice(0,n.lastIndexOf(".partial-")))){const e=await t.stat(n);if(Date.now()-e.mtimeMs>12e4)await t.rm(n,{recursive:!0,force:!0}),r.partials.delete(n);else{const e=await Promise.all((await t.readdir(n)).map(e=>t.stat(s.join(n,e))));r.partials.set(n,e.reduce((e,t)=>e+t.size,0))}}}r.entries=i}async locked(e,t){const s=await this.rootIndex(e),r=s.lock.then(()=>t(s));return s.lock=r.catch(()=>{}),r}async makeRoom(e,s,r=0,i=!0){let a=[...s.entries.values()].reduce((e,t)=>e+t.bytes,0)+[...s.partials.values()].reduce((e,t)=>e+t,0)+r;for(const r of[...s.entries.values()].sort((e,t)=>e.time-t.time)){if(a<=this.limit)break;if(!this.pins.has(r.dir)&&!this.jobs.has(r.dir)){try{await t.rm(r.dir,{recursive:!0,force:!0})}catch(t){throw await this.scan(e,s),t}s.entries.delete(r.dir),a-=r.bytes}}if(a>this.limit&&i)return await this.scan(e,s),this.makeRoom(e,s,r,!1);if(a>this.limit)throw new Error("frame cache capacity exceeded");return a}async room(e,t=0,r){const i=()=>this.locked(e,async s=>(r&&s.partials.set(r,t),this.makeRoom(e,s,r?0:t)));try{return await i()}catch(t){const a=r&&this.jobs.get(r.slice(0,r.lastIndexOf(".partial-")));if(!/capacity/.test(t.message)||"demand"!==a?.queued.priority)throw t;const n=new Set,o=new Set;for(const t of this.sessions.values())for(const r of t.leases.values())s.dirname(r.dir)===e&&("demand"===r.priority?o:n).add(r.dir);for(const e of o)n.delete(e);for(const e of n)"demand"===this.jobs.get(e)?.queued.priority&&n.delete(e);if(!n.size)throw t;const c=[...n].map(e=>this.jobs.get(e)).filter(Boolean);for(const e of this.sessions.values())for(const[t,s]of e.leases)n.has(s.dir)&&this.removeLease(e,t);return await Promise.allSettled(c.map(e=>e.promise)),i()}}async build(e,i,a,o,h,m={}){const u=i+".partial-"+r.randomBytes(6).toString("hex");await t.mkdir(u,{recursive:!0});const f=[];let w="";const b=Math.max(0,5*o-2/a.fps),g=5*(o+1)+1/a.fps,y=await(d||(d=(async()=>{const e=l(await c("ffmpeg",["-version"]));if(e)return e;const t=l(await c("ffmpeg",["-hide_banner","-h","full"]));if(!t)throw new Error("ffmpeg 缺少 -fps_mode 和 -vsync");return t})().catch(e=>{throw d=void 0,e})),d),v=["-hide_banner","-loglevel","info","-nostdin","-y","-copyts","-ss",String(Math.max(0,b-2)),"-t",String(g-Math.max(0,b-2)+1),"-i",a.file,"-map","0:v:0","-an","-vf",`select='gte(t,${b-1e-5})*lt(t,${g})',showinfo`,...y,"-threads",String(n),"-compression_level","1",s.join(u,"%06d.png")];let k,E,S=Promise.resolve(),M=!1;const j=new AbortController,I=()=>j.abort();h.addEventListener("abort",I,{once:!0});try{await this.room(e,0,u),k=setInterval(()=>{M||(M=!0,S=(async()=>{const r=await t.readdir(u),i=await Promise.all(r.map(e=>t.stat(s.join(u,e))));await this.room(e,i.reduce((e,t)=>e+t.size,0),u)})().catch(e=>{E=e,j.abort()}).finally(()=>{M=!1}))},250),h.aborted&&j.abort();const r=Date.now();try{await c("ffmpeg",v,j.signal,e=>{w+=e;const t=w.split(/[\r\n]/);w=t.pop();for(const e of t){const t=/\bn:\s*\d+.*?pts_time:([\d.e+\-]+)/.exec(e);t&&f.push(Number(t[1]))}})}finally{m.decodeMs=Date.now()-r}const n=Date.now();if(clearInterval(k),await S,E)throw E;if(!p(f,a.fps))throw new Error("variable or invalid frame timestamps");const o=(await t.readdir(u)).filter(e=>e.endsWith(".png"));if(o.length!==f.length)throw new Error("incomplete extracted frames");const l=(await Promise.all(o.map(e=>t.stat(s.join(u,e))))).reduce((e,t)=>e+t.size,0);await this.room(e,l,u);const d={times:f,bytes:l,width:a.width,height:a.height};if(await t.writeFile(s.join(u,"manifest.json"),JSON.stringify(d)),h.aborted)throw new Error("cancelled");return await this.locked(e,async s=>{await this.makeRoom(e,s),await t.rename(u,i),s.partials.delete(u),s.entries.set(i,{dir:i,bytes:l,time:Date.now(),manifest:d})}),m.publishMs=Date.now()-n,d}catch(e){if(E)throw E;throw e}finally{clearInterval(k),await S,h.removeEventListener("abort",I),await this.locked(e,async e=>{await t.rm(u,{recursive:!0,force:!0}),e.partials.delete(u)})}}async block(e,t,s,r,i={}){const a=this.get(e,t),n=this.loadBlock(a,s,r,i);a.operations.add(n);try{return await n}finally{a.operations.delete(n)}}async loadBlock(e,i,a,{priority:n="demand",neededAt:o=0,sequence:c}={}){if(!["demand","prefetch"].includes(n)||!Number.isFinite(o)||o<0)throw new Error("invalid cache priority");await e.ready;const l=e.sources.get(i);if(!l||e.stats.fallbacks[i])return{fallback:e.stats.fallbacks[i]||"source unavailable"};if(!Number.isInteger(a)||a<Math.floor(l.start/5)||a>Math.floor(l.end/5))throw new Error("block outside clip interval");const d=i+":"+a,h=()=>"demand"===n||"demand"===e.leases.get(d)?.priority||null===e.prefetchPlan||c<=e.prefetchSequence&&e.prefetchPlan.has(d);let p,m;try{if(!h())return{skipped:"obsolete prefetch"};const c=await t.stat(l.file);if(`${c.size}:${c.mtimeMs}`!==l.stamp)throw new Error("source changed during export");const f=s.join(e.pp.dir,".export-cache"),w=await this.rootIndex(f),b=(u=JSON.stringify([2,l.hash,a,l.fps,"png-1"]),r.createHash("sha256").update(u).digest("hex"));if(p=s.join(f,b),e.controller.signal.aborted)throw new Error("cancelled");if(!h())return{skipped:"obsolete prefetch"};this.pin(e,p),m={clipId:i,block:a,key:b,dir:p,priority:"demand"===e.leases.get(d)?.priority?"demand":n},e.leases.set(d,m);for(const[t,s]of e.leases)"demand"===n&&s.clipId===i&&s.block<a-1&&(e.leases.delete(t),[...e.leases.values()].some(e=>e.dir===s.dir)||(e.blocks.delete(s.key),this.unpin(e,s.dir)));let g;try{g=await this.locked(f,async e=>{try{await t.access(s.join(p,"manifest.json"));const r=e.entries.get(p)?.manifest;if(!r)throw new Error("cache block not indexed");return r}catch(t){throw e.entries.delete(p),t}}),e.stats.hits++}catch{if(e.controller.signal.aborted)throw new Error("cancelled");e.stats.misses++;const t=this.jobs.get(p);if(t?.controller.signal.aborted&&await t.promise.catch(()=>{}),e.controller.signal.aborted)throw new Error("cancelled");if(!this.jobs.has(p)){const t=new AbortController,s=Date.now(),r={},i=this.queue.enqueue(async s=>{e.stats.queueWaitMs+=s;try{return await this.build(f,p,l,a,t.signal,r)}finally{e.stats.decodeMs+=r.decodeMs||0,e.stats.publishMs+=r.publishMs||0}},n,o,t.signal,e.id),c=i.promise;this.jobs.set(p,{controller:t,promise:c,queued:i}),c.finally(()=>{this.jobs.delete(p),e.stats.extractionMs+=Date.now()-s}).catch(()=>{})}const s=this.jobs.get(p);this.queue.promote(s.queued,n,o),g=await s.promise}if(e.controller.signal.aborted)throw new Error("cancelled");if(!h()||!e.leases.has(d))return{skipped:"obsolete prefetch"};const y=new Date;return await t.utimes(p,y,y),w.entries.has(p)&&(w.entries.get(p).time=y.getTime()),e.blocks.set(b,{clipId:i,block:a,dir:p,manifest:g}),e.stats.peakDiskBytes=Math.max(e.stats.peakDiskBytes,[...w.entries.values()].reduce((e,t)=>e+t.bytes,0)+[...w.partials.values()].reduce((e,t)=>e+t,0)),{key:b,...g}}catch(t){if("prefetch"===n&&!/variable or invalid frame timestamps|incomplete extracted frames/.test(t.message))return e.stats.prefetchSkipped++,e.leases.get(d)===m&&"prefetch"===m?.priority&&this.removeLease(e,d),{skipped:t.message};/capacity/.test(t.message)&&e.stats.capacityFallbacks++;const s=new Set(/variable or invalid frame timestamps|incomplete extracted frames/.test(t.message)?[...e.sources].filter(([,e])=>e.hash===l.hash).map(([e])=>e):[i]);for(const r of s)e.stats.fallbacks[r]=t.message;for(const[t,r]of e.leases)s.has(r.clipId)&&(e.leases.delete(t),[...e.leases.values()].some(e=>e.dir===r.dir)||(e.blocks.delete(r.key),this.unpin(e,r.dir)));return{fallback:t.message}}var u}removeLease(e,t){const s=e.leases.get(t);s&&(e.leases.delete(t),[...e.leases.values()].some(e=>e.dir===s.dir)||(e.blocks.delete(s.key),this.unpin(e,s.dir),this.pins.has(s.dir)||this.jobs.get(s.dir)?.controller.abort()))}retain(e,t,s,r,i=[]){const a=this.get(e,t);if(!Number.isSafeInteger(s)||s<0||!Array.isArray(r)||r.length>3||r.some(e=>"string"!=typeof e.clipId||!Number.isSafeInteger(e.block)||e.block<0))throw new Error("invalid prefetch plan");if(!Array.isArray(i)||i.length>a.project.clips.length||i.some(e=>!a.sources.has(e.clipId)||!Number.isSafeInteger(e.block)||e.block<0))throw new Error("invalid current blocks");if(!(s<=a.prefetchSequence)){a.prefetchSequence=s,a.prefetchPlan=new Set(r.map(e=>e.clipId+":"+e.block));for(const e of i){const t=a.leases.get(e.clipId+":"+e.block);if(t){t.priority="demand";const e=this.jobs.get(t.dir);e&&this.queue.promote(e.queued,"demand",0)}}for(const[e,t]of a.leases)"prefetch"!==t.priority||a.prefetchPlan.has(e)||this.removeLease(a,e)}}reportWait(e,t,{sequence:s,reason:r,elapsedMs:i=0}){const a=this.get(e,t);if(!Number.isSafeInteger(s)||s<0||![null,"source-block","source-image","encoder","video-seek","frame-assets","audio-mix"].includes(r)||!Number.isFinite(i)||i<0||i>864e5)throw new Error("invalid export wait");s<=a.waitSequence||(a.waitSequence=s,a.wait=r?{reason:r,since:Date.now()-i}:null)}drop(e,t,s){const r=this.get(e,t);if(!Array.isArray(s)||s.length>r.project.clips.length)throw new Error("invalid clip list");const i=new Set(s);for(const[e,t]of r.leases)i.has(t.clipId)&&(r.leases.delete(e),[...r.leases.values()].some(e=>e.dir===t.dir)||(r.blocks.delete(t.key),this.unpin(r,t.dir),this.pins.has(t.dir)||this.jobs.get(t.dir)?.controller.abort()))}frame(e,t,r,i){const a=this.get(e,t).blocks.get(r);if(!a||!Number.isInteger(i)||i<0||i>=a.manifest.times.length)throw new Error("unknown cache frame");return s.join(a.dir,String(i+1).padStart(6,"0")+".png")}release(e,t){const s=this.sessions.get(e);if(!s)return this.releases.get(e)?.projectId===t?this.releases.get(e).done:void 0;if(s.pp.id!==t)return;this.sessions.delete(e),s.controller.abort();const r=[s.ready,...s.operations];for(const e of[...s.pins])if(this.unpin(s,e),!this.pins.has(e)){const t=this.jobs.get(e);t&&(t.controller.abort(),r.push(t.promise))}const i=Promise.allSettled(r).finally(()=>this.releases.delete(e));return this.releases.set(e,{projectId:t,done:i}),i}close(){clearInterval(this.timer);for(const e of this.sessions.values())this.release(e.id,e.pp.id)}},ExtractionQueue:u,frameIndex:function(e,t){let s=0,r=e.length;for(;s<r;){const i=s+r>>>1;e[i]<=t+1e-5?s=i+1:r=i}return s-1},frameSyncArgs:l,supported:h,validFrameTimes:p,localMedia:m,command:c,BLOCK_SECONDS:5};