# FFmpegProgressBar

A Raku module that adds a progress bar to ffmpeg commands.

```
output.mp4 ████████████░░░░░░ 75% 00:00:05 ETA: 2s
```

With optional frame/bitrate info:
```
output.mp4 ████████████░░░░░░ 75% 00:00:05 ETA: 2s [750/1000 (25.5fps)] (2.5Mbps)
```

## Features

- **Command-line interface** - Use `ffpb` command to run ffmpeg with a progress bar
- **Can be used as a library** - Use in your Raku scripts
- **Progress bar** - Shows percentage, elapsed time, and ETA during
  encoding
  - **Optional display features** - Show frames, bitrate, or verbose output with CLI flags
- **Auto duration detection** - Automatically detects video duration from ffprobe or parses -t/-to/-ss arguments
- **Multi-input duration** - Correctly handles `-ss` per input (e.g., `-ss 10 -i a.mp4 -ss 30 -i b.mp4`)
- **Multi-output support** - Handles multiple output files (e.g., `-i input.mp4 output1.mp4 output2.mkv`)
- **-map support** - Filters duration detection to relevant inputs when `-map` is used (e.g., `-map 0:v -map 1:a`)
- **Flexible time parsing** - Supports HH:MM:SS, MM:SS, and unit formats (1h30m, 45m30s)
- **Two-pass encoding** - Automatically detects and runs pass 1 before
  showing progress for pass 2
- **Progress Tracking API** - `get-progress()`, `progress-supply()`, `watch-progress()` for external monitoring (see section below)

## Requirements

- [ffmpeg](https://ffmpeg.org/) - Must be installed and in PATH
- [Raku](https://www.raku.org/) - Version 6.d or later
- [Terminal::Spinners](https://raku.land/cpan:RYNIX/Terminal::Spinners) -
  Progress bar rendering (dependency)
- [Terminal::Size](https://raku.land/zef:demayl/Terminal::Size) - Terminal
  width detection (dependency)
- [Pod::To::Man](https://raku.land/zef:samy/Pod::To::Man) - Man page
  rendering for `--man` (dependency)

## Installation

```bash
zef install ffmpegprogressbar
```

### Installing from source

To install from a local folder:

```bash
cd /path/to/FFmpegProgressBar
zef install .
```

## Usage

### Command Line

```bash
ffpb -i input.mp4 -c:v libx264 output.mp4
```

### Command Line Options

- `-V`, `--verbose` - Show detected duration and executed command
- `-F`, `--frames` - Show current frame and encoding fps
- `-B`, `--bitrate` - Show output bitrate
- `-S`, `--style` - Set progress bar style (bar, hash, hash-dash, equals)
- `-D`, `--duration` - Set duration in seconds (skip auto-detection)
- `-M`, `--ffmpeg` - Path to ffmpeg binary
- `-P`, `--ffprobe` - Path to ffprobe binary
- `-E`, `--stderr` - Show ffmpeg stderr on success (last 20 lines, use `--stderr all` for all)
- `-Q`, `--quiet` - Suppress progress bar rendering (useful when only using progress API)


### Library

```raku
use FFmpegProgressBar;

my $progress = FfmpegProgress.new(:duration(30), :verbose(True));
$progress.run('-i', 'input.mp4', 'output.mp4');
```

Or use the subroutine interface:

```raku
ffmpeg-progress(
    '-i', 'input.mp4',
    '-c:v', 'libx264',
    'output.mp4',
    :duration(30),
:verbose(True)
)
```

## Library Options

- `$ffmpeg` - Path to ffmpeg binary (default: 'ffmpeg')
- `$ffprobe` - Path to ffprobe binary (default: 'ffprobe')
- `$duration` - Manually set video duration (default: 0, auto-detected)
- `$verbose` - Show detected duration and executed command
- `$quiet` - Suppress progress bar rendering (useful when only using progress API)
- `$show-frames` - Show current frame and encoding fps
- `$show-bitrate` - Show output bitrate
- `$bar-type` - Progress bar style (bar, hash, hash-dash, equals)
- `$no-color` - Disable colored output
- `$stderr-lines` - Show ffmpeg stderr on success ('20', '50', 'all', or '' for off)
- `$ffmpeg-loglevel` - Set ffmpeg log level (default: 'error')

### Library Methods

- `$ff.quit()` - Send 'q' to gracefully stop encoding (call from external code)
- `$ff.quit(:force)` - Force kill ffmpeg immediately

```raku
use FFmpegProgressBar;

my $ff = FfmpegProgress.new(:duration(30), :verbose(True));
$ff.run('-i', 'input.mp4', 'output.mp4');

# Or control externally:
my $ff2 = FfmpegProgress.new(:ffmpeg('/path/to/ffmpeg'));
$ff2.run('-i', 'input.mp4', 'output.mp4');
# ... in another thread or loop:
$ff2.quit() if $some-condition;
$ff2.quit(:force);  # force kill
```

## Progress Tracking API

FFmpegProgressBar provides three ways to monitor encoding progress externally:

### watch-progress() (Recommended)

Simple async iteration that yields percent directly. Use `:quiet` to suppress the progress bar:

```raku
use FFmpegProgressBar;

my $p = FfmpegProgress.new(:quiet);
my $promise = start { $p.run('-i', 'input.mp4', 'output.mp4') };

for $p.watch-progress(:interval(0.5)) -> $percent {
    say "Progress: {$percent.fmt('%.1f')}%";
    $p.quit() if $percent >= 50;
}

await $promise;
say $p.get-progress().summary;
```

With full snapshots (`watch-progress(:emit)`):

```raku
for $p.watch-progress(:emit) -> $snap {
    say $snap.summary;
    $p.quit() if $snap.is-stalled;
}
```

### get-progress()

One-off read - returns a `ProgressSnapshot`:

```raku
my $snap = $p.get-progress();
say $snap.percent;       # 75.0
say $snap.fps;          # 25.0
say $snap.is-complete;  # Bool
say $snap.is-failed;    # Bool
say $snap.summary;
```

### progress-supply()

Reactive supply for event-driven code:

```raku
$p.progress-supply.tap: -> $snap {
    say "Progress: {$snap.percent.fmt('%.1f')}%";
};
```

The progress API returns time-based percentage that matches the progress bar exactly.

## Dotfile Configuration

You can create a config file to set default options. The following paths
are checked in order:

### Unix/Linux/macOS
- `~/.ffpbrc`
- `~/.config/ffpbrc`
- `~/.config/ffpb/config`
- `/etc/ffpbrc`

### Windows
- `%USERPROFILE%\.ffpbrc`
- `%USERPROFILE%\.config\ffpbrc`
- `%USERPROFILE%\.config\ffpb\config`
- `%APPDATA%\ffpb\config`
- `%APPDATA%\ffpbrc`

Each line should contain one option (like CLI arguments). Lines
starting with `#` are treated as comments.

Example `~/.ffpbrc`:

```bash
# Always show verbose info, frame info and use hash style
-V
-F
-S hash
```

## Examples

```bash
# Basic encoding
ffpb -i input.mp4 output.mkv

# With verbose output
ffpb -V -i input.mp4 output.mp4

# With frames and bitrate
ffpb -F -B -i input.mp4 output.mp4

# With custom bar style
ffpb -S hash -i input.mp4 output.mp4

# With duration override
ffpb -D 60 -i input.mp4 output.mp4

# With custom ffmpeg/ffprobe paths
ffpb -M /usr/bin/ffmpeg -P /usr/bin/ffprobe -i input.mp4 output.mp4

# Show stderr on success
ffpb -E -i input.mp4 output.mp4

# Last 50 lines				
ffpb -E 50 -i input.mp4 output.mp4

# All stderr output
ffpb -E all -i input.mp4 output.mp4

# Two-pass encoding
ffpb -i input.mp4 -c:v libx264 -pass 2 -f mp4 output.mp4
```

FFmpegProgressBar automatically detects `-pass 2` and runs the analysis pass (pass 1) silently before displaying the progress bar for the encoding pass.

## Bar styles (use `-S` or `--style`)

- `bar`   - ████████████░░░░░░ (default)
- `hash`  - [████████...     ]
- `hash-dash` - [████████-----]
- `equals` - [========        ]

## Windows Support

Full Windows support is implemented. The following features work on Windows 10 and later:

- **Progress bar** - Works in Windows Terminal, VS Code terminal, or modern conhost
- **Unicode support** - Uses console code page detection
- **Non-blocking keyboard input** - Uses Win32 Console API
- **Binary lookup** - Automatically finds ffmpeg with .exe, .bat, .cmd extensions
- **Config file locations** - Supports %APPDATA% and %USERPROFILE% paths

### Requirements on Windows

- Windows 10 or later (for ANSI color support)
- [ffmpeg](https://ffmpeg.org/) installed and in PATH
- [Raku](https://www.raku.org/) version 6.d or later

For best results, use [Windows Terminal](https://github.com/microsoft/terminal) which has full ANSI/VT support.

### Note on Keyboard Input

- **Unix/Linux/macOS**: Pressing 'q' or Ctrl+C cleanly stops encoding. First Ctrl+C sends 'q' (graceful), second Ctrl+C force-kills ffmpeg, third Ctrl+C exits the program entirely.
- **Windows**: Pressing 'q' provides graceful shutdown (recommended). Ctrl+C force kills ffmpeg immediately due to limitations with how the native executable wrapper handles console signals on Windows.

# AUTHOR

Sasha Abbott <sashaa@disroot.org>

# LICENSE

This library is free software; you can redistribute it and/or modify it under CC0.
