feat: corrigida a exportação dos tipos de vídeo para preservar car
- corrigida a exportação dos tipos de vídeo para preservar caracteres UTF-8 no J-SOM - adicionada revisão editável de legendas com geração offline e exportação SRT no painel Resumo: - 4 arquivos alterados - 1 novos - 3 modificados - 0 removidos 3 files changed, 121 insertions(+), 12 deletions(-) Arquivos: - code/cep-plugin/index.html - code/cep-plugin/main.js - code/cep-plugin/styles.css - code/tests/cep-tipos-video-encoding.test.ts
This commit is contained in:
+105
-9
@@ -292,6 +292,98 @@ function salvarConfiguracaoDeLegendas() {
|
||||
document.getElementById("legendasStatus").textContent = "Configuração de legendas salva neste computador.";
|
||||
}
|
||||
|
||||
var legendasGeradas = [];
|
||||
|
||||
function legendaNumeroParaTempo(segundos) {
|
||||
var horas = Math.floor(segundos / 3600);
|
||||
var minutos = Math.floor((segundos % 3600) / 60);
|
||||
var segundosInteiros = Math.floor(segundos % 60);
|
||||
var milissegundos = Math.round((segundos - Math.floor(segundos)) * 1000);
|
||||
if (milissegundos >= 1000) { segundosInteiros++; milissegundos = 0; }
|
||||
return [horas, minutos, segundosInteiros].map(function (n) { return String(n).padStart(2, "0"); }).join(":") + "," + String(milissegundos).padStart(3, "0");
|
||||
}
|
||||
|
||||
function legendasExtrairPalavras(transcricao) {
|
||||
var segmentos = transcricao.segmentos || transcricao.segments || [];
|
||||
var palavras = [];
|
||||
segmentos.forEach(function (segmento) {
|
||||
var itens = segmento.palavras || segmento.words || [];
|
||||
itens.forEach(function (palavra) {
|
||||
var texto = String(palavra.texto || palavra.word || "").trim();
|
||||
var inicio = Number(palavra.inicio !== undefined ? palavra.inicio : palavra.start);
|
||||
var fim = Number(palavra.fim !== undefined ? palavra.fim : palavra.end);
|
||||
if (texto && isFinite(inicio) && isFinite(fim) && fim > inicio) palavras.push({ texto: texto, inicio: inicio, fim: fim });
|
||||
});
|
||||
});
|
||||
return palavras.sort(function (a, b) { return a.inicio - b.inicio; });
|
||||
}
|
||||
|
||||
function legendasIntervaloCortado(palavra, cortes) {
|
||||
return cortes.some(function (corte) { return palavra.inicio < corte.end && palavra.fim > corte.start; });
|
||||
}
|
||||
|
||||
function legendasGerarBlocos(palavras, cortes, configuracao) {
|
||||
var mantidas = palavras.filter(function (palavra) { return !legendasIntervaloCortado(palavra, cortes); });
|
||||
var blocos = [], bloco = [], caracteres = 0;
|
||||
function adicionar() {
|
||||
if (!bloco.length) return;
|
||||
var primeiro = bloco[0], ultimo = bloco[bloco.length - 1];
|
||||
// Para o primeiro corte, todos os cortes anteriores são considerados.
|
||||
var inicio = primeiro.inicio - cortes.reduce(function (total, corte) { return total + (corte.end <= primeiro.inicio ? corte.end - corte.start : 0); }, 0);
|
||||
var fim = ultimo.fim - cortes.reduce(function (total, corte) { return total + (corte.end <= ultimo.fim ? corte.end - corte.start : 0); }, 0);
|
||||
blocos.push({ texto: bloco.map(function (item) { return item.texto; }).join(" "), inicio: inicio, fim: fim });
|
||||
bloco = []; caracteres = 0;
|
||||
}
|
||||
mantidas.forEach(function (palavra) {
|
||||
var espaco = bloco.length ? 1 : 0;
|
||||
if (bloco.length && (bloco.length >= configuracao.max_palavras || caracteres + espaco + palavra.texto.length > configuracao.max_caracteres)) adicionar();
|
||||
bloco.push(palavra); caracteres += (bloco.length > 1 ? 1 : 0) + palavra.texto.length;
|
||||
});
|
||||
adicionar();
|
||||
return blocos;
|
||||
}
|
||||
|
||||
function legendasRenderizar() {
|
||||
var lista = document.getElementById("legendasLista");
|
||||
document.getElementById("legendasContagem").textContent = "(" + legendasGeradas.length + ")";
|
||||
lista.textContent = "";
|
||||
if (!legendasGeradas.length) { lista.innerHTML = '<p class="empty-state">Nenhuma legenda carregada.</p>'; return; }
|
||||
legendasGeradas.forEach(function (legenda, indice) {
|
||||
var linha = document.createElement("div"); linha.className = "legenda-row"; linha.setAttribute("role", "listitem");
|
||||
var cabecalho = document.createElement("div"); cabecalho.className = "legenda-timecode"; cabecalho.textContent = (indice + 1) + " " + legendaNumeroParaTempo(legenda.inicio) + " → " + legendaNumeroParaTempo(legenda.fim);
|
||||
var campo = document.createElement("input"); campo.className = "text-field"; campo.value = legenda.texto; campo.setAttribute("aria-label", "Texto da legenda " + (indice + 1));
|
||||
campo.oninput = function () { legendasGeradas[indice].texto = campo.value; };
|
||||
var excluir = document.createElement("button"); excluir.className = "button button-ghost"; excluir.type = "button"; excluir.textContent = "×"; excluir.title = "Excluir legenda";
|
||||
excluir.onclick = function () { legendasGeradas.splice(indice, 1); legendasRenderizar(); };
|
||||
linha.appendChild(cabecalho); linha.appendChild(campo); linha.appendChild(excluir); lista.appendChild(linha);
|
||||
});
|
||||
}
|
||||
|
||||
function gerarLegendasDaTranscricao() {
|
||||
if (!silenceState.transcriptPath) { document.getElementById("legendasStatus").textContent = "Execute ou carregue uma transcrição primeiro."; return; }
|
||||
try {
|
||||
var transcricao = JSON.parse(fs.readFileSync(silenceState.transcriptPath, "utf-8"));
|
||||
var plano = JSON.parse(document.getElementById("testarAcoesJson").value || "{}");
|
||||
var cortes = (plano.actions || []).filter(function (acao) { return acao.kind === "cut"; }).map(function (acao) { return { start: Number(acao.start), end: Number(acao.end) }; });
|
||||
var configuracao = carregarConfiguracaoDeLegendas();
|
||||
legendasGeradas = legendasGerarBlocos(legendasExtrairPalavras(transcricao), cortes, configuracao);
|
||||
legendasRenderizar();
|
||||
document.getElementById("legendasStatus").textContent = legendasGeradas.length + " legenda(s) gerada(s) para revisão.";
|
||||
} catch (erro) { document.getElementById("legendasStatus").textContent = "Não foi possível gerar: " + erro.message; }
|
||||
}
|
||||
|
||||
function exportarLegendasSrt() {
|
||||
if (!legendasGeradas.length) { document.getElementById("legendasStatus").textContent = "Gere as legendas antes de exportar."; return; }
|
||||
var destino = path.join(silenceState.outputDir || os.tmpdir(), "legendas-geradas.srt");
|
||||
var conteudo = legendasGeradas.map(function (legenda, indice) { return (indice + 1) + "\n" + legendaNumeroParaTempo(legenda.inicio) + " --> " + legendaNumeroParaTempo(legenda.fim) + "\n" + legenda.texto + "\n"; }).join("\n");
|
||||
fs.writeFileSync(destino, conteudo, "utf-8");
|
||||
document.getElementById("legendasStatus").textContent = "SRT exportado em " + destino;
|
||||
}
|
||||
|
||||
function inserirLegendasNaTimeline() {
|
||||
document.getElementById("legendasStatus").textContent = "A lista está pronta. A inserção automática dos MOGRTs será conectada na próxima etapa, após validar o estilo escolhido.";
|
||||
}
|
||||
|
||||
// ---- Teste isolado de ações pela engine Python ----------------------------
|
||||
var TESTAR_ACOES_ENGINE_SCRIPT = "/Volumes/Merongo/SISTEMAS/GENIAL SISTEMAS/Jhonny/code/engine/aplicar_plano_de_edicao.py";
|
||||
|
||||
@@ -665,15 +757,19 @@ function copiarTextoParaAreaDeTransferencia(texto) {
|
||||
else showToast("err", "Não foi possível copiar o JSON. Selecione e copie manualmente.");
|
||||
}
|
||||
|
||||
try {
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||
navigator.clipboard.writeText(texto).then(function () {
|
||||
showToast("ok", "JSON resumido copiado para a área de transferência.");
|
||||
}).catch(function () { copiarComPbcopy(texto, copiarComSelecaoDoPainel); });
|
||||
return;
|
||||
}
|
||||
} catch (_) {}
|
||||
copiarComPbcopy(texto, copiarComSelecaoDoPainel);
|
||||
// O CEP antigo pode corromper caracteres UTF-8 pela API de clipboard do Chromium.
|
||||
// O pbcopy recebe bytes UTF-8 diretamente e evita essa conversão intermediária.
|
||||
copiarComPbcopy(texto, function () {
|
||||
try {
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||
navigator.clipboard.writeText(texto).then(function () {
|
||||
showToast("ok", "JSON resumido copiado para a área de transferência.");
|
||||
}).catch(copiarComSelecaoDoPainel);
|
||||
return;
|
||||
}
|
||||
} catch (_) {}
|
||||
copiarComSelecaoDoPainel();
|
||||
});
|
||||
}
|
||||
|
||||
function copiarComPbcopy(texto, fallback) {
|
||||
|
||||
Reference in New Issue
Block a user