UXP v2.1.5: main.js — fix relink handler: await getActiveProject, use requestExternal + arrayBuffer
This commit is contained in:
parent
469521d524
commit
7f0ca5922f
1 changed files with 35 additions and 63 deletions
|
|
@ -1,4 +1,4 @@
|
|||
// Dragonflight UXP Panel — main.js v2.1.3
|
||||
// Dragonflight UXP Panel — main.js v2.1.5
|
||||
|
||||
(function () {
|
||||
if (window.__df_uxp_started) return;
|
||||
|
|
@ -10,7 +10,6 @@
|
|||
$('connect-btn').disabled = !$('server-url').value.trim() || !$('api-token').value.trim();
|
||||
}
|
||||
|
||||
// ── Connect ──────────────────────────────────────────────────────
|
||||
async function tryConnect(serverUrl, apiToken) {
|
||||
UI.setStatus('#connect-status', 'Connecting…', 'muted');
|
||||
try {
|
||||
|
|
@ -30,7 +29,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
// ── Connect pane ─────────────────────────────────────────────────
|
||||
function wireConnectPane() {
|
||||
$('server-url').value = API.state.serverUrl;
|
||||
$('api-token').value = API.state.apiToken;
|
||||
|
|
@ -44,7 +42,6 @@
|
|||
});
|
||||
}
|
||||
|
||||
// ── Library pane ─────────────────────────────────────────────────
|
||||
function wireLibraryPane() {
|
||||
$('disconnect-btn').addEventListener('click', () => {
|
||||
API.disconnect();
|
||||
|
|
@ -77,33 +74,28 @@
|
|||
|
||||
$('refresh-btn').addEventListener('click', () => Library.refresh($('search-input').value));
|
||||
|
||||
// ── Import proxy ──
|
||||
$('import-proxy-btn').addEventListener('click', async () => {
|
||||
const a = Library.selectedAsset();
|
||||
if (!a) return;
|
||||
const a = Library.selectedAsset(); if (!a) return;
|
||||
_disableImportBtns(true);
|
||||
try {
|
||||
const { localPath, safeName } = await Import.proxy(a);
|
||||
Library.recordImport(localPath, { assetId: a.id, displayName: a.display_name || a.filename });
|
||||
Library.recordImport(localPath, { assetId: a.id, displayName: a.display_name || a.filename });
|
||||
Library.recordImport('name:' + safeName, { assetId: a.id, displayName: a.display_name || a.filename });
|
||||
} catch (e) { UI.hideProgress(); UI.toast('Proxy import failed: ' + e.message, 'error'); }
|
||||
finally { _disableImportBtns(false); Library._syncActions(); }
|
||||
});
|
||||
|
||||
// ── Import hi-res ──
|
||||
$('import-hires-btn').addEventListener('click', async () => {
|
||||
const a = Library.selectedAsset();
|
||||
if (!a) return;
|
||||
const a = Library.selectedAsset(); if (!a) return;
|
||||
_disableImportBtns(true);
|
||||
try {
|
||||
const { localPath, safeName } = await Import.hires(a);
|
||||
Library.recordImport(localPath, { assetId: a.id, displayName: a.display_name || a.filename });
|
||||
Library.recordImport(localPath, { assetId: a.id, displayName: a.display_name || a.filename });
|
||||
Library.recordImport('name:' + safeName, { assetId: a.id, displayName: a.display_name || a.filename });
|
||||
} catch (e) { UI.hideProgress(); UI.toast('Hi-res import failed: ' + e.message, 'error'); }
|
||||
finally { _disableImportBtns(false); Library._syncActions(); }
|
||||
});
|
||||
|
||||
// ── Import all ──
|
||||
$('import-all-btn').addEventListener('click', async () => {
|
||||
const assets = Library.state.assets;
|
||||
if (!assets.length) { UI.toast('No assets', 'error'); return; }
|
||||
|
|
@ -112,7 +104,7 @@
|
|||
for (const a of assets) {
|
||||
try {
|
||||
const { localPath, safeName } = await Import.proxy(a);
|
||||
Library.recordImport(localPath, { assetId: a.id, displayName: a.display_name || a.filename });
|
||||
Library.recordImport(localPath, { assetId: a.id, displayName: a.display_name || a.filename });
|
||||
Library.recordImport('name:' + safeName, { assetId: a.id, displayName: a.display_name || a.filename });
|
||||
ok++;
|
||||
} catch (_) { fail++; }
|
||||
|
|
@ -123,10 +115,8 @@
|
|||
Library._syncActions();
|
||||
});
|
||||
|
||||
// ── Mount live ──
|
||||
$('mount-live-btn').addEventListener('click', async () => {
|
||||
const a = Library.selectedAsset();
|
||||
if (!a) return;
|
||||
const a = Library.selectedAsset(); if (!a) return;
|
||||
$('mount-live-btn').disabled = true;
|
||||
UI.showProgress('Resolving live path…', 10);
|
||||
try {
|
||||
|
|
@ -138,16 +128,14 @@
|
|||
Library.startLiveStatusPoll(a.id);
|
||||
UI.hideProgress();
|
||||
UI.toast('Mounted live: ' + (info.display_name || a.id), 'ok');
|
||||
} catch (e) {
|
||||
UI.hideProgress();
|
||||
UI.toast('Mount live failed: ' + e.message, 'error');
|
||||
} finally { Library._syncActions(); }
|
||||
} catch (e) { UI.hideProgress(); UI.toast('Mount live failed: ' + e.message, 'error'); }
|
||||
finally { Library._syncActions(); }
|
||||
});
|
||||
|
||||
// ── Relink single asset (proxy → hi-res) ──
|
||||
// ALL premierepro calls must be awaited — runtime returns Promises
|
||||
$('relink-btn').addEventListener('click', async () => {
|
||||
const a = Library.selectedAsset();
|
||||
if (!a) return;
|
||||
const a = Library.selectedAsset(); if (!a) return;
|
||||
const entry = Library.getImport('live:' + a.id);
|
||||
if (!entry) { UI.toast('No live mount recorded', 'error'); return; }
|
||||
$('relink-btn').disabled = true;
|
||||
|
|
@ -157,25 +145,22 @@
|
|||
const safeName = UI.sanitizeFilename(info.filename || (a.display_name || a.id) + '.' + (info.ext || 'mxf'));
|
||||
const dest = await Import._tempPath(safeName);
|
||||
UI.showProgress('Downloading ' + safeName + '…', 20);
|
||||
const r = await API.requestFollow(info.url, {});
|
||||
// S3 presigned URL — no auth, auto-follow redirects (UXP handles)
|
||||
const r = await API.requestExternal(info.url);
|
||||
if (!r.ok) throw new Error('Download HTTP ' + r.status);
|
||||
await Import._streamToFile(r, dest, ({ received, total }) => {
|
||||
const pct = total ? 20 + (received / total) * 60 : 20;
|
||||
UI.showProgress(UI.formatBytes(received) + '…', pct);
|
||||
});
|
||||
UI.showProgress('Writing to disk…', 65);
|
||||
const buf = await r.arrayBuffer();
|
||||
await Import._writeBuffer(dest, buf);
|
||||
UI.showProgress('Relinking…', 85);
|
||||
// Timeline._relinkInProject uses ppro() internally (sync getActiveProject)
|
||||
const P = require('premierepro');
|
||||
const proj = P.Project.getActiveProject(); // sync — no await
|
||||
const proj = await P.Project.getActiveProject(); // ← must await
|
||||
if (!proj) throw new Error('No active project');
|
||||
await Timeline._relinkInProject(proj, entry.livePath, dest);
|
||||
Library.recordImport(dest, { assetId: a.id, displayName: a.display_name || a.filename });
|
||||
UI.hideProgress();
|
||||
UI.toast('Relinked: ' + safeName, 'ok');
|
||||
} catch (e) {
|
||||
UI.hideProgress();
|
||||
UI.toast('Relink failed: ' + e.message, 'error');
|
||||
} finally { Library._syncActions(); }
|
||||
} catch (e) { UI.hideProgress(); UI.toast('Relink failed: ' + e.message, 'error'); }
|
||||
finally { Library._syncActions(); }
|
||||
});
|
||||
|
||||
$('export-timeline-btn').addEventListener('click', openExportPanel);
|
||||
|
|
@ -187,7 +172,6 @@
|
|||
['import-proxy-btn','import-hires-btn'].forEach(id => { $(id).disabled = dis; });
|
||||
}
|
||||
|
||||
// ── Export timeline panel ─────────────────────────────────────────
|
||||
let _seqCache = null;
|
||||
|
||||
async function openExportPanel() {
|
||||
|
|
@ -222,7 +206,6 @@
|
|||
});
|
||||
}
|
||||
|
||||
// ── Conform panel ─────────────────────────────────────────────────
|
||||
async function openConformPanel() {
|
||||
UI.showProgress('Reading Premiere sequence…', 20);
|
||||
try { _seqCache = await Timeline.readActiveSequence(); }
|
||||
|
|
@ -237,8 +220,7 @@
|
|||
if (conformProj) {
|
||||
conformProj.innerHTML = '<option value="">— Select project —</option>';
|
||||
Library.state.projects.forEach(p => {
|
||||
const o = document.createElement('option');
|
||||
o.value = p.id; o.textContent = p.name;
|
||||
const o = document.createElement('option'); o.value = p.id; o.textContent = p.name;
|
||||
conformProj.appendChild(o);
|
||||
});
|
||||
}
|
||||
|
|
@ -250,20 +232,16 @@
|
|||
$('conform-cancel-btn').addEventListener('click', () => UI.closeSlide('conform-overlay', 'conform-panel'));
|
||||
$('conform-overlay').addEventListener('click', () => UI.closeSlide('conform-overlay', 'conform-panel'));
|
||||
$('preset-cards').addEventListener('click', e => {
|
||||
const card = e.target.closest('.preset-card');
|
||||
if (!card) return;
|
||||
const card = e.target.closest('.preset-card'); if (!card) return;
|
||||
document.querySelectorAll('.preset-card').forEach(c => c.classList.remove('selected'));
|
||||
card.classList.add('selected');
|
||||
const presets = {
|
||||
broadcast: { codec:'prores_hq', quality:'high', resolution:'1080p', audio:'broadcast' },
|
||||
web: { codec:'h264', quality:'medium', resolution:'1080p', audio:'web' },
|
||||
archive: { codec:'prores_4444', quality:'high', resolution:'uhd', audio:'archive' },
|
||||
broadcast: { codec:'prores_hq', quality:'high', resolution:'1080p', audio:'broadcast' },
|
||||
web: { codec:'h264', quality:'medium', resolution:'1080p', audio:'web' },
|
||||
archive: { codec:'prores_4444', quality:'high', resolution:'uhd', audio:'archive' },
|
||||
};
|
||||
const p = presets[card.dataset.preset];
|
||||
if (p) {
|
||||
$('conform-codec').value = p.codec; $('conform-quality').value = p.quality;
|
||||
$('conform-resolution').value = p.resolution; $('conform-audio').value = p.audio;
|
||||
}
|
||||
if (p) { $('conform-codec').value=p.codec; $('conform-quality').value=p.quality; $('conform-resolution').value=p.resolution; $('conform-audio').value=p.audio; }
|
||||
});
|
||||
$('conform-start-btn').addEventListener('click', async () => {
|
||||
if (!_seqCache) return;
|
||||
|
|
@ -274,22 +252,21 @@
|
|||
UI.showProgress('Starting conform job…', 15);
|
||||
try {
|
||||
const jobId = await Timeline.startConform(projectId, _seqCache.sequenceName, _seqCache, {
|
||||
codec: $('conform-codec').value, quality: $('conform-quality').value,
|
||||
resolution: $('conform-resolution').value, audio: $('conform-audio').value,
|
||||
codec:$('conform-codec').value, quality:$('conform-quality').value,
|
||||
resolution:$('conform-resolution').value, audio:$('conform-audio').value,
|
||||
});
|
||||
Timeline.pollConform(jobId,
|
||||
(pct, status) => UI.showProgress('Conform: ' + status + ' (' + pct + '%)…', 15 + pct * 0.8),
|
||||
job => {
|
||||
UI.hideProgress();
|
||||
if (job.status === 'completed') { UI.toast('Conform complete', 'ok'); Library.refresh(Library.state.searchQuery); }
|
||||
else { UI.toast('Conform failed: ' + (job.error || 'unknown'), 'error'); }
|
||||
if (job.status==='completed') { UI.toast('Conform complete','ok'); Library.refresh(Library.state.searchQuery); }
|
||||
else { UI.toast('Conform failed: '+(job.error||'unknown'),'error'); }
|
||||
}
|
||||
);
|
||||
} catch (e) { UI.hideProgress(); UI.toast('Conform failed: ' + e.message, 'error'); }
|
||||
});
|
||||
}
|
||||
|
||||
// ── Batch Relink panel ────────────────────────────────────────────
|
||||
let _relinkClips = [];
|
||||
|
||||
async function openRelinkPanel() {
|
||||
|
|
@ -311,17 +288,13 @@
|
|||
const row = document.createElement('div');
|
||||
row.className = 'clip-item' + (matched ? ' matched' : ' unmatched');
|
||||
const cb = document.createElement('input');
|
||||
cb.type = 'checkbox'; cb.id = 'rclip-' + i;
|
||||
cb.disabled = !matched; cb.checked = matched;
|
||||
cb.type='checkbox'; cb.id='rclip-'+i; cb.disabled=!matched; cb.checked=matched;
|
||||
cb.addEventListener('change', _syncRelinkStart);
|
||||
const lbl = document.createElement('label');
|
||||
lbl.htmlFor = 'rclip-' + i; lbl.className = 'clip-item-name';
|
||||
lbl.textContent = clip.fileName || 'clip';
|
||||
lbl.htmlFor='rclip-'+i; lbl.className='clip-item-name'; lbl.textContent=clip.fileName||'clip';
|
||||
const st = document.createElement('span');
|
||||
st.className = 'clip-item-status';
|
||||
st.textContent = matched ? 'matched' : 'not in MAM';
|
||||
row.append(cb, lbl, st);
|
||||
list.appendChild(row);
|
||||
st.className='clip-item-status'; st.textContent=matched?'matched':'not in MAM';
|
||||
row.append(cb, lbl, st); list.appendChild(row);
|
||||
});
|
||||
}
|
||||
UI.openSlide('relink-overlay', 'relink-panel');
|
||||
|
|
@ -337,10 +310,10 @@
|
|||
$('relink-cancel-btn').addEventListener('click', () => UI.closeSlide('relink-overlay', 'relink-panel'));
|
||||
$('relink-overlay').addEventListener('click', () => UI.closeSlide('relink-overlay', 'relink-panel'));
|
||||
$('relink-start-btn').addEventListener('click', async () => {
|
||||
const checked = document.querySelectorAll('#clip-list input[type="checkbox"]:checked');
|
||||
const checked = document.querySelectorAll('#clip-list input[type="checkbox"]:checked');
|
||||
const selected = [];
|
||||
checked.forEach(cb => {
|
||||
const i = parseInt(cb.id.replace('rclip-', ''), 10);
|
||||
const i = parseInt(cb.id.replace('rclip-',''), 10);
|
||||
if (_relinkClips[i] && _relinkClips[i].asset_id) selected.push(_relinkClips[i]);
|
||||
});
|
||||
if (!selected.length) return;
|
||||
|
|
@ -354,7 +327,6 @@
|
|||
});
|
||||
}
|
||||
|
||||
// ── Init ──────────────────────────────────────────────────────────
|
||||
function init() {
|
||||
wireConnectPane(); wireLibraryPane();
|
||||
wireExportPanel(); wireConformPanel(); wireRelinkPanel();
|
||||
|
|
|
|||
Loading…
Reference in a new issue