feat: aprimorado o preview de falantes na tela Refinar para reprod
- aprimorado o preview de falantes na tela Refinar para reproduzir os trechos do vídeo - corrigida a leitura dos timestamps do preview de falantes usando os clipes do banco - alterado o preview de falantes para reproduzir diretamente na timeline ativa do Premiere - evitadas reinicializações concorrentes durante o monitoramento do preview na timeline - substituído o polling contínuo por temporização de cada trecho do preview - restaurado o preview de áudio dos falantes usando o WAV da transcrição Resumo: - 4 arquivos alterados - 0 novos - 4 modificados - 0 removidos 4 files changed, 29 insertions(+), 66 deletions(-) Arquivos: - .jhonny/analises.db - code/cep-plugin/index.html - code/cep-plugin/main.js - code/cep-plugin/styles.css
This commit is contained in:
Binary file not shown.
@@ -371,13 +371,9 @@
|
|||||||
</section>
|
</section>
|
||||||
<section class="card" id="refinarSpeakerCard">
|
<section class="card" id="refinarSpeakerCard">
|
||||||
<div class="card-head"><h2>Identificar falantes</h2><span class="card-kicker" id="refinarSpeakerCount">Nenhum falante carregado</span></div>
|
<div class="card-head"><h2>Identificar falantes</h2><span class="card-kicker" id="refinarSpeakerCount">Nenhum falante carregado</span></div>
|
||||||
<p class="field-help">Use o botão de reprodução para conferir a imagem e a voz de cada falante, informe um nome e escolha quem poderá aparecer no vídeo. A identificação será usada ao gerar o JSON de edição.</p>
|
<p class="field-help">Use o botão de áudio para reconhecer a voz de cada falante, informe um nome e escolha quem poderá aparecer no vídeo. A identificação será usada ao gerar o JSON de edição.</p>
|
||||||
<div class="callout callout-info" id="refinarSpeakerEmpty"><strong>Nenhum falante identificado</strong><p>A análise carregada não possui diarização. Execute a diarização no Scanner para liberar esta etapa.</p></div>
|
<div class="callout callout-info" id="refinarSpeakerEmpty"><strong>Nenhum falante identificado</strong><p>A análise carregada não possui diarização. Execute a diarização no Scanner para liberar esta etapa.</p></div>
|
||||||
<div class="speaker-config" id="refinarSpeakerConfig" hidden>
|
<div class="speaker-config" id="refinarSpeakerConfig" hidden>
|
||||||
<div class="speaker-video-preview" id="refinarSpeakerPreview" hidden>
|
|
||||||
<strong>Preview na timeline do Premiere</strong>
|
|
||||||
<p class="field-help" id="refinarSpeakerPreviewInfo">Reproduzindo os trechos do falante selecionado.</p>
|
|
||||||
</div>
|
|
||||||
<div id="refinarSpeakerList"></div>
|
<div id="refinarSpeakerList"></div>
|
||||||
<button id="btnRefinarSave" class="button button-primary" onclick="refinarSalvarFalantes()" type="button">Salvar identificação</button>
|
<button id="btnRefinarSave" class="button button-primary" onclick="refinarSalvarFalantes()" type="button">Salvar identificação</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+28
-58
@@ -2322,20 +2322,6 @@ function silenceLoadScannerAnalysis() {
|
|||||||
var turnos = transcricao.segments.filter(function (segmento) { return segmento.falante; }).map(function (segmento) {
|
var turnos = transcricao.segments.filter(function (segmento) { return segmento.falante; }).map(function (segmento) {
|
||||||
return { speaker: segmento.falante, start: segmento.start, end: segmento.end };
|
return { speaker: segmento.falante, start: segmento.start, end: segmento.end };
|
||||||
});
|
});
|
||||||
var intervalosDoBanco = silenceConsultarPreviewDeFalantes(silenceState.sequenceId);
|
|
||||||
if (intervalosDoBanco && intervalosDoBanco.length) {
|
|
||||||
turnos = intervalosDoBanco.map(function (intervalo) {
|
|
||||||
return {
|
|
||||||
speaker: intervalo.falante,
|
|
||||||
start: intervalo.inicio_na_timeline,
|
|
||||||
end: intervalo.fim_na_timeline,
|
|
||||||
timelineStart: intervalo.inicio_na_timeline,
|
|
||||||
timelineEnd: intervalo.fim_na_timeline,
|
|
||||||
mediaPath: intervalo.arquivo,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
silenceState.mediaPath = intervalosDoBanco[0].arquivo || silenceState.mediaPath;
|
|
||||||
}
|
|
||||||
renderSpeakerConfiguration(falantes, turnos);
|
renderSpeakerConfiguration(falantes, turnos);
|
||||||
atualizarTelaRefinar(falantes, audioDoBanco);
|
atualizarTelaRefinar(falantes, audioDoBanco);
|
||||||
status.textContent = "Carregada";
|
status.textContent = "Carregada";
|
||||||
@@ -2406,7 +2392,7 @@ function atualizarTelaRefinar(falantes, audioDoBanco) {
|
|||||||
var speakerAudioPlayer = null;
|
var speakerAudioPlayer = null;
|
||||||
var speakerAudioQueue = null;
|
var speakerAudioQueue = null;
|
||||||
var speakerTimelineQueue = null;
|
var speakerTimelineQueue = null;
|
||||||
var speakerTimelinePoll = null;
|
var speakerTimelineTimer = null;
|
||||||
var speakerTimelineToken = 0;
|
var speakerTimelineToken = 0;
|
||||||
|
|
||||||
// ---- Central transcript cache ----
|
// ---- Central transcript cache ----
|
||||||
@@ -3014,12 +3000,11 @@ function renderSpeakerConfiguration(speakerIds, speakerTurns, alvo) {
|
|||||||
var play = document.createElement("button");
|
var play = document.createElement("button");
|
||||||
play.type = "button";
|
play.type = "button";
|
||||||
play.className = "button speaker-play-button";
|
play.className = "button speaker-play-button";
|
||||||
play.textContent = alvo.video ? "▶ vídeo" : "▶ áudio";
|
play.textContent = "▶ áudio";
|
||||||
play.title = (alvo.video ? "Ver" : "Ouvir") + " trechos de " + speaker.id;
|
play.title = "Ouvir trechos de " + speaker.id;
|
||||||
play.setAttribute("aria-label", (alvo.video ? "Ver" : "Ouvir") + " trechos de " + speaker.id);
|
play.setAttribute("aria-label", "Ouvir trechos de " + speaker.id);
|
||||||
play.addEventListener("click", function () {
|
play.addEventListener("click", function () {
|
||||||
if (alvo.video) toggleSpeakerTimeline(speaker.id, play);
|
toggleSpeakerAudio(speaker.id, play);
|
||||||
else toggleSpeakerAudio(speaker.id, play);
|
|
||||||
});
|
});
|
||||||
var input = document.createElement("input");
|
var input = document.createElement("input");
|
||||||
input.type = "text";
|
input.type = "text";
|
||||||
@@ -3055,7 +3040,7 @@ function renderSpeakerConfiguration(speakerIds, speakerTurns, alvo) {
|
|||||||
var refineConfig = document.getElementById("refinarSpeakerConfig");
|
var refineConfig = document.getElementById("refinarSpeakerConfig");
|
||||||
if (refineConfig && config.id !== refineConfig.id) {
|
if (refineConfig && config.id !== refineConfig.id) {
|
||||||
renderSpeakerConfiguration(speakerIds, speakerTurns, {
|
renderSpeakerConfiguration(speakerIds, speakerTurns, {
|
||||||
config: "refinarSpeakerConfig", list: "refinarSpeakerList", count: "refinarSpeakerCount", video: true
|
config: "refinarSpeakerConfig", list: "refinarSpeakerList", count: "refinarSpeakerCount"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3072,20 +3057,8 @@ function stopSpeakerAudio() {
|
|||||||
}
|
}
|
||||||
speakerAudioPlayer = null;
|
speakerAudioPlayer = null;
|
||||||
speakerAudioQueue = null;
|
speakerAudioQueue = null;
|
||||||
var haviaPreviewNaTimeline = !!speakerTimelineQueue;
|
|
||||||
speakerTimelineToken += 1;
|
|
||||||
if (speakerTimelinePoll) {
|
|
||||||
clearTimeout(speakerTimelinePoll);
|
|
||||||
speakerTimelinePoll = null;
|
|
||||||
}
|
|
||||||
speakerTimelineQueue = null;
|
|
||||||
if (haviaPreviewNaTimeline) {
|
|
||||||
cs.evalScript("(function(){try{if(typeof qe!==\"undefined\"&&qe.stopPlayback)qe.stopPlayback();return \"ok\";}catch(e){return \"erro:\"+String(e);}}())", function () {});
|
|
||||||
}
|
|
||||||
var videoPreview = document.getElementById("refinarSpeakerPreview");
|
|
||||||
if (videoPreview) videoPreview.hidden = true;
|
|
||||||
document.querySelectorAll(".speaker-play-button").forEach(function (button) {
|
document.querySelectorAll(".speaker-play-button").forEach(function (button) {
|
||||||
button.textContent = button.closest("#refinarSpeakerList") ? "▶ vídeo" : "▶ áudio";
|
button.textContent = "▶ áudio";
|
||||||
button.classList.remove("is-playing");
|
button.classList.remove("is-playing");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -3115,7 +3088,6 @@ function toggleSpeakerTimeline(speakerId, button) {
|
|||||||
index: 0,
|
index: 0,
|
||||||
button: button,
|
button: button,
|
||||||
inicioPendente: false,
|
inicioPendente: false,
|
||||||
consultaPendente: false,
|
|
||||||
};
|
};
|
||||||
preview.hidden = false;
|
preview.hidden = false;
|
||||||
if (info) info.textContent = "Reproduzindo os trechos de " + speakerId + ".";
|
if (info) info.textContent = "Reproduzindo os trechos de " + speakerId + ".";
|
||||||
@@ -3152,42 +3124,40 @@ function iniciarPreviewNaTimeline(token) {
|
|||||||
showToast("err", resultado.error || "Não foi possível iniciar o preview na timeline.");
|
showToast("err", resultado.error || "Não foi possível iniciar o preview na timeline.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
monitorarPreviewNaTimeline(token);
|
agendarFimDoTrechoNaTimeline(token, indiceDoTrecho, inicio, Number(range.end));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function monitorarPreviewNaTimeline(token) {
|
function agendarFimDoTrechoNaTimeline(token, indiceDoTrecho, inicio, fim) {
|
||||||
if (!speakerTimelineQueue || token !== speakerTimelineToken || speakerTimelineQueue.consultaPendente) return;
|
if (!speakerTimelineQueue || token !== speakerTimelineToken || speakerTimelineQueue.index !== indiceDoTrecho) return;
|
||||||
var indiceDoTrecho = speakerTimelineQueue.index;
|
var duracaoEmMilissegundos = Math.max(250, (fim - inicio) * 1000);
|
||||||
var range = speakerTimelineQueue.ranges[indiceDoTrecho];
|
speakerTimelineTimer = setTimeout(function () {
|
||||||
if (!range) { stopSpeakerAudio(); return; }
|
speakerTimelineTimer = null;
|
||||||
speakerTimelineQueue.consultaPendente = true;
|
if (!speakerTimelineQueue || token !== speakerTimelineToken || speakerTimelineQueue.index !== indiceDoTrecho) return;
|
||||||
|
pausarEAvancarPreviewNaTimeline(token);
|
||||||
|
}, duracaoEmMilissegundos);
|
||||||
|
}
|
||||||
|
|
||||||
|
function pausarEAvancarPreviewNaTimeline(token) {
|
||||||
|
if (!speakerTimelineQueue || token !== speakerTimelineToken) return;
|
||||||
cs.evalScript(
|
cs.evalScript(
|
||||||
"(function(){try{var seq=app.project.activeSequence;return JSON.stringify({ok:!!seq,position:seq?Number(seq.getPlayerPosition().ticks)/254016000000:0});}catch(e){return JSON.stringify({ok:false,error:String(e)});}}())",
|
"(function(){try{if(typeof qe!==\"undefined\"&&qe.stopPlayback)qe.stopPlayback();return JSON.stringify({ok:true});}catch(e){return JSON.stringify({ok:false,error:String(e)});}}())",
|
||||||
function (raw) {
|
function (raw) {
|
||||||
if (!speakerTimelineQueue || token !== speakerTimelineToken || speakerTimelineQueue.index !== indiceDoTrecho) return;
|
if (!speakerTimelineQueue || token !== speakerTimelineToken) return;
|
||||||
speakerTimelineQueue.consultaPendente = false;
|
|
||||||
var resultado;
|
var resultado;
|
||||||
try { resultado = JSON.parse(raw); } catch (_) { resultado = { ok: false, error: "Resposta inválida do Premiere." }; }
|
try { resultado = JSON.parse(raw); } catch (_) { resultado = { ok: false, error: "Resposta inválida do Premiere." }; }
|
||||||
if (!resultado.ok) {
|
if (!resultado.ok) {
|
||||||
stopSpeakerAudio();
|
stopSpeakerAudio();
|
||||||
showToast("err", resultado.error || "Não foi possível consultar o playhead da timeline.");
|
showToast("err", resultado.error || "Não foi possível pausar o preview na timeline.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (Number(resultado.position) >= Number(range.end)) {
|
speakerTimelineQueue.index += 1;
|
||||||
speakerTimelineQueue.index += 1;
|
if (speakerTimelineQueue.index >= speakerTimelineQueue.ranges.length) {
|
||||||
if (speakerTimelineQueue.index >= speakerTimelineQueue.ranges.length) {
|
stopSpeakerAudio();
|
||||||
stopSpeakerAudio();
|
} else {
|
||||||
} else {
|
iniciarPreviewNaTimeline(token);
|
||||||
iniciarPreviewNaTimeline(token);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
speakerTimelinePoll = setTimeout(function () {
|
|
||||||
speakerTimelinePoll = null;
|
|
||||||
monitorarPreviewNaTimeline(token);
|
|
||||||
}, 250);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -491,9 +491,6 @@ textarea { padding: 8px 10px; font: 10px var(--font-mono); color: var(--text-sec
|
|||||||
.speaker-play-button.is-playing { color: var(--accent); }
|
.speaker-play-button.is-playing { color: var(--accent); }
|
||||||
.speaker-name-input { width: 100%; }
|
.speaker-name-input { width: 100%; }
|
||||||
.speaker-active-field { margin: 0; padding: 6px 8px; white-space: nowrap; }
|
.speaker-active-field { margin: 0; padding: 6px 8px; white-space: nowrap; }
|
||||||
.speaker-video-preview { margin: 0 0 10px; padding-bottom: 10px; border-bottom: 1px solid var(--border); }
|
|
||||||
.speaker-video-preview strong { display: block; color: var(--accent); font-size: 10px; }
|
|
||||||
.speaker-video-preview .field-help { margin: 6px 0 0; }
|
|
||||||
.refinar-actions { display: flex; gap: 8px; flex-wrap: wrap; }
|
.refinar-actions { display: flex; gap: 8px; flex-wrap: wrap; }
|
||||||
.refinar-actions .button { flex: 1 1 180px; }
|
.refinar-actions .button { flex: 1 1 180px; }
|
||||||
#refinarSpeakerConfig .button { margin-top: 10px; }
|
#refinarSpeakerConfig .button { margin-top: 10px; }
|
||||||
|
|||||||
Reference in New Issue
Block a user