@motionharness/bridge-davinci 0.0.22 → 0.0.25

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@motionharness/bridge-davinci",
3
- "version": "0.0.22",
3
+ "version": "0.0.25",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -9,7 +9,7 @@
9
9
  "url": "git+https://github.com/VibeMG/vibe-motion-graphics.git",
10
10
  "directory": "packages/bridge/davinci"
11
11
  },
12
- "description": "Optional DaVinci Resolve adapter for the Hotion Harness CLI",
12
+ "description": "MotionHarness Bridge Component for DaVinci Resolve",
13
13
  "exports": {
14
14
  ".": "./dist/runner.mjs"
15
15
  },
@@ -2,7 +2,7 @@
2
2
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
3
  <plist version="1.0"><dict>
4
4
  <key>CFBundleIdentifier</key><string>com.hotionharness.bridge.davinci</string>
5
- <key>CFBundleName</key><string>Hotion Harness</string>
5
+ <key>CFBundleName</key><string>MotionHarness Bridge Component</string>
6
6
  <key>CFBundleExecutable</key><string>HotionHarness.ofx</string>
7
7
  <key>CFBundlePackageType</key><string>BNDL</string>
8
8
  <key>CFBundleVersion</key><string>1</string>
@@ -2,9 +2,9 @@
2
2
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
3
  <plist version="1.0"><dict>
4
4
  <key>CFBundleIdentifier</key><string>com.hotionharness.bridge.status</string>
5
- <key>CFBundleName</key><string>Hotion Harness</string>
6
- <key>CFBundleDisplayName</key><string>Hotion Harness</string>
7
- <key>CFBundleExecutable</key><string>HotionHarnessStatus</string>
5
+ <key>CFBundleName</key><string>MotionHarness Bridge Component</string>
6
+ <key>CFBundleDisplayName</key><string>MotionHarness Bridge Component</string>
7
+ <key>CFBundleExecutable</key><string>MotionHarnessBridge</string>
8
8
  <key>CFBundlePackageType</key><string>APPL</string>
9
9
  <key>CFBundleVersion</key><string>1</string>
10
10
  <key>CFBundleShortVersionString</key><string>1.0</string>
@@ -0,0 +1,2 @@
1
+ "CFBundleDisplayName" = "MotionHarness Bridge Component";
2
+ "CFBundleName" = "MotionHarness Bridge Component";
@@ -0,0 +1,2 @@
1
+ "CFBundleDisplayName" = "MotionHarness 桥接组件";
2
+ "CFBundleName" = "MotionHarness 桥接组件";
@@ -1,4 +1,4 @@
1
- -- Hotion Harness legacy entry forwarder v1
1
+ -- Motion Harness legacy entry forwarder v1
2
2
  -- Explicit button callbacks only; image evaluation never executes this file.
3
3
  local helper, config, workspace = @@HELPER@@, @@CONFIG@@, @@WORKSPACE@@
4
4
  local function quote(value)
@@ -48,7 +48,7 @@ return function(request)
48
48
  else
49
49
  action = 'error'
50
50
  payload = '{"workspace":' .. json_string(workspace)
51
- .. ',"code":"SELECTION_UNAVAILABLE","message":"无法确认当前所选片段,请只选择一个 Hotion Harness 片段后重试。"}'
51
+ .. ',"code":"SELECTION_UNAVAILABLE","message":"无法确认当前所选片段,请只选择一个 MotionHarness 片段后重试。"}'
52
52
  end
53
53
  os.execute(quote(helper) .. ' --config ' .. quote(config) .. ' --action ' .. quote(action)
54
54
  .. ' --request ' .. quote(payload) .. ' >/dev/null 2>&1 &')
@@ -9,6 +9,13 @@ import uuid
9
9
  from pathlib import Path
10
10
 
11
11
 
12
+ _translations = {}
13
+
14
+
15
+ def tr(source):
16
+ return _translations.get(source, source)
17
+
18
+
12
19
  class SelectionError(Exception):
13
20
  def __init__(self, code, message):
14
21
  super().__init__(message)
@@ -33,27 +40,28 @@ def command_environment(config):
33
40
  bridge_directory = config.get("bridgeDirectory")
34
41
  if isinstance(bridge_directory, str) and os.path.isabs(bridge_directory):
35
42
  environment["MH_BRIDGE_DIR"] = bridge_directory
43
+ environment["MH_UI_LOCALE"] = os.environ.get("MH_UI_LOCALE", config.get("locale", "zh-CN"))
36
44
  return environment
37
45
 
38
46
 
39
47
  def selected_target(application, management=False):
40
48
  if not application:
41
- raise SelectionError("RESOLVE_UNAVAILABLE", "达芬奇尚未连接。请打开工程后重试。")
49
+ raise SelectionError("RESOLVE_UNAVAILABLE", tr("达芬奇尚未连接。请打开工程后重试。"))
42
50
  manager = application.GetProjectManager()
43
51
  project = manager.GetCurrentProject()
44
52
  timeline = project.GetCurrentTimeline() if project else None
45
53
  if not timeline:
46
- raise SelectionError("NO_TIMELINE", "请打开时间线并选择一个 Hotion Harness 片段。")
54
+ raise SelectionError("NO_TIMELINE", tr("请打开时间线并选择一个 MotionHarness 片段。"))
47
55
  if project.IsRenderingInProgress():
48
- raise SelectionError("RESOLVE_BUSY", "达芬奇正在导出,请完成后重试。")
56
+ raise SelectionError("RESOLVE_BUSY", tr("达芬奇正在导出,请完成后重试。"))
49
57
  selected = timeline.GetSelectedClips() or []
50
58
  identifiers = sorted(item.GetUniqueId() for item in selected)
51
59
  videos = [item for item in selected if item.GetType().lower() == "video"]
52
60
  if len(videos) != 1:
53
- raise SelectionError("SELECTION_AMBIGUOUS", "请只选择一个 Hotion Harness 视频片段。")
61
+ raise SelectionError("SELECTION_AMBIGUOUS", tr("请只选择一个 MotionHarness 视频片段。"))
54
62
  media = videos[0].GetMediaPoolItem()
55
63
  if not media:
56
- raise SelectionError("NOT_PLAIN_MEDIA", "所选片段没有普通视频素材。请先转换旧版生成器。")
64
+ raise SelectionError("NOT_PLAIN_MEDIA", tr("所选片段没有普通视频素材。请先转换旧版生成器。"))
57
65
  encoded = (media.GetThirdPartyMetadata() or {}).get("motionharness.bridge") if media else None
58
66
  try:
59
67
  link = json.loads(encoded) if isinstance(encoded, str) else None
@@ -63,19 +71,19 @@ def selected_target(application, management=False):
63
71
  isinstance(link.get(key), str) and link[key] for key in ("bindingId", "sourceId", "artifactId")
64
72
  )
65
73
  if not linked and not management:
66
- raise SelectionError("NOT_LINKED", "所选视频未关联 Hotion Harness 工程。")
74
+ raise SelectionError("NOT_LINKED", tr("所选视频未关联 MotionHarness 工程。"))
67
75
  database = manager.GetCurrentDatabase() if management else None
68
76
  if management and (not isinstance(database, dict) or not database):
69
- raise SelectionError("SCOPE_UNAVAILABLE", "无法确认当前工程位置,请检查达芬奇连接。")
77
+ raise SelectionError("SCOPE_UNAVAILABLE", tr("无法确认当前工程位置,请检查达芬奇连接。"))
70
78
  current = manager.GetCurrentProject()
71
79
  active = current.GetCurrentTimeline() if current else None
72
80
  if not current or current.GetUniqueId() != project.GetUniqueId() or not active or active.GetUniqueId() != timeline.GetUniqueId() or sorted(
73
81
  item.GetUniqueId() for item in (active.GetSelectedClips() or [])
74
82
  ) != identifiers:
75
- raise SelectionError("SELECTION_CHANGED", "所选片段已改变,请重新点击。")
83
+ raise SelectionError("SELECTION_CHANGED", tr("所选片段已改变,请重新点击。"))
76
84
  if management:
77
85
  if manager.GetCurrentDatabase() != database:
78
- raise SelectionError("SELECTION_CHANGED", "当前工程位置已改变,请重新点击。")
86
+ raise SelectionError("SELECTION_CHANGED", tr("当前工程位置已改变,请重新点击。"))
79
87
  database_id = "sha256:" + hashlib.sha256(json.dumps(database, sort_keys=True, separators=(",", ":"), ensure_ascii=False).encode()).hexdigest()
80
88
  return {"selection": {"scope": {"databaseId": database_id, "projectId": project.GetUniqueId()},
81
89
  "timelineId": timeline.GetUniqueId(), "itemId": videos[0].GetUniqueId(), "mediaPoolItemId": media.GetUniqueId(),
@@ -104,8 +112,8 @@ def main():
104
112
  config_path = Path(__HOTION_CONFIG_PATH_JSON__)
105
113
  status_path = Path(__HOTION_STATUS_PATH_JSON__)
106
114
  action = __HOTION_ACTION_JSON__
107
- if not status_path.is_absolute() or not status_path.is_file() or not os.access(status_path, os.X_OK):
108
- raise RuntimeError("缺少 Hotion Harness 状态窗口,请运行 mh bridge davinci install 修复组件。")
115
+ global _translations
116
+ _translations = {}
109
117
  repair = None
110
118
  try:
111
119
  config = json.loads(config_path.read_text(encoding="utf-8"))
@@ -113,12 +121,18 @@ def main():
113
121
  raise ValueError("invalid config")
114
122
  except (OSError, ValueError, TypeError):
115
123
  config = {}
116
- repair = "桥接安装配置缺失或损坏,请运行 mh bridge davinci install 修复组件。"
117
- if repair is None:
118
- cli_path = config.get("cliPath")
119
- executable = Path(cli_path) if isinstance(cli_path, str) and cli_path else None
120
- if not executable or not executable.is_absolute() or not executable.is_file() or not os.access(executable, os.X_OK):
121
- repair = "找不到 Hotion Harness 主程序,请运行 mh bridge davinci install 修复组件。"
124
+ repair = tr("桥接安装配置缺失或损坏,请运行 mh bridge davinci install 修复组件。")
125
+ if os.environ.get("MH_UI_LOCALE", config.get("locale", "zh-CN")).startswith("en"):
126
+ try:
127
+ translations = json.loads(Path(config["translationsPath"]).read_text(encoding="utf-8"))
128
+ if isinstance(translations, dict):
129
+ _translations = translations
130
+ except (OSError, ValueError, TypeError, KeyError):
131
+ pass
132
+ if not status_path.is_absolute() or not status_path.is_file() or not os.access(status_path, os.X_OK):
133
+ raise RuntimeError(tr("缺少 MotionHarness 状态窗口,请运行 mh bridge davinci install 修复组件。"))
134
+ # The shared helper resolves the installed CLI launcher. Checking the old
135
+ # platform-binary path here would incorrectly reject a completed npm upgrade.
122
136
  request = {}
123
137
  if isinstance(config.get("workspace"), str):
124
138
  request["workspace"] = config["workspace"]
@@ -133,7 +147,7 @@ def main():
133
147
  request.update(code=error.code, message=str(error))
134
148
  except (ImportError, AttributeError, RuntimeError):
135
149
  action = "error"
136
- request.update(code="SELECTION_UNAVAILABLE", message="无法读取所选片段,请检查达芬奇脚本连接。")
150
+ request.update(code="SELECTION_UNAVAILABLE", message=tr("无法读取所选片段,请检查达芬奇脚本连接。"))
137
151
  if action == "update":
138
152
  request["idempotencyKey"] = str(uuid.uuid4())
139
153
  arguments = [str(status_path), "--config", str(config_path), "--action", action,
@@ -141,9 +155,9 @@ def main():
141
155
  subprocess.Popen(arguments, stdin=subprocess.DEVNULL,
142
156
  stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
143
157
  env=command_environment(config), close_fds=True, start_new_session=True)
144
- print(request["message"] if action == "error" else "正在打开 Hotion Harness 工程…" if action == "edit" else
145
- "正在读取所选 Hotion Harness 片段…" if action == "manage" else
146
- "正在提交 Hotion Harness 请求,状态窗口将显示进度。")
158
+ print(request["message"] if action == "error" else tr("正在打开 MotionHarness 工程…") if action == "edit" else
159
+ tr("正在读取所选 MotionHarness 片段…") if action == "manage" else
160
+ tr("正在提交 MotionHarness 请求,状态窗口将显示进度。"))
147
161
 
148
162
 
149
163
  if __name__ == "__main__":
@@ -0,0 +1,13 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
4
+ <title>MotionHarness Bridge Component · Add the sidebar editing entry</title>
5
+ <link rel="stylesheet" href="guide.css">
6
+ <h1>Add the sidebar editing entry</h1><p>The media sent through the bridge is already linked to its source project. Adding this optional effect does not render the video again.</p>
7
+ <ol><li>On the <strong>Edit</strong> page in DaVinci Resolve, open the <strong>Effects Library</strong> (magic wand icon).</li><li>Search for <strong>MotionHarness Bridge Component</strong> and drag the Open FX effect onto the target animation clip.</li><li>Select the clip and click <strong>Edit MotionHarness project</strong> under <strong>Inspector → Effects → Open FX</strong>.</li></ol>
8
+ <div class="diagram" role="img" aria-label="Illustration: Effects Library, inspector and target clip">
9
+ <section class="panel"><h2>① Effects Library</h2><div class="search">⌕ MotionHarness</div><div class="effect">② MotionHarness Bridge Component</div></section>
10
+ <section class="panel"><h2>Inspector → Effects → Open FX</h2><div class="effect">Edit MotionHarness project</div><p>Update this media · Check status · More…</p></section>
11
+ <div class="timeline"><div class="clip">③ Target animation clip · Add the effect here</div></div></div>
12
+ <p class="caption">Layout illustration. Labels follow the language selected when installing the component. Search for “MotionHarness” in either language.</p><aside><p><strong>Shortcut:</strong> Select the clip, press <kbd>Shift</kbd> + <kbd>Space</kbd>, and search for MotionHarness. If your shortcuts are customized, use the Effects Library.</p><p><strong>Cannot find the effect?</strong> Install the MotionHarness Bridge Component with <code>mh bridge davinci install</code>. Save your project and restart DaVinci Resolve after installation.</p><p><strong>Menu alternative:</strong> Workspace → Scripts → Utility → MotionHarness Bridge Component → Edit project. Clips with the effect already attached do not need it added again.</p></aside>
13
+ </html>
@@ -0,0 +1,14 @@
1
+ /* Offline bridge guides use the graphite Studio palette in either language. */
2
+ :root{color-scheme:dark;font:14px/1.6 "PingFang SC",system-ui,sans-serif;color:#e8e8e6;background:#17181a}
3
+ *{box-sizing:border-box}
4
+ body{max-width:960px;margin:auto;padding:24px}
5
+ h1{margin:0 0 8px;font-size:22px;line-height:1.35}
6
+ p,li{color:#a5a6aa}li{margin:10px 0}strong{color:#e8e8e6}
7
+ code,kbd{padding:2px 6px;border-radius:4px;background:#25262a;font:12px/1.6 ui-monospace,monospace;overflow-wrap:anywhere}
8
+ .diagram{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;padding:16px;background:#1d1e21;border:1px solid #ffffff1c;border-radius:12px}
9
+ .panel{min-width:0;padding:12px;border:1px solid #ffffff1c;border-radius:6px}.panel h2{margin:0 0 12px;font-size:14px}
10
+ .search,.effect,.clip{margin:8px 0;padding:8px 10px;border-radius:4px;background:#25262a}
11
+ .effect,.clip{border-inline-start:2px solid #ff6a1a;background:#ff6a1a12}
12
+ .timeline{grid-column:1/-1;border-top:1px solid #ffffff1c;padding-top:12px}
13
+ .caption{font-size:12px}aside{border-top:1px solid #ffffff1c;margin-top:20px;padding-top:8px}
14
+ @media(max-width:600px){body{padding:16px}.diagram{grid-template-columns:minmax(0,1fr)}}
@@ -1,35 +1,13 @@
1
1
  <!doctype html>
2
2
  <html lang="zh-CN">
3
- <meta charset="utf-8">
4
- <meta name="viewport" content="width=device-width,initial-scale=1">
5
- <title>添加 Hotion Harness 侧栏入口</title>
6
- <style>
7
- :root{color-scheme:light dark;font:15px/1.7 system-ui,-apple-system,sans-serif;color:#e9e9ed;background:#191a1e}
8
- *{box-sizing:border-box}body{max-width:1080px;margin:auto;padding:32px 24px}h1{font-size:26px;line-height:1.3;margin:0 0 10px}p{margin:10px 0;color:#bfc0ca}
9
- ol{padding-left:24px}li{padding-left:6px;margin:14px 0}strong{color:#fff}kbd,code{font:inherit;background:#303139;border-radius:5px;padding:2px 6px}
10
- figure{position:relative;margin:24px 0 8px;border:1px solid #555661;border-radius:10px;overflow:hidden}img{display:block;width:100%;height:auto}
11
- .pin{position:absolute;color:#fff;background:#275bd9;border:2px solid white;border-radius:50%;width:25px;height:25px;line-height:21px;text-align:center;font-size:13px;font-weight:700;box-shadow:0 1px 6px #000}
12
- .one{left:13%;top:1%}.two{left:9%;top:7%}.three{left:23%;top:71%}
13
- .caption{font-size:13px}details{margin:14px 0}summary{cursor:pointer;color:#9cbeff}.full{overflow:auto;max-height:70vh;border:1px solid #555661;margin-top:10px}.full img{width:1512px;max-width:none}
14
- aside{border-top:1px solid #40414b;margin-top:24px;padding-top:16px}a{color:#9cbeff}
15
- @media(max-width:520px){body{padding:20px 16px}h1{font-size:22px}.pin{width:20px;height:20px;line-height:16px;font-size:11px}}
16
- </style>
17
- <h1>添加侧栏编辑入口</h1>
18
- <p>这是一个可选入口。通过桥接发送的素材已经关联源工程,添加效果不会重新导出视频。</p>
19
- <ol>
20
- <li>进入达芬奇的<strong>「剪辑」页</strong>,打开左上角的<strong>「特效库」</strong>(魔棒图标)。</li>
21
- <li>点击特效库的放大镜,搜索 <strong>Hotion Harness</strong>。找到 Open FX 中的同名效果,将它<strong>拖到时间线上的目标动效片段</strong>。</li>
22
- <li>选中这个片段,打开右侧<strong>「检查器 → 特效 → Open FX」</strong>,点击<strong>「编辑 Hotion Harness 工程」</strong>。</li>
23
- </ol>
24
- <figure>
25
- <img src="resolve-sidebar.png" alt="达芬奇真实界面:左上方打开特效库,搜索 Hotion Harness,搜索结果可拖到下方时间线的动效示例片段。">
26
- <span class="pin one" aria-hidden="true">1</span><span class="pin two" aria-hidden="true">2</span><span class="pin three" aria-hidden="true">3</span>
27
- </figure>
28
- <p class="caption">真实界面截图 · ① 特效库 ② 搜索框与效果列表 ③ 拖入目标片段。窗口宽度不同时,工具栏可能只显示图标。</p>
29
- <details><summary>放大截图</summary><div class="full"><img src="resolve-sidebar.png" alt="可横向滚动查看的达芬奇界面大图"></div></details>
30
- <aside>
31
- <p><strong>快捷方式:</strong>先选中片段,按 <kbd>Shift</kbd> + <kbd>Space</kbd>,搜索 Hotion Harness 并点击添加。快捷键被自定义时,请使用上面的特效库路径。</p>
32
- <p><strong>找不到效果?</strong>先安装桥接组件:<code>mh bridge davinci install</code>。安装完成后保存工程并重启达芬奇,再搜索。</p>
33
- <p><strong>暂时不添加也可以:</strong>从「工作区 → 脚本 → Utility → Hotion Harness → 编辑工程」打开工程。已经添加过效果的片段无需重复添加。</p>
34
- </aside>
3
+ <meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
4
+ <title>MotionHarness 桥接组件 · 添加侧栏编辑入口</title>
5
+ <link rel="stylesheet" href="guide.css">
6
+ <h1>添加侧栏编辑入口</h1><p>通过桥接发送的素材已关联源工程。添加这个可选效果不会重新导出视频。</p>
7
+ <ol><li>进入达芬奇的<strong>「剪辑」页</strong>,打开左上角的<strong>「特效库」</strong>(魔棒图标)。</li><li>搜索 <strong>MotionHarness 桥接组件</strong>,将 Open FX 中的同名效果拖到时间线上的目标动效片段。</li><li>选中片段,在<strong>「检查器 → 特效 → Open FX」</strong>中点击<strong>「编辑 MotionHarness 工程」</strong>。</li></ol>
8
+ <div class="diagram" role="img" aria-label="特效库、检查器和目标片段的布局示意">
9
+ <section class="panel"><h2>① 特效库</h2><div class="search">⌕ MotionHarness</div><div class="effect">② MotionHarness 桥接组件</div></section>
10
+ <section class="panel"><h2>检查器 → 特效 → Open FX</h2><div class="effect">编辑 MotionHarness 工程</div><p>更新此素材 · 查看状态 · 更多…</p></section>
11
+ <div class="timeline"><div class="clip">③ 目标动效片段 · 将效果拖到这里</div></div></div>
12
+ <p class="caption">布局示意图。名称按组件安装时的语言显示;中英文均可搜索“MotionHarness”。</p><aside><p><strong>快捷方式:</strong>选中片段,按 <kbd>Shift</kbd> + <kbd>Space</kbd>,搜索 MotionHarness 并添加。快捷键被自定义时,请使用特效库。</p><p><strong>找不到效果?</strong>先安装 MotionHarness 桥接组件:<code>mh bridge davinci install</code>。安装完成后保存工程并重启达芬奇。</p><p><strong>也可以使用菜单:</strong>工作区 → 脚本 → Utility → MotionHarness 桥接组件 → 编辑工程。已经添加过效果的片段无需重复添加。</p></aside>
35
13
  </html>