5.2 KiB
5.2 KiB
Copilot Instructions — Simple Multimedia Track Audio Editor
Visão do Produto
Editor gráfico (egui/eframe) que combina vídeo, áudio e legendas em um único arquivo MKV sem reencoding — apenas mux e ajuste de timestamps via FFmpeg. Pense no MKV como um banco de dados: as operações são INSERT de faixas e UPDATE de timestamps; nenhum byte de mídia é reprocessado.
Arquitetura — Clean Architecture (de dentro para fora)
domain/ ← núcleo puro; zero I/O, zero frameworks
application/ ← casos de uso + ports (traits); testável com mocks
adapters/ ← implementações concretas dos ports (FFmpeg, filesystem)
infrastructure/ ← execução assíncrona de processo real (tokio)
ui/ ← egui/eframe; única camada que lida com estado visual
Project(src/domain/entities/project.rs) é a única fonte de verdade do estado em memória. Toda mutação passa por métodos doProjectou pelos casos de uso.App(src/ui/app.rs) detém umOption<Project>e orquestra os componentes de UI.- Nenhuma camada interna (
domain,application) deve importareframe,tokio, ou qualquer crate de I/O.
Regras de Negócio Críticas
-c copyé invariante —FfmpegCommandBuildersempre emite-c copy. Nunca remova nem torne opcional.SyncOffseté semprei64em milissegundos — nunca usef64para representar offset internamente. A conversão para segundos ocorre apenas emFfmpegCommandBuilder::build()e na exibição (Display).output.path != source.path—Project::new()retornaErrse forem iguais.- Faixas externas adicionadas pelo usuário ficam em
project.tracks: Vec<Track>; faixas detectadas via ffprobe ficam emproject.existing_tracks: Vec<MediaTrackInfo>— nunca misture os dois vetores.
Convenções de Código
- Newtypes para todos os value objects:
FilePath(PathBuf),TrackId(u32),SyncOffset(i64),TrackLanguage(String). Não use os tipos primitivos diretamente nos casos de uso ou entidades. - Ports são traits em
src/application/ports/mod.rs. Toda comunicação cross-layer usaResult<T>deanyhow. - Casos de uso em
src/application/use_cases/recebem ports por referência (&impl Port) e oProjectpor&mut— nunca acessam FFmpeg diretamente. - Componentes de UI (
src/ui/components/) têm estado próprio (formulários, campos) mas não detêm oProject— recebem referências ou emitem valores de volta paraApp.
Comunicação Assíncrona (UI ↔ Background Thread)
A geração do MKV roda em thread separada (tokio). O padrão é:
UI → spawn(tokio) → run_ffmpeg_async(args, progress_tx, cancel_rx)
↓ BackgroundMsg (LogLine | Done | Error)
bg_rx (mpsc::Receiver) lido no loop update() do egui
App::bg_rxrecebe mensagens;App::cancel_txé umoneshot::Senderpara cancelamento.- O loop
update()do egui drenabg_rxa cada frame para atualizarExecutionPanel.
Fluxo de Dados Principal
Usuário seleciona vídeo
→ FilePickerAdapter → FilePath
→ LoadMediaInfo (use case) → FfprobeGateway → Vec<MediaTrackInfo>
→ App::try_build_project() → Project
Usuário adiciona faixa
→ AddAudioTrack / AddSubtitle (use case) → Project.tracks.push(Track)
Usuário clica "Gerar MKV"
→ FfmpegCommandBuilder::build(&project) → Vec<String>
→ run_ffmpeg_async(args, tx, cancel_rx) (infrastructure)
→ FfmpegGateway::execute() (adapter, modo síncrono — apenas em testes/uso direto)
Comandos de Desenvolvimento
cargo check # verificar compilação sem produzir binário
cargo test # rodar todos os testes (33 testes, todos devem passar)
cargo run # executar a aplicação (requer ffmpeg e ffprobe no PATH)
Dependências externas necessárias em runtime: ffmpeg e ffprobe disponíveis no PATH. A inicialização do App chama validate_dependencies() e exibe erro global se ausentes.
Arquivos-Chave
| Arquivo | Papel |
|---|---|
src/domain/entities/project.rs |
Entidade raiz; todas as mutações de estado |
src/domain/value_objects/sync_offset.rs |
Conversão ms ↔ segundos; testes unitários de parsing |
src/adapters/ffmpeg/command_builder.rs |
Tradução Project → argumentos FFmpeg; única responsável por -itsoffset e -map |
src/adapters/ffmpeg/ffprobe_gateway.rs |
Parser JSON do ffprobe → Vec<MediaTrackInfo> |
src/infrastructure/process/mod.rs |
run_ffmpeg_async com streaming de stderr e cancelamento |
src/ui/app.rs |
Orquestrador da UI; gerencia Project, canal de background e componentes |
src/application/ports/mod.rs |
Traits MediaInfoPort, MediaProcessorPort, FileSystemPort |