@kenkaiiii/gg-editor-premiere-panel 0.2.1
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 +21 -0
- package/README.md +200 -0
- package/dist/bin/cli.d.ts +3 -0
- package/dist/bin/cli.d.ts.map +1 -0
- package/dist/bin/cli.js +159 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +3 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/installer.d.ts +54 -0
- package/dist/src/installer.d.ts.map +1 -0
- package/dist/src/installer.js +166 -0
- package/dist/src/installer.js.map +1 -0
- package/dist/src/installer.test.d.ts +2 -0
- package/dist/src/installer.test.d.ts.map +1 -0
- package/dist/src/installer.test.js +68 -0
- package/dist/src/installer.test.js.map +1 -0
- package/dist/src/paths.d.ts +30 -0
- package/dist/src/paths.d.ts.map +1 -0
- package/dist/src/paths.js +60 -0
- package/dist/src/paths.js.map +1 -0
- package/dist/src/paths.test.d.ts +2 -0
- package/dist/src/paths.test.d.ts.map +1 -0
- package/dist/src/paths.test.js +47 -0
- package/dist/src/paths.test.js.map +1 -0
- package/package.json +42 -0
- package/panel/.debug +15 -0
- package/panel/CSXS/manifest.xml +60 -0
- package/panel/index.html +28 -0
- package/panel/jsx/runtime.jsx +163 -0
- package/panel/lib/cs-interface.js +31 -0
- package/panel/lib/server.js +161 -0
- package/panel-uxp/commands/consts.js +43 -0
- package/panel-uxp/commands/index.js +401 -0
- package/panel-uxp/commands/utils.js +115 -0
- package/panel-uxp/index.html +107 -0
- package/panel-uxp/main.js +264 -0
- package/panel-uxp/manifest.json +46 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
/**
|
|
3
|
+
* Utility helpers shared across the Premiere UXP command handlers.
|
|
4
|
+
*
|
|
5
|
+
* Verified against:
|
|
6
|
+
* - mikechambers/adb-mcp (uxp/pr/commands/utils.js)
|
|
7
|
+
* - AdobeDocs/uxp-premiere-pro-samples
|
|
8
|
+
*
|
|
9
|
+
* Async-everywhere: pretty much every getter on the Premiere DOM is async.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const ppro = require("premierepro");
|
|
13
|
+
const { TICKS_PER_SECOND } = require("./consts.js");
|
|
14
|
+
|
|
15
|
+
/** Active project, throwing a clear message if Premiere has nothing open. */
|
|
16
|
+
async function getActiveProject() {
|
|
17
|
+
const project = await ppro.Project.getActiveProject();
|
|
18
|
+
if (!project) throw new Error("No project open in Premiere.");
|
|
19
|
+
return project;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Active sequence, throwing a clear message if there is none. */
|
|
23
|
+
async function getActiveSequence() {
|
|
24
|
+
const project = await getActiveProject();
|
|
25
|
+
const seq = await project.getActiveSequence();
|
|
26
|
+
if (!seq) throw new Error("No active sequence in Premiere.");
|
|
27
|
+
return { project, sequence: seq };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Recursively walk the project bins looking for a project item by name.
|
|
32
|
+
* Returns null when not found (caller can decide whether to throw).
|
|
33
|
+
*/
|
|
34
|
+
async function findProjectItem(parent, name) {
|
|
35
|
+
const items = await parent.getItems();
|
|
36
|
+
for (const item of items) {
|
|
37
|
+
if (item.name === name) return item;
|
|
38
|
+
}
|
|
39
|
+
for (const item of items) {
|
|
40
|
+
const folder = ppro.FolderItem.cast(item);
|
|
41
|
+
if (folder) {
|
|
42
|
+
const found = await findProjectItem(folder, name);
|
|
43
|
+
if (found) return found;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Search the entire project tree from root for an item by name. */
|
|
50
|
+
async function findProjectItemByName(project, name) {
|
|
51
|
+
const root = await project.getRootItem();
|
|
52
|
+
return findProjectItem(root, name);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Compute frames-per-second for a sequence. Premiere stores `timebase` as
|
|
57
|
+
* ticks per frame; fps = TICKS_PER_SECOND / timebase.
|
|
58
|
+
*/
|
|
59
|
+
async function fpsOf(sequence) {
|
|
60
|
+
const tb = await sequence.getTimebase();
|
|
61
|
+
if (!tb) return 30;
|
|
62
|
+
return TICKS_PER_SECOND / tb;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Convert a frame count + sequence into a tick count. */
|
|
66
|
+
async function framesToTicks(frames, sequence) {
|
|
67
|
+
const tb = await sequence.getTimebase();
|
|
68
|
+
return Math.round(frames * tb);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Convert a tick count + sequence into a (rounded) frame number. */
|
|
72
|
+
async function ticksToFrames(ticks, sequence) {
|
|
73
|
+
const tb = await sequence.getTimebase();
|
|
74
|
+
if (!tb) return 0;
|
|
75
|
+
return Math.round(ticks / tb);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Convert seconds to ticks (used when adding markers etc). */
|
|
79
|
+
function secondsToTicks(seconds) {
|
|
80
|
+
return Math.round(seconds * TICKS_PER_SECOND);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Wrap a synchronous "build action list" callback in Premiere's required
|
|
85
|
+
* lockedAccess + executeTransaction envelope. The callback receives no
|
|
86
|
+
* arguments and must return an array of action objects to add to the
|
|
87
|
+
* compound transaction.
|
|
88
|
+
*
|
|
89
|
+
* Errors inside the transaction are re-thrown with context so the caller's
|
|
90
|
+
* try/catch sees a readable message.
|
|
91
|
+
*/
|
|
92
|
+
function withTransaction(project, getActions) {
|
|
93
|
+
try {
|
|
94
|
+
project.lockedAccess(() => {
|
|
95
|
+
project.executeTransaction((compoundAction) => {
|
|
96
|
+
const actions = getActions();
|
|
97
|
+
for (const a of actions) compoundAction.addAction(a);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
} catch (e) {
|
|
101
|
+
throw new Error("Premiere transaction failed: " + (e && e.message ? e.message : e));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
module.exports = {
|
|
106
|
+
getActiveProject,
|
|
107
|
+
getActiveSequence,
|
|
108
|
+
findProjectItem,
|
|
109
|
+
findProjectItemByName,
|
|
110
|
+
fpsOf,
|
|
111
|
+
framesToTicks,
|
|
112
|
+
ticksToFrames,
|
|
113
|
+
secondsToTicks,
|
|
114
|
+
withTransaction,
|
|
115
|
+
};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<title>GG Editor</title>
|
|
6
|
+
<style>
|
|
7
|
+
:root {
|
|
8
|
+
color-scheme: dark;
|
|
9
|
+
}
|
|
10
|
+
body {
|
|
11
|
+
font: 12px -apple-system, "Segoe UI", sans-serif;
|
|
12
|
+
margin: 0;
|
|
13
|
+
padding: 12px;
|
|
14
|
+
background: #1f2937;
|
|
15
|
+
color: #e5e7eb;
|
|
16
|
+
}
|
|
17
|
+
h1 {
|
|
18
|
+
font-size: 13px;
|
|
19
|
+
font-weight: 700;
|
|
20
|
+
color: #60a5fa;
|
|
21
|
+
margin: 0 0 10px;
|
|
22
|
+
}
|
|
23
|
+
.row {
|
|
24
|
+
display: flex;
|
|
25
|
+
justify-content: space-between;
|
|
26
|
+
align-items: center;
|
|
27
|
+
padding: 4px 0;
|
|
28
|
+
border-bottom: 1px solid #374151;
|
|
29
|
+
}
|
|
30
|
+
.row:last-child {
|
|
31
|
+
border-bottom: none;
|
|
32
|
+
}
|
|
33
|
+
.muted {
|
|
34
|
+
color: #9ca3af;
|
|
35
|
+
}
|
|
36
|
+
.pill {
|
|
37
|
+
background: #374151;
|
|
38
|
+
padding: 2px 8px;
|
|
39
|
+
border-radius: 3px;
|
|
40
|
+
font-size: 11px;
|
|
41
|
+
}
|
|
42
|
+
.pill.ok {
|
|
43
|
+
background: #064e3b;
|
|
44
|
+
color: #a7f3d0;
|
|
45
|
+
}
|
|
46
|
+
.pill.err {
|
|
47
|
+
background: #7f1d1d;
|
|
48
|
+
color: #fecaca;
|
|
49
|
+
}
|
|
50
|
+
.controls {
|
|
51
|
+
margin-top: 10px;
|
|
52
|
+
display: flex;
|
|
53
|
+
flex-direction: column;
|
|
54
|
+
gap: 6px;
|
|
55
|
+
}
|
|
56
|
+
.field {
|
|
57
|
+
display: flex;
|
|
58
|
+
gap: 6px;
|
|
59
|
+
align-items: center;
|
|
60
|
+
}
|
|
61
|
+
input[type="number"] {
|
|
62
|
+
flex: 1;
|
|
63
|
+
background: #111827;
|
|
64
|
+
color: #e5e7eb;
|
|
65
|
+
border: 1px solid #374151;
|
|
66
|
+
border-radius: 3px;
|
|
67
|
+
padding: 4px 6px;
|
|
68
|
+
font: inherit;
|
|
69
|
+
}
|
|
70
|
+
label {
|
|
71
|
+
display: flex;
|
|
72
|
+
gap: 6px;
|
|
73
|
+
align-items: center;
|
|
74
|
+
}
|
|
75
|
+
code {
|
|
76
|
+
background: #111827;
|
|
77
|
+
padding: 1px 4px;
|
|
78
|
+
border-radius: 2px;
|
|
79
|
+
font-family: ui-monospace, monospace;
|
|
80
|
+
}
|
|
81
|
+
</style>
|
|
82
|
+
</head>
|
|
83
|
+
<body>
|
|
84
|
+
<h1>GG Editor (UXP)</h1>
|
|
85
|
+
|
|
86
|
+
<div class="row"><span class="muted">Status</span><span id="status" class="pill">idle</span></div>
|
|
87
|
+
<div class="row"><span class="muted">Connected to</span><span id="endpoint" class="pill">—</span></div>
|
|
88
|
+
<div class="row"><span class="muted">Requests</span><span id="reqs">0</span></div>
|
|
89
|
+
<div class="row"><span class="muted">Last error</span><span id="lastErr" class="muted">—</span></div>
|
|
90
|
+
|
|
91
|
+
<div class="controls">
|
|
92
|
+
<div class="field">
|
|
93
|
+
<span class="muted">Port</span>
|
|
94
|
+
<input id="port" type="number" min="1024" max="65535" />
|
|
95
|
+
<sp-button id="connectBtn" size="s" variant="primary">Connect</sp-button>
|
|
96
|
+
</div>
|
|
97
|
+
<label>
|
|
98
|
+
<sp-checkbox id="autoConnect"></sp-checkbox>
|
|
99
|
+
<span>Connect on launch</span>
|
|
100
|
+
</label>
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
<div class="row" style="margin-top: 10px"><span class="muted">CLI</span><code>ggeditor --host premiere</code></div>
|
|
104
|
+
|
|
105
|
+
<script src="main.js"></script>
|
|
106
|
+
</body>
|
|
107
|
+
</html>
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
/**
|
|
3
|
+
* GG Editor UXP plugin entrypoint.
|
|
4
|
+
*
|
|
5
|
+
* UXP plugins cannot listen on TCP ports. So instead of being an HTTP
|
|
6
|
+
* server like the CEP panel, this plugin is a **WebSocket client**: it
|
|
7
|
+
* dials out to the ggeditor CLI's localhost WS server, sends a hello
|
|
8
|
+
* frame, and then handles RPC requests on the same connection.
|
|
9
|
+
*
|
|
10
|
+
* Wire protocol (matches PremiereWsBridge in @kenkaiiii/gg-editor):
|
|
11
|
+
*
|
|
12
|
+
* plugin → server (once, on connect):
|
|
13
|
+
* { kind: "hello", product, panelKind: "uxp", version }
|
|
14
|
+
*
|
|
15
|
+
* server → plugin:
|
|
16
|
+
* { id: "1", method: "get_timeline", params: {} }
|
|
17
|
+
*
|
|
18
|
+
* plugin → server:
|
|
19
|
+
* { id: "1", ok: true, result: ... }
|
|
20
|
+
* { id: "1", ok: false, error: "..." }
|
|
21
|
+
*
|
|
22
|
+
* Reconnection uses exponential backoff capped at 5s — handles the case
|
|
23
|
+
* where the user starts ggeditor *after* opening Premiere.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
const { handle } = require("./commands/index.js");
|
|
27
|
+
|
|
28
|
+
const PRODUCT = "gg-editor-premiere-panel";
|
|
29
|
+
const VERSION = "0.2.0";
|
|
30
|
+
|
|
31
|
+
const DEFAULT_PORT = 7437;
|
|
32
|
+
const RECONNECT_INITIAL_MS = 500;
|
|
33
|
+
const RECONNECT_MAX_MS = 5000;
|
|
34
|
+
|
|
35
|
+
// ── Persisted prefs (UXP supports localStorage) ─────────────
|
|
36
|
+
|
|
37
|
+
function getPort() {
|
|
38
|
+
try {
|
|
39
|
+
const stored = localStorage.getItem("gg.port");
|
|
40
|
+
const n = stored ? parseInt(stored, 10) : NaN;
|
|
41
|
+
if (Number.isFinite(n) && n > 0 && n < 65536) return n;
|
|
42
|
+
} catch (_) {}
|
|
43
|
+
return DEFAULT_PORT;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function setPort(n) {
|
|
47
|
+
try {
|
|
48
|
+
localStorage.setItem("gg.port", String(n));
|
|
49
|
+
} catch (_) {}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function getAutoConnect() {
|
|
53
|
+
try {
|
|
54
|
+
return localStorage.getItem("gg.autoConnect") === "1";
|
|
55
|
+
} catch (_) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function setAutoConnect(b) {
|
|
61
|
+
try {
|
|
62
|
+
localStorage.setItem("gg.autoConnect", b ? "1" : "0");
|
|
63
|
+
} catch (_) {}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ── UI plumbing ─────────────────────────────────────────────
|
|
67
|
+
|
|
68
|
+
let reqCount = 0;
|
|
69
|
+
|
|
70
|
+
function $(id) {
|
|
71
|
+
return document.getElementById(id);
|
|
72
|
+
}
|
|
73
|
+
function setStatus(kind, label) {
|
|
74
|
+
const el = $("status");
|
|
75
|
+
if (!el) return;
|
|
76
|
+
el.textContent = label;
|
|
77
|
+
el.className = "pill " + (kind || "");
|
|
78
|
+
}
|
|
79
|
+
function setEndpoint(text) {
|
|
80
|
+
const el = $("endpoint");
|
|
81
|
+
if (el) el.textContent = text;
|
|
82
|
+
}
|
|
83
|
+
function bumpReqs() {
|
|
84
|
+
reqCount += 1;
|
|
85
|
+
const el = $("reqs");
|
|
86
|
+
if (el) el.textContent = String(reqCount);
|
|
87
|
+
}
|
|
88
|
+
function setLastErr(msg) {
|
|
89
|
+
const el = $("lastErr");
|
|
90
|
+
if (!el) return;
|
|
91
|
+
el.textContent = msg || "—";
|
|
92
|
+
el.className = msg ? "err" : "muted";
|
|
93
|
+
}
|
|
94
|
+
function setConnectButtonLabel(label) {
|
|
95
|
+
const el = $("connectBtn");
|
|
96
|
+
if (el) el.textContent = label;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ── WS client ───────────────────────────────────────────────
|
|
100
|
+
|
|
101
|
+
let socket = null;
|
|
102
|
+
let reconnectDelay = RECONNECT_INITIAL_MS;
|
|
103
|
+
let reconnectTimer = null;
|
|
104
|
+
let manuallyDisconnected = false;
|
|
105
|
+
let currentPort = DEFAULT_PORT;
|
|
106
|
+
|
|
107
|
+
function disconnect() {
|
|
108
|
+
manuallyDisconnected = true;
|
|
109
|
+
if (reconnectTimer) {
|
|
110
|
+
clearTimeout(reconnectTimer);
|
|
111
|
+
reconnectTimer = null;
|
|
112
|
+
}
|
|
113
|
+
if (socket) {
|
|
114
|
+
try {
|
|
115
|
+
socket.close(1000, "user disconnected");
|
|
116
|
+
} catch (_) {}
|
|
117
|
+
socket = null;
|
|
118
|
+
}
|
|
119
|
+
setStatus("", "idle");
|
|
120
|
+
setEndpoint("—");
|
|
121
|
+
setConnectButtonLabel("Connect");
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function connect() {
|
|
125
|
+
manuallyDisconnected = false;
|
|
126
|
+
if (socket && (socket.readyState === 0 || socket.readyState === 1)) {
|
|
127
|
+
return; // already connecting / connected
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
currentPort = getPort();
|
|
131
|
+
const url = "ws://127.0.0.1:" + currentPort;
|
|
132
|
+
setStatus("", "connecting…");
|
|
133
|
+
setEndpoint(url);
|
|
134
|
+
setConnectButtonLabel("Disconnect");
|
|
135
|
+
|
|
136
|
+
let ws;
|
|
137
|
+
try {
|
|
138
|
+
ws = new WebSocket(url);
|
|
139
|
+
} catch (e) {
|
|
140
|
+
setStatus("err", "open failed");
|
|
141
|
+
setLastErr(String(e && e.message ? e.message : e));
|
|
142
|
+
scheduleReconnect();
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
socket = ws;
|
|
146
|
+
|
|
147
|
+
ws.addEventListener("open", () => {
|
|
148
|
+
reconnectDelay = RECONNECT_INITIAL_MS;
|
|
149
|
+
setStatus("ok", "connected");
|
|
150
|
+
setLastErr("");
|
|
151
|
+
try {
|
|
152
|
+
ws.send(
|
|
153
|
+
JSON.stringify({
|
|
154
|
+
kind: "hello",
|
|
155
|
+
product: PRODUCT,
|
|
156
|
+
panelKind: "uxp",
|
|
157
|
+
version: VERSION,
|
|
158
|
+
}),
|
|
159
|
+
);
|
|
160
|
+
} catch (e) {
|
|
161
|
+
setLastErr("hello send failed: " + e);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
ws.addEventListener("message", async (ev) => {
|
|
166
|
+
let msg;
|
|
167
|
+
try {
|
|
168
|
+
msg = JSON.parse(typeof ev.data === "string" ? ev.data : String(ev.data));
|
|
169
|
+
} catch (_) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (!msg || typeof msg.id !== "string" || typeof msg.method !== "string") return;
|
|
173
|
+
|
|
174
|
+
bumpReqs();
|
|
175
|
+
let response;
|
|
176
|
+
try {
|
|
177
|
+
const result = await handle(msg.method, msg.params || {});
|
|
178
|
+
response = { id: msg.id, ok: true, result: result === undefined ? null : result };
|
|
179
|
+
} catch (e) {
|
|
180
|
+
const errMsg = e && e.message ? String(e.message) : String(e);
|
|
181
|
+
setLastErr(errMsg);
|
|
182
|
+
response = { id: msg.id, ok: false, error: errMsg };
|
|
183
|
+
}
|
|
184
|
+
try {
|
|
185
|
+
if (ws.readyState === 1) ws.send(JSON.stringify(response));
|
|
186
|
+
} catch (e) {
|
|
187
|
+
setLastErr("send reply failed: " + e);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
ws.addEventListener("close", () => {
|
|
192
|
+
if (socket === ws) socket = null;
|
|
193
|
+
if (manuallyDisconnected) return;
|
|
194
|
+
setStatus("err", "disconnected");
|
|
195
|
+
scheduleReconnect();
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
ws.addEventListener("error", (ev) => {
|
|
199
|
+
setLastErr("ws error");
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function scheduleReconnect() {
|
|
204
|
+
if (manuallyDisconnected) return;
|
|
205
|
+
if (reconnectTimer) return;
|
|
206
|
+
setConnectButtonLabel("Cancel");
|
|
207
|
+
reconnectTimer = setTimeout(() => {
|
|
208
|
+
reconnectTimer = null;
|
|
209
|
+
if (manuallyDisconnected) return;
|
|
210
|
+
reconnectDelay = Math.min(reconnectDelay * 2, RECONNECT_MAX_MS);
|
|
211
|
+
connect();
|
|
212
|
+
}, reconnectDelay);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// ── Wire up UI on panel show ────────────────────────────────
|
|
216
|
+
|
|
217
|
+
function init(rootNode) {
|
|
218
|
+
const portEl = $("port");
|
|
219
|
+
const autoEl = $("autoConnect");
|
|
220
|
+
const btnEl = $("connectBtn");
|
|
221
|
+
|
|
222
|
+
if (portEl) {
|
|
223
|
+
portEl.value = String(getPort());
|
|
224
|
+
portEl.addEventListener("change", () => {
|
|
225
|
+
const n = parseInt(portEl.value, 10);
|
|
226
|
+
if (Number.isFinite(n) && n > 0 && n < 65536) setPort(n);
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (autoEl) {
|
|
231
|
+
if (getAutoConnect()) autoEl.setAttribute("checked", "");
|
|
232
|
+
autoEl.addEventListener("change", () => {
|
|
233
|
+
setAutoConnect(autoEl.checked || autoEl.hasAttribute("checked"));
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (btnEl) {
|
|
238
|
+
btnEl.addEventListener("click", () => {
|
|
239
|
+
if (socket && socket.readyState === 1) {
|
|
240
|
+
disconnect();
|
|
241
|
+
} else {
|
|
242
|
+
connect();
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (getAutoConnect()) {
|
|
248
|
+
connect();
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// ── UXP entrypoint registration ─────────────────────────────
|
|
253
|
+
|
|
254
|
+
const { entrypoints } = require("uxp");
|
|
255
|
+
|
|
256
|
+
entrypoints.setup({
|
|
257
|
+
panels: {
|
|
258
|
+
"ggeditor.panel": {
|
|
259
|
+
show(node) {
|
|
260
|
+
init(node);
|
|
261
|
+
},
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "com.kenkaiiii.gg-editor-premiere-panel.uxp",
|
|
3
|
+
"name": "GG Editor",
|
|
4
|
+
"version": "0.2.0",
|
|
5
|
+
"main": "index.html",
|
|
6
|
+
"manifestVersion": 5,
|
|
7
|
+
"host": [
|
|
8
|
+
{
|
|
9
|
+
"app": "premierepro",
|
|
10
|
+
"minVersion": "25.6.0"
|
|
11
|
+
}
|
|
12
|
+
],
|
|
13
|
+
"entrypoints": [
|
|
14
|
+
{
|
|
15
|
+
"type": "panel",
|
|
16
|
+
"id": "ggeditor.panel",
|
|
17
|
+
"label": {
|
|
18
|
+
"default": "GG Editor"
|
|
19
|
+
},
|
|
20
|
+
"minimumSize": { "width": 280, "height": 220 },
|
|
21
|
+
"preferredDockedSize": { "width": 320, "height": 260 },
|
|
22
|
+
"preferredFloatingSize": { "width": 360, "height": 280 }
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"requiredPermissions": {
|
|
26
|
+
"network": {
|
|
27
|
+
"domains": [
|
|
28
|
+
"ws://127.0.0.1:7437",
|
|
29
|
+
"ws://127.0.0.1:7438",
|
|
30
|
+
"ws://127.0.0.1:7439",
|
|
31
|
+
"ws://127.0.0.1:7440",
|
|
32
|
+
"ws://127.0.0.1:7441",
|
|
33
|
+
"ws://127.0.0.1:7442",
|
|
34
|
+
"ws://127.0.0.1:7443",
|
|
35
|
+
"ws://localhost:7437",
|
|
36
|
+
"ws://localhost:7438",
|
|
37
|
+
"ws://localhost:7439",
|
|
38
|
+
"ws://localhost:7440",
|
|
39
|
+
"ws://localhost:7441",
|
|
40
|
+
"ws://localhost:7442",
|
|
41
|
+
"ws://localhost:7443"
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"icons": []
|
|
46
|
+
}
|