Merge remote-tracking branch 'origin/feat/premiere-installer'
This commit is contained in:
commit
543248b8c2
29 changed files with 792 additions and 173 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -14,6 +14,9 @@ yarn-error.log*
|
||||||
# Build output
|
# Build output
|
||||||
dist/
|
dist/
|
||||||
build/
|
build/
|
||||||
|
# ...but the Premiere panel's packaging pipeline lives at build/ — keep it tracked.
|
||||||
|
!services/premiere-plugin/build/
|
||||||
|
!services/premiere-plugin/build/**
|
||||||
|
|
||||||
# OS
|
# OS
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
|
||||||
|
|
@ -29,15 +29,28 @@ and the panel relinks Premiere to the hi-res original.
|
||||||
|
|
||||||
## Premiere panel install
|
## Premiere panel install
|
||||||
|
|
||||||
```
|
Grab the latest release artifact and run it — the installer handles the file
|
||||||
# macOS
|
copy, registry/plist debug-mode flip, and removes any legacy
|
||||||
rsync -a services/premiere-plugin/ ~/Library/Application\ Support/Adobe/CEP/extensions/com.wilddragon.mam.panel/
|
`com.wilddragon.mam.panel` install:
|
||||||
|
|
||||||
# Windows
|
- **Windows:** `dragonflight-premiere-panel-<version>-windows-setup.exe`
|
||||||
robocopy services\premiere-plugin %APPDATA%\Adobe\CEP\extensions\com.wilddragon.mam.panel /MIR
|
- **macOS / Win:** `dragonflight-premiere-panel-<version>.zxp` — install via
|
||||||
|
[Anastasiy's ZXP Installer](https://install.anastasiy.com/) (free GUI)
|
||||||
|
|
||||||
|
Releases live at
|
||||||
|
<https://forge.wilddragon.net/zgaetano/dragonflight/releases>.
|
||||||
|
|
||||||
|
Building locally (requires Windows for the `.exe`, any OS for the `.zxp`):
|
||||||
|
|
||||||
|
```
|
||||||
|
cd services/premiere-plugin/build
|
||||||
|
npm install
|
||||||
|
powershell -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
|
# macOS
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<ExtensionList>
|
<ExtensionList>
|
||||||
<Extension Id="com.wilddragon.mam.panel">
|
<Extension Id="net.wilddragon.dragonflight.panel">
|
||||||
<HostList>
|
<HostList>
|
||||||
<Host Name="PPRO" Port="7737"/>
|
<Host Name="PPRO" Port="7737"/>
|
||||||
</HostList>
|
</HostList>
|
||||||
|
|
|
||||||
|
|
@ -1,71 +1,58 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<ExtensionManifest xmlns="http://ns.adobe.com/CSXS/manifest"
|
<ExtensionManifest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
ExtensionBundleId="net.wilddragon.dragonflight.panel"
|
||||||
xsi:schemaLocation="http://ns.adobe.com/CSXS/manifest http://ns.adobe.com/CSXS/manifest">
|
ExtensionBundleName="Wild Dragon MAM"
|
||||||
<ExtensionBundleVersion>1.0.0</ExtensionBundleVersion>
|
ExtensionBundleVersion="1.0.1"
|
||||||
<ExtensionBundleId>com.wilddragon.mam.panel</ExtensionBundleId>
|
Version="7.0">
|
||||||
<Author>Wild Dragon MAM</Author>
|
<ExtensionList>
|
||||||
|
<Extension Id="net.wilddragon.dragonflight.panel" Version="1.0" />
|
||||||
<License>
|
</ExtensionList>
|
||||||
<Text>Copyright 2026 Wild Dragon. All rights reserved.</Text>
|
<ExecutionEnvironment>
|
||||||
</License>
|
<HostList>
|
||||||
|
<Host Name="PPRO" Version="[22.0,99.9]" />
|
||||||
<AbstractionLayers>
|
</HostList>
|
||||||
<AbstractionLayerRequest Name="PProPanel"/>
|
<LocaleList>
|
||||||
</AbstractionLayers>
|
<Locale Code="All" />
|
||||||
|
</LocaleList>
|
||||||
<Extension Id="com.wilddragon.mam.panel">
|
<RequiredRuntimeList>
|
||||||
<Type>Panel</Type>
|
<RequiredRuntime Name="CSXS" Version="10.0" />
|
||||||
<HostList>
|
</RequiredRuntimeList>
|
||||||
<Host Name="PPRO" Version="[22.0,99.9]"/>
|
</ExecutionEnvironment>
|
||||||
</HostList>
|
<DispatchInfoList>
|
||||||
|
<Extension Id="net.wilddragon.dragonflight.panel">
|
||||||
<LocalizedStrings>
|
<DispatchInfo>
|
||||||
<LocalizedString locale="en_US">
|
|
||||||
<Token name="ExtensionWindowTitle">Wild Dragon MAM</Token>
|
|
||||||
<Token name="ExtensionShortDescription">Media Asset Management for Premiere Pro</Token>
|
|
||||||
<Token name="ExtensionLongDescription">Browse, search, and import proxy files from Wild Dragon MAM directly into your Premiere Pro project</Token>
|
|
||||||
</LocalizedString>
|
|
||||||
</LocalizedStrings>
|
|
||||||
|
|
||||||
<UI>
|
|
||||||
<Type>Panel</Type>
|
|
||||||
<Geometry>
|
|
||||||
<Size>
|
|
||||||
<Width>400</Width>
|
|
||||||
<Height>700</Height>
|
|
||||||
</Size>
|
|
||||||
<MinSize>
|
|
||||||
<Width>350</Width>
|
|
||||||
<Height>500</Height>
|
|
||||||
</MinSize>
|
|
||||||
</Geometry>
|
|
||||||
</UI>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Resources:
|
|
||||||
- MainPath: HTML entry point for the CEP panel UI
|
|
||||||
- ScriptPath: ExtendScript (.jsx) auto-loaded into the Premiere Pro host
|
|
||||||
- --enable-nodejs: unlocks Node.js require() for binary file downloads
|
|
||||||
- --mixed-context: allows Node.js and DOM to share the same V8 context
|
|
||||||
-->
|
|
||||||
<Resources>
|
<Resources>
|
||||||
<MainPath>index.html</MainPath>
|
<MainPath>./index.html</MainPath>
|
||||||
<ScriptPath>jsx/premiere.jsx</ScriptPath>
|
<ScriptPath>./jsx/premiere.jsx</ScriptPath>
|
||||||
<CEFCommandLine>
|
<CEFCommandLine>
|
||||||
<Parameter>--enable-nodejs</Parameter>
|
<Parameter>--enable-nodejs</Parameter>
|
||||||
<Parameter>--mixed-context</Parameter>
|
<Parameter>--mixed-context</Parameter>
|
||||||
</CEFCommandLine>
|
<Parameter>--allow-file-access-from-files</Parameter>
|
||||||
|
<Parameter>--allow-file-access</Parameter>
|
||||||
|
</CEFCommandLine>
|
||||||
</Resources>
|
</Resources>
|
||||||
|
<Lifecycle>
|
||||||
<CEPVersion>11.0</CEPVersion>
|
<AutoVisible>true</AutoVisible>
|
||||||
<RequiredRuntimeVersion>11.0</RequiredRuntimeVersion>
|
</Lifecycle>
|
||||||
|
<UI>
|
||||||
|
<Type>Panel</Type>
|
||||||
|
<Menu>Wild Dragon MAM</Menu>
|
||||||
|
<Geometry>
|
||||||
|
<Size>
|
||||||
|
<Height>700</Height>
|
||||||
|
<Width>400</Width>
|
||||||
|
</Size>
|
||||||
|
<MinSize>
|
||||||
|
<Height>500</Height>
|
||||||
|
<Width>385</Width>
|
||||||
|
</MinSize>
|
||||||
|
<MaxSize>
|
||||||
|
<Height>2000</Height>
|
||||||
|
<Width>800</Width>
|
||||||
|
</MaxSize>
|
||||||
|
</Geometry>
|
||||||
|
</UI>
|
||||||
|
</DispatchInfo>
|
||||||
</Extension>
|
</Extension>
|
||||||
|
</DispatchInfoList>
|
||||||
<ExtensionList/>
|
|
||||||
<ExecutionEnvironment>
|
|
||||||
<HostList>
|
|
||||||
<Host Name="PPRO" Version="[22.0,99.9]"/>
|
|
||||||
</HostList>
|
|
||||||
</ExecutionEnvironment>
|
|
||||||
</ExtensionManifest>
|
</ExtensionManifest>
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ FILE STRUCTURE AND PURPOSES
|
||||||
CSXS/manifest.xml
|
CSXS/manifest.xml
|
||||||
-----------------
|
-----------------
|
||||||
- CEP extension manifest file required by Adobe
|
- 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
|
- Specifies Premiere Pro (PPRO) version compatibility: 22.0 to 99.9
|
||||||
- Sets panel dimensions: 400x700 (responsive 350-500px width)
|
- Sets panel dimensions: 400x700 (responsive 350-500px width)
|
||||||
- Declares CEP version 11.0 requirement
|
- Declares CEP version 11.0 requirement
|
||||||
|
|
@ -173,20 +173,23 @@ PREMIERE PRO REQUIREMENTS
|
||||||
DEPLOYMENT INSTRUCTIONS
|
DEPLOYMENT INSTRUCTIONS
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
1. Copy entire com.wilddragon.mam.panel directory to CEP extensions folder:
|
Use the installer artifacts from the latest release:
|
||||||
Windows: C:\Users\USERNAME\AppData\Roaming\Adobe\CEP\extensions\
|
https://forge.wilddragon.net/zgaetano/dragonflight/releases
|
||||||
macOS: ~/Library/Application Support/Adobe/CEP/extensions/
|
|
||||||
|
|
||||||
2. Enable unsigned extension debugging (Windows Registry):
|
Windows: dragonflight-premiere-panel-<version>-windows-setup.exe
|
||||||
HKEY_CURRENT_USER\Software\Adobe\CSXS.11
|
Double-click. Installer copies bundle to
|
||||||
Create DWORD: PlayerDebugMode = 1
|
%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):
|
macOS: dragonflight-premiere-panel-<version>.zxp
|
||||||
defaults write /Library/Preferences/com.adobe.CSXS.11 PlayerDebugMode 1
|
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
|
DEVELOPMENT NOTES
|
||||||
=================
|
=================
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,40 @@
|
||||||
# Wild Dragon MAM - Premiere Pro Panel Quick Start
|
# Wild Dragon MAM - Premiere Pro Panel Quick Start
|
||||||
|
|
||||||
## Installation (5 minutes)
|
## Installation (1 minute)
|
||||||
|
|
||||||
|
Grab the installer from
|
||||||
|
<https://forge.wilddragon.net/zgaetano/dragonflight/releases>.
|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
```
|
```
|
||||||
1. Copy folder to:
|
1. Download dragonflight-premiere-panel-<version>-windows-setup.exe
|
||||||
C:\Users\<USERNAME>\AppData\Roaming\Adobe\CEP\extensions\com.wilddragon.mam.panel\
|
2. Double-click it. Next -> Finish.
|
||||||
|
3. Restart Premiere Pro.
|
||||||
2. Open Registry Editor (regedit.exe)
|
|
||||||
Navigate to: HKEY_CURRENT_USER\Software\Adobe\CSXS.11
|
|
||||||
Create DWORD: PlayerDebugMode = 1
|
|
||||||
|
|
||||||
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
|
### macOS
|
||||||
```
|
```
|
||||||
1. Copy folder to:
|
1. Download dragonflight-premiere-panel-<version>.zxp
|
||||||
~/Library/Application Support/Adobe/CEP/extensions/com.wilddragon.mam.panel/
|
2. Open it with Anastasiy's ZXP Installer (https://install.anastasiy.com/)
|
||||||
|
3. Run once in Terminal:
|
||||||
2. Open Terminal and run:
|
defaults write com.adobe.CSXS.11 PlayerDebugMode 1
|
||||||
defaults write /Library/Preferences/com.adobe.CSXS.11 PlayerDebugMode 1
|
4. Restart Premiere Pro.
|
||||||
|
|
||||||
3. Restart Premiere Pro
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Building from source
|
||||||
|
|
||||||
|
```
|
||||||
|
cd services/premiere-plugin/build
|
||||||
|
npm install
|
||||||
|
powershell -File build-all.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
See [`build/README.md`](build/README.md).
|
||||||
|
|
||||||
## Access the Panel
|
## Access the Panel
|
||||||
|
|
||||||
Window > Extensions > Wild Dragon MAM
|
Window > Extensions > Wild Dragon MAM
|
||||||
|
|
@ -91,8 +101,9 @@ services/premiere-plugin/
|
||||||
│ └── main.js Panel logic
|
│ └── main.js Panel logic
|
||||||
├── jsx/
|
├── jsx/
|
||||||
│ └── premiere.jsx Premiere integration
|
│ └── premiere.jsx Premiere integration
|
||||||
|
├── build/ Installer build pipeline (.zxp + .exe)
|
||||||
├── README.md Full docs
|
├── README.md Full docs
|
||||||
└── QUICK_START.md This file
|
└── QUICK_START.md This file
|
||||||
```
|
```
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
|
||||||
|
|
@ -16,30 +16,41 @@ A professional media asset management (MAM) plugin for Adobe Premiere Pro that a
|
||||||
|
|
||||||
## Installation
|
## 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:
|
| File | Platform | How to install |
|
||||||
```
|
|------|----------|----------------|
|
||||||
C:\Users\<YourUsername>\AppData\Roaming\Adobe\CEP\extensions\com.wilddragon.mam.panel\
|
| `dragonflight-premiere-panel-<version>-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-<version>.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:
|
### macOS ZXP — one extra step
|
||||||
- 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
|
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:
|
```
|
||||||
```
|
defaults write com.adobe.CSXS.11 PlayerDebugMode 1
|
||||||
~/Library/Application Support/Adobe/CEP/extensions/com.wilddragon.mam.panel/
|
```
|
||||||
```
|
|
||||||
|
|
||||||
2. For unsigned extensions, enable debug mode in the plist:
|
Restart Premiere Pro afterward. The Windows `.exe` installer does this
|
||||||
- Open Terminal
|
automatically for every CEP version Premiere might use (CSXS 8 through 13).
|
||||||
- Run: `defaults write /Library/Preferences/com.adobe.CSXS.11 PlayerDebugMode 1`
|
|
||||||
- Restart Premiere Pro
|
### 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
|
### 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**
|
2. Go to **Window** > **Extensions** > **Wild Dragon MAM**
|
||||||
3. The panel will open as a floating window on the right side
|
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
|
## Usage
|
||||||
|
|
||||||
### Connect to MAM Server
|
### Connect to MAM Server
|
||||||
|
|
@ -102,7 +129,7 @@ To change the server URL:
|
||||||
## File Structure
|
## File Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
com.wilddragon.mam.panel/
|
net.wilddragon.dragonflight.panel/ # installed bundle
|
||||||
├── CSXS/
|
├── CSXS/
|
||||||
│ └── manifest.xml # CEP extension manifest
|
│ └── manifest.xml # CEP extension manifest
|
||||||
├── css/
|
├── css/
|
||||||
|
|
@ -113,8 +140,15 @@ com.wilddragon.mam.panel/
|
||||||
├── jsx/
|
├── jsx/
|
||||||
│ └── premiere.jsx # Premiere Pro ExtendScript
|
│ └── premiere.jsx # Premiere Pro ExtendScript
|
||||||
├── index.html # Main panel UI
|
├── index.html # Main panel UI
|
||||||
├── .debug # CEP debug configuration
|
├── .debug # CEP debug configuration
|
||||||
└── README.md # This file
|
└── 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
|
## API Integration
|
||||||
|
|
|
||||||
4
services/premiere-plugin/build/.gitignore
vendored
Normal file
4
services/premiere-plugin/build/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
|
stage/
|
||||||
|
*.log
|
||||||
86
services/premiere-plugin/build/README.md
Normal file
86
services/premiere-plugin/build/README.md
Normal file
|
|
@ -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-<version>.zxp` | macOS + Windows | Drag into [Anastasiy's ZXP Installer](https://install.anastasiy.com/) |
|
||||||
|
| `dist/dragonflight-premiere-panel-<version>-windows-setup.exe` | Windows | Double-click, Next → Finish |
|
||||||
|
|
||||||
|
The version is read from `CSXS/manifest.xml`'s `<ExtensionBundleVersion>`. 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
|
||||||
|
powershell -File build-all.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
Artifacts land in `services/premiere-plugin/build/dist/`.
|
||||||
|
|
||||||
|
To build just one:
|
||||||
|
|
||||||
|
```
|
||||||
|
node build-zxp.mjs # cross-platform .zxp
|
||||||
|
powershell -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)
|
||||||
|
```
|
||||||
34
services/premiere-plugin/build/build-all.ps1
Normal file
34
services/premiere-plugin/build/build-all.ps1
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
# Dragonflight Premiere panel — build everything
|
||||||
|
#
|
||||||
|
# Produces both artifacts in dist/:
|
||||||
|
# - dragonflight-premiere-panel-<version>.zxp (Mac + Win)
|
||||||
|
# - dragonflight-premiere-panel-<version>-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)
|
||||||
|
}
|
||||||
60
services/premiere-plugin/build/build-installer.ps1
Normal file
60
services/premiere-plugin/build/build-installer.ps1
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
# 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"
|
||||||
|
}
|
||||||
|
# Regex over XML because [xml] is strict about things Adobe CEP tolerates.
|
||||||
|
# Accept either the element form (<ExtensionBundleVersion>X.Y.Z</...>) or the
|
||||||
|
# attribute form (ExtensionBundleVersion="X.Y.Z") used by CSXS 7.0+ manifests.
|
||||||
|
$manifestRaw = Get-Content -Raw -Path $manifestPath
|
||||||
|
$version = $null
|
||||||
|
if ($manifestRaw -match '<ExtensionBundleVersion>([^<]+)</ExtensionBundleVersion>') {
|
||||||
|
$version = $Matches[1].Trim()
|
||||||
|
} elseif ($manifestRaw -match 'ExtensionBundleVersion\s*=\s*"([^"]+)"') {
|
||||||
|
$version = $Matches[1].Trim()
|
||||||
|
}
|
||||||
|
if (-not $version) {
|
||||||
|
throw 'Could not read ExtensionBundleVersion from manifest.xml'
|
||||||
|
}
|
||||||
|
Write-Host "Dragonflight Premiere panel - Windows installer build v$version"
|
||||||
|
|
||||||
|
$iscc = Get-Command 'ISCC.exe' -ErrorAction SilentlyContinue
|
||||||
|
if (-not $iscc) {
|
||||||
|
# Common Inno Setup 6 install locations. winget user-scope drops it in
|
||||||
|
# %LOCALAPPDATA%\Programs; machine-wide installs land in Program Files.
|
||||||
|
$fallbacks = @(
|
||||||
|
"${env:LOCALAPPDATA}\Programs\Inno Setup 6\ISCC.exe",
|
||||||
|
"${env:ProgramFiles(x86)}\Inno Setup 6\ISCC.exe",
|
||||||
|
"${env:ProgramFiles}\Inno Setup 6\ISCC.exe"
|
||||||
|
)
|
||||||
|
foreach ($p in $fallbacks) {
|
||||||
|
if (Test-Path $p) { $iscc = Get-Command $p; break }
|
||||||
|
}
|
||||||
|
if (-not $iscc) {
|
||||||
|
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)"
|
||||||
102
services/premiere-plugin/build/build-zxp.mjs
Normal file
102
services/premiere-plugin/build/build-zxp.mjs
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
// Build a signed .zxp for the Dragonflight Premiere panel.
|
||||||
|
//
|
||||||
|
// - Reads version from ../CSXS/manifest.xml (<ExtensionBundleVersion>)
|
||||||
|
// - 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-<version>.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');
|
||||||
|
|
||||||
|
// Top-level entries 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');
|
||||||
|
// Accept either <ExtensionBundleVersion>X.Y.Z</ExtensionBundleVersion> (the
|
||||||
|
// namespace-style manifest) or ExtensionBundleVersion="X.Y.Z" (the attribute
|
||||||
|
// form used by the CSXS 7.0+ schema).
|
||||||
|
const m = xml.match(/<ExtensionBundleVersion>([^<]+)<\/ExtensionBundleVersion>/)
|
||||||
|
|| xml.match(/\bExtensionBundleVersion\s*=\s*"([^"]+)"/);
|
||||||
|
if (!m) throw new Error(`Could not find ExtensionBundleVersion in ${MANIFEST}`);
|
||||||
|
return m[1].trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
async 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 });
|
||||||
|
await zxp.selfSignedCert({
|
||||||
|
country: 'US',
|
||||||
|
province: 'WA',
|
||||||
|
org: 'Wild Dragon LLC',
|
||||||
|
name: 'Wild Dragon LLC',
|
||||||
|
password: passphrase,
|
||||||
|
output: CERT_FILE,
|
||||||
|
validityDays: 365 * 25,
|
||||||
|
});
|
||||||
|
console.log(` wrote ${CERT_FILE}`);
|
||||||
|
console.log(` wrote ${PASS_FILE}`);
|
||||||
|
console.log(' >> COMMIT both files so future builds reuse them. <<');
|
||||||
|
return 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 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function signZxp(version, passphrase) {
|
||||||
|
mkdirSync(DIST_DIR, { recursive: true });
|
||||||
|
const output = join(DIST_DIR, `dragonflight-premiere-panel-${version}.zxp`);
|
||||||
|
if (existsSync(output)) rmSync(output);
|
||||||
|
await zxp.sign({
|
||||||
|
input: STAGE_DIR,
|
||||||
|
output,
|
||||||
|
cert: CERT_FILE,
|
||||||
|
password: passphrase,
|
||||||
|
});
|
||||||
|
const bytes = statSync(output).size;
|
||||||
|
console.log(`Built ${output} (${(bytes / 1024).toFixed(1)} KB)`);
|
||||||
|
return 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);
|
||||||
|
});
|
||||||
45
services/premiere-plugin/build/cert/README.md
Normal file
45
services/premiere-plugin/build/cert/README.md
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
The build script handles regeneration automatically — just delete both
|
||||||
|
files and re-run `node build-zxp.mjs`. If you need to invoke Adobe's
|
||||||
|
`ZXPSignCmd` directly (e.g. to inspect the generated cert), it ships inside
|
||||||
|
`node_modules/zxp-provider/bin/<version>/` after `npm install`.
|
||||||
1
services/premiere-plugin/build/cert/cert-passphrase.txt
Normal file
1
services/premiere-plugin/build/cert/cert-passphrase.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
k_rdrajiNn_qQcW2Oc9Z2Kc0rG4AP8vA
|
||||||
BIN
services/premiere-plugin/build/cert/dragonflight-selfsigned.p12
Normal file
BIN
services/premiere-plugin/build/cert/dragonflight-selfsigned.p12
Normal file
Binary file not shown.
79
services/premiere-plugin/build/installer.iss
Normal file
79
services/premiere-plugin/build/installer.iss
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
; 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;
|
||||||
|
|
||||||
|
[Run]
|
||||||
|
Filename: "{app}\README.md"; Description: "Open README"; Flags: shellexec postinstall skipifsilent unchecked
|
||||||
43
services/premiere-plugin/build/package-lock.json
generated
Normal file
43
services/premiere-plugin/build/package-lock.json
generated
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
{
|
||||||
|
"name": "dragonflight-premiere-panel-build",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "dragonflight-premiere-panel-build",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"devDependencies": {
|
||||||
|
"zxp-sign-cmd": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/zxp-provider": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/zxp-provider/-/zxp-provider-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-ja2YZwDnDrTdq5Q0EebOaHQK5f4tOf5488mKV4sVC/mKyNiXHyJlyKwLWB4SGIrvqqWWkDk/QCfsWms2jTQ/Tw==",
|
||||||
|
"dev": true,
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/zxp-sign-cmd": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/zxp-sign-cmd/-/zxp-sign-cmd-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-BzWNvp6kSL4RFmxWp8MkVtJ4NIuRq1238W0ojHWLgeAqWMaptFdY8Nh2Uguf7Fka8KyIinrf0+tTgCeGlWPMoA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"zxp-provider": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0",
|
||||||
|
"npm": ">=6.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
services/premiere-plugin/build/package.json
Normal file
18
services/premiere-plugin/build/package.json
Normal file
|
|
@ -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": "powershell -NoProfile -ExecutionPolicy Bypass -File build-installer.ps1",
|
||||||
|
"build": "powershell -NoProfile -ExecutionPolicy Bypass -File build-all.ps1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"zxp-sign-cmd": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
}
|
||||||
33
services/premiere-plugin/build/releases/v1.0.0/README.md
Normal file
33
services/premiere-plugin/build/releases/v1.0.0/README.md
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
# Dragonflight Premiere Panel — v1.0.0
|
||||||
|
|
||||||
|
Built 2026-05-23 from `feat/premiere-installer` (initial installer
|
||||||
|
release).
|
||||||
|
|
||||||
|
## Artifacts
|
||||||
|
|
||||||
|
| File | Size | Install path |
|
||||||
|
|------|------|--------------|
|
||||||
|
| [dragonflight-premiere-panel-1.0.0-windows-setup.exe](dragonflight-premiere-panel-1.0.0-windows-setup.exe) | 2.0 MB | Windows — double-click, Next → Finish |
|
||||||
|
| [dragonflight-premiere-panel-1.0.0.zxp](dragonflight-premiere-panel-1.0.0.zxp) | 35 KB | macOS + Windows — drag into [Anastasiy's ZXP Installer](https://install.anastasiy.com/) |
|
||||||
|
|
||||||
|
Bundle ID: `net.wilddragon.dragonflight.panel`. Replaces any prior
|
||||||
|
`com.wilddragon.mam.panel` install (the `.exe` offers to remove it via a
|
||||||
|
wizard checkbox; for the `.zxp`, delete the old folder manually).
|
||||||
|
|
||||||
|
## Reproducing
|
||||||
|
|
||||||
|
```
|
||||||
|
cd services/premiere-plugin/build
|
||||||
|
npm install
|
||||||
|
powershell -File build-all.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
Requires Node 18+ and Inno Setup 6 (`winget install JRSoftware.InnoSetup`).
|
||||||
|
See [`../README.md`](../../README.md) for the full build pipeline.
|
||||||
|
|
||||||
|
## ZXP signing cert
|
||||||
|
|
||||||
|
Signed with the self-signed cert at `../../cert/dragonflight-selfsigned.p12`
|
||||||
|
(CN: `Wild Dragon LLC`, valid until 2051-05-17). Editors installing the
|
||||||
|
`.zxp` must enable `PlayerDebugMode=1` once for CEP to accept the unsigned
|
||||||
|
chain. The `.exe` installer handles this automatically for CSXS 8..13.
|
||||||
Binary file not shown.
Binary file not shown.
43
services/premiere-plugin/build/releases/v1.0.1/README.md
Normal file
43
services/premiere-plugin/build/releases/v1.0.1/README.md
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
# Dragonflight Premiere Panel — v1.0.1
|
||||||
|
|
||||||
|
Built 2026-05-23 from `feat/premiere-installer`. First release that
|
||||||
|
actually loads under Premiere Pro 2025 (CEP 12) and connects to an
|
||||||
|
auth-enabled mam-api.
|
||||||
|
|
||||||
|
## What changed since v1.0.0
|
||||||
|
|
||||||
|
| Problem | Fix |
|
||||||
|
|---------|-----|
|
||||||
|
| `manifest.xml` had `--` inside an XML comment → CEP 12 refused to parse it | Comment rewritten without double hyphens |
|
||||||
|
| `manifest.xml` lacked a `Version="X.Y"` attribute on the root and used a non-standard `AbstractionLayers`/`ExtensionList` structure → CEP rejected with `Unsupported Manifest version ''` | Rewritten to the standard CSXS 7.0 schema (`ExtensionList` + `DispatchInfoList`), matching the working AMPP panel template |
|
||||||
|
| `main.js` re-declared `const csInterface` at top-level — CSInterface.js already declared the same binding. CEP 12 shares script-realm lexical scope across `<script>` tags, so main.js threw `Identifier 'csInterface' has already been declared` and never ran. The click handler for Connect was never attached → "nothing happens." | Removed the duplicate declaration; main.js now uses the binding set up by CSInterface.js |
|
||||||
|
| No way to authenticate against mam-api when `AUTH_ENABLED=true` (panel only sent `credentials: 'include'`, but it has no session cookie) | Added an "API Token" password field next to Server URL; persists to localStorage; `window.fetch` is monkey-patched to inject `Authorization: Bearer <token>` on every request to the configured server |
|
||||||
|
| Server URL field had a `change`-event listener that only fired on blur — quick "type URL → click Connect" cycles never saved the URL | Switched to `input` event so every keystroke commits. Also normalizes any trailing slash on restore so old saved `http://host/` values stop producing `//api/v1` 404s |
|
||||||
|
| New token input was `type="password"`, but the CSS selector was `input[type="text"].server-url` → unstyled, invisible against the dark theme. The 3-column grid layout also crammed the new row into a button-width slot | Connection bar restructured into a `.connection-controls--stacked` flex column of two `.server-input-row` flex rows; CSS input selector generalized to `input.server-url` |
|
||||||
|
| Build scripts' version-extraction regex only matched the old `<ExtensionBundleVersion>X</...>` element form | Now matches both element and attribute forms |
|
||||||
|
|
||||||
|
## Artifacts
|
||||||
|
|
||||||
|
| File | Size | Install |
|
||||||
|
|------|------|---------|
|
||||||
|
| [dragonflight-premiere-panel-1.0.1-windows-setup.exe](dragonflight-premiere-panel-1.0.1-windows-setup.exe) | 2.0 MB | Windows — double-click |
|
||||||
|
| [dragonflight-premiere-panel-1.0.1.zxp](dragonflight-premiere-panel-1.0.1.zxp) | 35 KB | macOS + Windows — [Anastasiy's ZXP Installer](https://install.anastasiy.com/) |
|
||||||
|
|
||||||
|
## Configuring after install
|
||||||
|
|
||||||
|
1. Open Premiere → **Window → Extensions → Wild Dragon MAM**
|
||||||
|
2. **Server URL**: e.g. `http://10.0.0.25:47434`
|
||||||
|
3. **API token**: generate one via
|
||||||
|
```
|
||||||
|
curl -c cookies.txt -X POST $API/api/v1/auth/login \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"username":"USER","password":"PASS"}'
|
||||||
|
|
||||||
|
curl -b cookies.txt -X POST $API/api/v1/tokens \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"name":"premiere-panel"}'
|
||||||
|
```
|
||||||
|
Paste the returned `token` value (starts with `wd_`) into the panel.
|
||||||
|
4. Click **Connect** — status dot turns green and projects populate the dropdown.
|
||||||
|
|
||||||
|
If your `mam-api` runs with `AUTH_ENABLED` unset/false, the token field can be left empty.
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -79,7 +79,19 @@ html, body {
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="text"].server-url {
|
.connection-controls--stacked {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.server-input-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.server-url {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
background-color: var(--bg-tertiary);
|
background-color: var(--bg-tertiary);
|
||||||
|
|
@ -91,13 +103,13 @@ input[type="text"].server-url {
|
||||||
transition: border-color 0.2s;
|
transition: border-color 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="text"].server-url:focus {
|
input.server-url:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
border-color: var(--accent);
|
border-color: var(--accent);
|
||||||
box-shadow: 0 0 0 2px rgba(233, 69, 96, 0.1);
|
box-shadow: 0 0 0 2px rgba(233, 69, 96, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="text"].server-url::placeholder {
|
input.server-url::placeholder {
|
||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,18 +10,28 @@
|
||||||
<div id="panel-container">
|
<div id="panel-container">
|
||||||
<!-- Connection Bar -->
|
<!-- Connection Bar -->
|
||||||
<div class="connection-bar">
|
<div class="connection-bar">
|
||||||
<div class="connection-controls">
|
<div class="connection-controls connection-controls--stacked">
|
||||||
<div class="server-input-group">
|
<div class="server-input-row">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
id="server-url"
|
id="server-url"
|
||||||
class="server-url"
|
class="server-url"
|
||||||
placeholder="http://localhost:7434"
|
placeholder="http://10.0.0.25:47434"
|
||||||
title="MAM server URL"
|
title="MAM server URL"
|
||||||
>
|
>
|
||||||
<div class="status-indicator" id="status-indicator"></div>
|
<div class="status-indicator" id="status-indicator"></div>
|
||||||
</div>
|
</div>
|
||||||
<button id="connect-btn" class="connect-btn">Connect</button>
|
<div class="server-input-row">
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
id="api-token"
|
||||||
|
class="server-url"
|
||||||
|
placeholder="API token (wd_…)"
|
||||||
|
title="API token — create with POST /api/v1/tokens"
|
||||||
|
autocomplete="off"
|
||||||
|
>
|
||||||
|
<button id="connect-btn" class="connect-btn">Connect</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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'
|
|
||||||
|
|
@ -32,7 +32,7 @@ class CSInterface {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.requestIdCount = 1;
|
this.requestIdCount = 1;
|
||||||
this.requestMap = new Map();
|
this.requestMap = new Map();
|
||||||
this.extensionId = "com.wilddragon.mam.panel";
|
this.extensionId = "net.wilddragon.dragonflight.panel";
|
||||||
|
|
||||||
// Initialize event listener for messages from ExtendScript
|
// Initialize event listener for messages from ExtendScript
|
||||||
if (window.__adobe_cep__ !== undefined) {
|
if (window.__adobe_cep__ !== undefined) {
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,10 @@
|
||||||
* Main JavaScript file for the CEP panel
|
* Main JavaScript file for the CEP panel
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Adobe CEP interface — must be instantiated before any host (ExtendScript) calls
|
// Adobe CEP interface — CSInterface.js already declared `const csInterface`
|
||||||
const csInterface = new CSInterface();
|
// at the script-realm scope (top-level `const` is shared across non-module
|
||||||
|
// <script> tags), so re-declaring it here throws SyntaxError under CEP 12.
|
||||||
|
// We just use the binding that CSInterface.js provides.
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// State Management
|
// State Management
|
||||||
|
|
@ -12,6 +14,7 @@ const csInterface = new CSInterface();
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
serverUrl: localStorage.getItem('mam_server_url') || 'http://localhost:7434',
|
serverUrl: localStorage.getItem('mam_server_url') || 'http://localhost:7434',
|
||||||
|
apiToken: localStorage.getItem('mam_api_token') || '',
|
||||||
isConnected: false,
|
isConnected: false,
|
||||||
isConnecting: false,
|
isConnecting: false,
|
||||||
selectedAsset: null,
|
selectedAsset: null,
|
||||||
|
|
@ -41,6 +44,7 @@ let elements = {};
|
||||||
function initDOMElements() {
|
function initDOMElements() {
|
||||||
elements = {
|
elements = {
|
||||||
serverUrlInput: document.getElementById('server-url'),
|
serverUrlInput: document.getElementById('server-url'),
|
||||||
|
apiTokenInput: document.getElementById('api-token'),
|
||||||
connectBtn: document.getElementById('connect-btn'),
|
connectBtn: document.getElementById('connect-btn'),
|
||||||
statusIndicator: document.getElementById('status-indicator'),
|
statusIndicator: document.getElementById('status-indicator'),
|
||||||
searchInput: document.getElementById('search-input'),
|
searchInput: document.getElementById('search-input'),
|
||||||
|
|
@ -126,11 +130,17 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
function setupEventListeners() {
|
function setupEventListeners() {
|
||||||
elements.serverUrlInput.addEventListener('change', (e) => {
|
// Commit serverUrl on every keystroke so clicking Connect right after
|
||||||
|
// typing works even before the input loses focus.
|
||||||
|
elements.serverUrlInput.addEventListener('input', (e) => {
|
||||||
state.serverUrl = e.target.value.trim().replace(/\/$/, '');
|
state.serverUrl = e.target.value.trim().replace(/\/$/, '');
|
||||||
localStorage.setItem('mam_server_url', state.serverUrl);
|
localStorage.setItem('mam_server_url', state.serverUrl);
|
||||||
state.thumbCache = {};
|
state.thumbCache = {};
|
||||||
});
|
});
|
||||||
|
elements.apiTokenInput.addEventListener('input', (e) => {
|
||||||
|
state.apiToken = e.target.value.trim();
|
||||||
|
localStorage.setItem('mam_api_token', state.apiToken);
|
||||||
|
});
|
||||||
elements.connectBtn.addEventListener('click', connectToServer);
|
elements.connectBtn.addEventListener('click', connectToServer);
|
||||||
elements.searchInput.addEventListener('input', debounce(handleSearch, 300));
|
elements.searchInput.addEventListener('input', debounce(handleSearch, 300));
|
||||||
elements.projectFilter.addEventListener('change', handleProjectFilter);
|
elements.projectFilter.addEventListener('change', handleProjectFilter);
|
||||||
|
|
@ -147,9 +157,36 @@ function setupEventListeners() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function restoreSettings() {
|
function restoreSettings() {
|
||||||
|
// Normalize any trailing slash that the old `change`-event listener may
|
||||||
|
// have missed on previous sessions — otherwise fetches produce //api/v1
|
||||||
|
// and nginx 404s.
|
||||||
|
state.serverUrl = state.serverUrl.replace(/\/+$/, '');
|
||||||
|
localStorage.setItem('mam_server_url', state.serverUrl);
|
||||||
elements.serverUrlInput.value = state.serverUrl;
|
elements.serverUrlInput.value = state.serverUrl;
|
||||||
|
elements.apiTokenInput.value = state.apiToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Auth: monkey-patch fetch to inject Bearer token on every same-origin call
|
||||||
|
// to the configured MAM server. Mam-api requires this when AUTH_ENABLED=true.
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
const _originalFetch = window.fetch.bind(window);
|
||||||
|
window.fetch = function (input, init) {
|
||||||
|
init = init || {};
|
||||||
|
const url = typeof input === 'string' ? input : (input && input.url) || '';
|
||||||
|
// Only attach the token for requests aimed at the configured MAM server.
|
||||||
|
// Signed S3 download URLs etc. must NOT get our Authorization header.
|
||||||
|
if (state.apiToken && state.serverUrl && url.startsWith(state.serverUrl)) {
|
||||||
|
const headers = new Headers(init.headers || {});
|
||||||
|
if (!headers.has('Authorization')) {
|
||||||
|
headers.set('Authorization', 'Bearer ' + state.apiToken);
|
||||||
|
}
|
||||||
|
init.headers = headers;
|
||||||
|
}
|
||||||
|
return _originalFetch(input, init);
|
||||||
|
};
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Server Connection
|
// Server Connection
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue