davinci-resolve-mcp 2.79.0 → 2.79.2
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/CHANGELOG.md +84 -0
- package/README.md +1 -1
- package/docs/guides/conforming-an-avid-aaf.md +7 -0
- package/docs/reference/api-limitations.md +2 -2
- package/install.py +1 -1
- package/package.json +1 -1
- package/resolve-advanced/server/editorial.mjs +13 -4
- package/resolve-advanced/server/tools/drt.mjs +18 -3
- package/resolve-advanced/server/tools/editorial.mjs +6 -2
- package/src/granular/common.py +1 -1
- package/src/server.py +1 -1
- package/src/utils/api_truth.py +76 -31
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,90 @@
|
|
|
2
2
|
|
|
3
3
|
Release history for the DaVinci Resolve MCP Server. The latest release is summarized in the root README; older entries live here to keep the README focused.
|
|
4
4
|
|
|
5
|
+
## What's New in v2.79.2
|
|
6
|
+
|
|
7
|
+
A published contract was **wrong**. This release corrects it. If you read the retime entry in
|
|
8
|
+
v2.79.0 or v2.79.1 and built anything on it, read this.
|
|
9
|
+
|
|
10
|
+
### Corrected
|
|
11
|
+
|
|
12
|
+
- **The `Clip speed / retime ratio and speed ramps` entry stated a rule that does not exist,
|
|
13
|
+
and missed the hazard that does.** The interchange half of that entry claimed *"any
|
|
14
|
+
`<in>`/`<pproTicksIn>` inconsistency is silently REJECTED, measured in BOTH orientations."*
|
|
15
|
+
**That claim is false and has been removed.** It came from an emitter that wrote
|
|
16
|
+
`ticks = in × ticks-per-frame` at every speed — so what it measured was its own malformed
|
|
17
|
+
files being refused, not a rule of Resolve's importer. In a real Premiere FCP7 export a
|
|
18
|
+
retimed clip's `<in>` and `pproTicksIn` are *supposed* to disagree, by exactly the speed
|
|
19
|
+
ratio: `<in>`/`<out>` are the post-retime (warped) domain and span the **record** duration,
|
|
20
|
+
`pproTicksIn/Out` carry the **true source** position, and `<duration>` is the file length in
|
|
21
|
+
the warped domain. The entry now states that convention with the tick arithmetic shown
|
|
22
|
+
(254016000000/24 = 10584000000 ticks per frame), and notes that
|
|
23
|
+
`resolve-advanced/server/prproj.mjs` already derives Premiere speed from the same tick
|
|
24
|
+
geometry.
|
|
25
|
+
- **The graphdict evidence has been replaced.** The "dead in FOUR separate shapes / 0 of 2
|
|
26
|
+
landed" table and the "200% clip emitted `in 200 / out 296` clamped to `out 248`" line
|
|
27
|
+
described that same malformed input being normalized, and did not support the conclusion
|
|
28
|
+
they were cited for. Re-tested on 19.1.3.7 in Premiere's actual convention — one 100%
|
|
29
|
+
control clip plus one 200% clip per timeline — the document imports, the control lands
|
|
30
|
+
correct, and the retimed clip reads back `src 1500..1548`: a 48-frame source span over a
|
|
31
|
+
48-frame record span, i.e. no retime. Identical result with the graphdict removed. **The
|
|
32
|
+
conclusion is unchanged** — the scripting-API xmeml import builds no retime — only the
|
|
33
|
+
evidence behind it.
|
|
34
|
+
- **The real hazard, previously absent, is now documented.** **Resolve reads `<in>` literally
|
|
35
|
+
as the true source frame**, honouring neither the ticks nor the graphdict. So importing a
|
|
36
|
+
genuine Premiere XML that contains retimes places every retimed clip at `in ÷ ratio` — the
|
|
37
|
+
200% clip above lands on source frame 1957 instead of 3914. No error, cut lengths still
|
|
38
|
+
correct, every clip linked and online, timeline renders. It reads as a good conform while
|
|
39
|
+
sitting at the wrong moment of the right file — the same failure class as the Avid AAF
|
|
40
|
+
camera-file link, and `docs/guides/conforming-an-avid-aaf.md` now cross-references it.
|
|
41
|
+
- **The claim is scoped honestly.** All of it describes the **scripting-API** import
|
|
42
|
+
(`ImportTimelineFromFile`). Resolve's **UI** importer (File > Import > Timeline) is
|
|
43
|
+
**untested**, and that is how editors usually conform a Premiere XML — the entry no longer
|
|
44
|
+
implies otherwise. The existing "no positive control" caveat is kept: no clip *known* to be
|
|
45
|
+
retimed has been read back through `GetLeftOffset`/`GetRightOffset`, because there is no
|
|
46
|
+
scripting path to create one.
|
|
47
|
+
|
|
48
|
+
The `SetProperty`/`GetProperty` half of the entry was re-measured on 19.1.3.7 and is
|
|
49
|
+
unaffected. `docs/reference/api-limitations.md` is generated from `src/utils/api_truth.py` and
|
|
50
|
+
was regenerated.
|
|
51
|
+
|
|
52
|
+
### Validation
|
|
53
|
+
|
|
54
|
+
- `gen_api_limitations.py --check`, `test_api_limitations_doc`, static/drift guards,
|
|
55
|
+
`audit_api_parity.py`, agent-rules drift, `--help`/`--version`, `npm pack --dry-run`,
|
|
56
|
+
`git diff --check`: clean.
|
|
57
|
+
- Docs-only; no code path changed, so no live Resolve validation was required.
|
|
58
|
+
|
|
59
|
+
## What's New in v2.79.1
|
|
60
|
+
|
|
61
|
+
One redirect that was never written, in a dispatcher whose other container formats all have one.
|
|
62
|
+
|
|
63
|
+
### Fixed
|
|
64
|
+
|
|
65
|
+
- **`parse_interchange` told `.drt`/`.drp` callers the format was unknown — for formats the
|
|
66
|
+
same package parses.** `parseInterchange(format, content)` gives AAF and `.prproj` explicit,
|
|
67
|
+
helpful redirects to their path-based readers, but `drt` and `drp` had no case at all and
|
|
68
|
+
fell through to `unknown format 'drt' (edl|otio|xml|xmeml|fcp7|aaf|prproj)`. Meanwhile
|
|
69
|
+
`list_sequences` in the same cluster parses both by path, and the tool description advertises
|
|
70
|
+
it. So the cluster supports DRT, documents that it supports DRT, then tells the
|
|
71
|
+
content-shaped caller it does not. The failure is silent downstream: a consumer that reads
|
|
72
|
+
"unknown format" (or hands `{ content }` to `drt.parse`, whose schema wants `{ drtPath }`)
|
|
73
|
+
records **zero events**, and an empty sequence is indistinguishable from an unsupported one.
|
|
74
|
+
`parseInterchange` now throws the same shape of redirect the AAF and `.prproj` cases throw —
|
|
75
|
+
naming the ZIP container, `parseDRT(path)`, and the two callable entry points — and the
|
|
76
|
+
`default:` message lists `drt|drp` among the known formats. The `editorial`
|
|
77
|
+
`parse_interchange` schema accepts `drt`/`drp` so the tool-level caller gets that redirect
|
|
78
|
+
instead of a bare enum rejection, and `drt.parse` / `list_sequences` / `validate` now name
|
|
79
|
+
the path argument they wanted rather than emitting a raw zod issue dump.
|
|
80
|
+
|
|
81
|
+
### Validation
|
|
82
|
+
|
|
83
|
+
- `resolve-advanced` suite: 778 tests, 748 pass, 30 skipped, 0 fail (4 new assertions, written
|
|
84
|
+
first and confirmed failing on v2.79.0).
|
|
85
|
+
- Static/drift checks, `--help`/`--version`, `npm pack --dry-run`, `git diff --check`: clean.
|
|
86
|
+
- No Resolve behavior changed; this path never touches the Resolve API, so live validation was
|
|
87
|
+
not required.
|
|
88
|
+
|
|
5
89
|
## What's New in v2.79.0
|
|
6
90
|
|
|
7
91
|
Six silent failures in the conform path, found by conforming a real Avid picture turnover
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# DaVinci Resolve MCP Server
|
|
2
2
|
|
|
3
|
-
[](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
|
|
4
4
|
[](https://www.npmjs.com/package/davinci-resolve-mcp)
|
|
5
5
|
[](docs/reference/api-coverage.md)
|
|
6
6
|
[-blue.svg)](#server-modes)
|
|
@@ -86,6 +86,13 @@ state as the thing it is checking cannot contradict it.
|
|
|
86
86
|
including `MediaPool.ImportTimelineFromFile` and the `AppendToTimeline`
|
|
87
87
|
placement and durability limits you will hit if you build the timeline
|
|
88
88
|
yourself.
|
|
89
|
+
- `docs/reference/api-limitations.md` → *Clip speed / retime ratio and speed
|
|
90
|
+
ramps* — the same failure class in the Premiere XML route. Importing an FCP7
|
|
91
|
+
XML that contains retimes through the scripting API places every retimed clip
|
|
92
|
+
at `<in>`, which is the true source frame divided by the speed ratio. Lengths
|
|
93
|
+
correct, links correct, wrong moment of the right file, no warning. If your
|
|
94
|
+
turnover is a Premiere XML rather than an AAF, read that entry before trusting
|
|
95
|
+
the conform.
|
|
89
96
|
- `docs/guides/headless-edit-loop.md` — which interchange formats relink at all
|
|
90
97
|
when media has moved (DRT, OTIO and EDL do not).
|
|
91
98
|
</content>
|
|
@@ -117,8 +117,8 @@ equivalent, blocking full automation.
|
|
|
117
117
|
### Clip speed / retime ratio and speed ramps
|
|
118
118
|
|
|
119
119
|
- **Object:** `TimelineItem`
|
|
120
|
-
- **Behavior:** SetProperty exposes only retime *quality* (RetimeProcess, MotionEstimation) and transform/crop/composite/opacity keys — not the speed value itself. There is no way to set a clip to a given % speed, reverse it, or author a speed ramp. Verified against the documented SetProperty key list AND by live mutating attempt on 21.0.0: SetProperty('Speed'|'PlaybackSpeed'|'RetimeSpeed'|'ClipSpeed', 50) all return False, while SetProperty('RetimeProcess', 1) returns True. THE READ SIDE IS AS DEAD AS THE WRITE SIDE, which is easy to miss: re-measured on Studio 19.1.3.7 against a placed item, GetProperty('Speed'), GetProperty('PlaybackSpeed'), GetProperty('RetimeSpeed') and GetProperty('ClipSpeed') ALL return None, and the keyless GetProperty() dict (26 keys on that item) carries no speed value at all — its only retime key is RetimeProcess, which is quality, not ratio. SetProperty('Speed', 1.75) returned False on 19.1.3.7 too, so the write refusal is not specific to 21.0.0. Note the 21.0.0 stamp above covers the SetProperty measurements only. THE
|
|
121
|
-
- **Workaround / current handling:** Set clip speed/retime in the Resolve UI; no scripted equivalent exists, and
|
|
120
|
+
- **Behavior:** SetProperty exposes only retime *quality* (RetimeProcess, MotionEstimation) and transform/crop/composite/opacity keys — not the speed value itself. There is no way to set a clip to a given % speed, reverse it, or author a speed ramp. Verified against the documented SetProperty key list AND by live mutating attempt on 21.0.0: SetProperty('Speed'|'PlaybackSpeed'|'RetimeSpeed'|'ClipSpeed', 50) all return False, while SetProperty('RetimeProcess', 1) returns True. THE READ SIDE IS AS DEAD AS THE WRITE SIDE, which is easy to miss: re-measured on Studio 19.1.3.7 against a placed item, GetProperty('Speed'), GetProperty('PlaybackSpeed'), GetProperty('RetimeSpeed') and GetProperty('ClipSpeed') ALL return None, and the keyless GetProperty() dict (26 keys on that item) carries no speed value at all — its only retime key is RetimeProcess, which is quality, not ratio. SetProperty('Speed', 1.75) returned False on 19.1.3.7 too, so the write refusal is not specific to 21.0.0. Note the 21.0.0 stamp above covers the SetProperty measurements only. THE SCRIPTING-API xmeml IMPORT BUILDS NO RETIME — and the way it fails is worse than a no-op. First, what Premiere actually writes, because having this backwards is what produced the wrong contract this entry published in 2.79.0–2.79.1 (see CORRECTION below). In an FCP7 XML a retimed clipitem's <in>/<out> live in the POST-RETIME (warped) domain and always span the RECORD duration; pproTicksIn/pproTicksOut carry the TRUE SOURCE position; and <duration> is the file length expressed in the warped domain. A real 200% clip at 24 fps: <in>1957</in> <out>1971</out> — span 14, EQUAL to its record span; pproTicksIn 41425776000000 and pproTicksOut 41722128000000, which at 254016000000/24 = 10584000000 ticks per frame are source frames 3914 and 3942, exactly 1957x2 and 1971x2, a 28-frame source span over a 14-frame record span; <duration>24292</duration> for a 48584-frame file; and a graphdict mapping warped to true source with the ratio as its slope (when 17910 -> value 35820). So for a retimed clip <in> and pproTicksIn are SUPPOSED to disagree, by exactly the ratio. The same relationship seen from the other side is already encoded in this repo: resolve-advanced/server/prproj.mjs derives Premiere speed from tick geometry as |srcSpan / recSpan| * 100, reversing when in > out. Against that convention, measured on 19.1.3/19.1.3.7: (a) the importer IGNORES the scalar Time Remap speed filter and the clips arrive at 100%; (b) `graphdict` is ignored too — re-tested in Premiere's exact convention with one 100% control clip and one 200% clip per timeline, a document carrying warped <in>/<out>, true-source pproTicks, <duration> = fileLen/ratio and a constant-slope graphdict imports cleanly, the control lands correct, and the 200% clip reads back src 1500..1548 — a 48-frame source span over a 48-frame record span, i.e. NO retime; emitting the identical document WITHOUT the graphdict gives the identical result; (c) `reverse` does not survive either; (d) THE HAZARD, and it is the part that bites: Resolve reads <in> LITERALLY as the true source frame, honouring neither the ticks nor the graphdict. Import a genuine Premiere XML that contains retimes and every retimed clip is placed at in / ratio — the 200% clip above lands on source frame 1957 instead of 3914. There is no error, the cut lengths are still correct, every clip is linked and online, and the timeline renders — so it reads as a good conform while sitting at the wrong moment of the right file. This is the same failure class as the Avid AAF camera-file link (docs/guides/conforming-an-avid-aaf.md): wrong in a way only a frame comparison against a reference can see. SCOPE: all of the above is the SCRIPTING-API import (ImportTimelineFromFile). Resolve's UI importer (File > Import > Timeline) has NOT been tested, and that is how editors usually conform a Premiere XML — do not read this as covering it. CORRECTION: this entry as published in 2.79.0–2.79.1 also claimed that any <in>/<pproTicksIn> inconsistency is silently REJECTED in both orientations. That claim was FALSE and has been removed — it came from an emitter writing ticks = in x ticks-per-frame at every speed, so what it observed was its own malformed files being refused. The graphdict evidence published with it (dead in FOUR shapes, 0 of 2 landed, a 200% clip emitted in 200 / out 296 'clamped' to out 248) described that same malformed input being normalized and is replaced by the re-test above. The conclusion is unchanged; only its evidence is. Placement is NOT the problem: the same route imported 573 clips with 572 of 573 matching by track and record position with source frames exact, and the importer BUILT a 59-frame dissolve. The retime gap is specific, not general. TRAP: Resolve's own FCP7 export cannot witness a speed. It writes a DEGENERATE Time Remap on every clip — `speed` value 0 (not 100) and a graphdict whose keyframe `value`s are all 0 while its `when`s carry the clip's source in/out — so anyone verifying a retime by round-tripping through EXPORT_FCP_7_XML is reading furniture, and the identity Time Remap blocks present on every clip are what make the route look like it should work.
|
|
121
|
+
- **Workaround / current handling:** Set clip speed/retime in the Resolve UI; no scripted equivalent exists, and the scripting-API xmeml import does not carry one in. Do NOT read speed back with GetProperty (None) or witness it via EXPORT_FCP_7_XML (degenerate). Read the clip's GEOMETRY instead — GetLeftOffset / GetRightOffset, whose source span is what shows whether a retime was built (the re-tested 200% clip read src 1500..1548, 48 source frames over a 48-frame record, so none was). Caveat worth keeping: there is still no positive control — no clip KNOWN to be retimed has been read back through those two witnesses, because there is no scripting path to create one, so the geometry witness is the best available, not a proven one. And if you are importing a real Premiere XML that contains retimes, treat every retimed clip's source position as WRONG — placed at <in>, i.e. in / ratio — until it is checked against a reference; the lengths and the links will look right.
|
|
122
122
|
- **Tags:** missing-method, timeline, retime, speed, interchange, silent-failure, unreliable-return
|
|
123
123
|
|
|
124
124
|
### Color node graph editing and primary grade values
|
package/install.py
CHANGED
|
@@ -36,7 +36,7 @@ from src.utils.update_check import (
|
|
|
36
36
|
|
|
37
37
|
# ─── Version ──────────────────────────────────────────────────────────────────
|
|
38
38
|
|
|
39
|
-
VERSION = "2.79.
|
|
39
|
+
VERSION = "2.79.2"
|
|
40
40
|
# Only hard floor: mcp[cli] requires Python 3.10+. There is no upper bound —
|
|
41
41
|
# Resolve's scripting bridge loads into newer interpreters on recent builds
|
|
42
42
|
# (Python 3.14 verified against Resolve Studio 20.3.2). Older Resolve builds
|
package/package.json
CHANGED
|
@@ -196,9 +196,13 @@ export function parseXMEMLEvents(xml, opts = {}) {
|
|
|
196
196
|
}
|
|
197
197
|
|
|
198
198
|
/**
|
|
199
|
-
* Dispatch by format (SYNC, pure over TEXT). Binary formats are handled out-of-band by
|
|
200
|
-
* path-based readers — AAF via aaf.mjs `parseAAF` (async, pyaaf2), .prproj via prproj.mjs
|
|
201
|
-
* `parsePrproj` (gunzip+XML). This throws to route callers
|
|
199
|
+
* Dispatch by format (SYNC, pure over TEXT). Binary/container formats are handled out-of-band by
|
|
200
|
+
* their own path-based readers — AAF via aaf.mjs `parseAAF` (async, pyaaf2), .prproj via prproj.mjs
|
|
201
|
+
* `parsePrproj` (gunzip+XML), .drt/.drp via drt.mjs `parseDRT` (ZIP). This throws to route callers
|
|
202
|
+
* there rather than faking a parse. Every container format gets a NAMED redirect: falling through
|
|
203
|
+
* to `unknown format` would tell a caller the cluster does not support a format it does support
|
|
204
|
+
* (list_sequences parses .drt/.drp), and an empty parse is indistinguishable downstream from an
|
|
205
|
+
* unsupported one.
|
|
202
206
|
*/
|
|
203
207
|
export function parseInterchange(format, content, opts = {}) {
|
|
204
208
|
switch (String(format).toLowerCase()) {
|
|
@@ -218,8 +222,13 @@ export function parseInterchange(format, content, opts = {}) {
|
|
|
218
222
|
throw new Error(
|
|
219
223
|
'parse_interchange: .prproj is gzip-compressed XML — parse it via the path-based reader (prproj.mjs `parsePrproj`), not the sync parseInterchange().',
|
|
220
224
|
);
|
|
225
|
+
case 'drt':
|
|
226
|
+
case 'drp':
|
|
227
|
+
throw new Error(
|
|
228
|
+
`parse_interchange: .${String(format).toLowerCase()} is a ZIP container — parse it via the path-based reader (drt.mjs \`parseDRT(path)\`), not the sync parseInterchange(). Entry points: editorial \`list_sequences({path})\` or drt \`parse({drtPath})\`.`,
|
|
229
|
+
);
|
|
221
230
|
default:
|
|
222
|
-
throw new Error(`parse_interchange: unknown format '${format}' (edl|otio|xml|xmeml|fcp7|aaf|prproj)`);
|
|
231
|
+
throw new Error(`parse_interchange: unknown format '${format}' (edl|otio|xml|xmeml|fcp7|drt|drp|aaf|prproj)`);
|
|
223
232
|
}
|
|
224
233
|
}
|
|
225
234
|
|
|
@@ -70,17 +70,32 @@ const downgradeSchema = z.object({
|
|
|
70
70
|
appVersionString: z.string().optional().describe('DbAppVer comment to stamp (default derived from targetAppVersion, else "<v>.0.0.0000")'),
|
|
71
71
|
});
|
|
72
72
|
|
|
73
|
+
/**
|
|
74
|
+
* .drt/.drp are ZIP containers, so every reader here takes a FILE PATH. A caller reaching for the
|
|
75
|
+
* content-shaped convention its sibling text formats use (`{ content }`) otherwise gets a bare zod
|
|
76
|
+
* dump that never names the key it wanted.
|
|
77
|
+
*/
|
|
78
|
+
function requirePathArg(args, key, action) {
|
|
79
|
+
const a = args && typeof args === 'object' ? args : {};
|
|
80
|
+
if (typeof a[key] === 'string' && a[key]) return a;
|
|
81
|
+
const given = Object.keys(a).filter((k) => a[k] !== undefined);
|
|
82
|
+
throw new Error(
|
|
83
|
+
`drt.${action}: pass \`${key}\` — an absolute path to the .drt/.drp. A .drt/.drp is a ZIP container, so this action reads a FILE PATH, never file content` +
|
|
84
|
+
`${given.length ? ` (got: ${given.join(', ')})` : ' (got no arguments)'}.`,
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
73
88
|
export const drtTool = {
|
|
74
89
|
name: 'drt',
|
|
75
90
|
description:
|
|
76
91
|
'DaVinci Resolve Timeline (.drt) operations — offline, no Resolve required. Actions: parse, list_sequences (enumerate the timelines inside a .drp/.drt → [{id,name,eventCount,index}] to drive a "which sequence?" picker), author, validate, inject_into_drp, extract_from_drp (pull one SeqContainer out as a .drt — feed the .drt to the Python davinci-resolve MCP timeline.import_timeline_checked, or use timeline.import_from_drp to do both), downgrade (stamp <ProjectVersion> down so an OLDER Resolve will import a .drt/.drp from a newer one — pass targetAppVersion like "19.1.3" or targetProjectVersion).',
|
|
77
92
|
async handler({ action, args }) {
|
|
78
93
|
if (action === 'parse') {
|
|
79
|
-
const p = parseSchema.parse(args);
|
|
94
|
+
const p = parseSchema.parse(requirePathArg(args, 'drtPath', 'parse'));
|
|
80
95
|
return drt().parseDRT(p.drtPath);
|
|
81
96
|
}
|
|
82
97
|
if (action === 'list_sequences') {
|
|
83
|
-
const p = listSequencesSchema.parse(args);
|
|
98
|
+
const p = listSequencesSchema.parse(requirePathArg(args, 'drpPath', 'list_sequences'));
|
|
84
99
|
const parsed = await drt().parseDRT(p.drpPath);
|
|
85
100
|
const sequences = summarizeDrtTimelines(parsed);
|
|
86
101
|
return { path: p.drpPath, count: sequences.length, sequences };
|
|
@@ -92,7 +107,7 @@ export const drtTool = {
|
|
|
92
107
|
return { outputPath: p.outputPath, bytes: buf.length };
|
|
93
108
|
}
|
|
94
109
|
if (action === 'validate') {
|
|
95
|
-
const p = validateSchema.parse(args);
|
|
110
|
+
const p = validateSchema.parse(requirePathArg(args, 'drtPath', 'validate'));
|
|
96
111
|
return drt().validateDRT(p.drtPath);
|
|
97
112
|
}
|
|
98
113
|
if (action === 'inject_into_drp') {
|
|
@@ -32,11 +32,15 @@ async function parseAnySource(sourcePath, sourceFormat) {
|
|
|
32
32
|
return parseInterchange(fmt, content, {});
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
// drt/drp are accepted only so the caller gets parseInterchange's NAMED redirect to the
|
|
36
|
+
// path-based reader instead of a bare enum-rejection that reads as "unsupported".
|
|
35
37
|
const parseSchema = z.object({
|
|
36
|
-
format: z.enum(['edl', 'otio', 'xml', 'xmeml', 'fcp7', 'aaf', 'prproj']),
|
|
38
|
+
format: z.enum(['edl', 'otio', 'xml', 'xmeml', 'fcp7', 'aaf', 'prproj', 'drt', 'drp']),
|
|
37
39
|
content: z
|
|
38
40
|
.union([z.string(), z.object({}).passthrough()])
|
|
39
|
-
.describe(
|
|
41
|
+
.describe(
|
|
42
|
+
'EDL text / OTIO JSON (string or object) / XMEML string. For AAF or PRPROJ (binary): the file PATH. For .drt/.drp (ZIP): use list_sequences or drt.parse — this action redirects.',
|
|
43
|
+
),
|
|
40
44
|
fps: z.number().optional(),
|
|
41
45
|
});
|
|
42
46
|
|
package/src/granular/common.py
CHANGED
|
@@ -85,7 +85,7 @@ if not logging.getLogger().handlers:
|
|
|
85
85
|
handlers=[logging.StreamHandler()],
|
|
86
86
|
)
|
|
87
87
|
|
|
88
|
-
VERSION = "2.79.
|
|
88
|
+
VERSION = "2.79.2"
|
|
89
89
|
logger = logging.getLogger("davinci-resolve-mcp")
|
|
90
90
|
logger.info(f"Starting DaVinci Resolve MCP Server v{VERSION}")
|
|
91
91
|
logger.info(f"Detected platform: {get_platform()}")
|
package/src/server.py
CHANGED
package/src/utils/api_truth.py
CHANGED
|
@@ -680,25 +680,66 @@ API_TRUTH: List[Dict[str, Any]] = [
|
|
|
680
680
|
"'Speed', 1.75) returned False on 19.1.3.7 too, so the write "
|
|
681
681
|
"refusal is not specific to 21.0.0. Note the 21.0.0 stamp above "
|
|
682
682
|
"covers the SetProperty measurements only. "
|
|
683
|
-
"THE
|
|
684
|
-
"
|
|
685
|
-
"
|
|
686
|
-
"
|
|
687
|
-
"
|
|
688
|
-
"
|
|
689
|
-
"
|
|
690
|
-
"
|
|
691
|
-
"
|
|
692
|
-
"
|
|
693
|
-
"
|
|
694
|
-
"
|
|
695
|
-
"
|
|
696
|
-
"
|
|
697
|
-
"
|
|
698
|
-
"
|
|
699
|
-
"
|
|
700
|
-
"
|
|
701
|
-
"
|
|
683
|
+
"THE SCRIPTING-API xmeml IMPORT BUILDS NO RETIME — and the way "
|
|
684
|
+
"it fails is worse than a no-op. "
|
|
685
|
+
"First, what Premiere actually writes, because having this "
|
|
686
|
+
"backwards is what produced the wrong contract this entry "
|
|
687
|
+
"published in 2.79.0–2.79.1 (see CORRECTION below). In an FCP7 "
|
|
688
|
+
"XML a retimed clipitem's <in>/<out> live in the POST-RETIME "
|
|
689
|
+
"(warped) domain and always span the RECORD duration; "
|
|
690
|
+
"pproTicksIn/pproTicksOut carry the TRUE SOURCE position; and "
|
|
691
|
+
"<duration> is the file length expressed in the warped domain. A "
|
|
692
|
+
"real 200% clip at 24 fps: <in>1957</in> <out>1971</out> — span "
|
|
693
|
+
"14, EQUAL to its record span; pproTicksIn 41425776000000 and "
|
|
694
|
+
"pproTicksOut 41722128000000, which at 254016000000/24 = "
|
|
695
|
+
"10584000000 ticks per frame are source frames 3914 and 3942, "
|
|
696
|
+
"exactly 1957x2 and 1971x2, a 28-frame source span over a "
|
|
697
|
+
"14-frame record span; <duration>24292</duration> for a "
|
|
698
|
+
"48584-frame file; and a graphdict mapping warped to true source "
|
|
699
|
+
"with the ratio as its slope (when 17910 -> value 35820). So for "
|
|
700
|
+
"a retimed clip <in> and pproTicksIn are SUPPOSED to disagree, by "
|
|
701
|
+
"exactly the ratio. The same relationship seen from the other "
|
|
702
|
+
"side is already encoded in this repo: "
|
|
703
|
+
"resolve-advanced/server/prproj.mjs derives Premiere speed from "
|
|
704
|
+
"tick geometry as |srcSpan / recSpan| * 100, reversing when in > "
|
|
705
|
+
"out. "
|
|
706
|
+
"Against that convention, measured on 19.1.3/19.1.3.7: (a) the "
|
|
707
|
+
"importer IGNORES the scalar Time Remap speed filter and the "
|
|
708
|
+
"clips arrive at 100%; (b) `graphdict` is ignored too — re-tested "
|
|
709
|
+
"in Premiere's exact convention with one 100% control clip and "
|
|
710
|
+
"one 200% clip per timeline, a document carrying warped "
|
|
711
|
+
"<in>/<out>, true-source pproTicks, <duration> = fileLen/ratio "
|
|
712
|
+
"and a constant-slope graphdict imports cleanly, the control "
|
|
713
|
+
"lands correct, and the 200% clip reads back src 1500..1548 — a "
|
|
714
|
+
"48-frame source span over a 48-frame record span, i.e. NO "
|
|
715
|
+
"retime; emitting the identical document WITHOUT the graphdict "
|
|
716
|
+
"gives the identical result; (c) `reverse` does not survive "
|
|
717
|
+
"either; (d) THE HAZARD, and it is the part that bites: Resolve "
|
|
718
|
+
"reads <in> LITERALLY as the true source frame, honouring neither "
|
|
719
|
+
"the ticks nor the graphdict. Import a genuine Premiere XML that "
|
|
720
|
+
"contains retimes and every retimed clip is placed at in / ratio "
|
|
721
|
+
"— the 200% clip above lands on source frame 1957 instead of "
|
|
722
|
+
"3914. There is no error, the cut lengths are still correct, "
|
|
723
|
+
"every clip is linked and online, and the timeline renders — so "
|
|
724
|
+
"it reads as a good conform while sitting at the wrong moment of "
|
|
725
|
+
"the right file. This is the same failure class as the Avid AAF "
|
|
726
|
+
"camera-file link (docs/guides/conforming-an-avid-aaf.md): wrong "
|
|
727
|
+
"in a way only a frame comparison against a reference can see. "
|
|
728
|
+
"SCOPE: all of the above is the SCRIPTING-API import "
|
|
729
|
+
"(ImportTimelineFromFile). Resolve's UI importer (File > Import > "
|
|
730
|
+
"Timeline) has NOT been tested, and that is how editors usually "
|
|
731
|
+
"conform a Premiere XML — do not read this as covering it. "
|
|
732
|
+
"CORRECTION: this entry as published in 2.79.0–2.79.1 also "
|
|
733
|
+
"claimed that any <in>/<pproTicksIn> inconsistency is silently "
|
|
734
|
+
"REJECTED in both orientations. That claim was FALSE and has been "
|
|
735
|
+
"removed — it came from an emitter writing ticks = in x "
|
|
736
|
+
"ticks-per-frame at every speed, so what it observed was its own "
|
|
737
|
+
"malformed files being refused. The graphdict evidence published "
|
|
738
|
+
"with it (dead in FOUR shapes, 0 of 2 landed, a 200% clip emitted "
|
|
739
|
+
"in 200 / out 296 'clamped' to out 248) described that same "
|
|
740
|
+
"malformed input being normalized and is replaced by the re-test "
|
|
741
|
+
"above. The conclusion is unchanged; only its evidence is. "
|
|
742
|
+
"Placement is NOT the problem: the same route imported "
|
|
702
743
|
"573 clips with 572 of 573 matching by track and record position "
|
|
703
744
|
"with source frames exact, and the importer BUILT a 59-frame "
|
|
704
745
|
"dissolve. The retime gap is specific, not general. "
|
|
@@ -711,18 +752,22 @@ API_TRUTH: List[Dict[str, Any]] = [
|
|
|
711
752
|
"present on every clip are what make the route look like it "
|
|
712
753
|
"should work.",
|
|
713
754
|
"recommended": "Set clip speed/retime in the Resolve UI; no scripted "
|
|
714
|
-
"equivalent exists, and
|
|
715
|
-
"in. Do NOT read speed back with GetProperty
|
|
716
|
-
"witness it via EXPORT_FCP_7_XML (degenerate).
|
|
717
|
-
"clip's GEOMETRY instead — GetLeftOffset /
|
|
718
|
-
"
|
|
719
|
-
"
|
|
720
|
-
"
|
|
721
|
-
"
|
|
722
|
-
"
|
|
723
|
-
"
|
|
724
|
-
"
|
|
725
|
-
"
|
|
755
|
+
"equivalent exists, and the scripting-API xmeml import does "
|
|
756
|
+
"not carry one in. Do NOT read speed back with GetProperty "
|
|
757
|
+
"(None) or witness it via EXPORT_FCP_7_XML (degenerate). "
|
|
758
|
+
"Read the clip's GEOMETRY instead — GetLeftOffset / "
|
|
759
|
+
"GetRightOffset, whose source span is what shows whether a "
|
|
760
|
+
"retime was built (the re-tested 200% clip read src "
|
|
761
|
+
"1500..1548, 48 source frames over a 48-frame record, so "
|
|
762
|
+
"none was). Caveat worth keeping: there is still no positive "
|
|
763
|
+
"control — no clip KNOWN to be retimed has been read back "
|
|
764
|
+
"through those two witnesses, because there is no scripting "
|
|
765
|
+
"path to create one, so the geometry witness is the best "
|
|
766
|
+
"available, not a proven one. And if you are importing a real "
|
|
767
|
+
"Premiere XML that contains retimes, treat every retimed "
|
|
768
|
+
"clip's source position as WRONG — placed at <in>, i.e. "
|
|
769
|
+
"in / ratio — until it is checked against a reference; the "
|
|
770
|
+
"lengths and the links will look right.",
|
|
726
771
|
"tags": ["missing-method", "timeline", "retime", "speed", "interchange",
|
|
727
772
|
"silent-failure", "unreliable-return"],
|
|
728
773
|
"submit": "missing",
|