davinci-resolve-mcp 2.57.4 → 2.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +20 -0
- package/CHANGELOG.md +197 -2
- package/LICENSE +1 -1
- package/README.md +73 -1
- package/bin/davinci-resolve-advanced-mcp.mjs +20 -0
- package/docs/README.md +19 -0
- package/docs/SKILL.md +62 -1
- package/docs/contributing.md +1 -1
- package/docs/guides/control-panel.md +9 -0
- package/docs/kernels/README.md +21 -0
- package/docs/kernels/audio-fairlight-kernel.md +22 -0
- package/docs/kernels/color-grade-kernel.md +51 -0
- package/docs/kernels/fusion-composition-kernel.md +17 -0
- package/docs/kernels/media-pool-ingest-kernel.md +20 -0
- package/docs/kernels/render-deliver-kernel.md +32 -0
- package/docs/kernels/timeline-conform-interchange-kernel.md +39 -0
- package/docs/kernels/timeline-edit-kernel.md +17 -0
- package/docs/process/release-process.md +29 -7
- package/docs/reference/api-coverage.md +1 -1
- package/docs/reference/api-limitations.md +38 -1
- package/install.py +27 -4
- package/package.json +23 -2
- package/resolve-advanced/README.md +194 -0
- package/resolve-advanced/package.json +50 -0
- package/resolve-advanced/server/black-balance.mjs +92 -0
- package/resolve-advanced/server/capabilities.mjs +86 -0
- package/resolve-advanced/server/cdl-io.mjs +76 -0
- package/resolve-advanced/server/contrast-normalize.mjs +180 -0
- package/resolve-advanced/server/db-patch.mjs +91 -0
- package/resolve-advanced/server/deliverable-entities.mjs +86 -0
- package/resolve-advanced/server/deliverable-qc.mjs +270 -0
- package/resolve-advanced/server/editorial.mjs +370 -0
- package/resolve-advanced/server/exposure-level.mjs +129 -0
- package/resolve-advanced/server/extract-frames.mjs +196 -0
- package/resolve-advanced/server/ffprobe-media.mjs +88 -0
- package/resolve-advanced/server/gamut-legal.mjs +112 -0
- package/resolve-advanced/server/grade-body-patch.mjs +246 -0
- package/resolve-advanced/server/grade-transfer.mjs +66 -0
- package/resolve-advanced/server/group-grade-read.mjs +137 -0
- package/resolve-advanced/server/index.mjs +105 -0
- package/resolve-advanced/server/lib.mjs +84 -0
- package/resolve-advanced/server/libs.mjs +65 -0
- package/resolve-advanced/server/lineage-db.mjs +479 -0
- package/resolve-advanced/server/lut-apply.mjs +61 -0
- package/resolve-advanced/server/match-to-reference.mjs +173 -0
- package/resolve-advanced/server/media-inventory.mjs +169 -0
- package/resolve-advanced/server/media-ops.mjs +243 -0
- package/resolve-advanced/server/node-meta-db.mjs +62 -0
- package/resolve-advanced/server/node-provenance.mjs +102 -0
- package/resolve-advanced/server/offline-ref-db.mjs +420 -0
- package/resolve-advanced/server/offline-ref.mjs +179 -0
- package/resolve-advanced/server/project-db.mjs +233 -0
- package/resolve-advanced/server/provenance-audit.mjs +210 -0
- package/resolve-advanced/server/qc-frame.mjs +224 -0
- package/resolve-advanced/server/qc-sampler.mjs +67 -0
- package/resolve-advanced/server/readback.mjs +77 -0
- package/resolve-advanced/server/render-manifest.mjs +93 -0
- package/resolve-advanced/server/reverse-clip-db.mjs +270 -0
- package/resolve-advanced/server/runner-apply-contract.mjs +64 -0
- package/resolve-advanced/server/runner.mjs +244 -0
- package/resolve-advanced/server/saturation-match.mjs +108 -0
- package/resolve-advanced/server/scope-read.mjs +257 -0
- package/resolve-advanced/server/season-look.mjs +96 -0
- package/resolve-advanced/server/shot-intent.mjs +82 -0
- package/resolve-advanced/server/shot-match.mjs +147 -0
- package/resolve-advanced/server/skin-match.mjs +205 -0
- package/resolve-advanced/server/spec-compile.mjs +217 -0
- package/resolve-advanced/server/tone-curve-transfer.mjs +184 -0
- package/resolve-advanced/server/tool-catalog.mjs +265 -0
- package/resolve-advanced/server/tools/audio.mjs +54 -0
- package/resolve-advanced/server/tools/audio_plan.mjs +58 -0
- package/resolve-advanced/server/tools/capabilities.mjs +16 -0
- package/resolve-advanced/server/tools/color_trace.mjs +165 -0
- package/resolve-advanced/server/tools/conform.mjs +291 -0
- package/resolve-advanced/server/tools/deliverable.mjs +105 -0
- package/resolve-advanced/server/tools/drp.mjs +232 -0
- package/resolve-advanced/server/tools/drt.mjs +200 -0
- package/resolve-advanced/server/tools/drx.mjs +943 -0
- package/resolve-advanced/server/tools/editorial.mjs +69 -0
- package/resolve-advanced/server/tools/fairlight.mjs +108 -0
- package/resolve-advanced/server/tools/fusion.mjs +64 -0
- package/resolve-advanced/server/tools/media.mjs +102 -0
- package/resolve-advanced/server/tools/offline_ref.mjs +123 -0
- package/resolve-advanced/server/tools/pipeline.mjs +137 -0
- package/resolve-advanced/server/tools/project_db.mjs +200 -0
- package/resolve-advanced/server/tools/project_read.mjs +212 -0
- package/resolve-advanced/server/tools/provenance.mjs +73 -0
- package/resolve-advanced/server/verify-grade.mjs +113 -0
- package/resolve-advanced/server/white-balance-match.mjs +122 -0
- package/resolve-advanced/vendor/audio/format-converter.js +330 -0
- package/resolve-advanced/vendor/audio/split.js +173 -0
- package/resolve-advanced/vendor/audio/trim.js +188 -0
- package/resolve-advanced/vendor/audio-fairlight/index.js +391 -0
- package/resolve-advanced/vendor/conform-qc/adapters/frame-sampler.js +56 -0
- package/resolve-advanced/vendor/conform-qc/adapters/local-ffmpeg-sampler.js +65 -0
- package/resolve-advanced/vendor/conform-qc/adapters/rendernode-ffmpeg-sampler.js +50 -0
- package/resolve-advanced/vendor/conform-qc/adapters/resolve/driver.py +176 -0
- package/resolve-advanced/vendor/conform-qc/adapters/resolve-driver.js +61 -0
- package/resolve-advanced/vendor/conform-qc/adapters/resolve-headless-driver.js +86 -0
- package/resolve-advanced/vendor/conform-qc/adapters/vision-validator.js +75 -0
- package/resolve-advanced/vendor/conform-qc/cli.js +63 -0
- package/resolve-advanced/vendor/conform-qc/compare/advisory.js +106 -0
- package/resolve-advanced/vendor/conform-qc/compare/decode.js +36 -0
- package/resolve-advanced/vendor/conform-qc/compare/index.js +61 -0
- package/resolve-advanced/vendor/conform-qc/compare/locate.js +70 -0
- package/resolve-advanced/vendor/conform-qc/compare/metrics.js +409 -0
- package/resolve-advanced/vendor/conform-qc/docs/runbook.md +72 -0
- package/resolve-advanced/vendor/conform-qc/index.js +49 -0
- package/resolve-advanced/vendor/conform-qc/knowledge/index.js +110 -0
- package/resolve-advanced/vendor/conform-qc/ops/conform-core.js +137 -0
- package/resolve-advanced/vendor/conform-qc/ops/conform-diff.js +109 -0
- package/resolve-advanced/vendor/conform-qc/ops/insert.js +108 -0
- package/resolve-advanced/vendor/conform-qc/ops/local-conform.js +61 -0
- package/resolve-advanced/vendor/conform-qc/ops/patch.js +80 -0
- package/resolve-advanced/vendor/conform-qc/ops/trigger.js +32 -0
- package/resolve-advanced/vendor/conform-qc/ops/verify.js +105 -0
- package/resolve-advanced/vendor/conform-qc/ops/workflow.js +30 -0
- package/resolve-advanced/vendor/conform-qc/oracle/emulate.js +155 -0
- package/resolve-advanced/vendor/conform-qc/oracle/index.js +38 -0
- package/resolve-advanced/vendor/conform-qc/oracle/resolve.js +196 -0
- package/resolve-advanced/vendor/conform-qc/package.json +16 -0
- package/resolve-advanced/vendor/conform-qc/packaging/emit-aaf.js +30 -0
- package/resolve-advanced/vendor/conform-qc/packaging/emit-fcp7.js +64 -0
- package/resolve-advanced/vendor/conform-qc/packaging/index.js +169 -0
- package/resolve-advanced/vendor/conform-qc/packaging/media-ops.js +56 -0
- package/resolve-advanced/vendor/conform-qc/packaging/otio.js +50 -0
- package/resolve-advanced/vendor/conform-qc/packaging/relink.js +50 -0
- package/resolve-advanced/vendor/conform-qc/packaging/surgical-relink.js +195 -0
- package/resolve-advanced/vendor/conform-qc/parse/index.js +54 -0
- package/resolve-advanced/vendor/conform-qc/parse/merge-dto.js +27 -0
- package/resolve-advanced/vendor/conform-qc/parse/xmeml-geometry.js +256 -0
- package/resolve-advanced/vendor/conform-qc/reference/burnin-ocr.js +100 -0
- package/resolve-advanced/vendor/conform-qc/reference/sidecar.js +37 -0
- package/resolve-advanced/vendor/conform-qc/repair/analysis.js +62 -0
- package/resolve-advanced/vendor/conform-qc/repair/index.js +78 -0
- package/resolve-advanced/vendor/conform-qc/repair/media-analysis.js +139 -0
- package/resolve-advanced/vendor/conform-qc/repair/media-index.js +135 -0
- package/resolve-advanced/vendor/conform-qc/repair/strategies.js +250 -0
- package/resolve-advanced/vendor/conform-qc/report/index.js +133 -0
- package/resolve-advanced/vendor/conform-qc/roles/index.js +96 -0
- package/resolve-advanced/vendor/conform-qc/synthetic/generate.js +233 -0
- package/resolve-advanced/vendor/conform-qc/test/advisory.test.js +85 -0
- package/resolve-advanced/vendor/conform-qc/test/cli.test.js +39 -0
- package/resolve-advanced/vendor/conform-qc/test/compare.test.js +152 -0
- package/resolve-advanced/vendor/conform-qc/test/conform-diff.test.js +70 -0
- package/resolve-advanced/vendor/conform-qc/test/emulate.test.js +51 -0
- package/resolve-advanced/vendor/conform-qc/test/frame-sampler.test.js +30 -0
- package/resolve-advanced/vendor/conform-qc/test/geometry.test.js +112 -0
- package/resolve-advanced/vendor/conform-qc/test/knowledge.test.js +56 -0
- package/resolve-advanced/vendor/conform-qc/test/lifecycle.test.js +110 -0
- package/resolve-advanced/vendor/conform-qc/test/local-ffmpeg-sampler.test.js +66 -0
- package/resolve-advanced/vendor/conform-qc/test/locate.test.js +63 -0
- package/resolve-advanced/vendor/conform-qc/test/media-analysis.test.js +63 -0
- package/resolve-advanced/vendor/conform-qc/test/media-index-normalized.test.js +65 -0
- package/resolve-advanced/vendor/conform-qc/test/media-index-origin.test.js +53 -0
- package/resolve-advanced/vendor/conform-qc/test/metrics-fast.test.js +91 -0
- package/resolve-advanced/vendor/conform-qc/test/oracle-reverse.test.js +86 -0
- package/resolve-advanced/vendor/conform-qc/test/oracle.test.js +136 -0
- package/resolve-advanced/vendor/conform-qc/test/p0-acceptance.test.js +60 -0
- package/resolve-advanced/vendor/conform-qc/test/p1-acceptance.test.js +75 -0
- package/resolve-advanced/vendor/conform-qc/test/p45-patch-acceptance.test.js +102 -0
- package/resolve-advanced/vendor/conform-qc/test/packaging.test.js +133 -0
- package/resolve-advanced/vendor/conform-qc/test/parse-stubs.test.js +28 -0
- package/resolve-advanced/vendor/conform-qc/test/repair-strategies.test.js +128 -0
- package/resolve-advanced/vendor/conform-qc/test/repair.test.js +84 -0
- package/resolve-advanced/vendor/conform-qc/test/report.test.js +52 -0
- package/resolve-advanced/vendor/conform-qc/test/resolve-readback.test.js +71 -0
- package/resolve-advanced/vendor/conform-qc/test/roles.test.js +107 -0
- package/resolve-advanced/vendor/conform-qc/test/runbook.test.js +30 -0
- package/resolve-advanced/vendor/conform-qc/test/scale-residual.test.js +40 -0
- package/resolve-advanced/vendor/conform-qc/test/sidecar.test.js +51 -0
- package/resolve-advanced/vendor/conform-qc/test/smoke.test.js +87 -0
- package/resolve-advanced/vendor/conform-qc/test/surgical-relink.test.js +73 -0
- package/resolve-advanced/vendor/conform-qc/test/synthetic.test.js +98 -0
- package/resolve-advanced/vendor/conform-qc/test/verify.test.js +93 -0
- package/resolve-advanced/vendor/conform-qc/test/vision-validator.test.js +43 -0
- package/resolve-advanced/vendor/conform-qc/test/workflow-driver.test.js +46 -0
- package/resolve-advanced/vendor/conform-qc/toolset/index.js +53 -0
- package/resolve-advanced/vendor/drp-format/README.md +116 -0
- package/resolve-advanced/vendor/drp-format/__tests__/_resolve-verify.js +39 -0
- package/resolve-advanced/vendor/drp-format/__tests__/add-media-clip.test.js +30 -0
- package/resolve-advanced/vendor/drp-format/__tests__/assemble-timeline.test.js +68 -0
- package/resolve-advanced/vendor/drp-format/__tests__/author-project.test.js +57 -0
- package/resolve-advanced/vendor/drp-format/__tests__/composition-text.test.js +98 -0
- package/resolve-advanced/vendor/drp-format/__tests__/diff.test.js +272 -0
- package/resolve-advanced/vendor/drp-format/__tests__/effect-filters-compressed.test.js +143 -0
- package/resolve-advanced/vendor/drp-format/__tests__/fixtures/p0-3-session30-empty-effectfilters.drp +0 -0
- package/resolve-advanced/vendor/drp-format/__tests__/fixtures/retimed-timemap-50pct.hex +1 -0
- package/resolve-advanced/vendor/drp-format/__tests__/fixtures/retimed-timemap-dynamic.hex +1 -0
- package/resolve-advanced/vendor/drp-format/__tests__/inject-grades.test.js +238 -0
- package/resolve-advanced/vendor/drp-format/__tests__/keyed-dict.test.js +85 -0
- package/resolve-advanced/vendor/drp-format/__tests__/lut-refs.test.js +119 -0
- package/resolve-advanced/vendor/drp-format/__tests__/media-blobs.test.js +25 -0
- package/resolve-advanced/vendor/drp-format/__tests__/media-timemap.test.js +119 -0
- package/resolve-advanced/vendor/drp-format/__tests__/place-fusion-title.test.js +52 -0
- package/resolve-advanced/vendor/drp-format/__tests__/place-generator.test.js +40 -0
- package/resolve-advanced/vendor/drp-format/__tests__/place-transition.test.js +48 -0
- package/resolve-advanced/vendor/drp-format/__tests__/protobuf-wire.test.js +64 -0
- package/resolve-advanced/vendor/drp-format/__tests__/relink-media.test.js +106 -0
- package/resolve-advanced/vendor/drp-format/__tests__/splice-clips.test.js +256 -0
- package/resolve-advanced/vendor/drp-format/assemble-timeline.js +65 -0
- package/resolve-advanced/vendor/drp-format/author-project.js +118 -0
- package/resolve-advanced/vendor/drp-format/composition-text.js +213 -0
- package/resolve-advanced/vendor/drp-format/curves-encoder.js +763 -0
- package/resolve-advanced/vendor/drp-format/diff.js +310 -0
- package/resolve-advanced/vendor/drp-format/drp-packager.js +201 -0
- package/resolve-advanced/vendor/drp-format/drp-validator.js +809 -0
- package/resolve-advanced/vendor/drp-format/effect-encoder.js +640 -0
- package/resolve-advanced/vendor/drp-format/extract-lut-refs.js +119 -0
- package/resolve-advanced/vendor/drp-format/grade-encoder.example.js +133 -0
- package/resolve-advanced/vendor/drp-format/grade-encoder.js +401 -0
- package/resolve-advanced/vendor/drp-format/grade-encoder.test.js +171 -0
- package/resolve-advanced/vendor/drp-format/grade-encoder.verify.js +249 -0
- package/resolve-advanced/vendor/drp-format/grade-node-extractor.js +495 -0
- package/resolve-advanced/vendor/drp-format/grade-parameter-decoder.js +774 -0
- package/resolve-advanced/vendor/drp-format/index.js +174 -0
- package/resolve-advanced/vendor/drp-format/inject-grades.js +219 -0
- package/resolve-advanced/vendor/drp-format/keyed-dict.js +227 -0
- package/resolve-advanced/vendor/drp-format/marker-encoder.js +532 -0
- package/resolve-advanced/vendor/drp-format/media-blobs.js +53 -0
- package/resolve-advanced/vendor/drp-format/media-timemap.js +164 -0
- package/resolve-advanced/vendor/drp-format/mp-folder-builder.js +293 -0
- package/resolve-advanced/vendor/drp-format/node-tree-encoder.js +1246 -0
- package/resolve-advanced/vendor/drp-format/package.json +18 -0
- package/resolve-advanced/vendor/drp-format/place-fusion-title.js +131 -0
- package/resolve-advanced/vendor/drp-format/place-generator.js +77 -0
- package/resolve-advanced/vendor/drp-format/place-transition.js +91 -0
- package/resolve-advanced/vendor/drp-format/power-window-encoder.js +776 -0
- package/resolve-advanced/vendor/drp-format/protobuf-wire.js +111 -0
- package/resolve-advanced/vendor/drp-format/qualifier-encoder.js +706 -0
- package/resolve-advanced/vendor/drp-format/relink-media.js +218 -0
- package/resolve-advanced/vendor/drp-format/rich-title-encoder.js +447 -0
- package/resolve-advanced/vendor/drp-format/seq-container-builder.js +572 -0
- package/resolve-advanced/vendor/drp-format/seq-surgery.js +155 -0
- package/resolve-advanced/vendor/drp-format/splice-clips.js +445 -0
- package/resolve-advanced/vendor/drp-format/templates/empty-project.drp +0 -0
- package/resolve-advanced/vendor/drp-format/templates/fusion-title.xml +56 -0
- package/resolve-advanced/vendor/drp-format/templates/generator-solid-color.xml +21 -0
- package/resolve-advanced/vendor/drp-format/templates/media-clip-h264.drp +0 -0
- package/resolve-advanced/vendor/drp-format/templates/transition-cross-dissolve.xml +22 -0
- package/resolve-advanced/vendor/drp-format/tool-registry.descriptor.js +80 -0
- package/resolve-advanced/vendor/drp-format/utils/safe-archive.js +54 -0
- package/resolve-advanced/vendor/drp-format/xml-builder.js +759 -0
- package/resolve-advanced/vendor/drt-format/__tests__/_resolve-verify.js +21 -0
- package/resolve-advanced/vendor/drt-format/__tests__/build.test.js +113 -0
- package/resolve-advanced/vendor/drt-format/__tests__/multi-format.test.js +93 -0
- package/resolve-advanced/vendor/drt-format/__tests__/parse-real-resolve21.test.js +51 -0
- package/resolve-advanced/vendor/drt-format/__tests__/parse.test.js +134 -0
- package/resolve-advanced/vendor/drt-format/__tests__/resolve-versions.test.js +120 -0
- package/resolve-advanced/vendor/drt-format/__tests__/schema-fingerprint.test.js +62 -0
- package/resolve-advanced/vendor/drt-format/__tests__/smoke.test.js +27 -0
- package/resolve-advanced/vendor/drt-format/__tests__/validate.test.js +109 -0
- package/resolve-advanced/vendor/drt-format/capabilities.js +69 -0
- package/resolve-advanced/vendor/drt-format/capability-domains.js +56 -0
- package/resolve-advanced/vendor/drt-format/drt-builder.js +42 -0
- package/resolve-advanced/vendor/drt-format/drt-parser.js +164 -0
- package/resolve-advanced/vendor/drt-format/drt-validator.js +98 -0
- package/resolve-advanced/vendor/drt-format/index.js +45 -0
- package/resolve-advanced/vendor/drt-format/package.json +17 -0
- package/resolve-advanced/vendor/drt-format/resolve-versions.js +153 -0
- package/resolve-advanced/vendor/drt-format/schema-fingerprint.js +74 -0
- package/resolve-advanced/vendor/drt-format/templates/drt-project-shell.xml +124 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/curves-roundtrip.test.js +148 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-1-face-refinement.drx +58 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-1-filmgrain.drx +58 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-1-glow.drx +58 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-1-lens-flare.drx +58 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-3-beauty-25.drx +58 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p2-3-beauty-75.drx +58 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p5-1-node-no-lut.drx +58 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/fixtures/p5-1-node-with-lut.drx +58 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/hsl-curves-roundtrip.test.js +117 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/lut-refs-roundtrip.test.js +112 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/matte-roundtrip.test.js +167 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/ofx-roundtrip.test.js +215 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/ofx-slugs-discovery.test.js +149 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/power-window-roundtrip.test.js +230 -0
- package/resolve-advanced/vendor/drx-codec/__tests__/qualifier-roundtrip.test.js +226 -0
- package/resolve-advanced/vendor/drx-codec/cdl-exporter.js +470 -0
- package/resolve-advanced/vendor/drx-codec/color-nlp-parser.js +833 -0
- package/resolve-advanced/vendor/drx-codec/data/color-nlp-action-mappings.json +2232 -0
- package/resolve-advanced/vendor/drx-codec/drx-generator.js +4123 -0
- package/resolve-advanced/vendor/drx-codec/drx-merger.js +320 -0
- package/resolve-advanced/vendor/drx-codec/drx-parser.js +1808 -0
- package/resolve-advanced/vendor/drx-codec/extract-custom-curves.js +215 -0
- package/resolve-advanced/vendor/drx-codec/extract-hsl-curves.js +180 -0
- package/resolve-advanced/vendor/drx-codec/extract-lut-refs.js +158 -0
- package/resolve-advanced/vendor/drx-codec/extract-matte-finesse.js +83 -0
- package/resolve-advanced/vendor/drx-codec/extract-ofx-params.js +226 -0
- package/resolve-advanced/vendor/drx-codec/extract-power-window.js +184 -0
- package/resolve-advanced/vendor/drx-codec/extract-qualifier.js +99 -0
- package/resolve-advanced/vendor/drx-codec/index.js +109 -0
- package/resolve-advanced/vendor/drx-codec/node-layout.js +249 -0
- package/resolve-advanced/vendor/drx-codec/resolved-drx-generator.js +393 -0
- package/resolve-advanced/vendor/drx-codec/tool-resolver.js +974 -0
- package/resolve-advanced/vendor/drx-codec/training-examples.js +548 -0
- package/resolve-advanced/vendor/drx-codec/vocabulary-intents.js +539 -0
- package/resolve-advanced/vendor/drx-parameters/CALIBRATION-STATUS.md +319 -0
- package/resolve-advanced/vendor/drx-parameters/DRX-VALUE-SCALING.md +251 -0
- package/resolve-advanced/vendor/drx-parameters/calibrated-ranges.json +17737 -0
- package/resolve-advanced/vendor/drx-parameters/corrector-types.js +120 -0
- package/resolve-advanced/vendor/drx-parameters/index.js +193 -0
- package/resolve-advanced/vendor/drx-parameters/parameter-codec.js +451 -0
- package/resolve-advanced/vendor/drx-parameters/parameter-ids.js +1292 -0
- package/resolve-advanced/vendor/drx-parameters/parameter-ranges.js +570 -0
- package/resolve-advanced/vendor/drx-parameters/parameter-validator.js +392 -0
- package/resolve-advanced/vendor/drx-parameters/resolvefx-registry.json +14973 -0
- package/resolve-advanced/vendor/drx-parameters/tool-registry.descriptor.js +38 -0
- package/resolve-advanced/vendor/drx-parameters/tools/drx-analyzer.js +371 -0
- package/resolve-advanced/vendor/fairlight/index.js +833 -0
- package/resolve-advanced/vendor/fusion-codec/composition-generator.js +401 -0
- package/resolve-advanced/vendor/fusion-codec/templates/blur-region.js +103 -0
- package/resolve-advanced/vendor/fusion-codec/templates/color-correct.js +87 -0
- package/resolve-advanced/vendor/fusion-codec/templates/film-grain.js +106 -0
- package/resolve-advanced/vendor/fusion-codec/templates/lower-third.js +241 -0
- package/resolve-advanced/vendor/fusion-codec/templates/picture-in-picture.js +188 -0
- package/resolve-advanced/vendor/fusion-codec/templates/text-overlay.js +161 -0
- package/resolve-advanced/vendor/fusion-codec/templates/title-card.js +184 -0
- package/resolve-advanced/vendor/fusion-codec/templates/vignette.js +107 -0
- package/resolve-advanced/vendor/fusion-codec/templates/watermark.js +101 -0
- package/scripts/agent-rules/README.md +68 -0
- package/src/analysis_dashboard.py +233 -1
- package/src/granular/common.py +1 -1
- package/src/server.py +479 -29
- package/src/utils/api_truth.py +117 -0
- package/src/utils/cut_ir.py +1 -1
- package/src/utils/failure_tracker.py +0 -2
- package/src/utils/timeline_xml.py +405 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DaVinci Resolve DRP Structural Diff
|
|
3
|
+
*
|
|
4
|
+
* Compares two DRP archives and returns a normalized delta DTO. Clip
|
|
5
|
+
* identity is the Sm2TiVideoClip / Sm2TiAudioClip DbId; grade changes
|
|
6
|
+
* are detected by sha256 of the per-clip <Body> hex blob (DRX bytes
|
|
7
|
+
* are deterministic for the same grade, so byte equality is the right
|
|
8
|
+
* test). For per-parameter grade deltas, callers should pair this with
|
|
9
|
+
* drx-codec.grade.compare on the diffed clip's body.
|
|
10
|
+
*
|
|
11
|
+
* Schema documented in
|
|
12
|
+
* docs/design/drp-drx-drt-closeout-harness/knowledge/diff-dto-schema.md
|
|
13
|
+
*
|
|
14
|
+
* @module drp-format/diff
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const fs = require('node:fs/promises');
|
|
18
|
+
const crypto = require('node:crypto');
|
|
19
|
+
const JSZip = require('jszip');
|
|
20
|
+
|
|
21
|
+
const CLIP_TAGS = ['Sm2TiVideoClip', 'Sm2VideoClip', 'Sm2TiAudioClip', 'Sm2AudioClip'];
|
|
22
|
+
|
|
23
|
+
/** Find all SeqContainer*.xml entries regardless of folder name.
|
|
24
|
+
* Matches BOTH tool-authored `SeqContainer<N>.xml` AND real Resolve `SeqContainer/<uuid>.xml` (F1 fix). */
|
|
25
|
+
function listSeqContainerEntries(zip) {
|
|
26
|
+
const out = [];
|
|
27
|
+
zip.forEach((relativePath, entry) => {
|
|
28
|
+
if (entry.dir) return;
|
|
29
|
+
if (/(^|\/)SeqContainer(\d*\.xml|\/[^/]+\.xml)$/.test(relativePath)) {
|
|
30
|
+
out.push(relativePath);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
return out.sort();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function findProjectXmlEntry(zip) {
|
|
37
|
+
let found = null;
|
|
38
|
+
zip.forEach((p, e) => {
|
|
39
|
+
if (!e.dir && /(^|\/)project\.xml$/.test(p)) found = p;
|
|
40
|
+
});
|
|
41
|
+
return found;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function hashBody(bodyHex) {
|
|
45
|
+
return crypto.createHash('sha256').update(bodyHex).digest('hex');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function tagOf(match) { return match[1]; }
|
|
49
|
+
function trackTypeFromTag(tag) {
|
|
50
|
+
return tag.endsWith('VideoClip') ? 'video' : 'audio';
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Scrape clips out of a SeqContainer XML. Returns
|
|
55
|
+
* [{ clipId, trackType, mediaFilePath, start, duration, bodyHex|null }]
|
|
56
|
+
*
|
|
57
|
+
* Light regex parsing — we never write back through this path, so we
|
|
58
|
+
* don't need fast-xml-parser's lossy round-trip. The fields we extract
|
|
59
|
+
* are stable across Resolve's pretty-printing conventions.
|
|
60
|
+
*/
|
|
61
|
+
function extractClips(seqXml) {
|
|
62
|
+
const clips = [];
|
|
63
|
+
const tagAlternation = CLIP_TAGS.join('|');
|
|
64
|
+
// Open tag + attrs + content up to matching close tag. Nested clips of
|
|
65
|
+
// the same tag are not produced by Resolve's serializer in practice.
|
|
66
|
+
const clipRe = new RegExp(
|
|
67
|
+
`<(${tagAlternation})\\b([^>]*?)DbId="([^"]+)"([^>]*)>([\\s\\S]*?)</\\1>`,
|
|
68
|
+
'g',
|
|
69
|
+
);
|
|
70
|
+
let m;
|
|
71
|
+
while ((m = clipRe.exec(seqXml)) !== null) {
|
|
72
|
+
const tag = tagOf(m);
|
|
73
|
+
const dbId = m[3];
|
|
74
|
+
const inner = m[5];
|
|
75
|
+
const mediaFilePath = extractScalar(inner, 'MediaFilePath');
|
|
76
|
+
const start = extractInt(inner, 'Start');
|
|
77
|
+
const duration = extractInt(inner, 'Duration');
|
|
78
|
+
const bodyMatch = inner.match(/<Body>([0-9a-fA-F\s]*)<\/Body>/);
|
|
79
|
+
let bodyHex = null;
|
|
80
|
+
if (bodyMatch) {
|
|
81
|
+
const stripped = bodyMatch[1].replace(/[^0-9a-fA-F]/g, '');
|
|
82
|
+
if (stripped.length > 0) bodyHex = stripped;
|
|
83
|
+
}
|
|
84
|
+
clips.push({
|
|
85
|
+
clipId: dbId,
|
|
86
|
+
trackType: trackTypeFromTag(tag),
|
|
87
|
+
mediaFilePath,
|
|
88
|
+
start,
|
|
89
|
+
duration,
|
|
90
|
+
bodyHex,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
return clips;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function extractScalar(xml, tagName) {
|
|
97
|
+
const re = new RegExp(`<${tagName}>([\\s\\S]*?)</${tagName}>`);
|
|
98
|
+
const m = xml.match(re);
|
|
99
|
+
return m ? m[1].trim() : null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function extractInt(xml, tagName) {
|
|
103
|
+
const v = extractScalar(xml, tagName);
|
|
104
|
+
if (v === null || v === '') return null;
|
|
105
|
+
const n = Number.parseInt(v, 10);
|
|
106
|
+
return Number.isFinite(n) ? n : null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Walk a DRP and return a flat clip index plus project-level metadata.
|
|
111
|
+
*
|
|
112
|
+
* {
|
|
113
|
+
* seqContainers: [path, …],
|
|
114
|
+
* clipsById: Map<dbId, ClipRecord>,
|
|
115
|
+
* mediaPaths: Set<string>,
|
|
116
|
+
* projectXml: string | null,
|
|
117
|
+
* projectSettings: { projectName?, … } parsed from project.xml,
|
|
118
|
+
* }
|
|
119
|
+
*/
|
|
120
|
+
async function indexDrp(drpPath) {
|
|
121
|
+
const buf = await fs.readFile(drpPath);
|
|
122
|
+
const zip = await JSZip.loadAsync(buf);
|
|
123
|
+
|
|
124
|
+
const seqContainers = listSeqContainerEntries(zip);
|
|
125
|
+
const clipsById = new Map();
|
|
126
|
+
const mediaPaths = new Set();
|
|
127
|
+
|
|
128
|
+
for (const p of seqContainers) {
|
|
129
|
+
const xml = await zip.file(p).async('string');
|
|
130
|
+
const clips = extractClips(xml);
|
|
131
|
+
for (const c of clips) {
|
|
132
|
+
c.sequence = p;
|
|
133
|
+
// First occurrence wins on DbId collision (shouldn't happen with
|
|
134
|
+
// real Resolve UUIDs).
|
|
135
|
+
if (!clipsById.has(c.clipId)) clipsById.set(c.clipId, c);
|
|
136
|
+
if (c.mediaFilePath) mediaPaths.add(c.mediaFilePath);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const projEntry = findProjectXmlEntry(zip);
|
|
141
|
+
let projectXml = null;
|
|
142
|
+
let projectSettings = {};
|
|
143
|
+
if (projEntry) {
|
|
144
|
+
projectXml = await zip.file(projEntry).async('string');
|
|
145
|
+
projectSettings = extractProjectSettings(projectXml);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return { seqContainers, clipsById, mediaPaths, projectXml, projectSettings };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Pull a small whitelist of settings from project.xml for the
|
|
153
|
+
* timelineSettingDeltas section. Expand as concrete callers ask for
|
|
154
|
+
* more.
|
|
155
|
+
*/
|
|
156
|
+
function extractProjectSettings(projectXml) {
|
|
157
|
+
const settings = {};
|
|
158
|
+
// tool-authored DRPs use <Name>; some Resolve-exported variants
|
|
159
|
+
// use <ProjectName>. Check both.
|
|
160
|
+
const projectName =
|
|
161
|
+
extractScalar(projectXml, 'ProjectName') ||
|
|
162
|
+
extractScalar(projectXml, 'Name');
|
|
163
|
+
if (projectName !== null) settings.projectName = projectName;
|
|
164
|
+
const tlFrameRate = extractScalar(projectXml, 'TimelineFrameRate');
|
|
165
|
+
if (tlFrameRate !== null) settings.timelineFrameRate = tlFrameRate;
|
|
166
|
+
const tlResWidth = extractScalar(projectXml, 'TimelineResolutionWidth');
|
|
167
|
+
const tlResHeight = extractScalar(projectXml, 'TimelineResolutionHeight');
|
|
168
|
+
if (tlResWidth !== null && tlResHeight !== null) {
|
|
169
|
+
settings.timelineResolution = `${tlResWidth}x${tlResHeight}`;
|
|
170
|
+
}
|
|
171
|
+
const colorScience = extractScalar(projectXml, 'ColorScience');
|
|
172
|
+
if (colorScience !== null) settings.colorScience = colorScience;
|
|
173
|
+
return settings;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Diff two DRPs structurally. See diff-dto-schema.md for the return shape.
|
|
178
|
+
*
|
|
179
|
+
* @param {string} drpAPath - "before" / "left" DRP
|
|
180
|
+
* @param {string} drpBPath - "after" / "right" DRP
|
|
181
|
+
* @returns {Promise<DrpDiff>}
|
|
182
|
+
*/
|
|
183
|
+
async function diff(drpAPath, drpBPath) {
|
|
184
|
+
if (typeof drpAPath !== 'string' || typeof drpBPath !== 'string') {
|
|
185
|
+
throw new TypeError('diff: drpAPath and drpBPath must be strings');
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const [a, b] = await Promise.all([indexDrp(drpAPath), indexDrp(drpBPath)]);
|
|
189
|
+
|
|
190
|
+
const addedClips = [];
|
|
191
|
+
const removedClips = [];
|
|
192
|
+
const movedClips = [];
|
|
193
|
+
const gradeChanges = [];
|
|
194
|
+
|
|
195
|
+
// Walk A → find removed + (moved + gradeChanged within shared set)
|
|
196
|
+
for (const [clipId, clipA] of a.clipsById) {
|
|
197
|
+
const clipB = b.clipsById.get(clipId);
|
|
198
|
+
if (!clipB) {
|
|
199
|
+
removedClips.push(packClipDelta(clipA));
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Move detection: any change in (sequence, start) for the same clip.
|
|
204
|
+
if (clipA.sequence !== clipB.sequence || clipA.start !== clipB.start) {
|
|
205
|
+
movedClips.push({
|
|
206
|
+
clipId,
|
|
207
|
+
trackType: clipA.trackType,
|
|
208
|
+
before: { sequence: clipA.sequence, start: clipA.start },
|
|
209
|
+
after: { sequence: clipB.sequence, start: clipB.start },
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Grade detection: hash hex bodies, compare.
|
|
214
|
+
const beforeHash = clipA.bodyHex ? hashBody(clipA.bodyHex) : null;
|
|
215
|
+
const afterHash = clipB.bodyHex ? hashBody(clipB.bodyHex) : null;
|
|
216
|
+
if (beforeHash !== afterHash) {
|
|
217
|
+
gradeChanges.push({
|
|
218
|
+
clipId,
|
|
219
|
+
sequence: clipB.sequence,
|
|
220
|
+
beforeBodyHash: beforeHash,
|
|
221
|
+
afterBodyHash: afterHash,
|
|
222
|
+
hadGrade: Boolean(clipA.bodyHex),
|
|
223
|
+
hasGrade: Boolean(clipB.bodyHex),
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Walk B → find added
|
|
229
|
+
for (const [clipId, clipB] of b.clipsById) {
|
|
230
|
+
if (!a.clipsById.has(clipId)) {
|
|
231
|
+
addedClips.push(packClipDelta(clipB));
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Timeline settings diff (whitelist set extracted above).
|
|
236
|
+
const timelineSettingDeltas = diffSettings(a.projectSettings, b.projectSettings);
|
|
237
|
+
|
|
238
|
+
// Media pool diff — basic, source: clip MediaFilePath sets.
|
|
239
|
+
const mediaPoolDeltas = {
|
|
240
|
+
added: [...b.mediaPaths].filter((p) => !a.mediaPaths.has(p)),
|
|
241
|
+
removed: [...a.mediaPaths].filter((p) => !b.mediaPaths.has(p)),
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
// sameClipCount: clips present in both, no matter whether they changed.
|
|
245
|
+
let sameClipCount = 0;
|
|
246
|
+
for (const id of a.clipsById.keys()) {
|
|
247
|
+
if (b.clipsById.has(id)) sameClipCount += 1;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const summary = {
|
|
251
|
+
seqContainersA: a.seqContainers.length,
|
|
252
|
+
seqContainersB: b.seqContainers.length,
|
|
253
|
+
clipsA: a.clipsById.size,
|
|
254
|
+
clipsB: b.clipsById.size,
|
|
255
|
+
sameClipCount,
|
|
256
|
+
hasAnyChange:
|
|
257
|
+
addedClips.length > 0 ||
|
|
258
|
+
removedClips.length > 0 ||
|
|
259
|
+
movedClips.length > 0 ||
|
|
260
|
+
gradeChanges.length > 0 ||
|
|
261
|
+
timelineSettingDeltas.length > 0 ||
|
|
262
|
+
mediaPoolDeltas.added.length > 0 ||
|
|
263
|
+
mediaPoolDeltas.removed.length > 0,
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
return {
|
|
267
|
+
addedClips,
|
|
268
|
+
removedClips,
|
|
269
|
+
movedClips,
|
|
270
|
+
gradeChanges,
|
|
271
|
+
timelineSettingDeltas,
|
|
272
|
+
mediaPoolDeltas,
|
|
273
|
+
summary,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function packClipDelta(clip) {
|
|
278
|
+
return {
|
|
279
|
+
clipId: clip.clipId,
|
|
280
|
+
trackType: clip.trackType,
|
|
281
|
+
sequence: clip.sequence,
|
|
282
|
+
mediaFilePath: clip.mediaFilePath,
|
|
283
|
+
start: clip.start,
|
|
284
|
+
duration: clip.duration,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function diffSettings(beforeMap, afterMap) {
|
|
289
|
+
const keys = new Set([...Object.keys(beforeMap), ...Object.keys(afterMap)]);
|
|
290
|
+
const deltas = [];
|
|
291
|
+
for (const k of keys) {
|
|
292
|
+
const before = beforeMap[k];
|
|
293
|
+
const after = afterMap[k];
|
|
294
|
+
if (before !== after) {
|
|
295
|
+
deltas.push({ key: k, before: before ?? null, after: after ?? null });
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return deltas;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
module.exports = {
|
|
302
|
+
diff,
|
|
303
|
+
_internals: {
|
|
304
|
+
indexDrp,
|
|
305
|
+
extractClips,
|
|
306
|
+
extractProjectSettings,
|
|
307
|
+
diffSettings,
|
|
308
|
+
hashBody,
|
|
309
|
+
},
|
|
310
|
+
};
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DaVinci Resolve Project Packager
|
|
3
|
+
* Creates DRP files (ZIP archives) with proper structure
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const JSZip = require('jszip');
|
|
7
|
+
const { buildSeqContainerFile } = require('./seq-container-builder');
|
|
8
|
+
const { buildMpFolderFile } = require('./mp-folder-builder');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Package timeline data into a DRP file
|
|
12
|
+
* @param {string} projectXML - Project XML content
|
|
13
|
+
* @param {Object} options - Additional options
|
|
14
|
+
* @returns {Promise<Buffer>} DRP file as buffer
|
|
15
|
+
*/
|
|
16
|
+
async function packageDRP(projectXML, options = {}) {
|
|
17
|
+
const {
|
|
18
|
+
projectName = 'Untitled Project',
|
|
19
|
+
includeMetadata = true
|
|
20
|
+
} = options;
|
|
21
|
+
|
|
22
|
+
const zip = new JSZip();
|
|
23
|
+
|
|
24
|
+
// Add project.xml (required)
|
|
25
|
+
zip.file('project.xml', projectXML);
|
|
26
|
+
|
|
27
|
+
// Add metadata file if requested
|
|
28
|
+
if (includeMetadata) {
|
|
29
|
+
const metadata = {
|
|
30
|
+
projectName,
|
|
31
|
+
exportedAt: new Date().toISOString(),
|
|
32
|
+
exportedBy: 'Bradford Operations',
|
|
33
|
+
version: '1.0'
|
|
34
|
+
};
|
|
35
|
+
zip.file('metadata.json', JSON.stringify(metadata, null, 2));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Generate ZIP buffer
|
|
39
|
+
const buffer = await zip.generateAsync({
|
|
40
|
+
type: 'nodebuffer',
|
|
41
|
+
compression: 'DEFLATE',
|
|
42
|
+
compressionOptions: {
|
|
43
|
+
level: 6
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
return buffer;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Package a complete DRP file with all required components
|
|
52
|
+
*
|
|
53
|
+
* @param {Object} options - DRP configuration
|
|
54
|
+
* @param {string} options.projectXml - Project XML content
|
|
55
|
+
* @param {Array} options.timelines - Timeline configurations
|
|
56
|
+
* @param {Object} options.mediaPool - Media pool configuration
|
|
57
|
+
* @param {Object} options.metadata - Additional metadata
|
|
58
|
+
* @returns {Promise<Buffer>} Complete DRP file as buffer
|
|
59
|
+
*/
|
|
60
|
+
async function packageFullDRP(options) {
|
|
61
|
+
const {
|
|
62
|
+
projectXml,
|
|
63
|
+
timelines = [],
|
|
64
|
+
mediaPool = null,
|
|
65
|
+
metadata = {},
|
|
66
|
+
includeProjectXml = true,
|
|
67
|
+
} = options;
|
|
68
|
+
|
|
69
|
+
const zip = new JSZip();
|
|
70
|
+
|
|
71
|
+
// Add root project.xml (required for DRP, omitted for DRT).
|
|
72
|
+
if (includeProjectXml) {
|
|
73
|
+
if (!projectXml) {
|
|
74
|
+
throw new Error('packageFullDRP: projectXml is required when includeProjectXml is true');
|
|
75
|
+
}
|
|
76
|
+
zip.file('project.xml', projectXml);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Add metadata file
|
|
80
|
+
if (Object.keys(metadata).length > 0) {
|
|
81
|
+
zip.file('metadata.json', JSON.stringify({
|
|
82
|
+
...metadata,
|
|
83
|
+
exportedAt: metadata.exportedAt || new Date().toISOString(),
|
|
84
|
+
exportedFrom: 'Bradford Operations',
|
|
85
|
+
}, null, 2));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Create Primary1 folder for timeline data
|
|
89
|
+
const primary = zip.folder('Primary1');
|
|
90
|
+
|
|
91
|
+
// Add SeqContainer files for each timeline
|
|
92
|
+
for (const [idx, timeline] of timelines.entries()) {
|
|
93
|
+
const seqContainerXml = await buildSeqContainerFile(timeline, {
|
|
94
|
+
frameRate: timeline.frameRate || 24,
|
|
95
|
+
startTimecode: timeline.startTimecode || '01:00:00:00',
|
|
96
|
+
markers: timeline.markers || [],
|
|
97
|
+
resolution: timeline.resolution || '1920x1080',
|
|
98
|
+
});
|
|
99
|
+
primary.file(`SeqContainer${idx + 1}.xml`, seqContainerXml);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Add MpFolder if media pool is provided
|
|
103
|
+
if (mediaPool) {
|
|
104
|
+
const mpFolderXml = buildMpFolderFile(mediaPool);
|
|
105
|
+
primary.file('MpFolder.xml', mpFolderXml);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Generate ZIP buffer with DEFLATE compression
|
|
109
|
+
const buffer = await zip.generateAsync({
|
|
110
|
+
type: 'nodebuffer',
|
|
111
|
+
compression: 'DEFLATE',
|
|
112
|
+
compressionOptions: {
|
|
113
|
+
level: 6,
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
return buffer;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Validate DRP structure before packaging
|
|
122
|
+
*
|
|
123
|
+
* @param {Object} options - DRP configuration to validate
|
|
124
|
+
* @returns {Array} Array of validation errors (empty if valid)
|
|
125
|
+
*/
|
|
126
|
+
function validateDRPConfig(options) {
|
|
127
|
+
const errors = [];
|
|
128
|
+
|
|
129
|
+
// projectXml is only required when we'll actually include it. DRT
|
|
130
|
+
// builds pass includeProjectXml: false and don't supply one.
|
|
131
|
+
if (options.includeProjectXml !== false && !options.projectXml) {
|
|
132
|
+
errors.push('project.xml content is required');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (!options.timelines || options.timelines.length === 0) {
|
|
136
|
+
errors.push('At least one timeline is required');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Validate each timeline
|
|
140
|
+
options.timelines?.forEach((timeline, tlIdx) => {
|
|
141
|
+
if (!timeline.name) {
|
|
142
|
+
errors.push(`Timeline ${tlIdx}: name is required`);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Validate clips in tracks
|
|
146
|
+
timeline.videoTracks?.forEach((track, trackIdx) => {
|
|
147
|
+
track.clips?.forEach((clip, clipIdx) => {
|
|
148
|
+
if (clip.start === undefined) {
|
|
149
|
+
errors.push(`Timeline ${tlIdx} Video Track ${trackIdx} Clip ${clipIdx}: start position required`);
|
|
150
|
+
}
|
|
151
|
+
if (clip.duration === undefined) {
|
|
152
|
+
errors.push(`Timeline ${tlIdx} Video Track ${trackIdx} Clip ${clipIdx}: duration required`);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
return errors;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Validate DRP structure
|
|
163
|
+
*/
|
|
164
|
+
function validateDRPStructure(buffer) {
|
|
165
|
+
// Check ZIP magic bytes (PK)
|
|
166
|
+
if (!Buffer.isBuffer(buffer) || buffer.length < 4) {
|
|
167
|
+
return { valid: false, error: 'Invalid buffer' };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (buffer[0] !== 0x50 || buffer[1] !== 0x4B) {
|
|
171
|
+
return { valid: false, error: 'Not a ZIP file' };
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return { valid: true };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Get DRP file size estimate
|
|
179
|
+
*/
|
|
180
|
+
function estimateDRPSize(clipCount, hasGrades = false) {
|
|
181
|
+
// Base size: ~10KB for project structure
|
|
182
|
+
let size = 10 * 1024;
|
|
183
|
+
|
|
184
|
+
// Per clip: ~1KB base + grades if present
|
|
185
|
+
size += clipCount * 1024;
|
|
186
|
+
|
|
187
|
+
if (hasGrades) {
|
|
188
|
+
// Grade data: ~2-5KB per graded clip (estimate 50% graded)
|
|
189
|
+
size += (clipCount * 0.5) * 3 * 1024;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return size;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
module.exports = {
|
|
196
|
+
packageDRP,
|
|
197
|
+
packageFullDRP,
|
|
198
|
+
validateDRPConfig,
|
|
199
|
+
validateDRPStructure,
|
|
200
|
+
estimateDRPSize,
|
|
201
|
+
};
|