Skip to content

Domain API

This page documents the core domain models and events.

Models

Domain models are framework-agnostic business entities.

models

Domain models for video compression pipeline.

Defines the core entities (VideoFile, CompressionJob) and enumerations that represent the problem domain, independent of infrastructure and UI.

JobStatus

Bases: str, Enum

Enumeration of compression job states.

Attributes:

Name Type Description
PENDING

Waiting to be processed.

PROCESSING

Currently being compressed.

COMPLETED

Successfully compressed.

SKIPPED

Skipped due to filter (e.g., already AV1, below min size).

FAILED

Compression failed; .err marker created.

HW_CAP_LIMIT

GPU hardware capability exceeded; may retry on CPU if enabled.

INTERRUPTED

Ctrl+C during processing; partial output may exist.

ConfigSource

Bases: str, Enum

Source of configuration parameters.

Attributes:

Name Type Description
GLOBAL

Global conf/vbc.yaml configuration.

LOCAL

Local VBC.YAML in video directory.

CLI

CLI arguments (highest priority).

VideoMetadata

Bases: BaseModel

Extracted video stream information.

Attributes:

Name Type Description
width, height

Dimensions in pixels.

codec str

Primary video codec name (h264, hevc, av1, etc.).

audio_codec Optional[str]

Primary audio codec name (pcm_s16le, aac, etc.).

fps float

Frames per second.

camera_model Optional[str]

Inferred camera model from EXIF (for dynamic_quality matching).

camera_raw Optional[str]

Raw EXIF camera string before normalization.

custom_cq Optional[int]

Camera-specific CQ override from dynamic_quality[camera].cq.

bitrate_kbps Optional[float]

Input stream bitrate.

megapixels Optional[int]

Estimated megapixel value (for reference).

color_space Optional[str]

FFmpeg color space (e.g., "bt709", "yuv420p").

pix_fmt Optional[str]

Pixel format from ffprobe (e.g., "yuv420p10le").

duration Optional[float]

Total duration in seconds.

VideoFile

Bases: BaseModel

A discovered video file to process.

Attributes:

Name Type Description
path Path

Full path to the source file.

size_bytes int

File size in bytes.

metadata Optional[VideoMetadata]

Video stream information (extracted during discovery or processing).

CompressionJob

Bases: BaseModel

A video compression task being processed or completed.

Tracks the full lifecycle of a job from discovery through completion, including output metadata and error details.

Attributes:

Name Type Description
source_file VideoFile

The input video file.

status JobStatus

Current job state (PENDING, PROCESSING, COMPLETED, FAILED, etc.).

output_path Optional[Path]

Path where compressed video is written (created during processing).

output_size_bytes Optional[int]

Final output file size (set when complete).

error_message Optional[str]

Error description if status is FAILED or HW_CAP_LIMIT.

duration_seconds Optional[float]

Wall-clock time spent in FFmpeg (excludes metadata ops).

rotation_angle Optional[int]

Applied rotation in degrees (0, 90, 180, 270) or None.

progress_percent float

[0-100] progress during encoding (updated by FFmpeg adapter).

quality_value Optional[int]

CQ/CRF numeric value used for this job (legacy field).

quality_display Optional[str]

Human-readable quality label (e.g., "CQ45", "200 Mbps").

config_source ConfigSource

Configuration source (GLOBAL, LOCAL, or CLI).

verification_passed bool

Output verification result for completed jobs.

verification_error Optional[str]

Verification error details when verification fails.

Events

Domain events enable decoupled communication between components.

events

Domain events for the video compression pipeline.

Events represent state changes and notifications that flow through the EventBus, decoupling the pipeline orchestrator from the UI layer and enabling extensibility.

See infrastructure/event_bus.py for the pub/sub mechanism.

Event

Bases: BaseModel

Base class for all domain events.

Events are validated Pydantic models. They are not frozen by default.

JobEvent

Bases: Event

Base class for events related to a specific compression job.

JobStarted

Bases: JobEvent

Emitted when a job begins compression.

JobProgressUpdated

Bases: JobEvent

Emitted periodically as FFmpeg reports progress.

JobCompleted

Bases: JobEvent

Emitted when a job successfully completes.

JobFailed

Bases: JobEvent

Emitted when a job fails; .err marker is written.

HardwareCapabilityExceeded

Bases: JobEvent

Emitted when GPU hardware limit is hit (HW_CAP_LIMIT status).

Can trigger CPU fallback if configured.

DiscoveryStarted

Bases: Event

Emitted when file discovery begins.

DiscoveryErrorEntry

Bases: BaseModel

Discovery-time .err marker details used by Logs tab.

DiscoveryFinished

Bases: Event

Emitted after file discovery and filtering is complete.

Provides summary counters of discovered and filtered files.

QueueUpdated

Bases: Event

Emitted when the processing queue changes.

RefreshRequested

Bases: Event

Event to trigger re-scanning for new files.

InputDirsChanged

Bases: Event

Event emitted when active input_dirs list changes (Dirs tab apply).

RefreshFinished

Bases: Event

Event emitted after refresh completes (used for UI counters).

ThreadControlEvent

Bases: Event

Event emitted to adjust thread count (Keys '<' or '>').

RequestShutdown

Bases: Event

Event emitted when user requests graceful shutdown (Key 'S').

InterruptRequested

Bases: Event

Event emitted when user requests immediate interrupt (Ctrl+C).

ActionMessage

Bases: Event

Event for user action feedback (displayed in UI for 60s).

ProcessingFinished

Bases: Event

Event emitted when all tasks finish normally.

ProcessingPausedOnError

Bases: Event

Emitted when processing is paused due to a runtime verification failure.

WaitingForInput

Bases: Event

Emitted by orchestrator when wait_on_finish=True and processing is done. Signals UI to display WAITING status and R/S hint.

DirsCursorMove

Bases: Event

Move cursor up/down in the Dirs tab list.

DirsSwapSelected

Bases: Event

Swap the entry under cursor with adjacent entry (-1 up, +1 down).

DirsToggleSelected

Bases: Event

Toggle enabled/disabled state of the entry under cursor.

DirsEnterAddMode

Bases: Event

Enter add-path input mode in Dirs tab.

DirsMarkDelete

Bases: Event

Mark the entry under cursor for deletion (pending).

DirsInputChar

Bases: Event

Append a character to the add-path input buffer. Use char='\x7f' for backspace (removes last character).

DirsConfirmAdd

Bases: Event

Confirm the current input buffer as a new pending directory.

DirsCancelInput

Bases: Event

Cancel add-path input mode without saving.

DirsApplyChanges

Bases: Event

Apply all pending Dirs changes, save to YAML, and trigger refresh.

Usage Examples

Working with VideoFile

from pathlib import Path
from vbc.domain.models import VideoFile, VideoMetadata

# Create a VideoFile
video = VideoFile(
    path=Path("/videos/sample.mp4"),
    size_bytes=125829120  # 120 MB
)

# Add metadata after extraction
video.metadata = VideoMetadata(
    width=1920,
    height=1080,
    codec="h264",
    fps=60.0,
    camera_model="ILCE-7RM5",
    bitrate_kbps=15000.0
)

# Access metadata
print(f"Resolution: {video.metadata.width}x{video.metadata.height}")
print(f"Camera: {video.metadata.camera_model}")

Working with CompressionJob

from vbc.domain.models import CompressionJob, JobStatus, VideoFile
from pathlib import Path

# Create a job
job = CompressionJob(
    source_file=VideoFile(
        path=Path("/videos/sample.mp4"),
        size_bytes=125829120
    ),
    output_path=Path("/videos_out/sample.mp4"),
    rotation_angle=180
)

# Initial status
assert job.status == JobStatus.PENDING

# Update during processing
job.status = JobStatus.PROCESSING

# Mark as completed
job.status = JobStatus.COMPLETED
job.output_size_bytes = 45891200  # 43 MB
job.duration_seconds = 127.5

# Calculate compression ratio
ratio = job.output_size_bytes / job.source_file.size_bytes
savings = (1 - ratio) * 100
print(f"Compression: {savings:.1f}% savings")  # 63.5% savings

Using Events

from vbc.infrastructure.event_bus import EventBus
from vbc.domain.events import JobStarted, JobCompleted
from vbc.domain.models import CompressionJob, VideoFile
from pathlib import Path

# Create event bus
bus = EventBus()

# Subscribe to events
def on_job_started(event: JobStarted):
    print(f"Job started: {event.job.source_file.path.name}")

def on_job_completed(event: JobCompleted):
    print(f"Job completed: {event.job.source_file.path.name}")

bus.subscribe(JobStarted, on_job_started)
bus.subscribe(JobCompleted, on_job_completed)

# Publish events
job = CompressionJob(
    source_file=VideoFile(path=Path("video.mp4"), size_bytes=1000000)
)

bus.publish(JobStarted(job=job))
# Output: Job started: video.mp4

bus.publish(JobCompleted(job=job))
# Output: Job completed: video.mp4

Job Status Transitions

from vbc.domain.models import JobStatus

# Valid transitions
status = JobStatus.PENDING
status = JobStatus.PROCESSING
status = JobStatus.COMPLETED

# Error states
status = JobStatus.FAILED        # Generic failure
status = JobStatus.HW_CAP_LIMIT  # Hardware capability exceeded
status = JobStatus.SKIPPED       # Skipped (AV1, camera filter, etc.)
status = JobStatus.INTERRUPTED   # User interrupted (Ctrl+C)

Event Reference

Event Trigger Data Use Case
DiscoveryStarted Orchestrator starts scanning directory: Path UI: Show "Scanning..."
DiscoveryFinished Scanning complete File counts UI: Update totals
JobStarted Job begins processing job: CompressionJob UI: Add to active list
JobCompleted Job finishes successfully job: CompressionJob UI: Update stats
JobFailed Job fails job, error_message UI: Increment errors
HardwareCapabilityExceeded GPU lacks capability job UI: Show HW_CAP count
JobProgressUpdated FFmpeg progress update progress_percent UI: Update progress bar
QueueUpdated Pending files changed pending_files: List UI: Show next in queue
ActionMessage User action feedback message: str UI: Show for 60s
ProcessingFinished All jobs done - UI: Show completion
RefreshRequested User pressed 'R' - Orchestrator: Re-scan
ThreadControlEvent User pressed </> change: int Orchestrator: Adjust threads
RequestShutdown User pressed 'S' - Orchestrator: Stop accepting jobs
InterruptRequested User pressed Ctrl+C - Orchestrator: Terminate active jobs