dragonflight/services/premiere-plugin/js/CSInterface.js
Zac Gaetano f874009329 feat(premiere-plugin): ZXP + Windows installer build pipeline
Replaces the manual robocopy / install-windows.ps1 flow with two real
distributable artifacts:

  - dragonflight-premiere-panel-<version>.zxp          (Mac + Win)
  - dragonflight-premiere-panel-<version>-windows-setup.exe (Win)

The Windows installer copies the bundle to %APPDATA%\Adobe\CEP\extensions,
sets PlayerDebugMode=1 for CSXS 8..13, registers an uninstaller, and
offers to remove any legacy com.wilddragon.mam.panel folder so editors
don't end up with duplicate panels.

The .zxp is signed with a self-signed cert generated on first build and
committed to build/cert/ so signature continuity is preserved across
builds (Adobe rejects ZXP upgrades with a different cert fingerprint).

Also migrates the CEP bundle ID from com.wilddragon.mam.panel to
net.wilddragon.dragonflight.panel to match the wild-dragon -> dragonflight
repo rename. Manifest, .debug, CSInterface.js, install docs, and the
growing-files quickstart all updated.

build/ is normally swept by the root .gitignore; added an explicit
negation so the packaging pipeline stays tracked.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 16:13:20 -04:00

210 lines
6.3 KiB
JavaScript

/**
* CSInterface.js - Simplified Adobe CEP Interface
*
* This is a minimal shim implementation of Adobe's CSInterface.js for the
* Wild Dragon MAM Premiere Pro plugin.
*
* In production, use the official CSInterface.js from Adobe's CEP-Resources:
* https://github.com/Adobe-CEP/CEP-Resources/blob/master/CEP_11.0/CSInterface.js
*
* This version includes the key methods needed for the MAM panel:
* - evalScript: Execute ExtendScript in Premiere Pro
* - getSystemPath: Get system paths for file operations
* - requestOpenExtension: Open another extension
*/
/**
* Adobe CEP SystemPath enum
* Used to get common system directories
*/
const SystemPath = {
USER_DATA: "user_data",
COMMON_FILES: "common_files",
MY_DOCUMENTS: "my_documents",
APPLICATION_DATA: "application_data",
TEMPORARY: "temporary"
};
/**
* CSInterface class - Main interface to communicate with Premiere Pro
*/
class CSInterface {
constructor() {
this.requestIdCount = 1;
this.requestMap = new Map();
this.extensionId = "net.wilddragon.dragonflight.panel";
// Initialize event listener for messages from ExtendScript
if (window.__adobe_cep__ !== undefined) {
window.__adobe_cep__.addEventListener("edu.adobe.csxs.events.message", (event) => {
this._handleMessage(event);
});
}
}
/**
* Evaluates an ExtendScript in the context of the host application
* @param {string} script - The ExtendScript code to execute
* @param {function} callback - Callback function to receive the result
*/
evalScript(script, callback) {
if (window.__adobe_cep__ === undefined) {
console.error("Adobe CEP not available");
if (callback) callback("");
return;
}
const requestId = this.requestIdCount++;
if (callback) {
this.requestMap.set(requestId, callback);
}
try {
window.__adobe_cep__.evalScript(script, requestId);
} catch (error) {
console.error("Error evaluating script:", error);
if (callback) {
this.requestMap.delete(requestId);
callback("");
}
}
}
/**
* Gets a system path from the host application
* @param {string} pathType - Type of path from SystemPath enum
* @returns {string} The system path
*/
getSystemPath(pathType) {
const pathMap = {
[SystemPath.TEMPORARY]: this._getTempPath(),
[SystemPath.MY_DOCUMENTS]: this._getDocumentsPath(),
[SystemPath.APPLICATION_DATA]: this._getAppDataPath(),
[SystemPath.USER_DATA]: this._getUserDataPath(),
[SystemPath.COMMON_FILES]: this._getCommonFilesPath()
};
return pathMap[pathType] || "";
}
/**
* Requests to open another extension
* @param {string} extensionId - The extension ID to open
*/
requestOpenExtension(extensionId) {
if (window.__adobe_cep__ === undefined) {
console.error("Adobe CEP not available");
return;
}
try {
const event = new CSXSEvent("com.adobe.csxs.events.ApplicationActivate", "BROADCAST");
event.extensionId = extensionId;
window.__adobe_cep__.dispatchEvent(event);
} catch (error) {
console.error("Error opening extension:", error);
}
}
/**
* Gets the current extension ID
* @returns {string} The extension ID
*/
getExtensionId() {
return this.extensionId;
}
/**
* Adds an event listener for extension events
* @param {string} type - Event type
* @param {function} listener - Listener function
*/
addEventListener(type, listener) {
if (window.__adobe_cep__ !== undefined) {
window.__adobe_cep__.addEventListener(type, listener);
}
}
/**
* Dispatches an event
* @param {CSXSEvent} event - The event to dispatch
*/
dispatchEvent(event) {
if (window.__adobe_cep__ !== undefined) {
window.__adobe_cep__.dispatchEvent(event);
}
}
// Private helper methods for getting system paths
_getTempPath() {
if (navigator.platform.includes("Win")) {
return process.env.TEMP || "C:\\Users\\%USERNAME%\\AppData\\Local\\Temp";
} else {
return process.env.TMPDIR || "/tmp";
}
}
_getDocumentsPath() {
if (navigator.platform.includes("Win")) {
return process.env.USERPROFILE + "\\Documents";
} else {
return process.env.HOME + "/Documents";
}
}
_getAppDataPath() {
if (navigator.platform.includes("Win")) {
return process.env.APPDATA;
} else {
return process.env.HOME + "/Library/Application Support";
}
}
_getUserDataPath() {
if (navigator.platform.includes("Win")) {
return process.env.USERPROFILE + "\\AppData\\Roaming\\Adobe\\CEP\\extensions\\" + this.extensionId;
} else {
return process.env.HOME + "/Library/Application Support/Adobe/CEP/extensions/" + this.extensionId;
}
}
_getCommonFilesPath() {
if (navigator.platform.includes("Win")) {
return "C:\\Program Files\\Common Files";
} else {
return "/Library/Application Support";
}
}
_handleMessage(event) {
try {
const message = JSON.parse(event.data);
if (message.requestId !== undefined && this.requestMap.has(message.requestId)) {
const callback = this.requestMap.get(message.requestId);
this.requestMap.delete(message.requestId);
callback(message.result);
}
} catch (error) {
console.error("Error handling message:", error);
}
}
}
/**
* CSXSEvent - Simple event object for CEP communication
*/
class CSXSEvent {
constructor(type, scope = "APPLICATION") {
this.type = type;
this.scope = scope;
this.data = "";
}
}
// Initialize and export the CSInterface singleton
const csInterface = new CSInterface();
// Make it globally available
window.csInterface = csInterface;
window.SystemPath = SystemPath;
window.CSXSEvent = CSXSEvent;