Skip to content

Configuration API

This page documents the configuration models and loader.

Models

models

Configuration models for VBC application.

Pydantic models defining the YAML configuration schema with validation rules. All fields have defaults; empty YAML files are valid (use all defaults).

Key models: - AppConfig: Top-level configuration container - GeneralConfig: Core compression settings (threads, GPU, filters, metadata) - GpuConfig: GPU monitoring and sparkline display settings - UiConfig: Dashboard layout and display preferences - AutoRotateConfig: Filename pattern-based rotation rules

Configuration precedence: CLI args > YAML > defaults

GpuEncoderConfig

Bases: BaseModel

NVENC AV1 encoder settings.

CpuEncoderConfig

Bases: BaseModel

CPU encoder settings for SVT-AV1 and advanced AOM modes.

GpuConfig

Bases: BaseModel

GPU monitoring and dashboard sparkline configuration.

Controls GPU metrics sampling and visualization. Metrics include: utilization, memory usage, temperature, and power draw.

Attributes:

Name Type Description
enabled bool

Enable GPU monitoring and sparkline display.

refresh_rate int

[DEPRECATED] Use sample_interval_s instead.

sample_interval_s float

Seconds between GPU metric samples (min 0.1s).

history_window_s float

Total time window shown in sparklines (min 10s, default 5min).

nvtop_device_index int

GPU index to monitor (default 0 for primary GPU).

nvtop_device_name Optional[str]

Override device selection by name instead of index.

nvtop_path Optional[str]

Custom path to nvtop binary (e.g., /usr/local/bin/nvtop). Auto-detected if not set.

DynamicRateConfig

Bases: BaseModel

Per-camera bitrate rule for quality_mode='rate'.

DynamicQualityRule

Bases: BaseModel

Per-camera dynamic quality rule.

GeneralConfig

Bases: BaseModel

Core compression and processing configuration.

Controls threading, GPU/CPU selection, file filtering, and metadata handling. Quality targets can be controlled by CQ/CRF (default) or bitrate mode.

Attributes:

Name Type Description
threads int

Max concurrent compression jobs (default 1, min 1).

prefetch_factor int

Submit-on-demand multiplier (jobs = threads * prefetch_factor).

gpu bool

Use GPU (NVENC) instead of CPU (SVT-AV1) encoder.

gpu_refresh_rate int

[DEPRECATED] Use gpu_config.sample_interval_s.

queue_sort str

Queue sorting mode (name, rand, dir, size-asc, size-desc, ext).

queue_seed Optional[int]

Random seed for deterministic 'rand' sorting (None = random).

log_path Optional[str]

Path to FFmpeg log file (None = use /compression.log).

cpu_fallback bool

Retry with CPU if GPU hardware capability exceeded.

ffmpeg_cpu_threads Optional[int]

Limit threads per FFmpeg worker (None = FFmpeg decides).

copy_metadata bool

Preserve EXIF/XMP metadata from source video.

use_exif bool

Extract camera model from EXIF for dynamic_quality matching.

filter_cameras List[str]

Only process videos from these camera models (empty = all).

dynamic_quality Dict[str, DynamicQualityRule]

Per-camera rules (e.g., {"ILCE-7RM5": {"cq": 38}}).

quality_mode Literal['cq', 'rate']

Rate control mode: "cq" (default) or "rate" (bitrate).

bps Optional[str]

Target bitrate value for rate mode (absolute or ratio).

minrate Optional[str]

Optional minimum bitrate for rate mode (same class as bps).

maxrate Optional[str]

Optional maximum bitrate for rate mode (same class as bps).

rate_target_max_bps Optional[str]

Optional hard upper cap for resolved target bitrate in rate mode.

extensions List[str]

Video file extensions to process.

min_size_bytes int

Skip files smaller than this (default 1MiB).

clean_errors bool

Remove .err markers and retry failed jobs.

verify_fail_action Literal['false', 'log', 'pause', 'exit']

Output verification mode (false, log, pause, exit).

skip_av1 bool

Skip files already encoded in AV1 codec.

strip_unicode_display bool

Remove unicode chars from displayed filenames (UI safety).

manual_rotation Optional[int]

Force rotation angle (0, 90, 180, 270) for all videos (None = auto).

min_compression_ratio float

Minimum savings required (0.1 = 10%; keep original if below).

debug bool

Enable verbose logging and timing information.

AutoRotateConfig

Bases: BaseModel

Filename pattern-based automatic rotation configuration.

Maps regex patterns to rotation angles. If a filename matches a pattern, that rotation is applied automatically (overrides manual_rotation).

Attributes:

Name Type Description
patterns Dict[str, int]

Dict mapping regex patterns to angles (0, 90, 180, 270). Example: {"DJI_..MP4": 0, "GOPR..MP4": 180}

validate_angles classmethod
validate_angles(v: Dict[str, int]) -> Dict[str, int]

Validate that all rotation angles are 0, 90, 180, or 270 degrees.

Source code in vbc/config/models.py
@field_validator('patterns')
@classmethod
def validate_angles(cls, v: Dict[str, int]) -> Dict[str, int]:
    """Validate that all rotation angles are 0, 90, 180, or 270 degrees."""
    for pattern, angle in v.items():
        if angle not in {0, 90, 180, 270}:
            raise ValueError(f"Invalid rotation angle {angle} for pattern {pattern}. Must be 0, 90, 180, or 270.")
    return v

UiConfig

Bases: BaseModel

Dashboard UI display configuration.

Controls Rich dashboard layout, panel sizing, and display limits.

Attributes:

Name Type Description
activity_feed_max_items int

Max items in activity feed panel (1-20, default 5).

active_jobs_max_display int

Max concurrent jobs to show in panel (1-16, default 8).

panel_height_scale float

Dashboard height fraction (0.3-1.0, default 0.7 = 30% reduction).

WebServerConfig

Bases: BaseModel

Web dashboard server configuration.

Attributes:

Name Type Description
enabled bool

Start web dashboard automatically (default False).

port int

TCP port to listen on (default 8765).

host str

Bind address — "0.0.0.0" for all interfaces (LAN access), "127.0.0.1" for localhost only.

InputDirEntry

Bases: BaseModel

Configured input directory entry with enabled/disabled state.

AppConfig

Bases: BaseModel

Top-level VBC application configuration.

Combines all configuration sections: general, GPU monitoring, encoder, UI, autorotate, and directory mappings.

Directory mapping modes: 1. Suffix mode: input_dirs + suffix_output_dirs (e.g., /videos -> /videos_out) 2. Explicit mode: enabled input_dirs[i] -> output_dirs[i] (1:1 pairing required)

Attributes:

Name Type Description
general GeneralConfig

Core compression settings.

input_dirs List[InputDirEntry]

Ordered list of input directory entries (path + enabled state).

output_dirs List[str]

List of output directories for enabled input_dirs (empty = suffix mode).

suffix_output_dirs Optional[str]

Suffix for auto-generated output dirs (default "_out").

errors_dirs List[str]

List of .err marker directories for enabled input_dirs (empty = suffix mode).

suffix_errors_dirs Optional[str]

Suffix for auto-generated error dirs (default "_err").

autorotate AutoRotateConfig

Filename pattern-based rotation rules.

gpu_config GpuConfig

GPU monitoring configuration.

gpu_encoder GpuEncoderConfig

GPU encoder configuration.

cpu_encoder CpuEncoderConfig

CPU encoder configuration.

ui UiConfig

Dashboard UI configuration.

web_server WebServerConfig

Read-only HTMX web dashboard configuration.

DemoInputFolder

Bases: BaseModel

Demo input folder with mockup status and stats.

Attributes:

Name Type Description
name str

Folder path/name (e.g., "DEMO/Studio_A").

status Optional[str]

Folder status - "ok", "nonexist", "norw" (None defaults to "ok").

files Optional[int]

Number of files in folder (mockup data for demo display).

size Optional[str]

Folder size as string (e.g., "10MB", "1.5GB") for demo display.

normalize_queue_sort

normalize_queue_sort(value: Optional[str]) -> str

Normalize and validate queue sorting mode.

Parameters:

Name Type Description Default
value Optional[str]

Raw queue_sort value from config or CLI.

required

Returns:

Type Description
str

Normalized queue_sort mode ("name", "rand", "dir", "size-asc", "size-desc", "ext").

Raises:

Type Description
ValueError

If value is not a valid queue_sort choice.

Source code in vbc/config/models.py
def normalize_queue_sort(value: Optional[str]) -> str:
    """Normalize and validate queue sorting mode.

    Args:
        value: Raw queue_sort value from config or CLI.

    Returns:
        Normalized queue_sort mode ("name", "rand", "dir", "size-asc", "size-desc", "ext").

    Raises:
        ValueError: If value is not a valid queue_sort choice.
    """
    if value is None:
        return "name"
    normalized = str(value).strip().lower()
    if not normalized:
        return "name"
    normalized = QUEUE_SORT_ALIASES.get(normalized, normalized)
    if normalized not in QUEUE_SORT_CHOICES:
        allowed = ", ".join(QUEUE_SORT_CHOICES)
        raise ValueError(f"Invalid queue_sort '{value}'. Use one of: {allowed}.")
    return normalized

validate_queue_sort

validate_queue_sort(value: Optional[str], extensions: List[str]) -> str

Validate queue_sort mode with extension dependency check.

Parameters:

Name Type Description Default
value Optional[str]

Queue sort mode to validate.

required
extensions List[str]

List of file extensions (required for 'ext' mode).

required

Returns:

Type Description
str

Validated queue_sort mode.

Raises:

Type Description
ValueError

If 'ext' mode is used without extensions list.

Source code in vbc/config/models.py
def validate_queue_sort(value: Optional[str], extensions: List[str]) -> str:
    """Validate queue_sort mode with extension dependency check.

    Args:
        value: Queue sort mode to validate.
        extensions: List of file extensions (required for 'ext' mode).

    Returns:
        Validated queue_sort mode.

    Raises:
        ValueError: If 'ext' mode is used without extensions list.
    """
    normalized = normalize_queue_sort(value)
    if normalized == "ext" and not extensions:
        raise ValueError("queue_sort 'ext' requires a non-empty extensions list.")
    return normalized

Loader

loader

load_config

load_config(config_path: Path) -> AppConfig

Loads YAML config and parses it into AppConfig Pydantic model.

Source code in vbc/config/loader.py
def load_config(config_path: Path) -> AppConfig:
    """Loads YAML config and parses it into AppConfig Pydantic model."""
    if not config_path.exists():
        raise FileNotFoundError(f"Config file not found: {config_path}")

    with open(config_path, 'r') as f:
        data = yaml.safe_load(f) or {}

    autorotate = data.get("autorotate")
    if isinstance(autorotate, dict) and "patterns" not in autorotate:
        data["autorotate"] = {"patterns": autorotate}

    _validate_input_dirs_schema(data)

    # Existing vbc.yaml structure has 'general' and 'autorotate' at root
    return AppConfig(**data)

save_dirs_config

save_dirs_config(config_path: Path, input_dirs: List[Dict[str, Any]]) -> None

Update input_dirs field in the YAML config file.

Reads the existing YAML, updates only the input_dirs field, and writes back. All other YAML content is preserved.

Parameters:

Name Type Description Default
config_path Path

Path to the vbc.yaml config file.

required
input_dirs List[Dict[str, Any]]

New ordered list of input directory objects.

required
Source code in vbc/config/loader.py
def save_dirs_config(config_path: Path, input_dirs: List[Dict[str, Any]]) -> None:
    """Update input_dirs field in the YAML config file.

    Reads the existing YAML, updates only the input_dirs field, and writes back.
    All other YAML content is preserved.

    Args:
        config_path: Path to the vbc.yaml config file.
        input_dirs: New ordered list of input directory objects.
    """
    if not config_path.exists():
        return

    with open(config_path, 'r') as f:
        data = yaml.safe_load(f) or {}

    data['input_dirs'] = input_dirs
    if 'disabled_input_dirs' in data:
        del data['disabled_input_dirs']

    with open(config_path, 'w') as f:
        yaml.dump(data, f, default_flow_style=False, allow_unicode=True, sort_keys=False)

load_demo_config

load_demo_config(config_path: Path) -> DemoConfig

Loads YAML config and parses it into DemoConfig Pydantic model.

Source code in vbc/config/loader.py
def load_demo_config(config_path: Path) -> DemoConfig:
    """Loads YAML config and parses it into DemoConfig Pydantic model."""
    if not config_path.exists():
        raise FileNotFoundError(f"Demo config file not found: {config_path}")

    with open(config_path, 'r') as f:
        data = yaml.safe_load(f) or {}

    return DemoConfig(**data)

CLI Overrides

Helpers that apply CLI option values to loaded YAML configuration.

overrides

build_job_config

build_job_config(base_config: AppConfig, local_registry: Optional[LocalConfigRegistry], file_path: Path, cli_overrides: Optional[CliConfigOverrides]) -> Tuple[AppConfig, ConfigSource]

Build config for a specific job with proper hierarchy.

Applies configuration overrides in priority order: 1. Global config (base_config) 2. Local VBC.YAML (if exists for file's directory) 3. CLI arguments (if provided)

Parameters:

Name Type Description Default
base_config AppConfig

Global configuration from conf/vbc.yaml.

required
local_registry Optional[LocalConfigRegistry]

Registry of local VBC.YAML files (optional).

required
file_path Path

Path to video file being processed.

required
cli_overrides Optional[CliConfigOverrides]

CLI argument overrides (optional).

required

Returns:

Type Description
AppConfig

Tuple of (merged_config, config_source_indicator)

ConfigSource
  • merged_config: Final configuration with all overrides applied
Tuple[AppConfig, ConfigSource]
  • config_source_indicator: Highest priority source (GLOBAL, LOCAL, or CLI)
Source code in vbc/config/overrides.py
def build_job_config(
    base_config: AppConfig,
    local_registry: Optional["LocalConfigRegistry"],
    file_path: Path,
    cli_overrides: Optional[CliConfigOverrides],
) -> Tuple[AppConfig, ConfigSource]:
    """Build config for a specific job with proper hierarchy.

    Applies configuration overrides in priority order:
    1. Global config (base_config)
    2. Local VBC.YAML (if exists for file's directory)
    3. CLI arguments (if provided)

    Args:
        base_config: Global configuration from conf/vbc.yaml.
        local_registry: Registry of local VBC.YAML files (optional).
        file_path: Path to video file being processed.
        cli_overrides: CLI argument overrides (optional).

    Returns:
        Tuple of (merged_config, config_source_indicator)
        - merged_config: Final configuration with all overrides applied
        - config_source_indicator: Highest priority source (GLOBAL, LOCAL, or CLI)
    """
    # Start with global config (deep copy to avoid mutation)
    config = base_config.model_copy(deep=True)
    source = ConfigSource.GLOBAL

    # Apply local config if exists
    if local_registry:
        local_entry = local_registry.get_applicable_config(file_path)
        if local_entry:
            config = merge_local_config(config, local_entry.data, None)
            source = ConfigSource.LOCAL

    # Apply CLI overrides (highest priority)
    if cli_overrides and cli_overrides.has_overrides:
        cli_overrides.apply(config)
        source = ConfigSource.CLI

    return config, source

Rate Control

Validation and normalization helpers for CQ and bitrate-based quality modes.

rate_control

Helpers for bitrate-based quality mode parsing and validation.

Local Registry

Helpers for local configuration discovery and persistence.

local_registry

Registry for hierarchical local VBC.YAML configuration files.

Manages discovery and resolution of directory-specific config overrides. Local configs apply to all files in a directory and its subdirectories.

LocalConfigEntry dataclass

LocalConfigEntry(path: Path, directory: Path, data: Dict[str, Any], depth: int)

A discovered local VBC.YAML configuration.

Attributes:

Name Type Description
path Path

Absolute path to VBC.YAML file.

directory Path

Directory containing VBC.YAML.

data Dict[str, Any]

Parsed and validated config data (dict).

depth int

Directory depth for hierarchy resolution (number of path parts).

LocalConfigRegistry

LocalConfigRegistry()

Thread-safe registry for local VBC.YAML configurations.

Manages discovery and hierarchical resolution of local config files. Nearest ancestor VBC.YAML wins (child overrides parent).

Initialize empty registry.

Source code in vbc/config/local_registry.py
def __init__(self):
    """Initialize empty registry."""
    self._configs: Dict[Path, LocalConfigEntry] = {}
    self._lock = threading.Lock()
    self._logger = logging.getLogger(__name__)
register
register(config_path: Path, config_data: Dict[str, Any]) -> None

Register a discovered VBC.YAML file.

Parameters:

Name Type Description Default
config_path Path

Absolute path to VBC.YAML file.

required
config_data Dict[str, Any]

Parsed and validated config dictionary.

required
Source code in vbc/config/local_registry.py
def register(self, config_path: Path, config_data: Dict[str, Any]) -> None:
    """Register a discovered VBC.YAML file.

    Args:
        config_path: Absolute path to VBC.YAML file.
        config_data: Parsed and validated config dictionary.
    """
    directory = config_path.parent
    depth = len(directory.parts)

    entry = LocalConfigEntry(
        path=config_path,
        directory=directory,
        data=config_data,
        depth=depth,
    )

    with self._lock:
        self._configs[directory] = entry
        self._logger.debug(
            "Registered local config: %s (depth=%d)", config_path, depth
        )
get_applicable_config
get_applicable_config(file_path: Path) -> Optional[LocalConfigEntry]

Get nearest ancestor VBC.YAML for a file path.

Walks up from file's parent directory to find first matching VBC.YAML.

Parameters:

Name Type Description Default
file_path Path

Absolute path to video file.

required

Returns:

Type Description
Optional[LocalConfigEntry]

LocalConfigEntry if found, None otherwise.

Source code in vbc/config/local_registry.py
def get_applicable_config(self, file_path: Path) -> Optional[LocalConfigEntry]:
    """Get nearest ancestor VBC.YAML for a file path.

    Walks up from file's parent directory to find first matching VBC.YAML.

    Args:
        file_path: Absolute path to video file.

    Returns:
        LocalConfigEntry if found, None otherwise.
    """
    current = file_path.parent

    with self._lock:
        # Walk up directory tree
        while True:
            if current in self._configs:
                entry = self._configs[current]
                self._logger.debug(
                    "Found applicable config for %s: %s", file_path, entry.path
                )
                return entry

            # Stop at filesystem root
            if current.parent == current:
                break

            current = current.parent

    self._logger.debug("No local config found for %s", file_path)
    return None
build_from_discovery
build_from_discovery(root_dirs: List[Path]) -> None

Scan directory trees and register all VBC.YAML files.

Parameters:

Name Type Description Default
root_dirs List[Path]

List of root directories to scan recursively.

required
Source code in vbc/config/local_registry.py
def build_from_discovery(self, root_dirs: List[Path]) -> None:
    """Scan directory trees and register all VBC.YAML files.

    Args:
        root_dirs: List of root directories to scan recursively.
    """
    for root_dir in root_dirs:
        if not root_dir.exists():
            self._logger.warning("Root directory does not exist: %s", root_dir)
            continue

        if not root_dir.is_dir():
            self._logger.warning("Root path is not a directory: %s", root_dir)
            continue

        self._logger.debug("Scanning for VBC.YAML files in: %s", root_dir)
        self._scan_directory(root_dir)

Input Directories

Validation and mapping helpers for multi-input directory configuration.

input_dirs

can_write_output_dir_path

can_write_output_dir_path(output_dir: Path) -> bool

Public wrapper for output/errors dir writability check.

Source code in vbc/config/input_dirs.py
def can_write_output_dir_path(output_dir: Path) -> bool:
    """Public wrapper for output/errors dir writability check."""
    return _can_write_output_dir_path(output_dir)

Usage Example

from pathlib import Path
from vbc.config.loader import load_config
from vbc.infrastructure.ffmpeg import extract_quality_value

# Load from default location
config = load_config(Path("conf/vbc.yaml"))

# Load from custom path
config = load_config(Path("custom.yaml"))

# Access settings
print(f"Threads: {config.general.threads}")
print(f"GPU quality: {extract_quality_value(config.gpu_encoder.common_args)}")
print(f"GPU: {config.general.gpu}")

# Validation happens when creating/parsing models
from vbc.config.models import GeneralConfig
from pydantic import ValidationError
try:
    GeneralConfig(threads=0)
except ValidationError as e:
    print(e)

Configuration Validation

Pydantic models provide automatic validation:

from vbc.config.models import GeneralConfig
from pydantic import ValidationError

# Valid config
config = GeneralConfig(threads=8)

# Invalid: threads must be > 0
try:
    config = GeneralConfig(threads=0)
except ValidationError as e:
    print(e)
    # Field required to be greater than 0

# Invalid: min_compression_ratio must be 0.0-1.0
try:
    config = GeneralConfig(min_compression_ratio=1.5)
except ValidationError as e:
    print(e)
    # Field required to be less than or equal to 1.0

Auto-Rotation Validation

from vbc.config.models import AutoRotateConfig
from pydantic import ValidationError

# Valid patterns
config = AutoRotateConfig(patterns={
    "DJI_.*\\.MP4": 180,
    "GOPR.*": 90
})

# Invalid: angle must be 0, 90, 180, or 270
try:
    config = AutoRotateConfig(patterns={
        "pattern": 45  # Invalid angle
    })
except ValidationError as e:
    print(e)
    # Invalid rotation angle 45. Must be 0, 90, 180, or 270.