feat: implementa painel de debug para exibir o comando gerado pelo FFmpeg/mkvmerge na ExecutionPanel, com opção de cópia
This commit is contained in:
@@ -393,7 +393,7 @@ src/
|
|||||||
| DT-07 | Compatibilidade com Jellyfin mobile | Faixas não selecionadas automaticamente | Investigando — RF-10 (`title`) e RF-11 (`disposition`) implementados; comportamento no Jellyfin mobile requer testes com arquivo gerado |
|
| DT-07 | Compatibilidade com Jellyfin mobile | Faixas não selecionadas automaticamente | Investigando — RF-10 (`title`) e RF-11 (`disposition`) implementados; comportamento no Jellyfin mobile requer testes com arquivo gerado |
|
||||||
| DT-08 | mkvmerge não embutido | Usuário precisa instalar MKVToolNix | Dependência opcional; feat. de drift desabilitada visualmente se ausente; verificação soft na inicialização |
|
| DT-08 | mkvmerge não embutido | Usuário precisa instalar MKVToolNix | Dependência opcional; feat. de drift desabilitada visualmente se ausente; verificação soft na inicialização |
|
||||||
| DT-09 | Testes de integração com FFmpeg real | Regressões em comandos gerados | Pendente — requer `ffmpeg` no CI; coberto indiretamente pelos testes unitários do `FfmpegCommandBuilder` |
|
| DT-09 | Testes de integração com FFmpeg real | Regressões em comandos gerados | Pendente — requer `ffmpeg` no CI; coberto indiretamente pelos testes unitários do `FfmpegCommandBuilder` |
|
||||||
| DT-10 | Comando FFmpeg não visível ao usuário | Difícil de debugar manualmente | Planejado — painel colapsável com o comando gerado na `ExecutionPanel` (modo debug) |
|
| DT-10 | Comando FFmpeg não visível ao usuário | Difícil de debugar manualmente | ✅ Resolvido — painel colapsável "🛠 Comando gerado" na `ExecutionPanel` e em cada item do modo Lote; botão de cópia para clipboard |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -402,7 +402,6 @@ src/
|
|||||||
- Preview de vídeo embutido na interface
|
- Preview de vídeo embutido na interface
|
||||||
- Detecção automática de sincronização entre faixas
|
- Detecção automática de sincronização entre faixas
|
||||||
- Suporte a perfis de configuração reutilizáveis (presets de idioma, offset, drift)
|
- Suporte a perfis de configuração reutilizáveis (presets de idioma, offset, drift)
|
||||||
- Painel colapsável com o comando FFmpeg/mkvmerge gerado (modo debug, DT-10)
|
|
||||||
- Mensagens de erro mais amigáveis a partir do stderr do FFmpeg
|
- Mensagens de erro mais amigáveis a partir do stderr do FFmpeg
|
||||||
- Testes de integração com FFmpeg real no CI (DT-09)
|
- Testes de integração com FFmpeg real no CI (DT-09)
|
||||||
- Testes de snapshot para o `FfmpegCommandBuilder` e `MkvmergeCommandBuilder` com projetos complexos
|
- Testes de snapshot para o `FfmpegCommandBuilder` e `MkvmergeCommandBuilder` com projetos complexos
|
||||||
@@ -431,6 +430,7 @@ src/
|
|||||||
- [x] É possível cancelar a geração em andamento
|
- [x] É possível cancelar a geração em andamento
|
||||||
- [x] Nenhum reencoding ocorre (verificável via `ffprobe` no arquivo de saída)
|
- [x] Nenhum reencoding ocorre (verificável via `ffprobe` no arquivo de saída)
|
||||||
- [x] O flag `-c copy` está sempre presente no comando FFmpeg gerado (verificável via testes unitários)
|
- [x] O flag `-c copy` está sempre presente no comando FFmpeg gerado (verificável via testes unitários)
|
||||||
|
- [x] O comando FFmpeg/mkvmerge gerado é exibido em painel colapsável na ExecutionPanel (DT-10)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Implementação — DT-10: Painel de Debug do Comando Gerado
|
# Implementação — DT-10: Painel de Debug do Comando Gerado
|
||||||
|
|
||||||
**Data:** 01/03/2026
|
**Data:** 01/03/2026
|
||||||
**Status:** Planejado
|
**Status:** ✅ Implementado
|
||||||
**Prioridade:** Baixa — melhoria de DX para usuário técnico
|
**Prioridade:** Baixa — melhoria de DX para usuário técnico
|
||||||
**Arquivos afetados:**
|
**Arquivos afetados:**
|
||||||
|
|
||||||
@@ -151,12 +151,12 @@ Ao concluir a implementação:
|
|||||||
|
|
||||||
## Critério de aceitação
|
## Critério de aceitação
|
||||||
|
|
||||||
- [ ] O painel "🛠 Comando gerado" aparece na `ExecutionPanel` após a primeira geração
|
- [x] O painel "🛠 Comando gerado" aparece na `ExecutionPanel` após a primeira geração
|
||||||
- [ ] O painel está colapsado por padrão
|
- [x] O painel está colapsado por padrão
|
||||||
- [ ] O conteúdo exibe o binário (`ffmpeg` ou `mkvmerge`) seguido de todos os argumentos
|
- [x] O conteúdo exibe o binário (`ffmpeg` ou `mkvmerge`) seguido de todos os argumentos
|
||||||
- [ ] Argumentos com espaços internos são envolvidos em aspas duplas
|
- [x] Argumentos com espaços internos são envolvidos em aspas duplas
|
||||||
- [ ] O botão "📋 Copiar" coloca o texto no clipboard
|
- [x] O botão "📋 Copiar" coloca o texto no clipboard
|
||||||
- [ ] O comando é exibido também para gerações canceladas
|
- [x] O comando é exibido também para gerações canceladas
|
||||||
- [ ] O painel **não** aparece antes da primeira geração (estado `Idle` inicial)
|
- [x] O painel **não** aparece antes da primeira geração (estado `Idle` inicial)
|
||||||
- [ ] Modo Lote exibe o comando do último item processado
|
- [x] Modo Lote exibe o comando do último item processado
|
||||||
- [ ] `cargo test` — 33 testes passando sem regressão
|
- [x] `cargo test` — 68 testes passando sem regressão
|
||||||
|
|||||||
@@ -245,6 +245,19 @@ impl App {
|
|||||||
} else {
|
} else {
|
||||||
FfmpegCommandBuilder::build(&project)
|
FfmpegCommandBuilder::build(&project)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Formatar comando legível para o painel de debug
|
||||||
|
let binary = if uses_mkvmerge { "mkvmerge" } else { "ffmpeg" };
|
||||||
|
let cmd_str = format!(
|
||||||
|
"{} {}",
|
||||||
|
binary,
|
||||||
|
args.iter()
|
||||||
|
.map(|a| if a.contains(' ') { format!("\"{}\"", a) } else { a.clone() })
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(" ")
|
||||||
|
);
|
||||||
|
self.execution_panel.last_command = Some(cmd_str);
|
||||||
|
|
||||||
let (tx, rx) = mpsc::channel::<BackgroundMsg>();
|
let (tx, rx) = mpsc::channel::<BackgroundMsg>();
|
||||||
self.bg_rx = Some(rx);
|
self.bg_rx = Some(rx);
|
||||||
self.execution_panel.state = ExecutionState::Running;
|
self.execution_panel.state = ExecutionState::Running;
|
||||||
@@ -311,6 +324,19 @@ impl App {
|
|||||||
} else {
|
} else {
|
||||||
FfmpegCommandBuilder::build(&project)
|
FfmpegCommandBuilder::build(&project)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Formatar comando legível para o painel de debug do item de lote
|
||||||
|
let binary = if uses_mkvmerge { "mkvmerge" } else { "ffmpeg" };
|
||||||
|
let cmd_str = format!(
|
||||||
|
"{} {}",
|
||||||
|
binary,
|
||||||
|
args.iter()
|
||||||
|
.map(|a| if a.contains(' ') { format!("\"{}\"", a) } else { a.clone() })
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(" ")
|
||||||
|
);
|
||||||
|
self.batch_items[index].last_command = Some(cmd_str);
|
||||||
|
|
||||||
let (tx, rx) = mpsc::channel::<BackgroundMsg>();
|
let (tx, rx) = mpsc::channel::<BackgroundMsg>();
|
||||||
self.bg_rx = Some(rx);
|
self.bg_rx = Some(rx);
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ pub struct BatchItem {
|
|||||||
pub project: Project,
|
pub project: Project,
|
||||||
pub state: ExecutionState,
|
pub state: ExecutionState,
|
||||||
pub log_lines: Vec<String>,
|
pub log_lines: Vec<String>,
|
||||||
|
/// Comando completo enviado ao FFmpeg/mkvmerge na última geração deste item.
|
||||||
|
pub last_command: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BatchItem {
|
impl BatchItem {
|
||||||
@@ -25,6 +27,7 @@ impl BatchItem {
|
|||||||
project,
|
project,
|
||||||
state: ExecutionState::Idle,
|
state: ExecutionState::Idle,
|
||||||
log_lines: Vec::new(),
|
log_lines: Vec::new(),
|
||||||
|
last_command: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -254,7 +257,20 @@ impl BatchPanel {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if let Some(cmd) = &item.last_command {
|
||||||
|
ui.collapsing("🛠 Comando gerado", |ui| {
|
||||||
|
let mut cmd_str = cmd.as_str();
|
||||||
|
ui.add(
|
||||||
|
egui::TextEdit::multiline(&mut cmd_str)
|
||||||
|
.desired_rows(3)
|
||||||
|
.desired_width(f32::INFINITY)
|
||||||
|
.font(egui::TextStyle::Monospace),
|
||||||
|
);
|
||||||
|
if ui.small_button("📋 Copiar").clicked() {
|
||||||
|
ui.output_mut(|o| o.copied_text = cmd.clone());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
} });
|
||||||
}); // push_id
|
}); // push_id
|
||||||
ui.add_space(4.0);
|
ui.add_space(4.0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ pub enum ExecutionState {
|
|||||||
pub struct ExecutionPanel {
|
pub struct ExecutionPanel {
|
||||||
pub state: ExecutionState,
|
pub state: ExecutionState,
|
||||||
pub log_lines: Vec<String>,
|
pub log_lines: Vec<String>,
|
||||||
|
/// Comando completo enviado ao FFmpeg/mkvmerge na última geração.
|
||||||
|
/// Exemplo: "ffmpeg -i input.mkv -c copy ... output.mkv"
|
||||||
|
pub last_command: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExecutionPanel {
|
impl ExecutionPanel {
|
||||||
@@ -22,6 +25,7 @@ impl ExecutionPanel {
|
|||||||
ExecutionPanel {
|
ExecutionPanel {
|
||||||
state: ExecutionState::Idle,
|
state: ExecutionState::Idle,
|
||||||
log_lines: Vec::new(),
|
log_lines: Vec::new(),
|
||||||
|
last_command: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,6 +107,22 @@ impl ExecutionPanel {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Painel de debug: comando gerado
|
||||||
|
if let Some(cmd) = &self.last_command {
|
||||||
|
ui.collapsing("🛠 Comando gerado", |ui| {
|
||||||
|
let mut cmd_str = cmd.as_str();
|
||||||
|
ui.add(
|
||||||
|
egui::TextEdit::multiline(&mut cmd_str)
|
||||||
|
.desired_rows(3)
|
||||||
|
.desired_width(f32::INFINITY)
|
||||||
|
.font(egui::TextStyle::Monospace),
|
||||||
|
);
|
||||||
|
if ui.small_button("📋 Copiar").clicked() {
|
||||||
|
ui.output_mut(|o| o.copied_text = cmd.clone());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
(generate_clicked, cancel_clicked)
|
(generate_clicked, cancel_clicked)
|
||||||
|
|||||||
Reference in New Issue
Block a user