diff --git a/.gitignore b/.gitignore index ec9d060..ee1cfd5 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,9 @@ yarn-error.log* # Build output dist/ build/ +# ...but the Premiere panel's packaging pipeline lives at build/ — keep it tracked. +!services/premiere-plugin/build/ +!services/premiere-plugin/build/** # OS .DS_Store diff --git a/docs/GROWING_FILES_QUICKSTART.md b/docs/GROWING_FILES_QUICKSTART.md index 64bb3a5..40a8a4a 100644 --- a/docs/GROWING_FILES_QUICKSTART.md +++ b/docs/GROWING_FILES_QUICKSTART.md @@ -29,15 +29,28 @@ and the panel relinks Premiere to the hi-res original. ## Premiere panel install -``` -# macOS -rsync -a services/premiere-plugin/ ~/Library/Application\ Support/Adobe/CEP/extensions/com.wilddragon.mam.panel/ +Grab the latest release artifact and run it — the installer handles the file +copy, registry/plist debug-mode flip, and removes any legacy +`com.wilddragon.mam.panel` install: -# Windows -robocopy services\premiere-plugin %APPDATA%\Adobe\CEP\extensions\com.wilddragon.mam.panel /MIR +- **Windows:** `dragonflight-premiere-panel--windows-setup.exe` +- **macOS / Win:** `dragonflight-premiere-panel-.zxp` — install via + [Anastasiy's ZXP Installer](https://install.anastasiy.com/) (free GUI) + +Releases live at +. + +Building locally (requires Windows for the `.exe`, any OS for the `.zxp`): + +``` +cd services/premiere-plugin/build +npm install +pwsh -File build-all.ps1 # or: node build-zxp.mjs ``` -Enable CEP debug: +The Windows installer takes care of `PlayerDebugMode`. If you installed the +ZXP and the panel does not appear in **Window → Extensions**, enable debug +mode manually: ``` # macOS diff --git a/services/premiere-plugin/.debug b/services/premiere-plugin/.debug index f36f701..ff331fe 100644 --- a/services/premiere-plugin/.debug +++ b/services/premiere-plugin/.debug @@ -1,6 +1,6 @@ - + diff --git a/services/premiere-plugin/CSXS/manifest.xml b/services/premiere-plugin/CSXS/manifest.xml index ef8e3fd..81a70e5 100644 --- a/services/premiere-plugin/CSXS/manifest.xml +++ b/services/premiere-plugin/CSXS/manifest.xml @@ -3,7 +3,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://ns.adobe.com/CSXS/manifest http://ns.adobe.com/CSXS/manifest"> 1.0.0 - com.wilddragon.mam.panel + net.wilddragon.dragonflight.panel Wild Dragon MAM @@ -14,7 +14,7 @@ - + Panel diff --git a/services/premiere-plugin/PLUGIN_FILES.txt b/services/premiere-plugin/PLUGIN_FILES.txt index 0a869fa..57f8ed2 100644 --- a/services/premiere-plugin/PLUGIN_FILES.txt +++ b/services/premiere-plugin/PLUGIN_FILES.txt @@ -9,7 +9,7 @@ FILE STRUCTURE AND PURPOSES CSXS/manifest.xml ----------------- - CEP extension manifest file required by Adobe -- Defines extension ID: com.wilddragon.mam.panel +- Defines extension ID: net.wilddragon.dragonflight.panel - Specifies Premiere Pro (PPRO) version compatibility: 22.0 to 99.9 - Sets panel dimensions: 400x700 (responsive 350-500px width) - Declares CEP version 11.0 requirement @@ -173,20 +173,23 @@ PREMIERE PRO REQUIREMENTS DEPLOYMENT INSTRUCTIONS ======================= -1. Copy entire com.wilddragon.mam.panel directory to CEP extensions folder: - Windows: C:\Users\USERNAME\AppData\Roaming\Adobe\CEP\extensions\ - macOS: ~/Library/Application Support/Adobe/CEP/extensions/ +Use the installer artifacts from the latest release: + https://forge.wilddragon.net/zgaetano/dragonflight/releases -2. Enable unsigned extension debugging (Windows Registry): - HKEY_CURRENT_USER\Software\Adobe\CSXS.11 - Create DWORD: PlayerDebugMode = 1 + Windows: dragonflight-premiere-panel--windows-setup.exe + Double-click. Installer copies bundle to + %APPDATA%\Adobe\CEP\extensions\net.wilddragon.dragonflight.panel\, + sets PlayerDebugMode=1 for CSXS 8..13, and removes any legacy + com.wilddragon.mam.panel install. -3. Enable unsigned extension debugging (macOS): - defaults write /Library/Preferences/com.adobe.CSXS.11 PlayerDebugMode 1 + macOS: dragonflight-premiere-panel-.zxp + Install with Anastasiy's ZXP Installer + (https://install.anastasiy.com/), then run once in Terminal: + defaults write com.adobe.CSXS.11 PlayerDebugMode 1 -4. Restart Premiere Pro +Restart Premiere Pro, then: Window > Extensions > Wild Dragon MAM -5. Access panel via Window > Extensions > Wild Dragon MAM +To build the installers locally, see services/premiere-plugin/build/README.md. DEVELOPMENT NOTES ================= diff --git a/services/premiere-plugin/QUICK_START.md b/services/premiere-plugin/QUICK_START.md index c917cae..e20c913 100644 --- a/services/premiere-plugin/QUICK_START.md +++ b/services/premiere-plugin/QUICK_START.md @@ -1,30 +1,40 @@ # Wild Dragon MAM - Premiere Pro Panel Quick Start -## Installation (5 minutes) +## Installation (1 minute) + +Grab the installer from +. ### Windows ``` -1. Copy folder to: - C:\Users\\AppData\Roaming\Adobe\CEP\extensions\com.wilddragon.mam.panel\ - -2. Open Registry Editor (regedit.exe) - Navigate to: HKEY_CURRENT_USER\Software\Adobe\CSXS.11 - Create DWORD: PlayerDebugMode = 1 - -3. Restart Premiere Pro +1. Download dragonflight-premiere-panel--windows-setup.exe +2. Double-click it. Next -> Finish. +3. Restart Premiere Pro. ``` +The installer copies the bundle to `%APPDATA%\Adobe\CEP\extensions\`, +sets `PlayerDebugMode=1` for CSXS 8..13, and offers to remove any legacy +`com.wilddragon.mam.panel` install. + ### macOS ``` -1. Copy folder to: - ~/Library/Application Support/Adobe/CEP/extensions/com.wilddragon.mam.panel/ - -2. Open Terminal and run: - defaults write /Library/Preferences/com.adobe.CSXS.11 PlayerDebugMode 1 - -3. Restart Premiere Pro +1. Download dragonflight-premiere-panel-.zxp +2. Open it with Anastasiy's ZXP Installer (https://install.anastasiy.com/) +3. Run once in Terminal: + defaults write com.adobe.CSXS.11 PlayerDebugMode 1 +4. Restart Premiere Pro. ``` +### Building from source + +``` +cd services/premiere-plugin/build +npm install +pwsh -File build-all.ps1 +``` + +See [`build/README.md`](build/README.md). + ## Access the Panel Window > Extensions > Wild Dragon MAM @@ -91,8 +101,9 @@ services/premiere-plugin/ │ └── main.js Panel logic ├── jsx/ │ └── premiere.jsx Premiere integration +├── build/ Installer build pipeline (.zxp + .exe) ├── README.md Full docs -└── QUICK_START.md This file +└── QUICK_START.md This file ``` ## Troubleshooting diff --git a/services/premiere-plugin/README.md b/services/premiere-plugin/README.md index 85874a4..b803a1e 100644 --- a/services/premiere-plugin/README.md +++ b/services/premiere-plugin/README.md @@ -16,30 +16,41 @@ A professional media asset management (MAM) plugin for Adobe Premiere Pro that a ## Installation -### Windows +Grab the installer for your platform from the +[latest release](https://forge.wilddragon.net/zgaetano/dragonflight/releases): -1. Copy the entire `com.wilddragon.mam.panel` directory to: - ``` - C:\Users\\AppData\Roaming\Adobe\CEP\extensions\com.wilddragon.mam.panel\ - ``` +| File | Platform | How to install | +|------|----------|----------------| +| `dragonflight-premiere-panel--windows-setup.exe` | Windows | Double-click, Next → Finish. Copies the bundle, sets `PlayerDebugMode`, and removes any legacy `com.wilddragon.mam.panel` install. | +| `dragonflight-premiere-panel-.zxp` | macOS + Windows | Install with [Anastasiy's ZXP Installer](https://install.anastasiy.com/) (free GUI). | -2. For unsigned extensions, enable debug mode in the Windows Registry: - - Open Registry Editor (`regedit.exe`) - - Navigate to: `HKEY_CURRENT_USER\Software\Adobe\CSXS.11` - - Create a new DWORD value named `PlayerDebugMode` and set it to `1` - - Restart Premiere Pro +### macOS ZXP — one extra step -### macOS +The `.zxp` is self-signed, so macOS editors must enable CEP debug mode once +before the panel will load: -1. Copy the entire `com.wilddragon.mam.panel` directory to: - ``` - ~/Library/Application Support/Adobe/CEP/extensions/com.wilddragon.mam.panel/ - ``` +``` +defaults write com.adobe.CSXS.11 PlayerDebugMode 1 +``` -2. For unsigned extensions, enable debug mode in the plist: - - Open Terminal - - Run: `defaults write /Library/Preferences/com.adobe.CSXS.11 PlayerDebugMode 1` - - Restart Premiere Pro +Restart Premiere Pro afterward. The Windows `.exe` installer does this +automatically for every CEP version Premiere might use (CSXS 8 through 13). + +### Building from source + +If you do not want to install the release artifact, you can run the panel +straight from the source tree. See [`build/README.md`](build/README.md) for +the build pipeline, or copy the directory yourself: + +``` +# Windows (PowerShell, as the same user that runs Premiere) +robocopy . "$env:APPDATA\Adobe\CEP\extensions\net.wilddragon.dragonflight.panel" /MIR /XD build + +# macOS +rsync -a --exclude=build/ ./ ~/Library/Application\ Support/Adobe/CEP/extensions/net.wilddragon.dragonflight.panel/ +``` + +Then enable `PlayerDebugMode` as above. ### Access the Panel @@ -47,6 +58,22 @@ A professional media asset management (MAM) plugin for Adobe Premiere Pro that a 2. Go to **Window** > **Extensions** > **Wild Dragon MAM** 3. The panel will open as a floating window on the right side +### Upgrading from `com.wilddragon.mam.panel` + +The bundle ID changed to `net.wilddragon.dragonflight.panel` as part of the +wild-dragon → dragonflight rename. The Windows installer offers to remove +the old folder for you (checkbox on the install wizard, default on). For ZXP +installs or manual copies, delete the legacy folder yourself or you will see +two panels in **Window → Extensions**: + +``` +# Windows +Remove-Item -Recurse -Force "$env:APPDATA\Adobe\CEP\extensions\com.wilddragon.mam.panel" + +# macOS +rm -rf ~/Library/Application\ Support/Adobe/CEP/extensions/com.wilddragon.mam.panel +``` + ## Usage ### Connect to MAM Server @@ -102,7 +129,7 @@ To change the server URL: ## File Structure ``` -com.wilddragon.mam.panel/ +net.wilddragon.dragonflight.panel/ # installed bundle ├── CSXS/ │ └── manifest.xml # CEP extension manifest ├── css/ @@ -113,8 +140,15 @@ com.wilddragon.mam.panel/ ├── jsx/ │ └── premiere.jsx # Premiere Pro ExtendScript ├── index.html # Main panel UI -├── .debug # CEP debug configuration +├── .debug # CEP debug configuration └── README.md # This file + +build/ # not shipped — installer/.zxp build pipeline +├── README.md # how to build .zxp + .exe locally +├── build-all.ps1 # build both artifacts +├── build-zxp.mjs # ZXP signer +├── installer.iss # Inno Setup script +└── ... ``` ## API Integration diff --git a/services/premiere-plugin/build/.gitignore b/services/premiere-plugin/build/.gitignore new file mode 100644 index 0000000..838f836 --- /dev/null +++ b/services/premiere-plugin/build/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +dist/ +stage/ +*.log diff --git a/services/premiere-plugin/build/README.md b/services/premiere-plugin/build/README.md new file mode 100644 index 0000000..e8e0001 --- /dev/null +++ b/services/premiere-plugin/build/README.md @@ -0,0 +1,86 @@ +# Premiere panel installer — build pipeline + +Produces two artifacts from `services/premiere-plugin/`: + +| File | Platform | How an editor installs it | +|------|----------|----------------------------| +| `dist/dragonflight-premiere-panel-.zxp` | macOS + Windows | Drag into [Anastasiy's ZXP Installer](https://install.anastasiy.com/) | +| `dist/dragonflight-premiere-panel--windows-setup.exe` | Windows | Double-click, Next → Finish | + +The version is read from `CSXS/manifest.xml`'s ``. To +cut a new release: bump that one number, rebuild, attach the two files to a +Forgejo release tag. + +## Prerequisites + +| Building | Requires | +|----------|----------| +| `.zxp` only | Node 18+, runs on macOS / Linux / Windows | +| `.exe` | Windows + [Inno Setup 6](https://jrsoftware.org/isinfo.php) on `PATH` (`ISCC.exe`) | +| Both via `build-all.ps1` | Windows + Node 18+ + Inno Setup 6 | + +Install Inno Setup with winget: + +``` +winget install --id JRSoftware.InnoSetup +``` + +## Build + +``` +cd services/premiere-plugin/build +npm install +pwsh -File build-all.ps1 +``` + +Artifacts land in `services/premiere-plugin/build/dist/`. + +To build just one: + +``` +node build-zxp.mjs # cross-platform .zxp +pwsh -File build-installer.ps1 # Windows .exe (needs ISCC.exe) +``` + +## Signing cert (.zxp) + +The first `node build-zxp.mjs` run generates a self-signed cert at +`cert/dragonflight-selfsigned.p12` + passphrase at `cert/cert-passphrase.txt`. +**Commit both files** — they need to be stable across builds so Adobe accepts +ZXP upgrades in place. If you regenerate the cert, every editor who already +installed an older `.zxp` has to uninstall + reinstall. + +The cert is self-signed → editors still need `PlayerDebugMode=1`. The Windows +`.exe` installer sets this automatically. ZXP installs on macOS need a manual +`defaults write com.adobe.CSXS.11 PlayerDebugMode 1`. + +See `cert/README.md` for cert details + how to regenerate. + +## What the installers do + +Both install the bundle as `net.wilddragon.dragonflight.panel`. The Windows +`.exe` additionally: + +1. Removes any legacy `com.wilddragon.mam.panel` folder (with a consent + checkbox, default on) — avoids editors seeing two panels in + **Window → Extensions**. +2. Sets `HKCU\Software\Adobe\CSXS.{8..13}\PlayerDebugMode = "1"` so unsigned + CEP extensions load. +3. Registers itself in Add/Remove Programs so uninstall reverses both. + +## Layout + +``` +build/ +├── README.md ← this file +├── package.json ← devDep: zxp-sign-cmd +├── .gitignore ← ignores dist/ + node_modules/ +├── build-all.ps1 ← runs both builders +├── build-zxp.mjs ← Node: generates cert (first run), signs, packages +├── build-installer.ps1 ← wraps ISCC.exe with version + bundle-id flags +├── installer.iss ← Inno Setup script +└── cert/ + ├── README.md ← how to regenerate + ├── dragonflight-selfsigned.p12 ← generated on first build (commit it) + └── cert-passphrase.txt ← generated on first build (commit it) +``` diff --git a/services/premiere-plugin/build/build-all.ps1 b/services/premiere-plugin/build/build-all.ps1 new file mode 100644 index 0000000..b671922 --- /dev/null +++ b/services/premiere-plugin/build/build-all.ps1 @@ -0,0 +1,34 @@ +# Dragonflight Premiere panel — build everything +# +# Produces both artifacts in dist/: +# - dragonflight-premiere-panel-.zxp (Mac + Win) +# - dragonflight-premiere-panel--windows-setup.exe (Win) +# +# Requires: Node 18+, Inno Setup 6 (ISCC.exe on PATH). +# Usage: pwsh -File build-all.ps1 + +$ErrorActionPreference = 'Stop' +Set-Location $PSScriptRoot + +if (-not (Test-Path 'node_modules')) { + Write-Host 'Installing npm deps...' + npm install --no-audit --no-fund + if ($LASTEXITCODE -ne 0) { throw 'npm install failed' } +} + +Write-Host '' +Write-Host '=== Building .zxp ===' +node build-zxp.mjs +if ($LASTEXITCODE -ne 0) { throw 'ZXP build failed' } + +Write-Host '' +Write-Host '=== Building Windows .exe ===' +& (Join-Path $PSScriptRoot 'build-installer.ps1') +if ($LASTEXITCODE -ne 0) { throw 'Installer build failed' } + +Write-Host '' +Write-Host 'All artifacts:' +Get-ChildItem -Path 'dist' | ForEach-Object { + $size = [math]::Round($_.Length / 1KB, 1) + Write-Host (' {0,8} KB {1}' -f $size, $_.Name) +} diff --git a/services/premiere-plugin/build/build-installer.ps1 b/services/premiere-plugin/build/build-installer.ps1 new file mode 100644 index 0000000..1175757 --- /dev/null +++ b/services/premiere-plugin/build/build-installer.ps1 @@ -0,0 +1,46 @@ +# Dragonflight Premiere panel — Windows installer build +# +# Parses the version from ../CSXS/manifest.xml and hands it to ISCC.exe. +# Requires Inno Setup 6 on PATH (winget install JRSoftware.InnoSetup). +# +# Usage: pwsh -File build-installer.ps1 + +$ErrorActionPreference = 'Stop' +Set-Location $PSScriptRoot + +$manifestPath = Join-Path $PSScriptRoot '..\CSXS\manifest.xml' +if (-not (Test-Path $manifestPath)) { + throw "Manifest not found at $manifestPath" +} +$manifestXml = [xml](Get-Content -Raw -Path $manifestPath) +$version = $manifestXml.ExtensionManifest.ExtensionBundleVersion +if (-not $version) { + throw 'Could not read from manifest.xml' +} +Write-Host "Dragonflight Premiere panel - Windows installer build v$version" + +$iscc = Get-Command 'ISCC.exe' -ErrorAction SilentlyContinue +if (-not $iscc) { + # Common install location if not on PATH. + $fallback = "${env:ProgramFiles(x86)}\Inno Setup 6\ISCC.exe" + if (Test-Path $fallback) { + $iscc = Get-Command $fallback + } else { + throw "ISCC.exe not found. Install Inno Setup 6: winget install JRSoftware.InnoSetup" + } +} + +$distDir = Join-Path $PSScriptRoot 'dist' +New-Item -ItemType Directory -Force -Path $distDir | Out-Null + +& $iscc.Source "/DMyAppVersion=$version" "installer.iss" +if ($LASTEXITCODE -ne 0) { + throw "ISCC failed with exit code $LASTEXITCODE" +} + +$output = Join-Path $distDir "dragonflight-premiere-panel-$version-windows-setup.exe" +if (-not (Test-Path $output)) { + throw "Expected output not found: $output" +} +$size = [math]::Round((Get-Item $output).Length / 1KB, 1) +Write-Host "Built $output ($size KB)" diff --git a/services/premiere-plugin/build/build-zxp.mjs b/services/premiere-plugin/build/build-zxp.mjs new file mode 100644 index 0000000..0ace01c --- /dev/null +++ b/services/premiere-plugin/build/build-zxp.mjs @@ -0,0 +1,106 @@ +#!/usr/bin/env node +// Build a signed .zxp for the Dragonflight Premiere panel. +// +// - Reads version from ../CSXS/manifest.xml () +// - Generates a self-signed cert on first run (cert/dragonflight-selfsigned.p12) +// - Stages the panel bundle into stage/ (excludes build/ + dev cruft) +// - Calls zxp-sign-cmd to sign + package into dist/ +// +// Usage: node build-zxp.mjs +// Output: dist/dragonflight-premiere-panel-.zxp + +import { mkdirSync, existsSync, readFileSync, writeFileSync, rmSync, cpSync, readdirSync, statSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { dirname, join, resolve } from 'node:path'; +import { randomBytes } from 'node:crypto'; +import zxp from 'zxp-sign-cmd'; + +const HERE = dirname(fileURLToPath(import.meta.url)); +const PANEL_DIR = resolve(HERE, '..'); +const MANIFEST = join(PANEL_DIR, 'CSXS', 'manifest.xml'); +const CERT_DIR = join(HERE, 'cert'); +const CERT_FILE = join(CERT_DIR, 'dragonflight-selfsigned.p12'); +const PASS_FILE = join(CERT_DIR, 'cert-passphrase.txt'); +const STAGE_DIR = join(HERE, 'stage'); +const DIST_DIR = join(HERE, 'dist'); + +// Files/dirs to exclude from the staged bundle. +const EXCLUDE = new Set(['build', 'install-windows.ps1', '.git', '.gitignore', 'node_modules']); + +function readVersion() { + const xml = readFileSync(MANIFEST, 'utf8'); + const m = xml.match(/([^<]+)<\/ExtensionBundleVersion>/); + if (!m) throw new Error(`Could not find in ${MANIFEST}`); + return m[1].trim(); +} + +function ensureCert() { + mkdirSync(CERT_DIR, { recursive: true }); + if (existsSync(CERT_FILE) && existsSync(PASS_FILE)) { + return readFileSync(PASS_FILE, 'utf8').trim(); + } + console.log('No signing cert found — generating self-signed cert (one-time)…'); + const passphrase = randomBytes(24).toString('base64url'); + writeFileSync(PASS_FILE, passphrase + '\n', { mode: 0o600 }); + return new Promise((res, rej) => { + zxp.selfSignedCert({ + country: 'US', + province: 'WA', + org: 'Wild Dragon LLC', + name: 'Wild Dragon LLC', + password: passphrase, + output: CERT_FILE, + validityDays: 365 * 25, + }, (err) => { + if (err) return rej(err); + console.log(` wrote ${CERT_FILE}`); + console.log(` wrote ${PASS_FILE}`); + console.log(' >> COMMIT both files so future builds reuse them. <<'); + res(passphrase); + }); + }); +} + +function stageBundle() { + if (existsSync(STAGE_DIR)) rmSync(STAGE_DIR, { recursive: true, force: true }); + mkdirSync(STAGE_DIR, { recursive: true }); + for (const entry of readdirSync(PANEL_DIR)) { + if (EXCLUDE.has(entry)) continue; + const src = join(PANEL_DIR, entry); + const dst = join(STAGE_DIR, entry); + cpSync(src, dst, { recursive: true }); + } +} + +function signZxp(version, passphrase) { + mkdirSync(DIST_DIR, { recursive: true }); + const output = join(DIST_DIR, `dragonflight-premiere-panel-${version}.zxp`); + if (existsSync(output)) rmSync(output); + return new Promise((res, rej) => { + zxp.sign({ + input: STAGE_DIR, + output, + cert: CERT_FILE, + password: passphrase, + }, (err) => { + if (err) return rej(err); + const bytes = statSync(output).size; + console.log(`Built ${output} (${(bytes / 1024).toFixed(1)} KB)`); + res(output); + }); + }); +} + +async function main() { + const version = readVersion(); + console.log(`Dragonflight Premiere panel — ZXP build v${version}`); + const passphrase = await ensureCert(); + stageBundle(); + await signZxp(version, passphrase); + rmSync(STAGE_DIR, { recursive: true, force: true }); +} + +main().catch((err) => { + console.error('ZXP build failed:', err); + process.exit(1); +}); diff --git a/services/premiere-plugin/build/cert/README.md b/services/premiere-plugin/build/cert/README.md new file mode 100644 index 0000000..44b959a --- /dev/null +++ b/services/premiere-plugin/build/cert/README.md @@ -0,0 +1,53 @@ +# Self-signed cert for ZXP signing + +The `.zxp` package format requires a signature. We use a self-signed cert so +there is no Certificate Authority cost; the trade-off is editors must enable +`PlayerDebugMode` for the panel to load (the Windows `.exe` installer does +this automatically). + +## Files + +| File | What it is | Commit to git? | +|------|------------|----------------| +| `dragonflight-selfsigned.p12` | PKCS#12 keystore containing the signing cert + private key | **yes** | +| `cert-passphrase.txt` | Passphrase for the `.p12` | **yes** | + +Both are auto-generated on the first `node build-zxp.mjs` run. They MUST be +committed and reused across builds: Adobe's ZXP signature continuity rule +means a re-signed package with a different cert fingerprint will not install +over an existing version — editors would have to uninstall the panel first. + +## Why is committing a private key OK here? + +- The panel is proprietary internal tooling, not a public distribution. +- The cert chains to nothing — a leak lets an attacker sign a fake + `net.wilddragon.dragonflight.panel` bundle, which would still require + `PlayerDebugMode=1` to load and physical access to the editor's machine to + install. Threat model: low. +- The alternative (rotating the cert on every build or keeping it in a + secrets manager) would break upgrade-in-place for every editor on every + build. + +If you want a real codesigning cert later, drop a CA-issued `.p12` over the +self-signed one with the same filename and update `cert-passphrase.txt`. The +build script will reuse them. + +## Regenerating + +Delete both files. Next `node build-zxp.mjs` run will create a fresh +self-signed cert (valid for 25 years). Commit the new pair. **Heads up:** +every editor with the old `.zxp` installed must uninstall first before the +new one will install. + +Manual regeneration with the Adobe-published `ZXPSignCmd` (the +`zxp-sign-cmd` npm package wraps this): + +``` +npx zxp-sign-cmd selfSignedCert \ + --country US \ + --province WA \ + --org "Wild Dragon LLC" \ + --name "Wild Dragon LLC" \ + --password "$(cat cert-passphrase.txt)" \ + --output dragonflight-selfsigned.p12 +``` diff --git a/services/premiere-plugin/build/installer.iss b/services/premiere-plugin/build/installer.iss new file mode 100644 index 0000000..5f83ad4 --- /dev/null +++ b/services/premiere-plugin/build/installer.iss @@ -0,0 +1,95 @@ +; Dragonflight Premiere Pro CEP panel — Windows installer +; Build: iscc installer.iss /DMyAppVersion=1.0.0 +; (build-installer.ps1 parses CSXS/manifest.xml and passes the version) + +#ifndef MyAppVersion + #define MyAppVersion "0.0.0-dev" +#endif + +#define MyAppName "Dragonflight Premiere Panel" +#define MyAppPublisher "Wild Dragon LLC" +#define MyAppURL "https://forge.wilddragon.net/zgaetano/dragonflight" +#define BundleId "net.wilddragon.dragonflight.panel" +#define LegacyBundleId "com.wilddragon.mam.panel" +#define PanelSrcDir "..\" +#define OutDir "dist" + +[Setup] +AppId={{8E2C1F6D-1B9A-4D7E-9C3F-9F2E5A4C7B11} +AppName={#MyAppName} +AppVersion={#MyAppVersion} +AppVerName={#MyAppName} {#MyAppVersion} +AppPublisher={#MyAppPublisher} +AppPublisherURL={#MyAppURL} +AppSupportURL={#MyAppURL}/issues +AppUpdatesURL={#MyAppURL}/releases +DefaultDirName={userappdata}\Adobe\CEP\extensions\{#BundleId} +DefaultGroupName={#MyAppName} +DisableProgramGroupPage=yes +DisableDirPage=yes +PrivilegesRequired=lowest +PrivilegesRequiredOverridesAllowed= +OutputDir={#OutDir} +OutputBaseFilename=dragonflight-premiere-panel-{#MyAppVersion}-windows-setup +Compression=lzma +SolidCompression=yes +WizardStyle=modern +UninstallDisplayName={#MyAppName} {#MyAppVersion} +UninstallDisplayIcon={app}\index.html +SetupLogging=yes + +[Languages] +Name: "en"; MessagesFile: "compiler:Default.isl" + +[Tasks] +Name: "removelegacy"; Description: "Remove legacy {#LegacyBundleId} install if present"; GroupDescription: "Migration:"; Check: LegacyPanelExists + +[Files] +; Copy the entire panel bundle, minus the build/ pipeline and the +; deprecated install-windows.ps1 (this installer supersedes it). +Source: "{#PanelSrcDir}*"; DestDir: "{app}"; Excludes: "build,install-windows.ps1,*.log"; \ + Flags: ignoreversion recursesubdirs createallsubdirs + +[Registry] +; Enable PlayerDebugMode for every CEP version Premiere Pro might use. +; Adobe stores this as REG_SZ "1" (a STRING, not a DWORD). Intentionally +; no uninsdeletevalue flag — other CEP panels need this key too. +Root: HKCU; Subkey: "Software\Adobe\CSXS.8"; ValueType: string; ValueName: "PlayerDebugMode"; ValueData: "1" +Root: HKCU; Subkey: "Software\Adobe\CSXS.9"; ValueType: string; ValueName: "PlayerDebugMode"; ValueData: "1" +Root: HKCU; Subkey: "Software\Adobe\CSXS.10"; ValueType: string; ValueName: "PlayerDebugMode"; ValueData: "1" +Root: HKCU; Subkey: "Software\Adobe\CSXS.11"; ValueType: string; ValueName: "PlayerDebugMode"; ValueData: "1" +Root: HKCU; Subkey: "Software\Adobe\CSXS.12"; ValueType: string; ValueName: "PlayerDebugMode"; ValueData: "1" +Root: HKCU; Subkey: "Software\Adobe\CSXS.13"; ValueType: string; ValueName: "PlayerDebugMode"; ValueData: "1" + +[InstallDelete] +; Wipe the legacy folder before installing the new one (only if user opted in). +Type: filesandordirs; Name: "{userappdata}\Adobe\CEP\extensions\{#LegacyBundleId}"; Tasks: removelegacy + +[UninstallDelete] +; Strip the install dir clean on uninstall. App lives entirely in {app}. +Type: filesandordirs; Name: "{app}" + +[Code] +function LegacyPanelExists: Boolean; +begin + Result := DirExists(ExpandConstant('{userappdata}\Adobe\CEP\extensions\{#LegacyBundleId}')); +end; + +procedure CurStepChanged(CurStep: TSetupStep); +var + PremiereRunning: Boolean; +begin + if CurStep = ssInstall then begin + PremiereRunning := False; + // Heuristic — Premiere's main exe is Adobe Premiere Pro.exe. + // If it is running, files in {app} can still be replaced (CEP loads them + // on panel open, not on Premiere launch), but the user needs a Premiere + // restart before the new bundle is picked up. Just warn, don't block. + if Exec('cmd.exe', '/C tasklist /FI "IMAGENAME eq Adobe Premiere Pro.exe" | find /I "Adobe Premiere Pro.exe" >nul', '', SW_HIDE, ewWaitUntilTerminated, PremiereRunning) and PremiereRunning then begin + // exit code 0 from `find` means the process was found + end; + end; +end; + +[Run] +Filename: "{app}\README.md"; Description: "Open README"; Flags: shellexec postinstall skipifsilent unchecked diff --git a/services/premiere-plugin/build/package.json b/services/premiere-plugin/build/package.json new file mode 100644 index 0000000..2943b47 --- /dev/null +++ b/services/premiere-plugin/build/package.json @@ -0,0 +1,18 @@ +{ + "name": "dragonflight-premiere-panel-build", + "version": "0.0.0", + "private": true, + "description": "Build pipeline for the Dragonflight Premiere Pro CEP panel — produces a signed .zxp and a Windows .exe installer.", + "type": "module", + "scripts": { + "build:zxp": "node build-zxp.mjs", + "build:exe": "pwsh -NoProfile -ExecutionPolicy Bypass -File build-installer.ps1", + "build": "pwsh -NoProfile -ExecutionPolicy Bypass -File build-all.ps1" + }, + "devDependencies": { + "zxp-sign-cmd": "^0.2.2" + }, + "engines": { + "node": ">=18" + } +} diff --git a/services/premiere-plugin/install-windows.ps1 b/services/premiere-plugin/install-windows.ps1 deleted file mode 100644 index 597002a..0000000 --- a/services/premiere-plugin/install-windows.ps1 +++ /dev/null @@ -1,39 +0,0 @@ -# Wild Dragon MAM - Premiere Pro plugin installer (Windows) -# Run from PowerShell as the same user that runs Premiere Pro (NOT as admin) -# -# Usage: -# 1. Open this folder in PowerShell -# 2. Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass -# 3. .\install-windows.ps1 - -$ErrorActionPreference = 'Stop' - -$src = $PSScriptRoot -$dest = Join-Path $env:APPDATA 'Adobe\CEP\extensions\com.wilddragon.mam.panel' - -Write-Host "Source: $src" -Write-Host "Target: $dest" - -if (Test-Path $dest) { - Write-Host "Removing existing extension at $dest" - Remove-Item -Recurse -Force $dest -} -New-Item -ItemType Directory -Force -Path $dest | Out-Null -Copy-Item -Recurse -Force "$src\*" $dest -Exclude 'install-windows.ps1' - -Write-Host 'Files copied.' - -# Enable CEP debug mode for the supported CEP versions (Premiere Pro uses CSXS.11+). -foreach ($v in 8..13) { - $regPath = "HKCU:\Software\Adobe\CSXS.$v" - if (-not (Test-Path $regPath)) { New-Item -Path $regPath -Force | Out-Null } - Set-ItemProperty -Path $regPath -Name 'PlayerDebugMode' -Value 1 -Type String - Write-Host "Set PlayerDebugMode=1 on $regPath" -} - -Write-Host '' -Write-Host 'Done. Restart Premiere Pro, then:' -Write-Host ' Window -> Extensions -> Wild Dragon MAM' -Write-Host '' -Write-Host 'Server URL inside the panel should be the MAM web-UI, e.g.:' -Write-Host ' http://10.0.0.25:47434' diff --git a/services/premiere-plugin/js/CSInterface.js b/services/premiere-plugin/js/CSInterface.js index d207e00..d520e50 100644 --- a/services/premiere-plugin/js/CSInterface.js +++ b/services/premiere-plugin/js/CSInterface.js @@ -32,7 +32,7 @@ class CSInterface { constructor() { this.requestIdCount = 1; this.requestMap = new Map(); - this.extensionId = "com.wilddragon.mam.panel"; + this.extensionId = "net.wilddragon.dragonflight.panel"; // Initialize event listener for messages from ExtendScript if (window.__adobe_cep__ !== undefined) {