audiobook-forge 2.9.0

CLI tool for converting audiobook directories to M4B format with chapters and metadata
Documentation
# AGENTS.md - Audiobook Forge (Rust)

## Project Overview

Audiobook Forge is a blazing-fast CLI tool for converting audiobook directories to M4B format with chapters and metadata. This is a complete Rust rewrite of the original Python version, delivering 3-4x faster performance with true multi-core utilization.

**Key Capabilities**:
- Parallel processing of multiple audiobooks
- Smart quality detection and preservation
- Chapter generation from multiple sources (files, CUE sheets, auto-detection)
- Metadata extraction and enhancement (ID3, M4A tags)
- Cover art detection and embedding
- Batch operations on entire libraries
- Error recovery with automatic retry
- Hardware acceleration support (Apple Silicon aac_at encoder)

**Project Status**: All 6 development phases complete. See `docs/development/phases/` for detailed implementation history.

---

## Build & Test Commands

### Building
```bash
# Development build
cargo build

# Release build (optimized)
cargo build --release

# Binary location
./target/debug/audiobook-forge    # debug
./target/release/audiobook-forge  # release
```

### Testing
```bash
# Run all tests
cargo test

# Run library tests only
cargo test --lib

# Run with output
cargo test -- --nocapture

# Run specific test
cargo test test_name
```

### Running
```bash
# Check dependencies
cargo run -- check

# Process audiobooks
cargo run -- build --root /path/to/audiobooks --parallel 4

# Organize library
cargo run -- organize --root /path/to/audiobooks

# Config management
cargo run -- config init
cargo run -- config show
cargo run -- config validate
```

---

## Architecture

### Module Structure

```
src/
├── main.rs              # CLI entry point
├── lib.rs               # Library root
├── models/              # Core data structures
│   ├── book.rs          # BookFolder, BookCase (A/B/C/D classification)
│   ├── track.rs         # Audio track representation
│   ├── quality.rs       # QualityProfile (bitrate, codec, etc.)
│   ├── config.rs        # Configuration structures
│   └── result.rs        # ProcessingResult
├── utils/               # Utilities
│   ├── config.rs        # ConfigManager (load/save YAML)
│   ├── validation.rs    # DependencyChecker (FFmpeg, etc.)
│   └── sorting.rs       # Natural sorting (track1, track2, track10)
├── cli/                 # CLI interface
│   └── commands.rs      # Clap command definitions
├── audio/               # Audio operations
│   ├── ffmpeg.rs        # FFmpeg wrapper (probe, concat, transcode)
│   ├── metadata.rs      # Metadata extraction (ID3, M4A)
│   ├── chapters.rs      # Chapter generation
│   └── cue.rs           # CUE file parsing
└── core/                # Core processing logic
    ├── processor.rs     # Single book processing
    ├── parallel.rs      # Parallel batch processing
    ├── organizer.rs     # Library organization
    └── progress.rs      # Progress tracking (indicatif)
```

### Key Concepts

**BookCase Classification**:
- **Case A**: Already M4B (skip)
- **Case B**: MP3 files only (requires conversion)
- **Case C**: M4A files only (can use fast concat)
- **Case D**: Mixed MP3/M4A (requires transcode to AAC)

**Quality Profiles**: Automatically detect best quality across tracks and preserve it. Support compatibility checking for concatenation.

**Processing Modes**:
- Copy mode: Ultra-fast concatenation without re-encoding (when compatible)
- Transcode mode: Convert to AAC when necessary

---

## Code Style & Conventions

### Rust Patterns
- Use `anyhow::Result<T>` for application errors
- Use `thiserror` for custom error types
- Prefer `?` operator over explicit error handling
- Use `.context()` to add error context
- Follow Rust naming conventions (snake_case for functions/variables, PascalCase for types)

### Error Handling
```rust
// Good - provides context
let tracks = discover_tracks(&path)
    .context(format!("Failed to discover tracks in {}", path.display()))?;

// Avoid - no context
let tracks = discover_tracks(&path)?;
```

### Async/Await
- Use tokio runtime for async operations
- FFmpeg calls use `tokio::process::Command`
- Parallel processing uses `tokio::spawn` with semaphore for resource limits

### Testing
- Unit tests in same file as implementation (`#[cfg(test)] mod tests`)
- Integration tests in `tests/` directory
- Use `tempfile` for temp directories in tests
- Mock external dependencies when possible

---

## Testing Guidelines

### Running Tests
All tests should pass before committing:
```bash
cargo test --lib
cargo test --all
```

### Writing Tests
```rust
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_something() {
        // Arrange
        let input = "value";

        // Act
        let result = function_under_test(input);

        // Assert
        assert_eq!(result, expected);
    }

    #[tokio::test]
    async fn test_async_function() {
        // For async tests
    }
}
```

### Test Coverage
- All public functions should have tests
- Edge cases should be covered (empty input, invalid data, etc.)
- Quality profile comparison logic is critical (heavily tested)

---

## Dependencies

### External Tools (Required)
The application requires these external tools to be installed:

```bash
# macOS
brew install ffmpeg atomicparsley gpac

# Ubuntu/Debian
apt install ffmpeg atomicparsley gpac
```

Validation: Use `audiobook-forge check` to verify installation.

### Rust Crates

**Core**:
- `clap 4.5` - CLI framework with derive API
- `tokio 1.35` - Async runtime
- `serde 1.0` + `serde_yaml 0.9` - Config serialization
- `anyhow 1.0` + `thiserror 1.0` - Error handling

**Audio/Metadata**:
- `id3 1.13` - MP3 metadata reading
- `mp4ameta 0.11` - M4B/M4A metadata reading

**Utilities**:
- `indicatif 0.17` - Progress bars
- `walkdir 2.4` - Directory traversal
- `natord 1.0` - Natural sorting
- `tracing 0.1` - Structured logging
- `which 6.0` - Executable lookup
- `dirs 5.0` - Config directory paths
- `chrono 0.4` - Date/time handling

**Testing**:
- `tempfile 3.8` - Temp files/directories
- `assert_cmd 2.0` - CLI testing
- `predicates 3.0` - Test assertions

---

## Phase History

The project was built in 6 phases. Full documentation available in `docs/development/phases/`:

1. **Phase 1 - Foundation** (`01-foundation.md`): Data models, CLI structure, config system
2. **Phase 2 - Audio Operations** (`02-audio-ops.md`): FFmpeg integration, metadata extraction
3. **Phase 3 - Parallel Processing** (`03-parallel.md`): Multi-core batch processing
4. **Phase 4 - Progress & Polish** (`04-progress.md`): Progress bars, error recovery
5. **Phase 5 - Organization** (`05-organize.md`): Library organization features
6. **Phase 6 - Final Polish** (`06-polish.md`): Performance optimization, final testing

**Current Status**: All phases complete, 77 tests passing.

---

## Common Tasks

### Adding a New CLI Command
1. Define command in `src/cli/commands.rs` using clap derive
2. Add handler function in `main.rs`
3. Implement logic in appropriate module
4. Add tests
5. Update help text

### Adding a New Audio Operation
1. Add function to `src/audio/ffmpeg.rs` or related module
2. Use `tokio::process::Command` for FFmpeg calls
3. Parse output with regex if needed
4. Add error handling with context
5. Write unit tests with temp files

### Modifying Configuration
1. Update structs in `src/models/config.rs`
2. Add serde defaults if needed
3. Update `templates/config.yaml` template
4. Update validation in `src/utils/config.rs`
5. Test serialization/deserialization

### Performance Optimization
- Profile with `cargo flamegraph` or similar tools
- Check parallel worker count (default: CPU cores / 2)
- Verify copy mode is used when possible (no transcoding)
- Monitor memory usage during batch operations

---

## Development Environment

### Recommended Tools
- `rust-analyzer` - LSP for IDE integration
- `cargo-watch` - Auto-rebuild on file changes
- `cargo-clippy` - Linting
- `cargo-fmt` - Code formatting

### Configuration Location
- Config file: `~/.config/audiobook-forge/config.yaml`
- Logs: stdout/stderr (structured with tracing)

### Platform Notes
- **macOS**: Apple Silicon encoder (`aac_at`) is automatically used when available
- **Linux**: Standard AAC encoder (`libfdk_aac` or `aac`)
- FFmpeg must be compiled with AAC support

---

## Commit & PR Guidelines

### Commit Messages
Follow conventional commits format:
```
<type>(<scope>): <description>

[optional body]
[optional footer]
```

Types: `feat`, `fix`, `docs`, `test`, `refactor`, `perf`, `chore`

Examples:
```
feat(audio): add CUE file parsing support
fix(metadata): handle missing album tag gracefully
docs(readme): update installation instructions
test(quality): add compatibility check tests
```

### Before Committing
1. Run tests: `cargo test --all`
2. Run clippy: `cargo clippy -- -D warnings`
3. Format code: `cargo fmt`
4. Update CHANGELOG.md if needed
5. Ensure binary builds: `cargo build --release`

---

## Security Considerations

- **Path Traversal**: Validate all user-provided paths
- **Command Injection**: Never interpolate user input into shell commands
  - Use `Command::arg()` instead of string interpolation
  - FFmpeg args are always passed as separate arguments
- **Resource Limits**: Semaphore limits concurrent FFmpeg processes
- **Temporary Files**: Always clean up temp files (use `tempfile` crate)

---

## Troubleshooting

### Common Issues

**FFmpeg not found**:
- Run `audiobook-forge check`
- Ensure FFmpeg is in PATH
- On macOS: `brew install ffmpeg`

**Tests failing**:
- Check external dependencies are installed
- Verify FFmpeg version is recent enough
- Check temp directory permissions

**Slow processing**:
- Check parallel worker count: `--parallel N`
- Verify copy mode is being used (check logs)
- Profile with release build, not debug

**Metadata extraction fails**:
- Ensure `atomicparsley` and `MP4Box` are installed
- Check file permissions
- Verify audio files are not corrupted

---

## Additional Resources

- Main documentation: `docs/`
- Phase implementation details: `docs/development/phases/`
- Specifications: `docs/specs/` (for future requirements)
- User guides: `docs/guides/`
- Changelog: `CHANGELOG.md` (in root)