feat: atualiza versão do projeto para 1.3 e revisa o plano de desenvolvimento e PRD com novas funcionalidades e requisitos
This commit is contained in:
+114
-7
@@ -1,9 +1,9 @@
|
||||
# Plano de Desenvolvimento — Simple Multimedia Track Audio Editor
|
||||
|
||||
**Versão:** 1.1
|
||||
**Versão:** 1.3
|
||||
**Data:** 28/02/2026
|
||||
**Status:** Concluído — todas as fases implementadas, 33 testes passando
|
||||
**Referência:** PRD v1.1
|
||||
**Status:** Fases 1–6 concluídas; Fase 7 (Persistência) e Fase 8 (Modo Lote) em planejamento
|
||||
**Referência:** PRD v1.2
|
||||
|
||||
---
|
||||
|
||||
@@ -46,7 +46,7 @@ Cada fase deve estar **compilando e com testes passando** antes de avançar para
|
||||
### Value Objects (`src/domain/value_objects/`)
|
||||
|
||||
| Tipo | Implementação |
|
||||
|---|---|
|
||||
| --------------- | ----------------------------------------------------------------------------------------------------- |
|
||||
| `FilePath` | Newtype sobre `PathBuf`; derivar `Clone`, `Debug`, `Serialize`, `Deserialize` |
|
||||
| `TrackId` | Newtype opaco sobre `u32`; derivar `Clone`, `Copy`, `Debug`, `PartialEq`, `Eq`, `Hash` |
|
||||
| `SyncOffset` | Newtype sobre `i64` (milissegundos, **nunca `f64`**); implementar método `from_seconds_str` e `as_ms` |
|
||||
@@ -55,7 +55,7 @@ Cada fase deve estar **compilando e com testes passando** antes de avançar para
|
||||
### Entities (`src/domain/entities/`)
|
||||
|
||||
| Tipo | Campos principais |
|
||||
|---|---|
|
||||
| ---------------- | ----------------------------------------------------------------------------------------------------------------- |
|
||||
| `VideoFile` | `path: FilePath` |
|
||||
| `AudioTrack` | `id: TrackId`, `path: FilePath`, `offset: SyncOffset`, `language: TrackLanguage` |
|
||||
| `SubtitleTrack` | `id: TrackId`, `path: FilePath`, `offset: SyncOffset`, `language: TrackLanguage` |
|
||||
@@ -111,7 +111,7 @@ pub trait FileSystemPort {
|
||||
Implementar nesta ordem (dependência crescente):
|
||||
|
||||
| # | Use Case | Descrição |
|
||||
|---|---|---|
|
||||
| --- | ----------------------- | ----------------------------------------------------------- |
|
||||
| 1 | `LoadMediaInfo` | Usa `MediaInfoPort` para popular `Project::existing_tracks` |
|
||||
| 2 | `AddAudioTrack` | Adiciona `AudioTrack` externo ao `Project::tracks` |
|
||||
| 3 | `AddSubtitle` | Adiciona `SubtitleTrack` externo ao `Project::tracks` |
|
||||
@@ -140,11 +140,13 @@ Implementar nesta ordem (dependência crescente):
|
||||
Responsabilidade única: converter `Project` em `Vec<String>` de argumentos para o FFmpeg.
|
||||
|
||||
Regras invariantes:
|
||||
|
||||
- `-c copy` **sempre presente** (RNF-01 — nunca opcional, nunca configurável)
|
||||
- `SyncOffset(i64 ms)` → `-itsoffset 1.200` (conversão feita **somente aqui**)
|
||||
- `TrackId` → `-map 0:a:N` (mapeamento de índice feito **somente aqui**)
|
||||
|
||||
Exemplo de saída esperada:
|
||||
|
||||
```
|
||||
ffmpeg -i input.mkv -itsoffset 1.200 -i audio_pt.aac -map 0:v -map 0:a -map 1:a -c copy -metadata:s:a:1 language=por output.mkv
|
||||
```
|
||||
@@ -156,9 +158,11 @@ ffmpeg -i input.mkv -itsoffset 1.200 -i audio_pt.aac -map 0:v -map 0:a -map 1:a
|
||||
#### `FfprobeGateway`
|
||||
|
||||
Implementa `MediaInfoPort`. Executa:
|
||||
|
||||
```
|
||||
ffprobe -v quiet -print_format json -show_streams <path>
|
||||
```
|
||||
|
||||
e mapeia a saída JSON para `Vec<MediaTrackInfo>`.
|
||||
|
||||
- [x] Implementar parsing de JSON via `serde_json`
|
||||
@@ -206,7 +210,7 @@ Implementa `MediaProcessorPort`. Executa o processo real do FFmpeg e captura std
|
||||
### Componentes (`src/ui/components/`), em ordem de construção
|
||||
|
||||
| # | Componente | Descrição |
|
||||
|---|---|---|
|
||||
| --- | ------------------- | -------------------------------------------------------------------------------------- |
|
||||
| 1 | `VideoSelector` | Seletor de arquivo de vídeo; dispara `LoadMediaInfo` ao confirmar |
|
||||
| 2 | `ExistingTrackList` | Lista faixas detectadas (áudio/legenda); permite editar offset de cada uma |
|
||||
| 3 | `AddAudioTrackForm` | Formulário para adicionar faixa de áudio externa (arquivo, idioma, offset) |
|
||||
@@ -227,6 +231,109 @@ Implementa `MediaProcessorPort`. Executa o processo real do FFmpeg e captura std
|
||||
|
||||
---
|
||||
|
||||
## Fase 7 — Persistência do Estado do Projeto
|
||||
|
||||
**Objetivo:** Salvar e carregar o estado do `Project` em disco, permitindo que o usuário retome uma sessão anterior sem precisar reconfigurar tudo.
|
||||
|
||||
**Pré-requisito para a Fase 8:** o modo lote se beneficia diretamente da persistência — um carrinho salvo pode ser retomado após fechar a aplicação.
|
||||
|
||||
**Restrição:** a serialização deve viver exclusivamente na camada de infraestrutura/UI. O `domain/` não deve depender de `serde` diretamente, mas as entidades **já derivam** `Serialize`/`Deserialize` — nenhuma mudança no domínio é necessária.
|
||||
|
||||
### Formato e local do arquivo
|
||||
|
||||
- Formato: **JSON** via `serde_json` (já disponível no `Cargo.toml`)
|
||||
- Local: diretório de configuração do usuário (`~/.config/simple-mkv-editor/session.json` no Linux; `AppData` no Windows)
|
||||
- Um único arquivo de sessão por vez (sobrescreve ao salvar)
|
||||
|
||||
### Quando salvar / carregar
|
||||
|
||||
| Evento | Ação |
|
||||
| ------------------------------- | ---------------------------------------------------------------- |
|
||||
| Usuário clica "Salvar sessão" | Serializa `Project` para disco |
|
||||
| Inicialização da aplicação | Verifica se existe arquivo de sessão; oferece opção de restaurar |
|
||||
| Usuário clica "Carregar sessão" | Desserializa e substitui `App::project` |
|
||||
|
||||
> Salvamento automático fica fora do escopo desta fase para evitar escritas freqüentes em disco.
|
||||
|
||||
### Mudanças necessárias
|
||||
|
||||
| Arquivo | O que muda |
|
||||
| --------------------------------------- | ------------------------------------------------------------------------------------- |
|
||||
| `src/infrastructure/persistence/mod.rs` | Novo módulo: `save_session(project)` e `load_session() -> Result<Project>` |
|
||||
| `src/infrastructure/mod.rs` | Expor `persistence` |
|
||||
| `src/ui/app.rs` | Botões "Salvar sessão" / "Carregar sessão" no header; chamar o módulo de persistência |
|
||||
|
||||
### Tarefas
|
||||
|
||||
- [ ] Criar `src/infrastructure/persistence/mod.rs` com `save_session` e `load_session`
|
||||
- [ ] Resolver caminho do arquivo via `dirs` crate (ou `std::env`)
|
||||
- [ ] Adicionar botões no header da UI
|
||||
- [ ] Tratar erros de desserialização (arquivo corrompido ou versão incompatível) com mensagem amigável
|
||||
|
||||
---
|
||||
|
||||
## Fase 8 — Modo Lote via Abas
|
||||
|
||||
**Objetivo:** Permitir que o usuário configure e processe múltiplos projetos sequencialmente, um por vez, sem sobrecarga de I/O.
|
||||
|
||||
**Modelo mental — carrinho:** o usuário adiciona itens livremente, na ordem que quiser, e só inicia o processamento quando clicar "Processar Tudo". Itens podem ser removidos do carrinho a qualquer momento antes de processar.
|
||||
|
||||
**Restrição:** Nenhuma camada abaixo da UI (`domain`, `application`, `adapters`, `infrastructure`) precisa ser alterada — `Project` já é a unidade de trabalho reutilizável.
|
||||
|
||||
### Seleção de arquivos
|
||||
|
||||
Igual ao modo Projeto Único — **diálogos nativos via `FilePickerAdapter` / `rfd`**. Nenhum path é digitado manualmente pelo usuário. O formulário de cada item do lote expõe os mesmos botões "Escolher..." já existentes.
|
||||
|
||||
### Formulário — Opção A (inline na aba Lote)
|
||||
|
||||
O formulário de configuração de um novo item **expande inline** na própria aba Lote, abaixo da lista. Não altera nem reutiliza a aba Projeto Único. Ao confirmar, o item é adicionado ao carrinho e o formulário é limpo.
|
||||
|
||||
```
|
||||
[ + Adicionar item ] ← clique expande o formulário abaixo
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ Vídeo: [ep03.mkv ] [Escolher...] │
|
||||
│ Saída: [ep03_pt.mkv ] [Escolher...] │
|
||||
│ Faixas: [+ Áudio] [+ Legenda] │
|
||||
│ [Cancelar] [Adicionar ✓] │
|
||||
└─────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Mudanças na UI
|
||||
|
||||
| Arquivo | O que muda |
|
||||
| ---------------------------------- | --------------------------------------------------------------------------------------------------------------- |
|
||||
| `src/ui/app.rs` | Adicionar `enum ActiveTab { Single, Batch }` e `active_tab: ActiveTab`; adicionar `batch_items: Vec<BatchItem>` |
|
||||
| `src/ui/components/batch_panel.rs` | Novo componente: carrinho de itens, formulário inline de adição, botão "Processar Tudo" |
|
||||
| `src/ui/components/mod.rs` | Expor `batch_panel` |
|
||||
|
||||
### Estrutura de `BatchItem`
|
||||
|
||||
```rust
|
||||
struct BatchItem {
|
||||
project: Project,
|
||||
state: ExecutionState, // reutiliza o enum já existente
|
||||
}
|
||||
```
|
||||
|
||||
### Fluxo de execução do lote
|
||||
|
||||
1. Usuário adiciona itens ao carrinho (zero ou mais), configura cada um com diálogo nativo
|
||||
2. Itens podem ser removidos do carrinho enquanto nenhum processamento estiver em curso
|
||||
3. Ao clicar "Processar Tudo", o lote é bloqueado (sem mais adições/remoções)
|
||||
4. Para cada item em ordem: `state → Running` → `run_ffmpeg_async` → aguarda `BackgroundMsg::Done | Error` → `state → Success | Error` → próximo item
|
||||
5. "Cancelar" interrompe o item atual via `cancel_tx`; os demais permanecem no carrinho com estado `Idle`
|
||||
|
||||
### Tarefas
|
||||
|
||||
- [ ] Criar `enum ActiveTab` e barra de abas no `update()` de `App`
|
||||
- [ ] Criar `BatchItem` e `batch_items: Vec<BatchItem>` em `App`
|
||||
- [ ] Criar componente `BatchPanel` com carrinho e formulário inline (Opção A)
|
||||
- [ ] Implementar loop sequencial de execução em `App::process_batch()`
|
||||
- [ ] Exibir estado individual por item (`Aguardando | Processando | Concluído | Erro`)
|
||||
- [ ] Bloquear adição/remoção de itens durante processamento
|
||||
|
||||
---
|
||||
|
||||
## Critérios de Conclusão (v1.0)
|
||||
|
||||
Alinhados com o PRD seção 12:
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# PRD — Simple Multimedia Track Audio Editor
|
||||
|
||||
**Versão:** 1.1
|
||||
**Versão:** 1.2
|
||||
**Data:** 28/02/2026
|
||||
**Status:** Em desenvolvimento
|
||||
**Revisão:** Incorporados feedbacks de arquitetura — modelo de sessão, ffprobe, tipos fortes e regra de no-reencode
|
||||
**Revisão:** v1.2 — Adicionado RF-09 (Modo Lote); batch promovido de backlog para requisito planejado
|
||||
|
||||
---
|
||||
|
||||
@@ -105,6 +105,17 @@ As ferramentas existentes são complexas (ex: interface direta do FFmpeg via CLI
|
||||
- A faixa original é remapeada com o novo timestamp via `ffmpeg -itsoffset` combinado com `-map`
|
||||
- Útil para corrigir atrasos em faixas de dublagem ou legenda já incorporadas ao arquivo
|
||||
|
||||
### RF-09 — Processamento em lote
|
||||
|
||||
- A interface oferece duas abas: **Projeto Único** (fluxo atual) e **Lote**
|
||||
- A aba Lote funciona como um **carrinho**: o usuário adiciona, revisa e remove itens livremente antes de processar
|
||||
- Cada item é um projeto completo e independente (vídeo, faixas e saída próprios), configurado via **formulário inline** na própria aba Lote — sem navegação para outra tela
|
||||
- A seleção de arquivos usa **diálogos nativos** (igual ao modo Projeto Único) — nenhum path é digitado manualmente
|
||||
- O processamento é **sequencial** — um projeto por vez, sem paralelismo, para evitar sobrecarga de I/O
|
||||
- Durante o processamento, o carrinho é bloqueado: não é possível adicionar nem remover itens
|
||||
- Cada item exibe seu estado individual: `Aguardando | Processando | Concluído | Erro`
|
||||
- É possível cancelar o item em execução; os demais permanecem no carrinho com estado `Aguardando`
|
||||
|
||||
---
|
||||
|
||||
## 7. Requisitos Não Funcionais
|
||||
@@ -159,7 +170,7 @@ Arquivo de saída (.mkv)
|
||||
### Stack
|
||||
|
||||
| Camada | Tecnologia | Motivo |
|
||||
|--------------|-------------------------------|---------------------------------------------|
|
||||
| ------------ | ------------------------------ | ------------------------------------ |
|
||||
| Interface | `egui` / `eframe` | Nativo, simples, multiplataforma |
|
||||
| Backend | Rust (`std::process::Command`) | Estável, sem dependências externas |
|
||||
| Erros | `anyhow` | Propagação de erros simplificada |
|
||||
@@ -209,7 +220,7 @@ As dependências sempre apontam de fora para dentro. Camadas internas não conhe
|
||||
Contém as entidades e objetos de valor do negócio. Não depende de nada externo.
|
||||
|
||||
| Tipo | Exemplos |
|
||||
|----------------|-----------------------------------------------------------------------------------|
|
||||
| ------------- | ------------------------------------------------------------------------------------ |
|
||||
| Entities | `Project`, `VideoFile`, `AudioTrack`, `SubtitleTrack`, `MkvOutput`, `MediaTrackInfo` |
|
||||
| Value Objects | `TrackId`, `SyncOffset`, `TrackLanguage`, `FilePath` |
|
||||
|
||||
@@ -233,7 +244,7 @@ Contém as regras de negócio da aplicação. Orquestra as entidades do domínio
|
||||
Define traits (ports) que as camadas externas devem implementar.
|
||||
|
||||
| Tipo | Exemplos |
|
||||
|------------|-------------------------------------------------------------------------------------------------------------------|
|
||||
| --------- | ---------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Use Cases | `LoadMediaInfo`, `AddAudioTrack`, `AddSubtitle`, `AdjustSync`, `EditExistingTrackSync`, `SetTrackLanguage`, `GenerateOutput` |
|
||||
| Ports | `MediaProcessorPort`, `MediaInfoPort`, `FileSystemPort` |
|
||||
|
||||
@@ -254,7 +265,7 @@ Define traits (ports) que as camadas externas devem implementar.
|
||||
Implementam os ports definidos na camada de Application. Traduzem dados entre o domínio e o mundo externo.
|
||||
|
||||
| Tipo | Exemplos |
|
||||
|--------------------|---------------------------------------------------------------------------|
|
||||
| ------------ | --------------------------------------------------------- |
|
||||
| Gateway | `FfmpegCommandBuilder`, `FfmpegGateway`, `FfprobeGateway` |
|
||||
| Presenter | `ErrorPresenter` (formata stderr do FFmpeg) |
|
||||
| File Adapter | `FilePickerAdapter` |
|
||||
@@ -268,7 +279,7 @@ Implementam os ports definidos na camada de Application. Traduzem dados entre o
|
||||
Camada mais externa. Contém o framework de UI e a execução real de processos.
|
||||
|
||||
| Tipo | Exemplos |
|
||||
|--------------|-------------------------------------------------------|
|
||||
| ---------- | ------------------------------------------------------ |
|
||||
| UI | `App` (eframe), componentes egui |
|
||||
| Process | Execução de `std::process::Command` / `tokio::process` |
|
||||
| Filesystem | Leitura e escrita de arquivos |
|
||||
@@ -301,7 +312,7 @@ src/
|
||||
## 10. Débitos Técnicos
|
||||
|
||||
| ID | Descrição | Impacto | Mitigação |
|
||||
|-----|--------------------------------------|------------------|--------------------------------------|
|
||||
| ----- | ----------------------------------- | ----------------------------------- | ------------------------------------------------------------------------------ |
|
||||
| DT-01 | FFmpeg não embutido | Usuário precisa instalar | Distribuir junto com a aplicação |
|
||||
| DT-02 | Dependência de processo externo | Menor controle interno | Encapsular via módulo de serviço |
|
||||
| DT-03 | Parsing de erros do FFmpeg (stderr) | Necessário tratamento manual | Parsear saída e exibir mensagem amigável |
|
||||
@@ -318,7 +329,6 @@ src/
|
||||
- Seleção de faixa padrão no container MKV
|
||||
- Remoção de faixas existentes do arquivo original
|
||||
- Suporte a perfis de configuração salvos
|
||||
- Modo de processamento em lote (batch)
|
||||
|
||||
---
|
||||
|
||||
@@ -345,17 +355,17 @@ src/
|
||||
|
||||
O FFmpeg é uma ferramenta de poder absurdo — e opacidade equivalente. O usuário não entende `track index`, `stream mapping` ou `itsoffset`. O usuário entende:
|
||||
|
||||
- *"Áudio em português está 1.2 segundos atrasado"*
|
||||
- *"Quero adicionar a legenda em inglês"*
|
||||
- *"Gerar o arquivo final"*
|
||||
- _"Áudio em português está 1.2 segundos atrasado"_
|
||||
- _"Quero adicionar a legenda em inglês"_
|
||||
- _"Gerar o arquivo final"_
|
||||
|
||||
Toda decisão de UX deve partir dessa perspectiva. Termos técnicos do FFmpeg nunca devem aparecer na interface.
|
||||
|
||||
| FFmpeg (interno) | Interface (usuário) |
|
||||
|-----------------------|--------------------------------------|
|
||||
| -------------------- | ------------------------------ |
|
||||
| `-itsoffset -1200ms` | "Adiantar 1.2s" |
|
||||
| `stream 0:a:1` | "Faixa de áudio 2 — Português" |
|
||||
| `-c copy` | *(invisível — nunca exposto)* |
|
||||
| `-c copy` | _(invisível — nunca exposto)_ |
|
||||
| `ffprobe output` | Lista de faixas detectadas |
|
||||
|
||||
---
|
||||
@@ -373,6 +383,7 @@ O MKV (Matroska) é estruturalmente um banco de dados multimídia. Suas operaç
|
||||
O arquivo de saída não é uma criação nova — é uma nova **visão** do container original com faixas adicionadas e metadados ajustados, sem tocar nos bytes de mídia.
|
||||
|
||||
Esse modelo mental simplifica a implementação:
|
||||
|
||||
- Sem buffers de vídeo
|
||||
- Sem pipelines de transcoding
|
||||
- Apenas mapeamento de streams e metadados
|
||||
|
||||
+20
-8
@@ -2,7 +2,7 @@
|
||||
|
||||
**Data:** 28/02/2026
|
||||
**Status:** Fases 1–6 concluídas + exportação de faixa + exibição/remoção de faixas adicionadas + layout responsivo + progresso em tempo real + cancelamento de geração — compilando, 33 testes passando, zero warnings do projeto, aplicação executável
|
||||
**Referência:** DEVELOPMENT_PLAN.md v1.1
|
||||
**Referência:** DEVELOPMENT_PLAN.md v1.3
|
||||
|
||||
---
|
||||
|
||||
@@ -14,6 +14,7 @@ Todas as 6 fases do plano de desenvolvimento foram implementadas. O projeto comp
|
||||
Todos os 14 warnings de `unused`/`dead_code` foram resolvidos: assignment morto em `command_builder.rs` removido, lifetime explícito em `FilePath::to_string_lossy` corrigido, e APIs arquiteturais não chamadas pela UI suprimidas com `#[allow(dead_code)]`.
|
||||
|
||||
Após a conclusão das fases, foram implementadas funcionalidades adicionais:
|
||||
|
||||
- Exportação de faixa de áudio ou legenda diretamente da lista de faixas existentes
|
||||
- Exibição das faixas externas adicionadas com opção de remoção individual
|
||||
- Layout responsivo com painéis fixos (cabeçalho, rodapé, barra lateral) e área central com scroll
|
||||
@@ -25,7 +26,7 @@ Após a conclusão das fases, foram implementadas funcionalidades adicionais:
|
||||
## Status por Fase
|
||||
|
||||
| Fase | Descrição | Status |
|
||||
|------|----------------------------------|-------------|
|
||||
| ---- | ------------------------------- | ------------ |
|
||||
| 1 | Setup do projeto | ✅ Concluída |
|
||||
| 2 | Domain (núcleo puro) | ✅ Concluída |
|
||||
| 3 | Application (use cases + ports) | ✅ Concluída |
|
||||
@@ -110,8 +111,9 @@ src/
|
||||
## Testes Unitários (33/33 passando)
|
||||
|
||||
### Domain — Value Objects
|
||||
|
||||
| Teste | Resultado |
|
||||
|-------|-----------|
|
||||
| ------------------------------------------------------------------------ | --------- |
|
||||
| `sync_offset::from_seconds_str_positivo` — `"1.2"` → `SyncOffset(1200)` | ✅ |
|
||||
| `sync_offset::from_seconds_str_negativo` — `"-0.5"` → `SyncOffset(-500)` | ✅ |
|
||||
| `sync_offset::from_seconds_str_com_sufixo_s` | ✅ |
|
||||
@@ -123,15 +125,17 @@ src/
|
||||
| `track_language::idioma_invalido_longo` — `"port"` | ✅ |
|
||||
|
||||
### Domain — Entities
|
||||
|
||||
| Teste | Resultado |
|
||||
|-------|-----------|
|
||||
| ------------------------------------------------------------------------- | --------- |
|
||||
| `project::projeto_valido` | ✅ |
|
||||
| `project::projeto_invalido_mesmo_caminho` — output == source retorna erro | ✅ |
|
||||
| `project::track_id_opaco` — TrackId não expõe indexação interna | ✅ |
|
||||
|
||||
### Application — Use Cases (todos com mocks, sem I/O real)
|
||||
|
||||
| Teste | Resultado |
|
||||
|-------|-----------|
|
||||
| ------------------------------------------------------------------ | --------- |
|
||||
| `load_media_info::carrega_faixas_no_projeto` | ✅ |
|
||||
| `add_audio_track::adiciona_audio_no_projeto` | ✅ |
|
||||
| `add_subtitle::adiciona_legenda_no_projeto` | ✅ |
|
||||
@@ -143,8 +147,9 @@ src/
|
||||
| `generate_output::sempre_inclui_c_copy` | ✅ |
|
||||
|
||||
### Adapters — FfmpegCommandBuilder
|
||||
|
||||
| Teste | Resultado |
|
||||
|-------|-----------|
|
||||
| -------------------------------------------------------- | --------- |
|
||||
| `sempre_contem_c_copy` — invariante RNF-01 | ✅ |
|
||||
| `output_e_o_ultimo_argumento` | ✅ |
|
||||
| `itsoffset_formato_correto` — `1200ms` → `"1.200"` | ✅ |
|
||||
@@ -152,8 +157,9 @@ src/
|
||||
| `metadata_idioma_audio` — `-metadata:s:a:0 language=por` | ✅ |
|
||||
|
||||
### Application — ExportTrack
|
||||
|
||||
| Teste | Resultado |
|
||||
|-------|-----------|
|
||||
| ----------------------------------------------------------------------------------------- | --------- |
|
||||
| `export_track::exporta_audio_com_c_a_copy` — `-c:a copy` presente, sem `-c copy` genérico | ✅ |
|
||||
| `export_track::exporta_audio_mapeia_stream_correto` — `0:stream_index` correto | ✅ |
|
||||
| `export_track::exporta_legenda_sem_c_copy` — nenhuma forma de `-c` para legendas | ✅ |
|
||||
@@ -161,8 +167,9 @@ src/
|
||||
| `export_track::rejeita_faixa_de_video` — retorna erro para `TrackKind::Video` | ✅ |
|
||||
|
||||
### Application — RemoveTrack
|
||||
|
||||
| Teste | Resultado |
|
||||
|-------|-----------|
|
||||
| ---------------------------------------------------------------------- | --------- |
|
||||
| `remove_track::remove_faixa_existente` — faixa removida do Vec | ✅ |
|
||||
| `remove_track::erro_se_id_inexistente` — retorna erro se id não existe | ✅ |
|
||||
|
||||
@@ -195,12 +202,16 @@ rfd = "0.14"
|
||||
## O Que Falta (Backlog de Refinamento)
|
||||
|
||||
### Funcional
|
||||
|
||||
- [x] Exportar faixa de áudio ou legenda existente para arquivo separado
|
||||
- [x] Exibição de faixas externas adicionadas com opção de remover
|
||||
- [x] Progresso em tempo real via `run_ffmpeg_async` — `run_ffmpeg_async` usa `std::sync::mpsc::Sender<String>`; `start_generation` cria tokio Runtime + thread encaminhadora; cada linha de stderr do FFmpeg aparece no log antes do término
|
||||
- [x] Cancelamento de geração — botão "Cancelar" visível durante `Running`; sinal via `tokio::sync::oneshot`; `child.kill().await` no `tokio::select!`; estado `ExecutionState::Cancelled` exibido em amarelo
|
||||
- [ ] **Fase 7 — Persistência do Estado** — salvar/carregar `Project` em JSON (`~/.config/...`); botões "Salvar sessão" / "Carregar sessão" no header; novo módulo `infrastructure/persistence` — ver DEVELOPMENT_PLAN.md Fase 7
|
||||
- [ ] **Fase 8 — Modo Lote via Abas** — navegação por abas (`Projeto Único` / `Lote`); `Vec<BatchItem>` em `App`; processamento sequencial (um por vez); novo componente `BatchPanel` — ver DEVELOPMENT_PLAN.md Fase 8
|
||||
|
||||
### Qualidade
|
||||
|
||||
- [x] Corrigir 14 warnings de `unused`/`dead_code` identificados por `cargo build`:
|
||||
- `next_input_idx += 1` removido do loop externo em `command_builder.rs` (assignment nunca lido)
|
||||
- Lifetime explícito `Cow<'_, str>` adicionado em `FilePath::to_string_lossy`
|
||||
@@ -210,6 +221,7 @@ rfd = "0.14"
|
||||
- [ ] Testes de snapshot para o `FfmpegCommandBuilder` com projetos mais complexos
|
||||
|
||||
### UI
|
||||
|
||||
- [x] Layout responsivo mais refinado
|
||||
- [ ] Exibição do comando FFmpeg gerado em modo debug (ex: painel colapsável na `ExecutionPanel`)
|
||||
- [ ] Persistência do estado do projeto em disco (`serde` já disponível)
|
||||
|
||||
Reference in New Issue
Block a user