UXP v2.1.3: import-flow — use window.path.join, replace fs.createWriteStream with fd-based chunked write
This commit is contained in:
parent
fcc737e05b
commit
046d99f57a
1 changed files with 44 additions and 34 deletions
|
|
@ -1,71 +1,80 @@
|
|||
// import-flow.js — v2.1.2
|
||||
// Download asset → write to temp → importFiles() via UXP premierepro.
|
||||
// NOTE: `path` module is NOT available in PPro 26 UXP. Use _join() helper.
|
||||
// Also exposes _tempPath / _streamToFile for timeline.js batch relink.
|
||||
// import-flow.js — v2.1.3
|
||||
// Fixes:
|
||||
// • require('path') → window.path (global, no require needed, UXP v6.4+)
|
||||
// • fs.createWriteStream does NOT exist in UXP fs — replaced with
|
||||
// fd-based chunked write: fs.open → loop fs.write(fd,buf,...) → fs.close
|
||||
// • os.tmpdir() not documented → use os.homedir() / process.env.TEMP fallback
|
||||
|
||||
(function () {
|
||||
const Import = {};
|
||||
|
||||
const fs = require('fs');
|
||||
// `path` is stripped in this UXP build — manual join instead.
|
||||
// path is window.path (global) — no require('path') in UXP
|
||||
// os.tmpdir() missing from docs; os.homedir() is available
|
||||
let os; try { os = require('os'); } catch (_) { os = {}; }
|
||||
let uxpFs; try { uxpFs = require('uxp').storage.localFileSystem; } catch (_) { uxpFs = null; }
|
||||
|
||||
// Simple path join that works on Windows (backslash) without require('path').
|
||||
function _join(base, name) {
|
||||
const sep = base.indexOf('/') === -1 ? '\\' : '/';
|
||||
return base.replace(/[\\/]+$/, '') + sep + name;
|
||||
}
|
||||
|
||||
// ── Temp folder ──────────────────────────────────────────────────
|
||||
// os.tmpdir() not in UXP docs → fall through to other methods
|
||||
async function _getTempBase() {
|
||||
// 1. os.tmpdir (may exist in some UXP builds)
|
||||
try { if (os.tmpdir) { const t = os.tmpdir(); if (typeof t === 'string' && t.length) return t; } } catch (_) {}
|
||||
// 2. UXP storage API
|
||||
// 1. UXP storage API (most portable)
|
||||
if (uxpFs && uxpFs.getTemporaryFolder) {
|
||||
try { const tmp = await uxpFs.getTemporaryFolder(); if (tmp && tmp.nativePath) return tmp.nativePath; } catch (_) {}
|
||||
try {
|
||||
const tmp = await uxpFs.getTemporaryFolder();
|
||||
if (tmp && tmp.nativePath) return tmp.nativePath;
|
||||
} catch (_) {}
|
||||
}
|
||||
// 3. Windows env vars (always present under PPro on Windows)
|
||||
// 2. Windows env vars (always set under PPro on Windows)
|
||||
try {
|
||||
const e = (typeof process !== 'undefined' && process.env) || {};
|
||||
if (e.TEMP) return e.TEMP;
|
||||
if (e.TMP) return e.TMP;
|
||||
if (e.TEMP && e.TEMP.length) return e.TEMP;
|
||||
if (e.TMP && e.TMP.length) return e.TMP;
|
||||
if (e.LOCALAPPDATA) return e.LOCALAPPDATA + '\\Temp';
|
||||
} catch (_) {}
|
||||
// 4. Homedir fallback (no path.join needed)
|
||||
try { if (os.homedir) { const h = os.homedir(); if (h) return h + '\\AppData\\Local\\Temp'; } } catch (_) {}
|
||||
// 3. os.homedir() is documented in UXP os module
|
||||
try {
|
||||
if (os.homedir) {
|
||||
const h = os.homedir();
|
||||
if (h) return h + '\\AppData\\Local\\Temp';
|
||||
}
|
||||
} catch (_) {}
|
||||
throw new Error('Cannot find writable temp folder');
|
||||
}
|
||||
|
||||
// window.path is a documented UXP global (v6.4+) — no require needed
|
||||
Import._tempPath = async function (safeName) {
|
||||
const base = await _getTempBase();
|
||||
return _join(base, 'dragonflight-' + safeName);
|
||||
return path.join(base, 'dragonflight-' + safeName);
|
||||
};
|
||||
|
||||
// ── Stream response body to disk ─────────────────────────────────
|
||||
// ── Stream response body to disk via fd-based chunked write ──────
|
||||
// fs.createWriteStream does NOT exist in UXP's require('fs').
|
||||
// Use open() → write() chunks → close() instead.
|
||||
// Chunk size 256 KB — balances memory vs syscall overhead.
|
||||
Import._streamToFile = async function (response, destPath, onProgress) {
|
||||
const total = Number(response.headers.get('content-length') || 0);
|
||||
const reader = response.body.getReader();
|
||||
const out = fs.createWriteStream(destPath);
|
||||
|
||||
// Open file for writing (create/truncate)
|
||||
const fd = await fs.open(destPath, 'w');
|
||||
let received = 0;
|
||||
const closed = new Promise((resolve, reject) => {
|
||||
out.on('finish', resolve);
|
||||
out.on('error', reject);
|
||||
});
|
||||
let filePos = 0;
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
const { value, done } = await reader.read();
|
||||
if (done) break;
|
||||
if (!out.write(Buffer.from(value))) {
|
||||
await new Promise(r => out.once('drain', r));
|
||||
}
|
||||
|
||||
// value is Uint8Array; fs.write needs ArrayBuffer
|
||||
const buf = value.buffer.slice(value.byteOffset, value.byteOffset + value.byteLength);
|
||||
const { bytesWritten } = await fs.write(fd, buf, 0, buf.byteLength, filePos);
|
||||
filePos += bytesWritten;
|
||||
received += value.byteLength;
|
||||
if (onProgress) onProgress({ received, total });
|
||||
}
|
||||
} finally {
|
||||
out.end();
|
||||
await fs.close(fd);
|
||||
}
|
||||
await closed;
|
||||
return destPath;
|
||||
};
|
||||
|
||||
|
|
@ -100,11 +109,12 @@
|
|||
return Import._ppro_mod;
|
||||
}
|
||||
|
||||
// Import a file already on disk into the active Premiere project.
|
||||
Import.importIntoProject = async function (filePath) {
|
||||
const P = _ppro();
|
||||
const project = await P.Project.getActiveProject();
|
||||
const project = P.Project.getActiveProject();
|
||||
if (!project) throw new Error('No active Premiere project');
|
||||
const root = await project.getRootItem();
|
||||
const root = project.getRootItem();
|
||||
const ok = await project.importFiles([filePath], true, root, false);
|
||||
if (!ok) throw new Error('Premiere refused to import file');
|
||||
return true;
|
||||
|
|
|
|||
Loading…
Reference in a new issue