UXP v2.1.2: import-flow — replace path.join (not in UXP) with manual join helper
This commit is contained in:
parent
f8fa0fa010
commit
17ca9bfc75
1 changed files with 20 additions and 15 deletions
|
|
@ -1,34 +1,45 @@
|
||||||
// import-flow.js — v2.1.1
|
// import-flow.js — v2.1.2
|
||||||
// Download asset → write to temp → importFiles() via UXP premierepro.
|
// 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.
|
// Also exposes _tempPath / _streamToFile for timeline.js batch relink.
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
const Import = {};
|
const Import = {};
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
// `path` is stripped in this UXP build — manual join instead.
|
||||||
let os; try { os = require('os'); } catch (_) { os = {}; }
|
let os; try { os = require('os'); } catch (_) { os = {}; }
|
||||||
let uxpFs; try { uxpFs = require('uxp').storage.localFileSystem; } catch (_) { uxpFs = null; }
|
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 ──────────────────────────────────────────────────
|
// ── Temp folder ──────────────────────────────────────────────────
|
||||||
async function _getTempBase() {
|
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 (_) {}
|
try { if (os.tmpdir) { const t = os.tmpdir(); if (typeof t === 'string' && t.length) return t; } } catch (_) {}
|
||||||
|
// 2. UXP storage API
|
||||||
if (uxpFs && uxpFs.getTemporaryFolder) {
|
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)
|
||||||
try {
|
try {
|
||||||
const e = (typeof process !== 'undefined' && process.env) || {};
|
const e = (typeof process !== 'undefined' && process.env) || {};
|
||||||
if (e.TEMP) return e.TEMP;
|
if (e.TEMP) return e.TEMP;
|
||||||
if (e.TMP) return e.TMP;
|
if (e.TMP) return e.TMP;
|
||||||
if (e.LOCALAPPDATA) return path.join(e.LOCALAPPDATA, 'Temp');
|
if (e.LOCALAPPDATA) return e.LOCALAPPDATA + '\\Temp';
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
try { if (os.homedir) return path.join(os.homedir(), 'AppData', 'Local', '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 (_) {}
|
||||||
throw new Error('Cannot find writable temp folder');
|
throw new Error('Cannot find writable temp folder');
|
||||||
}
|
}
|
||||||
|
|
||||||
Import._tempPath = async function (safeName) {
|
Import._tempPath = async function (safeName) {
|
||||||
const base = await _getTempBase();
|
const base = await _getTempBase();
|
||||||
return path.join(base, 'dragonflight-' + safeName);
|
return _join(base, 'dragonflight-' + safeName);
|
||||||
};
|
};
|
||||||
|
|
||||||
// ── Stream response body to disk ─────────────────────────────────
|
// ── Stream response body to disk ─────────────────────────────────
|
||||||
|
|
@ -39,7 +50,7 @@
|
||||||
let received = 0;
|
let received = 0;
|
||||||
const closed = new Promise((resolve, reject) => {
|
const closed = new Promise((resolve, reject) => {
|
||||||
out.on('finish', resolve);
|
out.on('finish', resolve);
|
||||||
out.on('error', reject);
|
out.on('error', reject);
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
@ -59,7 +70,6 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
// ── Manual redirect follow ───────────────────────────────────────
|
// ── Manual redirect follow ───────────────────────────────────────
|
||||||
// UXP strips Authorization on cross-origin redirects. Follow manually.
|
|
||||||
async function _fetchFollow(url, opts) {
|
async function _fetchFollow(url, opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
let current = url;
|
let current = url;
|
||||||
|
|
@ -70,7 +80,6 @@
|
||||||
const loc = r.headers.get('location');
|
const loc = r.headers.get('location');
|
||||||
if (!loc) throw new Error('Redirect with no Location');
|
if (!loc) throw new Error('Redirect with no Location');
|
||||||
const next = /^https?:\/\//i.test(loc) ? loc : new URL(loc, current).toString();
|
const next = /^https?:\/\//i.test(loc) ? loc : new URL(loc, current).toString();
|
||||||
// Drop auth on cross-origin hop
|
|
||||||
if (new URL(next).host !== new URL(current).host) {
|
if (new URL(next).host !== new URL(current).host) {
|
||||||
opts = Object.assign({}, opts, { headers: Object.assign({}, opts.headers || {}) });
|
opts = Object.assign({}, opts, { headers: Object.assign({}, opts.headers || {}) });
|
||||||
delete opts.headers['Authorization'];
|
delete opts.headers['Authorization'];
|
||||||
|
|
@ -91,7 +100,6 @@
|
||||||
return Import._ppro_mod;
|
return Import._ppro_mod;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Import a file that is already on disk into the active Premiere project.
|
|
||||||
Import.importIntoProject = async function (filePath) {
|
Import.importIntoProject = async function (filePath) {
|
||||||
const P = _ppro();
|
const P = _ppro();
|
||||||
const project = await P.Project.getActiveProject();
|
const project = await P.Project.getActiveProject();
|
||||||
|
|
@ -103,7 +111,6 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
// ── Proxy import ─────────────────────────────────────────────────
|
// ── Proxy import ─────────────────────────────────────────────────
|
||||||
// Returns { localPath, safeName } for caller to record import mapping.
|
|
||||||
Import.proxy = async function (asset) {
|
Import.proxy = async function (asset) {
|
||||||
const safeName = UI.sanitizeFilename((asset.display_name || asset.filename || asset.id) + '.mp4');
|
const safeName = UI.sanitizeFilename((asset.display_name || asset.filename || asset.id) + '.mp4');
|
||||||
const dest = await Import._tempPath(safeName);
|
const dest = await Import._tempPath(safeName);
|
||||||
|
|
@ -128,7 +135,6 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
// ── Hi-Res import ────────────────────────────────────────────────
|
// ── Hi-Res import ────────────────────────────────────────────────
|
||||||
// Returns { localPath, safeName }.
|
|
||||||
Import.hires = async function (asset) {
|
Import.hires = async function (asset) {
|
||||||
UI.showProgress('Resolving hi-res URL…', 4);
|
UI.showProgress('Resolving hi-res URL…', 4);
|
||||||
const info = await API.getHiresInfo(asset.id);
|
const info = await API.getHiresInfo(asset.id);
|
||||||
|
|
@ -136,7 +142,6 @@
|
||||||
const dest = await Import._tempPath(safeName);
|
const dest = await Import._tempPath(safeName);
|
||||||
|
|
||||||
UI.showProgress('Downloading ' + safeName + ' (' + UI.formatBytes(Number(info.file_size || 0)) + ')…', 8);
|
UI.showProgress('Downloading ' + safeName + ' (' + UI.formatBytes(Number(info.file_size || 0)) + ')…', 8);
|
||||||
// Presigned S3 URL — no Bearer needed
|
|
||||||
const r = await _fetchFollow(info.url, {});
|
const r = await _fetchFollow(info.url, {});
|
||||||
if (!r.ok) throw new Error('Download HTTP ' + r.status);
|
if (!r.ok) throw new Error('Download HTTP ' + r.status);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue