feat(connector): per-shot/version export folders, scene filter

Panel export paths now mirror the server's layout
({exportRoot}/{showId}/[{episode} if episodic]/{shotCode}/{version}) via a new
getShotExportDir helper, so farm and local renders land in the same folder.
Folder creation moves into the per-shot loop so one unwritable path no longer
aborts the whole queue.

Also adds an optional `scene` query param to the ext shots endpoint.
This commit is contained in:
twotalesanimation
2026-08-12 10:29:51 +02:00
parent 7dcb9303e5
commit c4abda2d63
2 changed files with 35 additions and 11 deletions
+33 -11
View File
@@ -315,6 +315,27 @@ var SETTINGS_KEY = "cfg";
return CONFIG.footageRoot + (showId ? "/" + showId : "");
}
// Mirrors the server's export layout so farm and local renders land together:
// {exportRoot}/{showId}/[{episode} for episodic]/{shotCode}/{version}
function getShotExportDir(shot) {
var path = getShowExportRoot();
var episode;
var match;
if (CURRENT_PROJECT && CURRENT_PROJECT.projectType === "EPISODIC") {
episode = trimText(shot.episode);
if (!episode) {
match = String(shot.shotCode).match(/^[A-Z]{3}_(\d{3})_/);
episode = match ? match[1] : "";
}
if (episode) {
path += "/" + episode;
}
}
return path + "/" + shot.shotCode + "/" + (shot.shotVersion || "v001");
}
function ensureFolder(path) {
var folder = new Folder(path);
var parent;
@@ -912,7 +933,7 @@ var SETTINGS_KEY = "cfg";
disableLayerByName(comp, "UNG_VFX_OVERLAY");
disableLayerByName(comp, "_SHOW LUT");
folderPath = getShowExportRoot() + "/" + shotCode;
folderPath = getShotExportDir(shot);
if (!ensureFolder(folderPath)) {
addFailure(result, comp.name, "Could not create output folder");
continue;
@@ -1242,14 +1263,9 @@ var SETTINGS_KEY = "cfg";
var mainComp;
var previewComp;
var outputPath;
var folderPath;
app.beginUndoGroup("VFXReview Connector - Queue " + label);
if (!ensureFolder(getShowExportRoot())) {
app.endUndoGroup();
updateStatus(comps.length, "Could not create export folder.");
return;
}
for (i = 0; i < comps.length; i += 1) {
shotCode = getShotCodeFromComp(comps[i]);
updateStatus(comps.length, "Preparing " + label + " preview for " + shotCode + " (" + (i + 1) + " of " + comps.length + ")");
@@ -1282,7 +1298,13 @@ var SETTINGS_KEY = "cfg";
}
updateStatus(comps.length, "Queueing " + label + " for " + shotCode + " (" + (i + 1) + " of " + comps.length + ")");
outputPath = getShowExportRoot() + "/" + shotCode + "_cmp_TT_" + (apiData.shot.shotVersion || "v001") + "." + extension;
folderPath = getShotExportDir(apiData.shot);
if (!ensureFolder(folderPath)) {
addFailure(result, comps[i].name, "Could not create output folder");
continue;
}
outputPath = folderPath + "/" + shotCode + "_cmp_TT_" + (apiData.shot.shotVersion || "v001") + "." + extension;
if (queueCompWithOutput(previewComp, templateName, outputPath)) {
queued += 1;
result.queued += 1;
@@ -1323,7 +1345,7 @@ var SETTINGS_KEY = "cfg";
disableLayerByName(comp, "UNG_VFX_OVERLAY");
disableLayerByName(comp, "_SHOW LUT");
folderPath = getShowExportRoot() + "/" + shotCode;
folderPath = getShotExportDir(shot);
if (!ensureFolder(folderPath)) {
addFailure(result, comp.name, "Could not create output folder");
continue;
@@ -1384,7 +1406,7 @@ var SETTINGS_KEY = "cfg";
continue;
}
exportFolder = new Folder(getShowExportRoot() + "/" + shot.shotCode);
exportFolder = new Folder(getShotExportDir(shot));
if (!exportFolder.exists) {
updateStatus(comps.length, "Export folder not found: " + exportFolder.fsName);
skipped += 1;
@@ -1596,7 +1618,7 @@ var SETTINGS_KEY = "cfg";
expectedBaseName = shotCode + "_cmp_TT_" + (shot.shotVersion || "v001");
exrOutputBase = shot.exrOutput || "";
sourceFolder = new Folder(getShowExportRoot() + "/" + shotCode);
sourceFolder = new Folder(getShotExportDir(shot));
if (!sourceFolder.exists) {
addFailure(result, comp.name, "Source export folder not found: " + sourceFolder.fsName);
continue;
@@ -18,6 +18,7 @@ function isAuthorized(req: NextRequest): boolean {
//
// Query params (all optional):
// episode e.g. 108
// scene e.g. 022
// sequence e.g. 004
// status e.g. IN_PROGRESS
// page (default 1)
@@ -60,6 +61,7 @@ export async function GET(
where: {
projectId: project.id,
...(episode ? { episode } : {}),
...(scene ? { scene } : {}),
...(sequence ? { sequence } : {}),
...(status ? { status: status as never } : {}),
},