feat: adicionada seleção de timeline do projeto na guia Editar víd

- adicionada seleção de timeline do projeto na guia Editar vídeo

Resumo:
- 3 arquivos alterados
- 0 novos
- 3 modificados
- 0 removidos

 3 files changed, 116 insertions(+), 17 deletions(-)

Arquivos:
  - code/cep-plugin/index.html
  - code/cep-plugin/main.js
  - code/cep-plugin/styles.css
This commit is contained in:
João Henrique
2026-09-09 10:03:25 -04:00
parent bea38cfeb3
commit b6c1b79336
3 changed files with 116 additions and 17 deletions
+106 -14
View File
@@ -1323,6 +1323,7 @@ var LANGUAGE_CATALOG = [
var DEFAULT_LANGUAGE = "pt";
var silenceState = {
sequenceId: null,
sequenceName: null,
mediaPath: null,
fileBaseName: null,
@@ -1442,21 +1443,108 @@ function slugify(name) {
.replace(/(^-|-$)/g, "") || "video";
}
function silenceDetectClip() {
function formatSequenceDuration(seconds) {
var total = Math.max(0, Math.round(Number(seconds) || 0));
var minutes = Math.floor(total / 60);
var remainder = total % 60;
return minutes + ":" + String(remainder).padStart(2, "0");
}
function silenceListSequences() {
setBusy("btnDetectClip", true);
setStep(1, "running", "Detectando…");
document.getElementById("silenceClipInfo").textContent = "Lendo a sequência ativa no Premiere…";
setStep(1, "running", "Carregando…");
document.getElementById("silenceClipInfo").textContent = "Lendo as timelines do projeto…";
cs.evalScript(
"(function(){" +
"try{" +
"var seq=app.project.activeSequence;" +
"if(!seq) return JSON.stringify({ok:false,error:'Nenhuma sequência ativa.'});" +
"if(!app.project) return JSON.stringify({ok:false,error:'Nenhum projeto aberto.'});" +
"var sequences=[];" +
"for(var i=0;i<app.project.sequences.numSequences;i++){" +
"var seq=app.project.sequences[i];" +
"sequences.push({id:String(seq.sequenceID),name:String(seq.name),duration:Number(seq.end.seconds)||0," +
"videoTracks:seq.videoTracks.numTracks||0,audioTracks:seq.audioTracks.numTracks||0," +
"active:app.project.activeSequence&&seq.sequenceID===app.project.activeSequence.sequenceID});" +
"}" +
"return JSON.stringify({ok:true,sequences:sequences});" +
"}catch(e){return JSON.stringify({ok:false,error:String(e)});}" +
"}())",
function (raw) {
setBusy("btnDetectClip", false);
var result;
try {
result = JSON.parse(raw);
} catch (e) {
result = { ok: false, error: "Resposta inesperada do Premiere." };
}
var picker = document.getElementById("silenceSequencePicker");
var select = document.getElementById("silenceSequenceSelect");
var info = document.getElementById("silenceClipInfo");
if (!result.ok) {
picker.hidden = true;
setStep(1, "error", "Não encontrado");
info.textContent = result.error || "Não foi possível listar as timelines.";
showToast("err", info.textContent);
lockStepsFrom(2);
return;
}
if (!result.sequences || result.sequences.length === 0) {
picker.hidden = true;
setStep(1, "error", "Sem timelines");
info.textContent = "O projeto não possui timelines.";
showToast("err", info.textContent);
lockStepsFrom(2);
return;
}
select.innerHTML = "";
result.sequences.forEach(function (sequence) {
var option = document.createElement("option");
option.value = sequence.id;
option.textContent = sequence.name + " · " + formatSequenceDuration(sequence.duration) +
" · V" + sequence.videoTracks + " / A" + sequence.audioTracks +
(sequence.active ? " · ativa" : "");
option.dataset.sequence = JSON.stringify(sequence);
select.appendChild(option);
});
var activeIndex = -1;
for (var sequenceIndex = 0; sequenceIndex < result.sequences.length; sequenceIndex++) {
if (result.sequences[sequenceIndex].active) {
activeIndex = sequenceIndex;
break;
}
}
select.selectedIndex = activeIndex >= 0 ? activeIndex : 0;
picker.hidden = false;
document.getElementById("silenceSequenceListInfo").textContent =
result.sequences.length + " timeline(s) encontrada(s).";
silenceSelectSequence();
}
);
}
function silenceSelectSequence() {
var select = document.getElementById("silenceSequenceSelect");
var option = select && select.options[select.selectedIndex];
if (!option || !option.dataset.sequence) return;
var sequence = JSON.parse(option.dataset.sequence);
setBusy("btnDetectClip", true);
setStep(1, "running", "Lendo timeline…");
document.getElementById("silenceClipInfo").textContent = "Lendo o primeiro clipe da timeline escolhida…";
var sequenceId = JSON.stringify(String(sequence.id));
cs.evalScript(
"(function(){" +
"try{" +
"var sequenceId=" + sequenceId + ";" +
"var seq=null;" +
"for(var i=0;i<app.project.sequences.numSequences;i++){if(String(app.project.sequences[i].sequenceID)===sequenceId){seq=app.project.sequences[i];break;}}" +
"if(!seq) return JSON.stringify({ok:false,error:'Timeline não encontrada.'});" +
"var vt=seq.videoTracks[0];" +
"if(!vt||vt.clips.numItems===0) return JSON.stringify({ok:false,error:'Vídeo 1 está vazio na sequência ativa.'});" +
"if(!vt||vt.clips.numItems===0) return JSON.stringify({ok:false,error:'Vídeo 1 está vazio nesta timeline.'});" +
"var clip=vt.clips[0];" +
"var projItem=clip.projectItem;" +
"var mediaPath=projItem&&projItem.getMediaPath?projItem.getMediaPath():'';" +
"return JSON.stringify({ok:true,sequenceName:seq.name,mediaPath:mediaPath,clipName:clip.name});" +
"return JSON.stringify({ok:true,sequenceId:String(seq.sequenceID),sequenceName:seq.name,mediaPath:mediaPath,clipName:clip.name});" +
"}catch(e){return JSON.stringify({ok:false,error:String(e)});}" +
"}())",
function (raw) {
@@ -1472,14 +1560,14 @@ function silenceDetectClip() {
if (!result.ok || !result.mediaPath) {
card.hidden = true;
setStep(1, "error", "Não encontrado");
info.textContent = (result.error || "Caminho de mídia vazio.") +
" Abra a sequência no Premiere e tente de novo.";
showToast("err", result.error || "Não foi possível ler a sequência ativa.");
setStep(1, "error", "Sem mídia");
info.textContent = result.error || "Caminho de mídia vazio.";
showToast("err", info.textContent);
lockStepsFrom(2);
return;
}
silenceState.sequenceId = result.sequenceId;
silenceState.sequenceName = result.sequenceName;
silenceState.mediaPath = result.mediaPath;
silenceState.fileBaseName = slugify(result.clipName || result.sequenceName);
@@ -1498,18 +1586,22 @@ function silenceDetectClip() {
card.hidden = false;
info.textContent = "";
setStep(1, "done", "Vídeo escolhido");
setStep(1, "done", "Timeline escolhida");
lockStepsFrom(2);
setStep(2, "ready", "Sua vez");
document.getElementById("btnTranscribe").disabled = false;
document.getElementById("silenceJsonCard").hidden = true;
document.getElementById("silencePlanInfo").textContent = "";
silenceLog("Clipe detectado: " + result.mediaPath);
silenceLog("Timeline escolhida: " + result.sequenceName + " — " + result.mediaPath);
renderCachedTranscripts();
}
);
}
function silenceDetectClip() {
silenceListSequences();
}
// Volta os passos seguintes ao estado travado quando o vídeo (ou a transcrição)
// muda — evita aplicar um plano gerado para outro material.
function lockStepsFrom(first) {
@@ -2029,7 +2121,7 @@ function applyEditorialActions() {
silenceLog("Aplicando plano de edição na timeline…");
runStreamed(
nodeBin,
[applyScript, "--plan", planPath, "--sequence", silenceState.sequenceName],
[applyScript, "--plan", planPath, "--sequence", silenceState.sequenceId || silenceState.sequenceName],
function (line) { silenceLog(line); },
function (code, lastErr) {
setBusy("btnApplyEditorialActions", false);