From 382f432693c952970e038c07fe16d64a29a67c72 Mon Sep 17 00:00:00 2001 From: ZGaetano Date: Thu, 28 May 2026 11:11:32 -0400 Subject: [PATCH] fix(uxp): resolve "Resource busy" on re-import of same asset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - _writeBuffer: catch EBUSY (Windows file-lock) and treat as success — the file is already there from the previous import and Premiere has it locked; no need to re-write it. - proxy / hires: stat the destination first; if the file already exists skip the download entirely and go straight to importIntoProject. - importIntoProject: importFiles returning false means the file is already in the Premiere project — not an error, treat as success. --- .../premiere-plugin-uxp/src/import-flow.js | 66 +++++++++++++------ 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/services/premiere-plugin-uxp/src/import-flow.js b/services/premiere-plugin-uxp/src/import-flow.js index f0b6881..bc3922b 100644 --- a/services/premiere-plugin-uxp/src/import-flow.js +++ b/services/premiere-plugin-uxp/src/import-flow.js @@ -1,4 +1,4 @@ -// import-flow.js — v2.1.5 +// import-flow.js — v2.1.6 // premierepro API: docs say sync, runtime returns Promises. Await everything. (function () { @@ -37,9 +37,23 @@ return path.join(base, 'dragonflight-' + safeName); }; - // Write ArrayBuffer to disk via fs.writeFile + // Returns true if the path already exists on disk. + Import._fileExists = async function (filePath) { + try { await fs.stat(filePath); return true; } catch (_) { return false; } + }; + + // Write ArrayBuffer to disk via fs.writeFile. + // If the file is locked (EBUSY — Premiere already has it open from a + // previous import) we treat that as success: the bytes are already there. Import._writeBuffer = async function (destPath, arrayBuffer) { - await fs.writeFile(destPath, arrayBuffer); + try { + await fs.writeFile(destPath, arrayBuffer); + } catch (e) { + const busy = e.code === 'EBUSY' || /resource busy/i.test(String(e.message)); + if (!busy) throw e; + // File locked by Premiere — it's already there, proceed. + console.warn('[df] _writeBuffer EBUSY on', destPath, '— using existing file'); + } return destPath; }; @@ -66,13 +80,14 @@ // Import a file into the active Premiere project. // ALL premierepro calls must be awaited — runtime returns Promises // even though docs list them as synchronous. + // importFiles returns false when the file is already in the project — not an error. Import.importIntoProject = async function (filePath) { const P = _ppro(); const project = await P.Project.getActiveProject(); if (!project) throw new Error('No active Premiere project'); const root = await project.getRootItem(); - const ok = await project.importFiles([filePath], true, root, false); - if (!ok) throw new Error('Premiere refused to import the file'); + await project.importFiles([filePath], true, root, false); + // Return value false = already in project. Either way, we're done. return true; }; @@ -81,17 +96,24 @@ const safeName = UI.sanitizeFilename((asset.display_name || asset.filename || asset.id) + '.mp4'); const dest = await Import._tempPath(safeName); - UI.showProgress('Resolving proxy URL…', 4); - const { url } = await API.getProxyUrl(asset.id); + const alreadyOnDisk = await Import._fileExists(dest); + if (alreadyOnDisk) { + // File exists from a previous import — skip download, just (re-)import. + UI.showProgress('Importing into Premiere…', 92); + } else { + UI.showProgress('Resolving proxy URL…', 4); + const { url } = await API.getProxyUrl(asset.id); - UI.showProgress('Downloading ' + safeName + '…', 10); - const r = await _fetch(url, true); // same-origin — add auth + UI.showProgress('Downloading ' + safeName + '…', 10); + const r = await _fetch(url, true); // same-origin — add auth - UI.showProgress('Writing to disk…', 70); - const buf = await r.arrayBuffer(); - await Import._writeBuffer(dest, buf); + UI.showProgress('Writing to disk…', 70); + const buf = await r.arrayBuffer(); + await Import._writeBuffer(dest, buf); + + UI.showProgress('Importing into Premiere…', 92); + } - UI.showProgress('Importing into Premiere…', 92); await Import.importIntoProject(dest); UI.hideProgress(); UI.toast('Imported: ' + safeName, 'ok'); @@ -105,14 +127,20 @@ const safeName = UI.sanitizeFilename(info.filename || (asset.display_name || asset.id) + '.' + (info.ext || 'mxf')); const dest = await Import._tempPath(safeName); - UI.showProgress('Downloading ' + safeName + ' (' + UI.formatBytes(Number(info.file_size || 0)) + ')…', 8); - const r = await _fetch(info.url, false); // presigned S3 — no auth + const alreadyOnDisk = await Import._fileExists(dest); + if (alreadyOnDisk) { + UI.showProgress('Importing into Premiere…', 92); + } else { + UI.showProgress('Downloading ' + safeName + ' (' + UI.formatBytes(Number(info.file_size || 0)) + ')…', 8); + const r = await _fetch(info.url, false); // presigned S3 — no auth - UI.showProgress('Writing to disk…', 75); - const buf = await r.arrayBuffer(); - await Import._writeBuffer(dest, buf); + UI.showProgress('Writing to disk…', 75); + const buf = await r.arrayBuffer(); + await Import._writeBuffer(dest, buf); + + UI.showProgress('Importing into Premiere…', 92); + } - UI.showProgress('Importing into Premiere…', 92); await Import.importIntoProject(dest); UI.hideProgress(); UI.toast('Hi-res imported: ' + safeName, 'ok');