@motionharness/bridge-davinci 0.0.0-stage → 0.0.22
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/LICENSE +201 -0
- package/NOTICE +13 -0
- package/OPENFX_LICENSE +24 -0
- package/README.md +114 -2
- package/THIRD_PARTY_NOTICES.md +196 -0
- package/bridge-manifest.json +107 -0
- package/dist/inspector_runtime.py +113 -0
- package/dist/instance_runtime.py +469 -0
- package/dist/intrinsic_runtime.py +125 -0
- package/dist/legacy_conversion.py +619 -0
- package/dist/resolve_rpc.py +1508 -0
- package/dist/runner.mjs +22203 -0
- package/dist/runtime_io.py +31 -0
- package/package.json +35 -4
- package/resources/HotionHarness.ofx.bundle/Contents/Info.plist +9 -0
- package/resources/HotionHarness.ofx.bundle/Contents/MacOS/HotionHarness.ofx +0 -0
- package/resources/HotionHarnessInstall +0 -0
- package/resources/HotionHarnessStatus.app/Contents/Info.plist +12 -0
- package/resources/HotionHarnessStatus.app/Contents/MacOS/HotionHarnessStatus +0 -0
- package/resources/legacy-forwarder.lua +55 -0
- package/resources/legacy-inspector-v1.lua +31 -0
- package/resources/menu-entry.py +150 -0
- package/resources/sidebar-help/index.html +35 -0
- package/resources/sidebar-help/resolve-sidebar.png +0 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"name": "@motionharness/bridge-davinci",
|
|
4
|
+
"version": "0.0.22",
|
|
5
|
+
"protocol": 1,
|
|
6
|
+
"cliVersion": "0.0.22",
|
|
7
|
+
"files": [
|
|
8
|
+
{
|
|
9
|
+
"path": "dist/inspector_runtime.py",
|
|
10
|
+
"sha256": "c02486992b71d8ecb506f9ede4c4d6bfcf32fcea4fcc00da6011e25b28b2dd0d"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"path": "dist/instance_runtime.py",
|
|
14
|
+
"sha256": "cdffb0aedf244a61991c378feed419f406dbf2f0fa635d33d24aa0b3381fb1ec"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"path": "dist/intrinsic_runtime.py",
|
|
18
|
+
"sha256": "a8841de53cfcb68e315cce58bb9f729bdf6feec10392b792d0d442ebefe2488f"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"path": "dist/legacy_conversion.py",
|
|
22
|
+
"sha256": "0581d63ac5c67a489e10887fba4fae0abdaf89f1640f9c450b7e1b911251769b"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"path": "dist/resolve_rpc.py",
|
|
26
|
+
"sha256": "cfb622ec26f3d33dc961fb498b7774330eaa9bd3455752b4a582af78ba92852a"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"path": "dist/runner.mjs",
|
|
30
|
+
"sha256": "e1c08679917fff1acc6d88af1671783b398045ee987393d4b580c5e5f304bf3b"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"path": "dist/runtime_io.py",
|
|
34
|
+
"sha256": "52efdd2ddf9b35d5c69e67e32d3dc92cf37ee350281de5f7afc5552681f1445c"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"path": "LICENSE",
|
|
38
|
+
"sha256": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"path": "NOTICE",
|
|
42
|
+
"sha256": "dbd3fd6e2ae4bed6332946051cfced0b9f3b559ec72f9f27d1ea9d4959d51d65"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"path": "OPENFX_LICENSE",
|
|
46
|
+
"sha256": "2f35ced026e843f83d3fdcc6b58976151ad4eab14eec6e8376783925393040c7"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"path": "README.md",
|
|
50
|
+
"sha256": "bfded59d2028d419e7d34961971bb69b0ebc161f9ec5ba4284463c7c9a91687f"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"path": "resources/HotionHarness.ofx.bundle/Contents/Info.plist",
|
|
54
|
+
"sha256": "8e856f10d851400c6a0d192724d4a01bfe5a3c9920f5c1044dfcb1fc1c0a1a25",
|
|
55
|
+
"executable": false
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"path": "resources/HotionHarness.ofx.bundle/Contents/MacOS/HotionHarness.ofx",
|
|
59
|
+
"sha256": "825783410ce6bd1b00cf0dbf3ee1e2a82d13bf5ad7bd5b628f99ba3ee729ba69",
|
|
60
|
+
"executable": true
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"path": "resources/HotionHarnessInstall",
|
|
64
|
+
"sha256": "39213a6e45578f0bb9f0c49bd6dd12c5402cf687b8eba2c6044cc4e1a20c5969",
|
|
65
|
+
"executable": true
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"path": "resources/HotionHarnessStatus.app/Contents/Info.plist",
|
|
69
|
+
"sha256": "a56fa4c4bbc618f9e0a362474637afa4e2463046677bd8396f5c5b7043c3dc71",
|
|
70
|
+
"executable": false
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"path": "resources/HotionHarnessStatus.app/Contents/MacOS/HotionHarnessStatus",
|
|
74
|
+
"sha256": "dda084047882a6de416d572a3a1f5df855d6bf3de14e4197cbd6b403cfc1429e",
|
|
75
|
+
"executable": true
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"path": "resources/legacy-forwarder.lua",
|
|
79
|
+
"sha256": "778edbabdd56947743f6028ac7f6ec212c8685f04a55244b18672bdb7f32e861",
|
|
80
|
+
"executable": false
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"path": "resources/legacy-inspector-v1.lua",
|
|
84
|
+
"sha256": "808965d5fabc6b9b457ef4b08fa4635e47d1efebc74e0e3d036e73ca2ef75ac5",
|
|
85
|
+
"executable": false
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"path": "resources/menu-entry.py",
|
|
89
|
+
"sha256": "08b4cb619d39735a4bdb468e6b8c00feb454c6c11ece14905c043b564d26398d",
|
|
90
|
+
"executable": false
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"path": "resources/sidebar-help/index.html",
|
|
94
|
+
"sha256": "4c6e51cd63b5310816af724877f4ef42d7f6293a41a97fbcb89a966b84f73db7",
|
|
95
|
+
"executable": false
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"path": "resources/sidebar-help/resolve-sidebar.png",
|
|
99
|
+
"sha256": "78a18d0047315a59217a897bf4958e9c4cd2445b7ea66039491c0b3721608985",
|
|
100
|
+
"executable": false
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"path": "THIRD_PARTY_NOTICES.md",
|
|
104
|
+
"sha256": "ca3e1bb03bf5601dda94cdb82fe69710cdd84147891710da5bce982e57d81e25"
|
|
105
|
+
}
|
|
106
|
+
]
|
|
107
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""Conservative readback for the experimental, image-routing-only MH macro.
|
|
2
|
+
|
|
3
|
+
No module import connects to Resolve. Native acceptance is deliberately separate
|
|
4
|
+
from this graph identity check; normal sync retains its previous support boundary.
|
|
5
|
+
"""
|
|
6
|
+
import hashlib
|
|
7
|
+
import json
|
|
8
|
+
import os
|
|
9
|
+
|
|
10
|
+
DATA_KEY = 'MotionHarness.Inspector.v1'
|
|
11
|
+
PRESENTATION = {'ViewInfo', 'CtrlWZoom', 'CtrlWShown', 'NameSet', 'ActiveTool', '__flags'}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def canonical(value):
|
|
15
|
+
if isinstance(value, dict):
|
|
16
|
+
return {str(key): canonical(item) for key, item in value.items() if key not in PRESENTATION}
|
|
17
|
+
if isinstance(value, (tuple, list)):
|
|
18
|
+
return [canonical(item) for item in value]
|
|
19
|
+
if value is None or isinstance(value, (str, int, float, bool)):
|
|
20
|
+
return value
|
|
21
|
+
raise ValueError('unrecognized Fusion settings value')
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def signature(value):
|
|
25
|
+
return 'sha256:' + hashlib.sha256(json.dumps(canonical(value), ensure_ascii=False, sort_keys=True, separators=(',', ':'), allow_nan=False).encode()).hexdigest()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def callbacks():
|
|
29
|
+
return {name: 'local entry = dofile(comp:MapPath("Scripts:Utility/MHBridgeInspector.lua")); entry({ action = "%s", workspaceKey = tool:GetInput("MHWorkspaceKey"), sourceId = tool:GetInput("MHSourceId"), bindingId = tool:GetInput("MHBindingId") })' % action
|
|
30
|
+
for name, action in (('MHEdit', 'edit'), ('MHMore', 'more'))}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def attrs(tool):
|
|
34
|
+
data = tool.GetAttrs()
|
|
35
|
+
if not isinstance(data, dict): raise ValueError('missing Fusion tool attributes')
|
|
36
|
+
return data
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def tool_name(tool): return attrs(tool).get('TOOLS_Name')
|
|
40
|
+
def tool_id(tool): return attrs(tool).get('TOOLS_RegID')
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def settings(tool):
|
|
44
|
+
saved = tool.SaveSettings()
|
|
45
|
+
value = saved.get('Tools', {}).get(tool_name(tool)) if isinstance(saved, dict) else None
|
|
46
|
+
if not isinstance(value, dict): raise ValueError('unrecognized Fusion tool serialization')
|
|
47
|
+
return value
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def connected_to(tool, name):
|
|
51
|
+
input_ = tool.FindMainInput(1)
|
|
52
|
+
output = input_.GetConnectedOutput() if input_ else None
|
|
53
|
+
return bool(output and tool_name(output.GetTool()) == name)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def graph(comp, identity):
|
|
57
|
+
tools = list((comp.GetToolList(False) or {}).values())
|
|
58
|
+
expected = {'MediaIn1': 'MediaIn', 'MHBridge': 'MacroOperator', 'MediaOut1': 'MediaOut'}
|
|
59
|
+
# Resolve includes macro children in GetToolList(False), unlike a top-level
|
|
60
|
+
# tools-only list. Accept exactly that one documented child in either form.
|
|
61
|
+
actual = {tool_name(t): tool_id(t) for t in tools}
|
|
62
|
+
if len(tools) != len(actual) or actual not in (expected, {**expected, 'MHBridgePipe': 'PipeRouter'}):
|
|
63
|
+
raise ValueError('not the isolated MH entry composition')
|
|
64
|
+
by_name = {tool_name(t): t for t in tools}
|
|
65
|
+
macro = by_name['MHBridge']
|
|
66
|
+
children = list((macro.GetChildrenList(False) or {}).values())
|
|
67
|
+
if len(children) != 1 or tool_id(children[0]) != 'PipeRouter' or tool_name(children[0]) != 'MHBridgePipe':
|
|
68
|
+
raise ValueError('the macro contains an unknown image operation')
|
|
69
|
+
if not connected_to(macro, 'MediaIn1') or not (connected_to(by_name['MediaOut1'], 'MHBridge') or connected_to(by_name['MediaOut1'], 'MHBridgePipe')):
|
|
70
|
+
raise ValueError('the native image route differs from the MH template')
|
|
71
|
+
own = settings(macro)
|
|
72
|
+
for group, key, source in (('Inputs', 'MainInput1', 'Input'), ('Outputs', 'MainOutput1', 'Output')):
|
|
73
|
+
link = own.get(group, {}).get(key, {})
|
|
74
|
+
if link.get('SourceOp') != 'MHBridgePipe' or link.get('Source') != source:
|
|
75
|
+
raise ValueError('the macro image interface was changed')
|
|
76
|
+
fields = {'MHSchema': 1, 'MHWorkspaceKey': identity['workspaceKey'], 'MHSourceId': identity['sourceId'], 'MHBindingId': identity['bindingId'],
|
|
77
|
+
'MHMediaPoolItemId': identity['mediaPoolItemId'], 'MHDatabaseId': identity['databaseId'], 'MHProjectId': identity['projectId']}
|
|
78
|
+
if any(macro.GetInput(key) != value for key, value in fields.items()):
|
|
79
|
+
raise ValueError('the macro ownership differs from the selected binding')
|
|
80
|
+
controls = own.get('UserControls', {})
|
|
81
|
+
if any(controls.get(key, {}).get('BTNCS_Execute') != code for key, code in callbacks().items()):
|
|
82
|
+
raise ValueError('the Inspector callback was changed')
|
|
83
|
+
return signature({tool_name(t): settings(t) for t in tools})
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def read_entry(item):
|
|
87
|
+
"""An edited/foreign graph is unknown, even if it retains an MH display name."""
|
|
88
|
+
try:
|
|
89
|
+
if item.GetFusionCompCount() != 1: return None
|
|
90
|
+
comp = item.GetFusionCompByIndex(1)
|
|
91
|
+
receipt = comp.GetData(DATA_KEY) if comp else None
|
|
92
|
+
if not isinstance(receipt, dict) or receipt.get('schemaVersion') != 1: return None
|
|
93
|
+
identity = receipt['identity']
|
|
94
|
+
media = item.GetMediaPoolItem()
|
|
95
|
+
link = json.loads((media.GetThirdPartyMetadata() or {}).get('motionharness.bridge', 'null')) if media else None
|
|
96
|
+
if (not isinstance(link, dict) or link.get('bindingId') != identity['bindingId'] or link.get('sourceId') != identity['sourceId']
|
|
97
|
+
or media.GetUniqueId() != identity['mediaPoolItemId']): return None
|
|
98
|
+
current = graph(comp, identity)
|
|
99
|
+
if current != receipt.get('graphFingerprint'): return None
|
|
100
|
+
return {**receipt, 'graphFingerprint': current}
|
|
101
|
+
except (AttributeError, TypeError, ValueError, KeyError, RuntimeError):
|
|
102
|
+
return None
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def experimental_enabled():
|
|
106
|
+
# This flag is for a later isolated acceptance run. The installer and button
|
|
107
|
+
# launcher never set it, and current release behavior remains conservative.
|
|
108
|
+
return os.environ.get('MH_BRIDGE_EXPERIMENTAL_INSPECTOR') == '1'
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def unknown_effects(effects, supported):
|
|
112
|
+
return [effect for effect in effects if not (str(effect.get('OTIO_SCHEMA', '')).startswith('Effect.')
|
|
113
|
+
and effect.get('effect_name') == 'Resolve Effect' and effect.get('metadata', {}).get('Resolve_OTIO', {}).get('Effect Name') in supported)]
|