--- url: /docs/swagger.md description: >- Find FFmate's comprehensive API documentation using Swagger (OpenAPI). Get the URL to access interactive specs for all REST endpoints, models, and parameters --- # API Documentation with Swagger (OpenAPI) FFmate provides comprehensive API documentation using the Swagger. This interactive documentation allows you to easily explore, understand, and test FFmate's REST API directly from your web browser. ## How to Access the Swagger UI Once your FFmate server is running, you can access the Swagger UI in your web browser at the following URL: **`http://:/swagger/index.html`** * Replace `` with the hostname or IP address where FFmate is running (e.g., `localhost` if running locally). * Replace `` with the port number FFmate is listening on (default is `3000`). ::: tip Default URL If you're running FFmate locally on the default port, just copy the URL below into your browser's address bar to access the Swagger (OpenAPI) interface: ```sh http://localhost:3000/swagger/index.html ``` ::: ## Postman Collection Prefer testing APIs in Postman? Click the button below to open the official FFmate Postman collection and start exploring the API with ready-made requests—no setup required. --- --- url: /docs/faq.md --- # FFmate FAQ FFmate is an automation layer built on top of FFmpeg to simplify media transcoding workflows. Learn more → [What is FFmate?](/docs/what-is-ffmate) FFmate runs on Windows, macOS, Linux, and Docker. Learn more → [Platform Support](/docs/getting-started#platform-support) The quickest path is Homebrew: ```bash brew tap welovemedia/ffmate --no-quarantine brew install ffmate ``` Learn more → [Download & Install FFmate](/docs/getting-started#download--install-ffmate) FFmate’s API & Web UI listen on port **3000** by default. Add `--port ` (or `-p`) when you start the server, e.g. `ffmate server --port 8080`, or set the `PORT` env‑var in Docker. Learn more → [Server Command Flags](/docs/flags#server-command-flags) Use `--ffmpeg "/full/path/to/ffmpeg"` (or `-f`) when launching `ffmate server`. In containers, set the `FFMPEG` env‑var or bake the binary into the image. FFmate will call that binary for every task. Learn more → [Server Command Flags](/docs/flags#server-command-flags) Send a `POST` to `/api/v1/tasks` with at minimum a `command` string. Example: ```bash curl -X POST http://localhost:3000/api/v1/tasks \ -H "Content-Type: application/json" \ -d '{ "command": "-y -i ${INPUT_FILE} -c:v libx264 -crf 23 ${OUTPUT_FILE}", "inputFile": "videos/input.mp4", "outputFile": "videos/output.mp4", "priority": 50 }' ``` FFmate queues the task, returns its UUID, and fires a `task.created` webhook. Learn more → [Creating a Task](/docs/tasks#creating-a-task) `GET /api/v1/tasks/{taskId}` returns a JSON payload including `status`, `progress`, and timestamps. You can also check the Web UI’s *Tasks* tab for live updates. Learn more → [Monitoring a Task](/docs/tasks#monitoring-a-task) `PATCH /api/v1/tasks/{taskId}/cancel` immediately stops queued or running jobs and marks them `DONE_CANCELED`. The Web UI offers a one‑click “Cancel” button too. Learn more → [Canceling a Task](/docs/tasks#canceling-a-task) POST an array of task objects to `/api/v1/tasks/batch`. FFmate assigns a shared `batch` ID so you can track them as a group while each task still runs independently. Learn more → [Submitting Multiple Tasks as a Batch](/docs/tasks#submitting-multiple-tasks-as-a-batch) `PATCH /api/v1/tasks/{taskId}/restart` resets the task to `QUEUED`, clears errors, and puts it back in the processing queue. Learn more → [Restarting a Task](/docs/tasks#restarting-a-task) POST to `/api/v1/watchfolders` with a filter: ```json "filter": { "extensions": { "include": ["mov"] } } ``` Learn more → [Creating a Watchfolder](/docs/watchfolder#creating-a-watchfolder) Each detected file passes through a **growth checks**: FFmate compares file size across `growthChecks` successive scans. Only when the size remains constant does the task start. This prevents half‑copied media from breaking jobs. Learn more → [How File Detection Works](/docs/watchfolder#how-file-detection-works) Create a preset (Web UI or `/api/v1/presets`) once, then reference its UUID in future tasks or watchfolders using `"preset": ""`. This keeps command‑lines DRY and centrally managed. Learn more → [Presets](/docs/presets) Embed placeholders like `${TIMESTAMP_SECONDS}` inside your `outputFile` or preset path. FFmate expands them at runtime so `clip_${TIMESTAMP_SECONDS}.mp4` becomes `clip_1717065600.mp4`. Learn more → [Wildcards](/docs/wildcards) Add a `preProcessing` or `postProcessing` when creating a task or watchfolder: ```json "preProcessing": { "scriptPath": "/scripts/prepare.sh" }, "postProcessing": { "scriptPath": "/scripts/cleanup.sh" } ``` FFmate executes them and passes a JSON sidecar with task metadata. Learn more → [Pre and Post Processing](/docs/pre-post-processing) ```bash ffmate server --port 8080 --max-concurrent-tasks 5 --loglevel warn ``` Learn more → [Server Command Flags](/docs/flags#server-command-flags) Start the FFmate server with `--debug="queue"` Learn more → [Global Flags](/docs/flags#global-flags) Start FFmate and open `/swagger` in your browser (e.g., ) to access the OpenAPI UI. Learn more → [Swagger](/docs/swagger) Run `ffmate update` for native installs, or pull the newest Docker image (`ghcr.io/welovemedia/ffmate:latest && docker compose up -d`). Homebrew users can `brew upgrade ffmate`. Learn more → [Updating FFmate](/docs/getting-started#updating-ffmate) Join the Discord community, file issues on GitHub, or reach out via the support links in the docs’ *Community & Support* page. Feedback on docs is welcome—every page has an “Edit this page” link! Learn more → [Community & Support](/docs/ffmate-community) --- --- url: /docs/ffmate-internals.md description: >- Explore FFmate's internal architecture. Understand how its REST API, SQLite DB, Web UI, Webhooks, Watchfolders & Task Queue interact for FFmpeg automation & integration --- # FFmate Internals This section breaks down FFmate’s core components and how they work together. It’s handy when you’re troubleshooting, tweaking settings, or plugging FFmate into your existing infrastructure ### High-Level Component Diagram ```mermaid graph TD %% ─── UI & API ───────────────────────── WebUI["Web UI"]:::ui REST_API["REST API"]:::api WebUI --> REST_API %% ─── Services (single row) ─────────── subgraph Services ["Services"] direction LR TaskSvc["Task Service"]:::svc PresetSvc["Preset Service"]:::svc WatchfolderSvc["Watchfolder Service"]:::svc WebhookSvc["Webhook Service"]:::svc end REST_API --> TaskSvc REST_API --> PresetSvc REST_API --> WatchfolderSvc REST_API --> WebhookSvc %% ─── Core & DB choice ──────────────── subgraph Core ["Core"] direction LR FFMate["FFmate"]:::core DBChoice{Database }:::core DB_SQLITE[(SQLite DB)]:::db DB_PG[(PostgreSQL DB)]:::db end TaskSvc --> FFMate PresetSvc --> FFMate WatchfolderSvc --> FFMate WebhookSvc --> FFMate FFMate --> DBChoice DBChoice -->|SQLite| DB_SQLITE DBChoice -->|PostgreSQL| DB_PG %% ─── ffmpeg binary in dashed box ───── subgraph FFmpegBlock [" "] direction LR FFmpeg["ffmpeg Binary"]:::ffbin end style FFmpegBlock stroke-dasharray:5 5,stroke:#555,fill:none FFMate --> FFmpeg %% ─── Stronger colour palette + black text ────────── classDef ui fill:#99d6ff,stroke:#2060a0,stroke-width:1.2px,color:#000000; classDef api fill:#b3e0ff,stroke:#2060a0,stroke-width:1.2px,color:#000000; classDef svc fill:#bdb4ff,stroke:#4b44a0,stroke-width:1.2px,color:#000000; classDef core fill:#99ff99,stroke:#2d7a2d,stroke-width:1.2px,color:#000000; classDef db fill:#ffcc80,stroke:#b36b00,stroke-width:1.2px,color:#000000; classDef ffbin fill:#ff99cc,stroke:#b3366b,stroke-width:1.2px,color:#000000; ``` ## REST API The [REST API](/docs/swagger.md), is the primary way external clients (including the FFmate Web UI, scripts, or other services) interact with and control FFmate. * **Functionality:** Provides endpoints for CRUD (Create, Read, Update, Delete) operations on: * Tasks – The core job management endpoints (e.g., create single or batch jobs, list all jobs, get real-time status, cancel, restart, and delete). * Presets – Manage reusable transcoding templates (e.g., create, list, update, and delete presets). * Watchfolders – Create jobs from a local or remote directory (e.g., create, list, update, and delete watch folder configurations). * Webhooks – Configure and trigger real-time notifications for your own applications (e.g., create, list, update, delete, and view execution history). * Clients – Monitor the instances in your cluster (e.g., list all connected nodes and their status). * System & Status – Manage and monitor the FFmate (e.g., check instance health, get the application version, and adjust log verbosity at runtime). ## Database FFmate supports **SQLite** for standalone instances (default out of the box) and **PostgreSQL** for clustered setups * **Data Stored:** * Tasks: All details about transcoding jobs, including their status, progress, input/output files, commands, priority, pre/post-processing info, timestamps, and any errors. * Presets: Definitions for reusable transcoding templates. * Webhooks: Configurations for URLs to be notified on specific events. * Watchfolders: Settings for monitored directories, including paths, intervals, associated presets, and filters. * Clients: A list of each FFmate node connected to the database, with its ID, version, OS, and a heartbeat timestamp of when it was last online. ## Web UI FFmate includes a modern [web-based user interface](/docs/web-ui.md)for managing and monitoring tasks, presets, watchfolders, webhooks and clients. * **Access:** When FFmate server starts, the web ui is served from the `/ui` path (e.g., `http://localhost:3000/ui`) * **Backend Communication:** The Web UI communicates with the FFmate service via: * `REST API`: For actions like creating tasks, fetching lists, deleting presets, etc. * `WebSockets`: For receiving real-time updates like task progress, new log messages, and status changes. ## Webhooks [Webhooks](/docs/webhooks.md) let FFmate notify external systems about events by sending HTTP `POST` requests to configured URLs. FFmate supports two types of webhooks: * [**Global**](/docs/webhooks.md#global-webhooks): define a single target endpoint per webhook event. * [**Direct**](/docs/webhooks.md#direct-webhooks): attach webhooks to individual [tasks](/docs/tasks.md#task-properties) or [presets](/docs/presets.md#presets-properties) for more fine-grained notifications. - **Configuration:** * Global webhooks can be created through the `REST API` (`/api/v1/webhooks`) or the [Web UI](/docs/web-ui.md#webhooks). * Direct webhooks are defined directly in a `task` or `preset`. * Each webhook configuration includes: * **Event (`event`):** The specific FFmate event that will trigger this webhook (e.g., `task.created`, `task.updated`, `batch.finished`, `preset.deleted`). * **URL (`url`):** The external HTTP(S) endpoint to which FFmate will send the notification. - **Triggering:** When a configured event occurs within FFmate: * FFmate automatically sends an HTTP POST request. * This request is sent to the `URL` defined in the webhook configuration. * The body of the request contains a JSON payload detailing the `event` that occurred and relevant `data` associated with it. - **Payload Structure:** ```json { "event": "event.name.here", "data": { ... } } ``` ## Watchfolder The [Watchfolder](/docs/watchfolder.md) feature allows FFmate to monitor directories for new files and automatically create transcoding tasks for them based on a specified preset. * **Configuration:** Watchfolders are configured via the `REST API` or `Web UI`. Each configuration includes: * **Path (`path`):** The directory to monitor. * **Preset (`preset`):** The name of the preset to apply to newly detected files. * **Interval (`interval`):** How often the directory is scanned (e.g., `10s`). * **Filters (`filters`):** (Optional) Rules to include or exclude specific files (e.g., by extension). * **Growth Checks (`growthChecks`):** (Optional) How many scan intervals a file must remain stable in size before being processed. * **Monitoring Process:** * FFmate starts monitoring configured directories upon startup or configuration changes. * Directories are scanned periodically based on the configured `interval`. * New files are detected. * Files must remain the same size for the number of scans defined by `growthChecks` before they are considered ready for processing. * Configured `filters` are applied to the relevant files. * If a file matches an extension in `exclude`, it will be skipped—even if it also matches `include`. * A new task is automatically created for each stable, filtered file. * The `preset` is applied to the new task. * FFmate creates an empty `.lock` file next to it (e.g., `movie.mp4` → `movie.mp4.lock`). This permanent marker makes sure the file won’t be processed again by the watchfolder. * FFmate keeps track of processed files to avoid creating duplicate tasks. * **Dynamic Updates:** Changes to Watchfolder settings (create, update, delete) in the API or UI are applied instantly, without the need for restarting FFmate. ## Task Queue This is the core process where your transcoding jobs are managed and processed from submission to completion. * **Queueing:** * New tasks (submitted via `API`, or `Watchfolders`) are added to a queue. * Tasks are processed based on their **Priority** (higher priority first) and then by creation time. * Initially, tasks are in the `QUEUED` status. * **Concurrency Control:** * FFmate limits the number of tasks running simultaneously. * This limit is controlled by the `--max-concurrent-tasks` server setting. * When a slot becomes available, the next task from the queue starts processing. * **Task Lifecycle:** Once a task is selected from the queue: * Its status is updated to `RUNNING`. * **Pre-processing:** If a pre-processing script is defined, it is executed before `ffmpeg`. * **`ffmpeg` Execution:** The primary transcoding command (`ffmpeg`) is executed. * **Progress Monitoring:** FFmate monitors `ffmpeg`'s output to track progress (e.g., percentage complete, time remaining). This progress is updated in the database and pushed via `WebSockets`. * **Post-processing:** If a post-processing script is defined and `ffmpeg` completed successfully, the post-processing script is executed. * **Completion:** The task status is updated to reflect the outcome: `DONE_SUCCESSFUL`, `DONE_ERROR`, or `DONE_CANCELED`. Error details are captured if applicable. * **Notifications:** Throughout a task's lifecycle, status changes and progress updates are broadcast via `WebSockets` (used by the `Web UI`) and can trigger configured `Webhooks`. ### Health Endpoint FFmate comes with a built-in **health endpoint** that shows if a node is up, initialized, and ready for requests. * **Endpoint:** `GET /health` #### Responses * **200 OK** — The node is running and connected to the database. ```json {"status":"ok"} ``` * **500 Internal Server Error** — The node isn’t ready yet (e.g., during startup) or failed to connect. ```json {"status":"error"} ``` #### When to Check It This endpoint is meant for **automated health checks**. Tools like **Kubernetes**, **Docker Swarm**, or any **load balancer** can ping it to decide if a node is ready to take traffic or still alive. ::: info This is a per-node check. A 200 OK means the node is running and connected to the database.It doesn’t confirm the state of other nodes or the pub/sub system. ::: Example ```bash curl -X GET http://localhost:3000/health ``` ### Client Endpoint This endpoint lists all `FFmate` instances (nodes) that are connected to the database and provides their current status and configuration details. * **Endpoint:** `GET /api/v1/clients` #### Responses * **200 OK** — Returns a JSON array of all known client instances, sorted with the most recently seen node first. ```json [ { "identifier": "transcoder-node-alpha", "session": "a1b2c3d4-...", "os": "linux", "arch": "amd64", "version": "2.0.0", "ffmpeg": "/usr/bin/ffmpeg", "lastSeen": 1678886400000, "self": true }, { "identifier": "transcoder-node-beta", "session": "e5f6g7h8-...", "os": "linux", "arch": "amd64", "version": "2.0.0", "ffmpeg": "/usr/bin/ffmpeg", "lastSeen": 1678886395000 } ] ``` * **`identifier`**: The unique name of the node (from the [--identifier](/docs/flags.md#server-command-flags) flag). * **`lastSeen`**: The "heartbeat" timestamp (in Unix milliseconds) when the node last checked in. * **`version`**: The version of `ffmate` running on that node. #### When to Check It This endpoint is designed for **monitoring and managing your FFmate** [cluster](/docs/clustering.md). It's the primary way to get a real-time overview of all active nodes. ::: info Each node sends a "heartbeat" update to the database every 15 seconds. You can consider a node offline if its `lastSeen` timestamp is older than a reasonable threshold (e.g., 30-60 seconds). ::: #### Example ```bash curl -X GET http://localhost:3000/api/v1/clients ``` ### Metrics FFmate exposes a set of internal counters via the **`GET /metrics`** endpoint, formatted for a **Prometheus server**. These metrics are updated in real-time as events occur within the application and can be scraped to monitor FFmate's activity and health. By default, you can access them at `http://localhost:3000/metrics` * **Batch Gauges** * `ffmate_batch_created` – Total number of batches created. * `ffmate_batch_finished` – Total number of batches where all associated tasks have completed (either successfully, with an error, or by being canceled). #### Example ```plain # HELP ffmate_batch_created Number of created batches # TYPE ffmate_batch_created gauge ffmate_batch_created 3 # HELP ffmate_batch_finished Number of finished batches # TYPE ffmate_batch_finished gauge ffmate_batch_finished 2 ``` * **Task Gauges** * `ffmate_task_created` – Total number of tasks added to the queue. * `ffmate_task_deleted` – Total number of tasks that have been deleted. * `ffmate_task_updated` – Total number of times a task's data has been updated (e.g., status change, progress update). * `ffmate_task_canceled` – Total number of tasks that have been explicitly canceled by a user. * `ffmate_task_restarted` – Total number of tasks that have been restarted. #### Example ```plain # HELP ffmate_task_created Number of created tasks # TYPE ffmate_task_created gauge ffmate_task_created 18 ffmate_task_deleted 4 ffmate_task_updated 155 ffmate_task_canceled 1 ffmate_task_restarted 1 ``` * **Preset Gauges** * `ffmate_preset_created` – Total number of presets created. * `ffmate_preset_updated` – Total number of presets that have been updated. * `ffmate_preset_deleted` – Total number of presets that have been deleted. #### Example ```plain # HELP ffmate_preset_created Number of created presets # TYPE ffmate_preset_created gauge ffmate_preset_created 5 ffmate_preset_updated 2 ffmate_preset_deleted 1 ``` * **Webhook Gauges** * `ffmate_webhook_created` – Total number of global webhooks created. * `ffmate_webhook_updated` – Total number of global webhooks updated. * `ffmate_webhook_deleted` – Total number of global webhooks deleted. * `ffmate_webhook_executed` – Total number of times a global webhook has been fired. * `ffmate_webhook_executed_direct` – Total number of times a "direct" webhook (defined inside a task or preset) has been fired. #### Example ```plain # HELP ffmate_webhook_created Number of created webhooks # TYPE ffmate_webhook_created gauge ffmate_webhook_created 4 ffmate_webhook_updated 1 ffmate_webhook_deleted 1 ffmate_webhook_executed 12 ffmate_webhook_executed_direct 25 ``` * **Watchfolder Gauges** * `ffmate_watchfolder_created` – Total number of watch folders created. * `ffmate_watchfolder_updated` – Total number of watch folders that have been updated. * `ffmate_watchfolder_deleted` – Total number of watch folders that have been deleted. * `ffmate_watchfolder_executed` – Total number of scan cycles that have been run across all watch folders. #### Example ```plain # HELP ffmate_watchfolder_created Number of created watchfolders # TYPE ffmate_watchfolder_created gauge ffmate_watchfolder_created 3 ffmate_watchfolder_updated 1 ffmate_watchfolder_deleted 0 ffmate_watchfolder_executed 27 ``` * **Websocket Gauges** * `ffmate_websocket_connect` – Total number of successful WebSocket connections. * `ffmate_websocket_disconnect` – Total number of WebSocket disconnections. * `ffmate_websocket_broadcast` – Total number of messages broadcast to all connected WebSocket clients. #### Example ```plain # HELP ffmate_websocket_connect Number of websocket connections # TYPE ffmate_websocket_connect gauge ffmate_websocket_connect 15 # HELP ffmate_websocket_disconnect Number of websocket disconnections # TYPE ffmate_websocket_disconnect gauge ffmate_websocket_disconnect 13 # HELP ffmate_websocket_broadcast Number of broadcasted messages # TYPE ffmate_websocket_broadcast gauge ffmate_websocket_broadcast 310 ``` * **REST API GaugeVec** * `ffmate_rest_api{method, path}` – Counts all incoming HTTP requests, labeled by the HTTP method and the API route path. #### Example ```plain # HELP ffmate_rest_api Number of requests against the REST API # TYPE ffmate_rest_api gauge ffmate_rest_api{method="GET",path="/api/v1/tasks"} 5 ffmate_rest_api{method="POST",path="/api/v1/tasks"} 10 ``` --- --- url: /docs/flags.md description: >- Comprehensive guide to all FFmate command-line flags. Learn to configure FFmate's server settings (FFmpeg path, port, DB), manage updates, enable debug logs, and more --- # Command-Line Interface (CLI) FFmate’s command-line interface is the main way to start and manage the application. It follows a standard `ffmate [command] [flags]` pattern and provides three distinct commands: * `server:` This is the main command that runs FFmate. * `update:` This is a utility command used to check for and install new versions of the FFmate binary. * `version:` This is a simple utility command that prints the currently installed version number. To see all commands and their flags, run: ```bash ffmate --help ffmate --help ``` ## Server Command Flags The `server` command starts FFmate. All flags listed in this section are specific to this command and allow you to configure everything from ports, database path, logging, and other configuration options. * **`--ffmpeg `** or **`--ffmpeg=""`** * **Purpose:** Set the path to the `ffmpeg` executable. * **Value:** The full path to your `ffmpeg` binary. * **Default:** `ffmpeg` (assumes `ffmpeg` is in your system's `PATH`). * **Example:** `ffmate server --ffmpeg="/usr/local/bin/ffmpeg"` * **`--port `** or **`--port=""`** * **Purpose:** Sets the port number on which the FFmate server (API and Web UI) will listen. * **Value:** A valid port number. * **Default:** `3000` * **Example:** `ffmate server --port="8080"` * **`--tray`** * **Purpose:** Enables the system tray icon (experimental). When enabled, FFmate will show an icon in your system tray with status information and basic controls. * **Default:** `false` (tray icon is disabled). * **Example:** `ffmate server --tray` * **`--database `** or **`--database=""`** * **Purpose:** Sets where FFmate stores its data (tasks, presets, webhooks, etc.). FFmate supports **SQLite** for standalone instances (default out of the box) and **PostgreSQL** for clustered setups. * **Value:** * **SQLite file path:** FFmate uses SQLite out of the box. By default, the database is created at: * Windows: `%APPDATA%\ffmate\db.sqlite` * macOS/Linux: `~/.ffmate/db.sqlite` * Docker: `/app/db/sqlite.db` You can specify an alternative location by passing the full file path with `--database`. * **Examples:** ``` # Unix example FFmate server --database="~/ffmate/data/production.sqlite" # Windows example FFmate server --database="C:\Users\YourName\AppData\Roaming\ffmate\data.sqlite" ``` * **PostgreSQL URI:** FFmate supports **PostgreSQL** for multi-node setups. If you pass a `URI` starting with `postgresql://` to `--database`, FFmate automatically switches into **cluster mode**, allowing all FFmate instances to share the same database. * **Connection URI:** ``` postgresql://user:password@host:port/dbname?options ``` ::: info The PostgreSQL database must exist before connecting a FFmate node to it. FFmate will create the required tables and schema at startup if they are not already present ::: * **Example:** ``` ffmate server --database="postgresql://ffuser:ffpass@localhost:5432/ffmatedb" ``` * **`--identifier `** or **`--identifier=""`** * **Purpose:** Assigns a unique name to an FFmate instance. This is essential in a cluster setup to distinguish between different processing nodes and in the Web UI it makes it clear which node is running each task. * **Value:** A string representing the unique name for the instance. * **Default:** The machine's hostname. * **Example:** `ffmate server --identifier=“node”-a` * **`--max-concurrent-tasks `** or **`--max-concurrent-tasks=""`** * **Purpose:** Sets the maximum number of `ffmpeg` tasks that FFmate will run simultaneously. * **Value:** A positive integer. * **Default:** `3` * **Example:** `ffmate server --max-concurrent-tasks="5"` (allows up to 5 tasks to run at once) * **`--send-telemetry `** or **`--send-telemetry=`** * **Purpose:** Enables or disables the sending of anonymous usage telemetry data to `telemetry.FFmate.io`. * **Value:** `true` or `false`. * **Default:** `true` (telemetry is enabled). * **Example:** `ffmate server --send-telemetry=false` * **`--no-ui`** * **Purpose:** Prevents FFmate from automatically opening the Web UI in your default web browser when the server starts. * **Default:** `false` (The UI is opened by default when running on a desktop OS). * **Example:** `ffmate server --no-ui` * **`--debug `** or **`-d `** * **Purpose:** FFmate uses a **namespace system** instead of classic levels (INFO, DEBUG, ERROR). It’s built on our own lightweight Go library, [yosev/debugo](https://github.com/yosev/debugo), inspired by the popular [debug-js](https://github.com/debug-js/debug) package. This gives you fine-grained control over which parts of the app produce logs. * **Default:** `info:?,warn:?,error:?`. * **Example:** ```bash ffmate server --debug="*:task,*:watchfolder" ``` The full debugging guide can be found in the [debugging documentation](/docs/debugging.md). # Update Command Checks for and applies new versions of the FFmate binary. * **Purpose:** Keep FFmate up to date with the latest release. * **Flags:** * `--dry` — checks for updates without installing them. * **Result:** Prints either `no newer version found` or `found newer version: X.Y.Z`. The binary itself is not modified. * **Default behavior:**\ If a newer version is available, FFmate downloads and replaces its own binary. You’ll see a success message, and you’ll need to restart the application to use the new version. **Examples:** ```bash # Check if an update is available (no install) ffmate update --dry ``` ```bash # Check for and apply the update if one is found ffmate update ``` ::: info\ If you installed FFmate with **Homebrew**, use `brew upgrade ffmate` to update instead of the built-in `update` command. ::: # Version Command Prints the currently installed FFmate version and exits. * **Purpose:** Quickly check which version of FFmate you’re running. * **Flags:** None * **Result:** Prints a single line to the console. **Example:** ```bash ffmate version Output: version: 2.0.0 ``` --- --- url: /docs/debugging.md description: >- Troubleshoot FFmate with this debugging guide. Control log verbosity using namespaces, command-line flags, environment variables, or dynamically via the REST API --- # Debugging FFmate offers powerful, fine-grained debugging options that allow you to capture detailed debug information from specific internal components, making it easier to trace issues and understand what’s happening under the hood. ## Enabling Debug Mode You can enable debug logging in two ways: 1. **Using the Command-Line Flag:** * The most common way is to use the global `--debug` flag when running any `ffmate` command (especially `ffmate server`). * **Syntax:** `ffmate server --debug="` * **Example:** `ffmate server --debug="error:?,*:task"` 2. **Using OS Environment Variable:** * You can set the environment variable before running FFmate. * **Syntax (Linux/macOS):** `export DEBUGO="*"; ffmate server` * **Syntax (Windows PowerShell):** `$env:DEBUGO="*"; ffmate server` * If both the flag and the environment variable are set, the command-line flag will take precedence. ## Understanding Namespaces Every log message in FFmate belongs to a **namespace**. You can think of these namespaces as structured labels that describe two things: 1. **Severity** – the log level (`info`, `debug`, `warn`, `error`). 2. **Component** – the part of the system the message comes from (`task`, `ffmpeg`, `http`, etc.). They’re combined in a `severity:component` format. For example: * `error:task` → logs an error that occurred in task processing * `debug:http` → logs debug information for each HTTP request The `--debug` flag lets you filter by these labels, so you control exactly what shows up in your logs. #### **info** – general, high-level messages * `info:task` – Logs the major stages of the tasks' lifecycle: when it's created, when it's picked from the queue to start processing, when it's restarted, when it's canceled, when it's deleted, and when it finishes successfully. * `info:watchfolder` – Logs when a new watchfolder is created, when its settings are updated, or when it is deleted. * `info:cluster` – Logs when the components responsible for communication between different FFmate instances (the "listener" and "notifier") have started successfully * **Example:** Use `--debug="info"` to get a high-level overview of what the application is doing without low-level details. #### **debug** – detailed messages for troubleshooting * `debug:service` – Logs each major internal component (like the Task processor, Webhook sender, etc.) as it starts up. Use this if FFmate fails to start. The last service logged before the crash can help pinpoint the problem. * `debug:http` – Logs every single API request that FFmate receives, including the HTTP method (GET, POST) and the path (e.g., /api/v1/tasks). * `debug:controller` – Logs the API endpoints (like /tasks, /presets) as they become active during startup. This is primarily for debugging the FFmate application itself. You generally won't need this unless you are modifying the source code. * `debug:websocket` – Logs every time a client (like the Web UI) connects to or disconnects from the WebSocket server. * `debug:client` – Logs the "heartbeat" of the FFmate instance. It logs the unique name the instance is using and a confirmation message every 15 seconds that it's connected to the database. * `debug:ffmpeg` – Logs the real-time progress of an active FFmpeg job, showing details like frame number, FPS, bitrate, and speed. * `debug:task` – Provides the most detailed, step-by-step view of the entire task processing system. It shows when the queue is checked for new jobs, when a task is picked up, and when its status changes. Turn this on when jobs seem to be "stuck" in the queue or are not being picked up as expected. * `debug:watchfolder` – Logs when a watchfolder is scanned, what files are found, and whether a file is ready to be processed. * `debug:webhook` – Logs the entire lifecycle of webhooks. It shows when you successfully register a new webhook URL and when FFmate attempts to send a notification to that URL. Enable this to confirm your webhooks are set up correctly. If your application isn't receiving notifications, this log will tell you if FFmate is successfully sending them. * `debug:cluster` – Logs the raw broadcast messages being sent and received between different FFmate instances when running in cluster mode. This is an advanced log for verifying that your clustered FFmate instances are communicating correctly over the shared PostgreSQL database. * `debug:middleware` – Logs the registration of background request processors, like the Gzip compressor or the debug:http logger itself.This is primarily for debugging the FFmate application itself. You generally won't need this unless you are modifying the source code. * **Example:** Use `--debug="debug:http,debug:task"` to see every incoming API call and all the detailed, verbose steps of the task processing queue, which is ideal for debugging a failing task. #### **warn** – warnings about possible issues * `warn:task` – Logs when a task has finished with a `DONE_ERROR` status. * `warn:cluster` – Logs when the internal message queue for cluster communication is full, which means a real-time update (like a task progress change) had to be dropped and was not broadcast to other FFmate instances * **Example:** Use `--debug="warn"` to see only potential problems, like a task that failed but didn't crash the system, or a cluster message that was dropped. #### **error** – errors and failures * `error:ffmpeg` – Logs an error if FFmate fails to read or parse the real-time progress output from a running FFmpeg process. This is an error in the monitoring of FFmpeg, not an error from the FFmpeg command itself. * `error:task` – Logs a critical error if the task processor fails to fetch queued jobs from the database. * `error:telemetry` – Logs any failure that occurs while FFmate tries to send anonymous usage data, such as a network error or a problem connecting to the telemetry server. * `error:cluster` – Logs a critical failure in the cluster communication system, most often caused by a lost connection to the PostgreSQL database or an issue with its `LISTEN/NOTIFY` feature. * **Example:** Use `--debug="error"` in a production environment to log only critical failures, ensuring you capture every error from any part of the application for immediate attention. ### Filtering Rules The value for `--debug` is a comma-separated string of rules that you can combine to create a precise logging output. * **`*` – Match Everything** * **Example:** `ffmate server --debug="*"` * **Result:** Shows every single log message from all namespaces. This is the best option for maximum verbosity. * **`name` (e.g., `debug`) – Match a Parent Namespace ONLY** * **Example:** `ffmate server --debug="warn"` * **Result:** Shows logs from the `warn` namespace itself, but will **not** show logs from its children, like `warn:task` or `warn:cluster`. * **`name:*` (e.g., `debug:*`) – Match Child Namespaces ONLY** * **Example:** `ffmate server --debug="debug:*"` * **Result:** Shows all logs from every child of `debug` (e.g., `debug:http`, `debug:task`) but will **not** show logs from the parent `debug` namespace itself. * **`name:?` (e.g., `debug:?`) – Match a Parent AND All Its Children** * **Example:** `ffmate server --debug="info:?"` * **Result:** Shows logs from the parent `info` namespace **and** all of its children (`info:task`, `info:ffmpeg`, etc.). This is the rule used in the default setting: `info:?,warn:?,error:?`. * **`-` – Exclude Namespaces** * **Example:** `ffmate server --debug="*,-debug:?"` * **Result:** Shows everything (`info`, `warn`, `error`, and all their children) *except* for logs from the `debug` parent and all of its children. * **`,` – Combine Multiple Rules** * **Example:** `ffmate server --debug="error:?,*:task,debug:http"` * **Result:** Creates a highly specific filter that shows: 1. All logs from the `error` namespace and its children. 2. *All* logs (info, debug, warn, error) from the `task` namespace's children only (e.g., `debug:task`). 3. All incoming HTTP requests from the `debug:http` namespace. ### Common Examples | Goal | Command | | --------------------------------------------------- | ------------------------------------------------------ | | **Default (status, warnings, errors)** | `ffmate server` (or `--debug="info:?,warn:?,error:?"`) | | **See everything** | `ffmate server --debug="*"` | | **See all `info` + `error` logs** | `ffmate server --debug="info:?,error:?"` | | **Focus on tasks and watch folders** | `ffmate server --debug="*:task,*:watchfolder"` | | **See all errors + API calls** | `ffmate server --debug="error:?,debug:http"` | | **Everything except debug noise** | `ffmate server --debug="*,-debug:?"` | | **No logs** | `ffmate server --debug=""` | ## Setting debug from the API FFmate provides API endpoints to change the debug namespaces *while the server is running*, which is extremely useful for enabling detailed logging on a live system without a restart: * **`PATCH /api/v1/debug/{namespaces}`** * **Purpose:** Sets the active debug namespaces. The [{namespaces}](#understanding-namespaces) part of the URL should be your comma-separated filter string. * **Example:** To see only task and webhook logs: ```sh curl -X 'PATCH' \ 'http://localhost:3000/api/v1/debug/*:task,*:webhook0' \ -H 'accept: application/json' ``` FFmate responds with a `204` No Content status. * **`DELETE /api/v1/debug`** * **Purpose:** Turns off all logging by resetting the namespace filter to an empty string. * **Example:** ```sh curl -X 'DELETE' \ 'http://localhost:3000/api/v1/debug' \ -H 'accept: application/json' ``` FFmate responds with a `204` No Content status. ## Debug Message Format All debug messages follow a consistent structure: ``` HH:MM:SS.mmm namespace:sub-namespace › MESSAGE ``` * **`HH:MM:SS.mmm`** – Timestamp (hours, minutes, seconds, and milliseconds) * **`namespace:sub-namespace`** – Identifies the component that generated the message * **``** – The actual debug log content **Example:** ``` 10:05:15.123 info:task › processing task (uuid: abc-123-def-456) ``` --- --- url: /docs/pre-post-prcessing.md description: >- Learn to use FFmate's pre & post-processing for FFmpeg. Run custom scripts, use JSON sidecars for task context, manage exit codes, and automate your media workflows --- # Pre and Post-Processing **Pre- and post-processing** in FFmate allow you to extend transcoding tasks by running custom scripts *before* the `ffmpeg` command starts and *after* it successfully completes. This powerful feature enables you to automate a wide range of activities, from input validation and file preparation to notifications, archiving, and integration with other systems. You can define pre and post-processing steps either directly within a task creation request or as part of a [Preset](/docs/presets.md). If defined in both, the task-specific definition will take precedence. ## Configuration Parameters For both pre-processing and post-processing, you can configure the following: * **`scriptPath`** *\[optional]* – The command or script FFmate should run before the main `ffmpeg` command. It supports [wildcards](/docs/wildcards.md) to pass dynamic values like filenames, UUIDs, or dates as arguments to your script. *Example*: `python3 /opt/ffmate_scripts/prepare_audio.py --input ${INPUT_FILE} --normalize-level -3dBFS` ::: details **Note:** {open} FFmate will attempt to run the `scriptPath` as a system command. Make sure the **script is executable** and the path is correct. It will run with the same environment and permissions as the FFmate process. #### How Exit Codes Work When a script finishes running, it returns an **exit code** — a number that tells `ffmate` whether it succeeded or failed. * An exit code of `0` means the script completed successfully. * A non-zero exit code means the script encountered an error. * For **pre-processing**, if the script fails, the `ffmpeg` command will *not* run, and the task will be marked as **failed**. * For **post-processing**, the `ffmpeg` command will already have completed successfully, but the task will still be marked as **failed** due to the post-processing error. ::: * **`sidecarPath`** *\[optional]* – Specifies the path where FFmate should write a JSON "sidecar" file containing detailed information about the current task. This path supports [wildcards](/docs/wildcards.md). Your script can then read this file to get full context and make decisions accordingly. * **What’s in the sidecard file?**\ The sidecar JSON contains a snapshot of the task at the time the script runs: * For **pre-processing**, this includes input/output paths (raw or partially resolved), task metadata, UUID, name, priority, and more. #### Example: ```json { "uuid": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", "name": "My Epic Movie.mov", "command": { "raw": "-i ${INPUT_FILE} -c:v libx264 -preset fast ${OUTPUT_FILE}", "resolved": "" }, "inputFile": { "raw": "/watch/My Epic Movie.mov", "resolved": "" }, "outputFile": { "raw": "/output/${INPUT_FILE_BASENAME}.mp4", "resolved": "" }, "metadata": { "show": "My Awesome Show", "season": 2, "episode": 5 }, "status": "PRE_PROCESSING", "progress": 0, "remaining": 0, "error": "", "priority": 5, "source": "watchfolder", "preProcessing": { "scriptPath": { "raw": "/scripts/preprocess.sh", "resolved": "/scripts/preprocess.sh" }, "sidecarPath": { "raw": "/temp/${UUID}.json", "resolved": "/temp/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d.json" }, "importSidecar": true, "startedAt": 1735689600000 }, "postProcessing": null, "startedAt": 0, "finishedAt": 0, "createdAt": 1735689590000, "updatedAt": 1735689600000 } ``` * For **post-processing**, it includes all of the above plus the final resolved output path from `ffmpeg`. The task status at this point will typically be `RUNNING`, just before it's marked `DONE_SUCCESSFUL` if post-processing completes without errors. ### Importing a Task’s Sidecar When the property `importSidecar` is set to **true**, FFmate will **re-import the sidecar JSON after your pre-processing script finishes**. The flow is simple: 1. When the task starts, FFmate writes the task’s [sidecar JSON](#example) to the path you configured in `preProcessing.sidecarPath`, then runs your pre-processing script. 2. Inside your script, you can **read and modify the sidecar JSON** programmatically — but only by changing existing properties. 3. When the script exits, FFmate re-imports the updated sidecar and continues processing the task with those updates. This lets you add custom logic to influence how FFmate processes a task. For example: * Run tools like `ffprobe` or `MediaInfo` and inject the results into the `metadata` object. * Adjust the [task’s](/docs/tasks.md#task-properties) command or preset dynamically based on resolution, bitrate, or aspect ratio. * Change the [task’s](/docs/tasks.md#task-properties) priority if the file comes from a specific location or matches certain conditions. > ⚠️ **Important:**\ > Only modify **existing properties** in the sidecar.\ > Do **not** add or remove keys or change the JSON structure; doing so will cause the FFmate task to fail. ## Workflow This section outlines how FFmate runs a task, showing where pre- and post-processing scripts fit, how wildcards are resolved, where the sidecar import happens, and how errors are handled. 1. **Task Queued** — A new task is created (directly or via a watchfolder). 2. **Pre-Processing (if defined)** * FFmate resolves wildcards in `sidecarPath` (if defined) and writes the task sidecar JSON. * FFmate resolves wildcards in `scriptPath`. * FFmate executes the pre-processing script. * If the script fails (non-zero exit code), the task status is set to `DONE_ERROR` and processing stops. The script error is logged. * **If `importSidecar` is true:** FFmate re-imports the updated sidecar JSON after the script finishes. If re-import fails, the task is set to `DONE_ERROR`. 3. **FFmpeg Processing** * If pre-processing was successful (or not defined), FFmate resolves wildcards for the main command, input file, and output file. * FFmate executes the FFmpeg command. * If FFmpeg fails, the task status is set to `DONE_ERROR` and processing stops. Post-processing will not run. 4. **Post-Processing (if defined)** * Assuming FFmpeg completed successfully, FFmate resolves wildcards in `sidecarPath` (if defined) and writes the task sidecar JSON (now including final output paths). * FFmate resolves wildcards in `scriptPath`. * FFmate executes the post-processing script. * If the script fails (non-zero exit code), the task status is set to `DONE_ERROR`. The script error is logged. 5. **Task Completion** * If post-processing was successful (or not defined), the task status is set to `DONE_SUCCESSFUL`. ```mermaid flowchart TD A[Task queued] --> B{Pre-processing defined?} B -- No --> E[Resolve command and paths] --> F[Run FFmpeg] B -- Yes --> C[Resolve pre sidecarPath and write sidecar] C --> D[Resolve pre scriptPath] D --> P[Run pre-processing script] P --> POK{Script exit code 0?} POK -- No --> X[Done error] POK -- Yes --> I{importSidecar true?} I -- Yes --> R[Re-import sidecar JSON] I -- No --> E R --> E F --> FOK{FFmpeg success?} FOK -- No --> X FOK -- Yes --> G{Post-processing defined?} G -- No --> S[Done successful] G -- Yes --> H[Resolve post sidecarPath and write sidecar] H --> J[Resolve post scriptPath] J --> Q[Run post-processing script] Q --> QOK{Script exit code 0?} QOK -- No --> X QOK -- Yes --> S classDef success fill:#bbf7d0,stroke:#22c55e,stroke-width:2px,color:#000 classDef error fill:#fecaca,stroke:#ef4444,stroke-width:2px,color:#000 classDef step fill:#bfdbfe,stroke:#3b82f6,stroke-width:2px,color:#000 class A,B,C,D,E,F,G,H,J,P,Q,R step class S success class X error ``` ## Examples #### Post-Processing – Upload to Cloud Storage and Notify Once transcoding completes successfully, upload the output file to an S3 bucket and send a Slack notification to keep your team informed. **Example:** This example shows how post-processing can be configured to run a custom script after a successful `ffmpeg` transcode, while also generating a sidecar JSON file containing task details. ```json { "postProcessing": { "scriptPath": "/opt/ffmate_scripts/upload_and_notify.sh", "sidecarPath": "${OUTPUT_FILE_DIR}/${OUTPUT_FILE_BASENAME}.post_task_info.json" } // ... other preset/task details } ``` * **`upload_and_notify.sh` (Conceptual):** ```bash #!/bin/bash set -e # Exit immediately if a command exits with a non-zero status. SIDECAR_FILE="" # Basic argument parsing (robust scripts would use getopts) if [ "$1" == "--sidecar" ] && [ -n "$2" ]; then SIDECAR_FILE="$2" else # If ffmate passes sidecar path as the first arg directly SIDECAR_FILE="$1" fi if [ -z "$SIDECAR_FILE" ] || [ ! -f "$SIDECAR_FILE" ]; then echo "Error: Sidecar file path not provided or file not found." >&2 exit 1 fi # Read data from sidecar using 'jq' (JSON processor) OUTPUT_FILE=$(jq -r '.outputFile.resolved' "$SIDECAR_FILE") TASK_NAME=$(jq -r '.name // "Untitled Task"' "$SIDECAR_FILE") TASK_UUID=$(jq -r '.uuid' "$SIDECAR_FILE") if [ -z "$OUTPUT_FILE" ]; then echo "Error: Could not extract output file from sidecar." >&2 exit 1 fi S3_BUCKET="s3://my-ffmate-outputs" SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK" echo "Uploading ${OUTPUT_FILE} to ${S3_BUCKET}..." aws s3 cp "${OUTPUT_FILE}" "${S3_BUCKET}/" if [ $? -ne 0 ]; then echo "Error: S3 upload failed for ${OUTPUT_FILE}." >&2 exit 2 fi echo "Upload successful." # Send Slack notification MESSAGE_TEXT="Task Complete: '${TASK_NAME}' (UUID: ${TASK_UUID}). Output: ${S3_BUCKET}/$(basename "${OUTPUT_FILE}")" PAYLOAD="{\"text\": \"${MESSAGE_TEXT}\"}" curl -X POST -H 'Content-type: application/json' --data "${PAYLOAD}" "${SLACK_WEBHOOK_URL}" if [ $? -ne 0 ]; then echo "Warning: Slack notification failed, but file was uploaded." >&2 # Decide if this should be a hard fail (exit 3) or just a warning fi echo "Post-processing complete for ${TASK_UUID}." exit 0 # Success ``` --- --- url: /docs/presets.md description: >- Simplify complex FFmpeg tasks with FFmate presets. Define reusable templates for commands, output paths, and processing scripts to streamline your media encoding and ensure consistency --- # Presets **Presets** in FFmate are reusable templates that make it easier to define and run `FFmpeg` tasks. With a preset, you can preconfigure `FFmpeg` commands, output patterns, priorities, and even pre- or post-processing scripts, so every task runs the same way without extra setup. FFmate ships with **20 built-in presets** covering the most common media tasks, including format conversion, frame rate adjustment, audio extraction, and platform-specific encodes for YouTube, TikTok, Instagram, Facebook, and Twitch. These ready-to-use presets save you from having to figure out the right `FFmpeg` command for everyday jobs. All presets are maintained in an [open GitHub repository](https://github.com/welovemedia/ffmate-presets), where you can suggest changes or contribute new ones through pull requests. You can also create your own custom presets at any time using the API or the [web interface](/docs/web-ui.md#presets) ## Creating a Preset To create a preset, send a `POST` request to the FFmate API: ```sh curl -X POST http://localhost:3000/api/v1/presets \ -H "Content-Type: application/json" \ -d '{ "name": "Analyze and Transcode MP4", "description": "Runs an analysis script to determine the best CRF value, which is then used in the transcode command.", "command": "-y -stats_period 5 -i ${INPUT_FILE} -c:v libx264 -preset medium -crf ${METADATA_crf_value} -c:a aac -b:a 128k ${OUTPUT_FILE}", "outputFile": "${INPUT_FILE_BASENAME}_analyzed.mp4", "priority": 5, "preProcessing": { "scriptPath": "/opt/ffmate/scripts/analyze_bitrate.sh --input ${INPUT_FILE} --sidecar ${SIDECAR_FILE}", "sidecarPath": "/var/tmp/${INPUT_FILE_BASENAME}.json", "importSidecar": true }, "postProcessing": { "scriptPath": "/opt/ffmate/scripts/cleanup.sh --file ${OUTPUT_FILE} --status success" }, "webhooks": [ { "event": "task.updated", "url": "https://workflow-engine.example.com/api/ffmate/job-status-update" } ] }' ``` FFmate returns a JSON object that contains the newly created preset including its `ID`. A `preset.created` event is also fired via [Global webhooks](/docs/webhooks#preset-events-1) and [Direct webhooks](/docs/webhooks#preset-events). 💡 Tip: Prefer a visual approach? You can create new presets directly in the [FFmate Web UI](/docs/web-ui.md) no API calls needed. ## Presets properties When you create a preset, you define parameters that are automatically applied to every task that uses it. * **`name`** *\[optional]* - A short, descriptive name to help you quickly identify the preset (e.g., "Convert to MP4 1080p", "Extract Audio as MP3"). * **`description`** *\[optional]* – A short note about what the preset is for or how it should be used (e.g., "Converts ProRes to H.264 for review copies"). * **`FFmpeg command`** *\[optional]* – The custom command FFmate will use to run `FFmpeg` for this preset. Use this to define exactly how the media should be processed—for example, which codec to use, what resolution to convert to, or which filters to apply. ⚠️ **Important details about how `command` works:** * You don’t need to add `ffmpeg` at the start of the command. FFmate automatically prepends it. By default, FFmate uses the `ffmpeg` binary in your system’s `PATH`. If you want to use a different version, you can override the default with the `--ffmpeg ` [command-line flag](/docs/flags.md#server-command-flags). * FFmate also implicitly adds the `-stats_period 1` [option](https://ffmpeg.org/ffmpeg-all.html#Advanced-options) to every command, which limits FFmpeg’s progress output to one update per second. You can override this by explicitly adding your own `-stats_period x` to the command. * This setting directly affects: * how often `task.updated` [Global webhook](/docs/webhooks#task-events-1) and [Direct webhook](/docs/webhooks#task-events) are sent, and * how often the job dashboard refreshes progress updates. * The `command` field also supports chaining multiple `FFmpeg` commands with `&&`. This is useful for advanced workflows such as **two-pass encoding**. When chaining commands, you must use the `${FFMPEG}` wildcard (see [FFmpeg Path](/docs/wildcards.md#ffmpeg-path) for more details). You can also use [wildcards](/docs/wildcards.md) like `${INPUT_FILE}` and `${OUTPUT_FILE}` inside the command string. FFmate will automatically replace them with the actual file paths when the task runs. * If a [task](/docs/tasks.md) references a preset, the `command` defined in the preset will **always** be used—any command provided directly in the [task](/docs/tasks.md) will be ignored. ::: tip Not sure which `FFmpeg` commands to use? * [OSTechNix – 20+ FFmpeg Commands For Beginners](https://ostechnix.com/20-ffmpeg-commands-beginners/) * [Abyssale – Top 20 best commands for FFmpeg](https://www.abyssale.com/blog/top-20-best-commands-for-ffmpeg) * [VideoProc – 31 Must-Haves FFmpeg Commands for Beginners](https://www.videoproc.com/resource/ffmpeg-commands.htm) * [GorillaSun – A Simple Guide to FFMPEG](https://www.gorillasun.de/blog/a-simple-guide-to-ffmpeg/) * [Bannerbear – Top 10 FFmpeg Command Options You Need to Know](https://www.bannerbear.com/blog/ffmpeg-101-top-10-command-options-you-need-to-know-with-examples/) * Ask ChatGPT ::: * **`output file path`** *\[optional]* – The path where the transcoded file should be saved. If the specified directory does not exist, FFmate will **create it automatically**. This can be a full path or a pattern that includes [Wildcards](/docs/wildcards.md) like `${INPUT_FILE_BASENAME}` to dynamically generate structured filenames (e.g., /exports/${INPUT\_FILE\_BASENAME}\_1080p.mp4). If a task also includes its own `outputFile`, that will be used instead of this one. In other words, the task's setting always takes priority over the preset. * **`priority`** *\[optional]* – Sets the task's priority in the processing queue. Higher numbers mean higher priority — for example, a task with priority `100` will be processed before one with `10`. If multiple tasks share the same priority, they’ll generally run in the order they were created (FIFO for that priority level). If a task defines its own `priority`, that will override the preset’s value. If neither is set, a default (usually `0`) is used. * **`pre-processing`** *\[optional]* – Defines a [Pre-Processing Script](/docs/pre-post-prcessing.md) to run before the task starts. Useful for preparing files, validating input, or setting up the environment. If the task includes its own `preProcessing` config, FFmate will use that instead of the preset’s. * **`scriptPath`**: The full path to the script or executable to run. * **`sidecarPath`**: The full path to the JSON file that contains all task data. * **`importSidecar`**: Defines if the task will [re-import the sidecar](/docs/pre-post-prcessing.md#importing-a-task-s-sidecar) JSON after the pre-processing script finishes. * **`postProcessing`** *\[optional]* – Defines a [Post-Processing Script](/docs/pre-post-prcessing.md) to run after the task completes. Useful for cleanup, moving output files, or triggering follow-up actions. If the task includes its own `postProcessing` config, FFmate will use that instead of the preset’s. * **`scriptPath`**: The full path to the script or executable to run. * **`sidecarPath`**: The full path to the JSON file that contains all task data. * **`Webhooks`** *\[optional]* : Defined a direct webhook target tied only to this preset. For example, it can notify a project management tool whenever the task's status changes. ### How to Use Presets in Tasks When creating a new [task](/docs/tasks.md), you can use either an [out-of-the-box preset](/docs/web-ui.md#presets) or one of your custom presets by providing its ID instead of writing a custom command. See [task properties](/docs/tasks.md#task-properties) for details. **Example: Creating a task with a preset via API** ```sh curl -X POST http://localhost:3000/api/v1/tasks \ -H "Content-Type: application/json" \ -d '{ "name": "Archive Raw Footage", "inputFile": "/path/to/raw_footage_01.mxf", "preset": "id-of-ProRes-HQ-for-Archive-preset", "metadata": { "project-id": "project_alpha_123", "shot_number": "005" } }' ``` ## Listing Presets To get a list of all available presets, send a `GET` request to the FFmate API ```sh curl -X GET 'http://localhost:3000/api/v1/presets?page=0&perPage=10' ``` FFmate returns a JSON array containing all configured presets. The `X-Total` response header provides the total number of presets available. **Query Parameters:** * **`page`** *\[optional]* – Specifies which page of results to retrieve. Default: `0`. * **`perPage`** *\[optional]* – Defines how many tasks should be included in each page. Default: `50`. 💡 Tip: Want to browse existing presets? The [FFmate Web UI](/docs/web-ui.md#presets) lets you view and search through all available presets with ease. ## Getting a Single Preset To retrieve the details of a specific preset, send a `GET` request to the FFmate API, including the preset's `ID` in the path. ```sh curl -X GET 'http://localhost:3000/api/v1/presets/a1b2c3d4-e5f6-7890-1234-567890abcdef' ``` FFmate returns a JSON object with the full details of the specified preset. 💡 Tip: Want a quick way to check the preset details? You can view preset configurations directly in the [FFmate Web UI](/docs/web-ui.md#presets) without using the API. ## Updating a Preset You can update an existing preset by sending a `PUT` request to the FFmate API, including the preset's `ID` in the path. The request body should contain the updated properties for the preset. You can find a list of all available properties in the [Presets properties](#presets-properties) section below. ```sh curl -X PUT http://localhost:3000/api/v1/presets/{presetId} \ -H "Content-Type: application/json" \ -d '{ "name": "MP4 High Quality (Updated)", "command": "-y -i ${INPUT_FILE} -c:v libx264 -preset slow -crf 18 -c:a aac -b:a 192k ${OUTPUT_FILE}", "description": "Converts video to MP4 with H.264 video and AAC audio, higher quality setting.", "outputFile": "${INPUT_FILE_BASENAME}_highquality.mp4", "priority": 5, "postProcessing": { "scriptPath": "/usr/local/bin/notify_completion.sh --file ${OUTPUT_FILE} --status success" } }' ``` FFmate returns the complete JSON object of the updated preset. A `preset.updated` event is also fired via [Global webhooks](/docs/webhooks#preset-events-1) and [Direct webhooks](/docs/webhooks#preset-events). 💡 Tip: Need to tweak an existing preset? You can update it directly in the [FFmate Web UI](/docs/web-ui.md#presets). ## Deleting a Preset To delete an existing preset, send a `DELETE` request to the FFmate API, replacing `{presetId}` with the `ID` of the preset you want to remove. ```sh curl -X DELETE 'http://localhost:3000/api/v1/presets/{presetId}' ``` FFmate responds with a `204` No Content status. The preset will be removed from the system. A `preset.deleted` event is also fired via [Global webhooks](/docs/webhooks#preset-events-1) and [Direct webhooks](/docs/webhooks#preset-events). 💡 Tip: Presets can be safely deleted from the [FFmate Web UI](/docs/web-ui.md), with helpful context to avoid accidental removals. --- --- url: /docs/release-notes.md description: >- Explore the latest FFmate release notes including new features, API changes, improvements, and bug fixes. Stay updated with every version of the open-source FFmpeg automation tool. --- # FFmate Release Notes An overview of new features, enhancements, and bug fixes for each version. ## Version 2.0 (26-09-2025) FFmate 2.0 is a **complete rewrite** of the project, powered by the amazing [Goyave](https://goyave.dev/) framework. This new version delivers a more structured, maintainable, and efficient codebase, paving the way for community members to get involved and shape FFmate’s future. While we’ve aimed to remain mostly backward-compatible with 1.x, some adjustments to existing setups may be necessary. ### Breaking Changes * **Task Batch** The endpoint has changed from `/api/v1/tasks/batch` to `/api/v1/batches`. For details, see [Batch Task](/docs/tasks.md#submitting-multiple-tasks-as-a-batch). * **Task Batch Format** The batch object format has been updated: it is now an object containing a `tasks` array instead of being an array itself. This change allows for future enhancements to the Batch feature. For details, see [Batch Task](/docs/tasks.md#submitting-multiple-tasks-as-a-batch). * **Log Level** The command-line argument for log level has been removed in favor of [Debugo](https://github.com/yosev/debugo). For details, see [Debugging](/docs/debugging.md). ### Deprecated * **Command-Line Arguments** The short version of command-line arguments (e.g., `-p` for `--port`) is now deprecated. Switch to the long version to ensure forward compatibility. This change was made due to the growing number of arguments, which makes it difficult to avoid conflicts with single-letter flags. For details, see [CLI](/docs/flags.md). ### New Features * **Cluster Mode** FFmate can now run in cluster mode with multiple instances sharing the same **Postgres** database. For details, see [Clustering](/docs/clustering.md). * **Clients Endpoint** Added an endpoint to list all FFmate instances connected to the cluster. For details, see [Listing Cluster Clients](/docs/ffmate-internals.md#client-endpoint). * **Identifier Argument** Added a new CLI argument to set the name for each FFmate instance, making it easier to recognize. For details, see [--identifier](/docs/flags.md#server-command-flags). * **Health Endpoint** Added a new `/health` endpoint that orchestration tools like Kubernetes can use to monitor the health of an FFmate instance. For details, see [Health Endpoint](/docs/ffmate-internals.md#health-endpoint). * **Extended Metrics** Added new gauges for `webhooks` and `websocket`. For details, see [Metrics](/docs/ffmate-internals.md#metrics). * **Direct Webhooks** Added support for fine-grained webhooks in tasks and presets. For details, see [Global and Direct Webhooks](/docs/webhooks.md). * **Webhook Logs & Retries** Webhook executions are now persistently stored in the database, and failed deliveries are retried automatically. For details, see [Webhook Logs](/docs/webhooks.md#webhook-logs) and [Webhook Retries](/docs/webhooks.md#setting-up-your-webhook-endpoint). * **Watchfolder Lock** Watchfolders now create `.lock` files for processed items. These prevent files from being reprocessed after restarts. For details, see [Watchfolder Lock](/docs/watchfolder.md#how-watchfolders-work). * **UI Refresh** The UI has been modernized as a first step toward a more polished and consistent experience, with more improvements planned. Images in this [documentation](/docs/web-ui.md) are temporarily outdated and will be updated once the full UI redesign is complete. ### Improvements * **Test Coverage** Test coverage has been expanded to cover all major core components of the codebase. ### Bug Fixes * **Race Conditions** Multiple race conditions have been resolved in watchfolders, tasks, and config handling. ### Changes * **FFmpeg Detection** In version 2.0, **FFmpeg** detection now runs once and is not repeated, saving resources. ## Version 1.2.0 (08-09-2025) ### New Features * **`${FFMPEG}` Wildcard** Added a wildcard that resolves to the configured FFmpeg binary path. For details, see the [wildcards](/docs/wildcards.md#ffmpeg-path). * **FFmpeg Command Chaining with `&&`** You can now chain multiple FFmpeg commands in a single task using `&&`. For details, see the [task properties](/docs/tasks.md#task-properties). * **Task Metadata Wildcard** Added `${METADATA_}` to resolve values from the task’s `metadata` object across commands, inputs, outputs, and scripts. For details, see the [wildcards](/docs/wildcards.md#task-metadata). * **Watchfolder Metadata** Tasks created by watchfolders now include file information under `metadata.ffmate.watchfolder` (fields include `path`, `relativeDir`, `relativePath`, and the watchfolder `uuid`). For details, see the [watchfolder](/docs/watchfolder.md#how-watchfolders-work). * **Sidecar Re-Import in Pre-Processing** Added the option to re-import the task’s `sidecar` after the pre-processing script finishes. For details, see the [Pre-Post Processing](/docs//pre-post-prcessing.md#importing-a-task-s-sidecar). * **Webhooks API: Get & Update** Added new REST endpoints to retrieve a single webhook and to update an existing webhook. For details, see the [webhooks](/docs/webhooks.md). * **Webhooks in the Web UI** The web UI now supports creating, viewing, and updating webhooks. For details, see the [webui](/docs/web-ui.md#webhooks). ### Changes * **Progress Output Throttling** FFmate now adds `-stats_period 1` to every FFmpeg command, limiting progress output to one update per second. For details, see the [task](/docs/tasks.md#task-properties). * **Docker Image Tools** The Docker image now includes `bash` and `jq`. * **Docker Environment Variable Rename** In the Dockerfile, the `DB` environment variable has been replaced with `DATABASE`. * **Go Runtime Update** Updated Go to version `1.25.0`. ## Version 1.1.0 (14-07-2025) ### New Features * **Automatic Output Folder Creation** FFmate now creates output directories automatically if they do not exist. * **FFmpeg Detection** FFmate checks for FFmpeg in the system’s default PATH or the location specified by the `--ffmpeg` flag, and logs a warning in both the web UI and logs if it’s not found. ### Changes * **Docker Debug Mode Disabled by Default** The Docker image now ships with debugging turned off by default. * **Removed AI Endpoint and flag** The `/ai` endpoint and the `--ai` flag introduced in v1.0.8 have been removed in favor of a future database-driven configuration setting. ### Bug Fixes * **Script Error Logging** FFmate now logs stderr output when a pre- or post-process script exits with a non-zero code. ## Version 1.0.8 (29-05-2025) ### New Features * **Windows Support** FFmate is now fully compatible with Windows. A dedicated installer is available for download — [get it here](https://github.com/welovemedia/ffmate/releases/tag/1.0.8). * **New API Endpoint: `/client`** Introduced a new endpoint that returns detailed information about the client environment, including system architecture, operating system, and FFmate version. * **FFmate AI (Preview)** Initial support for the upcoming FFmate AI assistant is now available. This release includes: * A new `--ai` flag to enable AI-related features * A new `/ai` REST endpoint to retrieve model-related information * **Suspend Watchfolder Scanning** A `suspended` flag has been added to enable temporary pausing of active watchfolders without removing or modifying their configuration. ### Improvements * **Automatic Update Checks** FFmate now performs periodic checks for new releases. When an update is available, a notification appears in the web UI or is printed to the console in headless mode. ### Bug Fixes * **Reduced CPU Usage in Queue Processing** Resolved an issue where the task update loop executed too frequently, resulting in high CPU usage. --- --- url: /docs/tasks.md description: >- Detailed FFmate task documentation: Understand the complete task lifecycle, statuses, and API usage for creating, monitoring, managing, and batching FFmpeg jobs --- # Understanding Tasks in FFmate A **task** in FFmate represents an `FFmpeg` command execution such as transcoding a video, extracting audio, or applying filters. When you submit a task, FFmate triggers `FFmpeg` under the hood to perform the media processing. Tasks can be submitted on their own or grouped into `batches` to handle multiple files efficiently in one go. Every task follows a structured **lifecycle**, progressing from submission to execution and ultimately reaching completion or failure. Before diving into task execution, let's first go through the **lifecycle** of tasks and their corresponding **statuses** in FFmate. | Status | Description | |-------------------|---------------------------------------------------| | `QUEUED` | The task is waiting in the processing queue | | `PRE_PROCESSING` | The task's pre-processing script is running | | `RUNNING` | The main FFmpeg command is currently executing | | `POST_PROCESSING` | The task's post-processing script is running | | `DONE_SUCCESSFUL` | The task completed successfully | | `DONE_ERROR` | The task encountered an error and failed | | `DONE_CANCELED` | The task was manually canceled before completion | ### Task Flow: The diagram below shows how a task progresses through its lifecycle in FFmate ```mermaid graph TD; queued -->|Starts processing| processing; processing -->|Finishes successfully| completed; processing -->|Fails| failed; queued -->|Canceled| canceled; classDef queued fill:#fdf6b2,stroke:#facc15,stroke-width:2px,color:#000; classDef processing fill:#bfdbfe,stroke:#3b82f6,stroke-width:2px,color:#000; classDef completed fill:#bbf7d0,stroke:#22c55e,stroke-width:2px,color:#000; classDef failed fill:#fecaca,stroke:#ef4444,stroke-width:2px,color:#000; classDef canceled fill:#e0e7ff,stroke:#6366f1,stroke-width:2px,color:#000; class queued queued; class processing processing; class completed completed; class failed failed; class canceled canceled; ``` Next, let's explore how to trigger and manage single tasks in FFmate ## Creating a Task To create a task, send a `POST` request to the FFmate API: ```sh curl -X POST http://localhost:3000/api/v1/tasks \ -H "Content-Type: application/json" \ -d '{ "name": "Final Render for Summer Ad Campaign", "command": "-y -i ${INPUT_FILE} -c:v libx264 -preset fast -crf 23 -vf \"drawtext=text='${METADATA_project_name}':x=10:y=10:fontsize=24:fontcolor=white\" -c:a aac -b:a 128k ${OUTPUT_FILE}", "inputFile": "/media/source/client_project_final_v1.mov", "outputFile": "/media/deliverables/${METADATA_client_id}/final_ad_spot.mp4", "priority": 10, "metadata": { "project_name": "Summer Ad Campaign", "client_id": "CUST-12345", "editor": "jane.doe" }, "preProcessing": { "scriptPath": "/opt/ffmate/scripts/verify_source.sh --input ${INPUT_FILE} --sidecar ${SIDECAR_FILE}", "sidecarPath": "/var/tmp/ffmate_sidecar_${UUID}.json", "importSidecar": true }, "postProcessing": { "scriptPath": "/opt/ffmate/scripts/upload_to_s3.sh --file ${OUTPUT_FILE} --client ${METADATA_client_id}" }, "webhooks": [ { "event": "task.updated", "url": "https://my-project-manager.com/api/hooks/ffmate-status" } ] }' ``` FFmate responds with a JSON object that contains the newly created task including its `ID`. This `taskId` can be used to monitor the task’s progress in the next section. A `task.created` event is also fired via [Global webhooks](/docs/webhooks#task-events) and [Direct webhooks](/docs/webhooks#task-events). ### Task Properties These are the properties you can set when creating a task in FFmate: * **`name`** *\[optional]* - A short, descriptive name to help identify and track the task in the web UI and API (e.g., "Final Render for Summer Ad Campaign") * **`command`** — The custom command FFmate will use to run `FFmpeg`. This field is **mandatory** unless you use a `preset`. ⚠️ **Important details about how `command` works:** * You don’t need to add `ffmpeg` at the start of the command. FFmate automatically prepends it. By default, FFmate uses the `ffmpeg` binary in your system’s `PATH`. If you want to use a different version, you can override the default with the `--ffmpeg ` [command-line flag](/docs/flags.md#server-command-flags). * FFmate also implicitly adds the `-stats_period 1` [option](https://ffmpeg.org/ffmpeg-all.html#Advanced-options) to every command, which limits FFmpeg’s progress output to one update per second. You can override this by explicitly adding your own `-stats_period x` to the command. * This setting directly affects: * how often `task.updated` [Global webhook](/docs/webhooks#task-events-1) and [Direct webhook](/docs/webhooks#task-events) are sent, and * how often the job dashboard refreshes progress updates. * The `command` field also supports chaining multiple `FFmpeg` commands with `&&`. This is useful for advanced workflows such as **two-pass encoding**. When chaining commands, you must use the `${FFMPEG}` wildcard (see [FFmpeg Path](/docs/wildcards.md#ffmpeg-path) for more details). You can also use [wildcards](/docs/wildcards.md) like `${INPUT_FILE}` and `${OUTPUT_FILE}` inside the command string. FFmate will automatically replace them with the actual file paths when the task runs. ::: tip Not sure which `FFmpeg` commands to use? * [OSTechNix – 20+ FFmpeg Commands For Beginners](https://ostechnix.com/20-ffmpeg-commands-beginners/) * [Abyssale – Top 20 best commands for FFmpeg](https://www.abyssale.com/blog/top-20-best-commands-for-ffmpeg) * [VideoProc – 31 Must-Haves FFmpeg Commands for Beginners](https://www.videoproc.com/resource/ffmpeg-commands.htm) * [GorillaSun – A Simple Guide to FFMPEG](https://www.gorillasun.de/blog/a-simple-guide-to-ffmpeg/) * [Bannerbear – Top 10 FFmpeg Command Options You Need to Know](https://www.bannerbear.com/blog/ffmpeg-101-top-10-command-options-you-need-to-know-with-examples/) * Ask ChatGPT ::: * **`inputFile`** *\[optional]* – The path to the input media file that will be processed. * **`outputFile`** *\[optional]* – The path where the transcoded file should be saved. If the specified directory does not exist, FFmate will **create it automatically**. ::: tip Handling Input and Output Files * The **`inputFile`** and **`outputFile`** properties are **optional** and should only be used if your command includes the placeholders `${INPUT_FILE}` and `${OUTPUT_FILE}`. * FFmate **automatically replaces** these placeholders with the actual file paths during execution. * If your command **directly specifies input and output paths**, you do **not** need to provide these properties separately. ::: * **`priority`** *\[optinal]* – Sets the task's priority in the processing queue. Higher numbers mean higher priority — for example, a task with priority `100` will be processed before one with `10`. If multiple tasks share the same priority, they’ll generally run in the order they were created (FIFO for that priority level). * **`preset`** - The UUID of a pre-configured [Preset](/docs/presets.md) to use for this task. This field is **mandatory** unless you use a `command`. * **`preProcessing`** *\[optional]* – Defines a [Pre-Processing Script](/docs/pre-post-prcessing.md) to run before the task starts. Useful for preparing files, validating input, or setting up the environment. * **`scriptPath`**: The full path to the script or executable to run. * **`sidecarPath`**: The full path to the JSON file that contains all task data. * **`importSidecar`**: Defines if the task will [re-import the sidecar](/docs/pre-post-prcessing.md#importing-a-task-s-sidecar) JSON after the pre-processing script finishes. * **`postProcessing`** *\[optional]* – Defines a [Post-Processing Script](/docs/pre-post-prcessing.md) to run after the task completes. Useful for cleanup, moving output files, or triggering follow-up actions. * **`scriptPath`**: The full path to the script or executable to run. * **`sidecarPath`**: The full path to the JSON file that contains all task data. * **`Webhooks`** *\[optional]* : Defined a direct webhook target tied only to this task. For example, it can notify a project management tool whenever the task's status changes. * **`metadata`** *\[optional]* — Any JSON object you want to attach to the task. Common uses include adding context, referencing source files, or integrating with external systems. ::: details **Example:** {open} A sample `metadata` object containing useful context about the source file, provided as key-value pairs: ```json "metadata": { "original_filename": "interview_session_03_cam_A.mxf", "project_code": "PROJ-SUMMER2025", "editor_notes": "Needs color correction pass after this transcode." } ``` ::: This is a powerful feature for: ##### Example 1: 1. Your upstream system (CMS/PAM/DAM/MAM/workflow manager) creates a task in FFmate and includes its own identifiers in `metadata` (e.g., `assetId`, `jobId`). 2. FFmate queues the task, then starts processing it. 3. When the task finishes, FFmate sends a `task.finished` webhook to your endpoint. 4. The original `metadata` you sent is returned in the webhook payload, so your system can correlate it back to the `assetId` / `jobId` that originated the task. ##### Example 2: 1. A file is dropped into a watchfolder. 2. FFmate creates a task and adds **watchfolder file metadata** to the task’s `metadata` JSON object. 3. In the task, use the **Task Metadata** wildcard `${METADATA_}` to read those values, for example, to recreate the input folder structure in your `outputFile`. ```json "outputFile": "/volumes/ffmate/processed/${METADATA_ffmate.watchfolder.relativeDir}/${INPUT_FILE_BASENAME}.mp4" ``` ## Monitoring a Task After submitting a task, you can check its current status by sending a `GET` request to the FFmate API: ```sh curl -X GET 'http://localhost:3000/api/v1/tasks/{taskId}' ``` Replace `{taskId}` with the actual task UUID returned in the response when the task was created. FFmate responds with a JSON object containing the full details of the task. 💡 Tip: You can also check the status of each task directly in the FFmate Web UI [FFmate Web UI](/docs/web-ui.md#monitoring-tasks) ## Monitoring All Tasks FFmate lets you retrieve a list of all tasks, no matter their current state—queued, processing, completed, or failed. To get a list of all tasks, send a `GET` request to the FFmate API: ```sh curl -X GET 'http://localhost:3000/api/v1/tasks?page=0&perPage=100' ``` FFmate returns a JSON array containing all configured tasks. The `X-Total` response header provides the total number of tasks. **Query Parameters:** * **`page`** *\[optional]* – Specifies which page of results to retrieve. Default: `0`. * **`perPage`** *\[optional]* – Defines how many tasks should be included in each page. Default: `100`. 💡 Tip: You can also check the status of all tasks: queued, processing, completed, or failed directly in the [FFmate Web UI](/docs/web-ui.md#monitoring-tasks) ## Canceling a Task FFmate lets you to cancel a task that is currently **queued** or **processing**. Once canceled, the task will not be executed or will be stopped if already in progress. To cancel a task, send a `PATCH` request to the FFmate API by including the task's `taskID` in the path: ```sh curl -X PATCH 'http://localhost:3000/api/v1/tasks/{taskId}/cancel' ``` FFmate responds with a JSON object containing the updated details of the task. The task's status will be changed to `DONE_CANCELED`, and the progress will be set to 100. A `task.canceled` event is also fired via [Global webhook](/docs/webhooks#task-events-1) and [Direct webhook](/docs/webhooks#task-events). > \[!NOTE] > If the task is already processing, FFmate will attempt to **stop** it, but cancellation may not always be immediate. 💡 Tip: You can also cancel a running task directly from the [FFmate Web UI](/docs/web-ui.md#canceling-tasks) with a single click—no API call needed. ## Restarting a Task If a task has failed or been canceled, FFmate allows you to restart it without needing to resubmit the job manually. To restart a task, send a `PATCH` request to the FFmate API by including the task's `ID` in the path: ```sh curl -X PATCH 'http://localhost:3000/api/v1/tasks/{taskId}/restart' ``` FFmate responds with a JSON object containing the updated details of the task. The task's `status` will be reset to `QUEUED`, `progress` to `0`, `error` cleared, and `startedAt`/`finishedAt` timestamps reset. The task will then be re-added to the processing queue according to its priority. > \[!Note] > > * Restarting a task will **re-run the exact same command** using the original input and output paths. > * If the task was previously processing, it will start from the beginning. Once restarted, the task will move back into the **queued** state and follow the standard [task lifecycle](#task-flow). A `task.created` event is also fired via [Global webhook](/docs/webhooks#task-events-1) and [Direct webhook](/docs/webhooks#task-events). 💡 Tip: Need to rerun a task? You can restart it directly in the [FFmate Web UI](/docs/web-ui.md#restarting-tasks) ## Deleting a Task Once a task is completed, canceled, or no longer needed, you can **permanently remove** it from FFmate. To delete a task, send a `DELETE` request to the FFmate API by including the task's `ID` in the path: ```sh curl -X DELETE 'http://localhost:3000/api/v1/tasks/{taskId}' ``` FFmate responds with a `204` No Content status. The task will be removed from the system. A `task.deleted` event is also fired via [Global webhook](/docs/webhooks#task-events-1) and [Direct webhook](/docs/webhooks#task-events). ::: warning Important * Deleting a task **removes the database entry** from FFmate but **does not** delete the input or output files. * If the task is still processing, FFmate will attempt to **stop** it before deletion. ::: 💡 Tip: Tasks can also be deleted from the [FFmate Web UI](/docs/web-ui.md#deleting-tasks) ## Submitting Multiple Tasks as a Batch FFmate allows you to submit multiple transcoding tasks in a single request, referred to as a `batch`. This is ideal when processing a set of files—whether they use the same settings or different ones—as it simplifies submission and keeps related tasks grouped together. Each batch is automatically assigned a unique `batch ID`, making it easy to monitor, manage, and reference the entire group of tasks as a single unit. While a batch groups multiple task submissions together, each task within it remains fully independent. Every task in the batch is submitted as a standalone task in FFmate. This means: * Each task follows its own lifecycle (`Queued`, `Running`, `Done`). * Each is executed independently by `ffmpeg`, based on its own command or preset. * Each task maintains its own progress, status, and error reporting. * A task's success or failure does not affect others in the same batch. ::: info FFmate processes batch tasks concurrently (up to the `max-concurrent-tasks` limit) or sequentially, based on priority and queue order. ::: ### How to Submit a Batch of Tasks You submit a batch by sending a `POST` request to the `/api/v1/batches` endpoint. The request body must be a **JSON object** with a single key, `tasks`, which contains an array of standard task objects (the same object you'd use for creating a single task via [/api/v1/tasks](#creating-a-task). To submit multiple tasks as a batch, send a `POST` request to the FFmate API: ```bash curl -X POST http://localhost:3000/api/v1/batches \ -H "Content-Type: application/json" \ -d '{ "tasks": [ { "name": "Convert Episode 1 to WebM", "inputFile": "/mnt/source_videos/seriesA/episode_01.mov", "preset": "uuid-of-webm-720p-preset", "priority": 20 }, { "name": "Convert Episode 2 to WebM", "inputFile": "/mnt/source_videos/seriesA/episode_02.mov", "preset": "uuid-of-webm-720p-preset", "priority": 20 }, { "name": "Extract Thumbnail for Promo Image", "command": "-i ${INPUT_FILE} -frames:v 1 -q:v 2 ${OUTPUT_FILE}", "inputFile": "/mnt/source_videos/seriesA/promo_material.mp4", "outputFile": "/mnt/output_images/promo_thumb.jpg", "priority": 50 } ] }' ``` The server will respond with a **JSON object** containing the unique `uuid` of the batch and a `tasks` array with the full details of each newly created task. ```json{2} { "uuid": "c4e8f12a-3b7d-4c9f-a1e8-5d0f2b3c4a9e", "tasks": [ { "uuid": "task-uuid-1", "batch": "c4e8f12a-3b7d-4c9f-a1e8-5d0f2b3c4a9e", "name": "Convert Episode 1 to WebM", "status": "QUEUED", // ... other task details }, { "uuid": "task-uuid-2", "batch": "c4e8f12a-3b7d-4c9f-a1e8-5d0f2b3c4a9e", "name": "Convert Episode 2 to WebM", "status": "QUEUED", // ... other task details } ] } ``` A `batch.created` event is fired when a batch starts, and a `batch.finished` event is fired once the last task in the batch is complete. [See batch webhook events](/docs/webhooks#batch-events) ### Managing and Monitoring Batches While FFmate treats each task in a batch individually for processing, the `batch ID` allows you to group and monitor them as a unit. **Listing Tasks by Batch ID** You can retrieve all tasks that belong to a specific batch by sending a `GET` request with the batch's `uuid`. ```sh curl -X GET 'http://localhost:3000/api/v1/batches/{batch_uuid}?page=0&perPage=10' ``` FFmate returns a **JSON object** containing the batch `uuid` and a paginated `tasks` array. The `X-Total` response header provides the total number of tasks in the batch. **Query Parameters:** * **`page`** *\[optional]* – Specifies which page of results to retrieve. Default: `0`. * **`perPage`** *\[optional]* – Defines how many tasks should be included in each page. Default: `100`. ::: tip 💡 Webhook Notifications for Batches **Webhooks Aren’t Just for single Tasks — Use Them to Track Batches Too** * **`batch.created`** – Triggered once when a batch of tasks is successfully submitted. The payload includes an array of the created task objects. * **`batch.finished`** – Triggered when all tasks in the batch have finished processing (either successfully, with errors, or canceled). The payload includes a summary of each task's final status, making this ideal for triggering follow-up actions once the entire batch is complete. ::: ### Common Use Cases for Batch Submission * **Bulk Transcoding** – Convert an entire folder of videos to a new format or resolution in one go. * **Multi-Renditions** – Generate multiple versions of the same source file (e.g., different bitrates or resolutions). Each rendition is submitted as an individual task within the batch. * **Sequential Asset Processing** – Submit tasks that represent different steps in a media pipeline (e.g., clean audio, transcode video, apply watermark). While FFmate handles each task independently based on queue rules, you can still track them together as part of a single batch. While FFmate processes them based on queue rules, you can monitor them as a batch. --- --- url: /docs/web-ui.md description: >- Explore the FFmate Web UI: an intuitive interface to manage FFmpeg jobs, monitor tasks, configure watchfolders, create presets, and view real-time logs --- # FFmate Web UI The FFmate Web UI offers a clean, intuitive way to manage and monitor your `FFmpeg` jobs in real time. You can easily track active tasks, configure watchfolders, create presets, and access detailed logs—all from your browser, without needing to use the API or command line. Whether you're a developer, media technician, or workflow specialist, the Web UI helps you stay in control of your transcoding operations from start to finish. ## Navigation Overview The FFmate Web UI is divided into four main sections, each designed to simplify and streamline your media processing workflows: 1. **`Dashboard`** – Monitor and manage all `FFmpeg` tasks in real time, including active, completed, and failed jobs. 2. **`Watchfolders`** – Configure folders to automatically trigger tasks when new media files are detected. 3. **`Presets`** – Define and reuse `FFmpeg` command templates for consistent, repeatable transcoding tasks. 4. **`Webhooks`** – Send real-time notifications to external systems whenever events occur, such as task progress, completion, or failure. 5. **`Logs`** – Access live system logs, including task execution, watchfolder activity, and background processing events. FFmate includes a built-in mechanism to check whether `FFmpeg` is installed and accessible. It looks for `FFmpeg` in the system’s default `PATH` or in the custom location specified via the `--ffmpeg` flag. If `FFmpeg` is not found, the Web UI will display a persistent notification in the navigation bar. This alert includes a direct link to the [documentation](/docs/getting-started#Installing-ffmpeg) with step-by-step instructions on how to install `FFmpeg` on all supported operating systems. > \[!NOTE] > FFmate requires **FFmpeg** to function. If **FFmpeg** is not accessible, FFmate will not be able to process any tasks. FFmate checks for the `ffmpeg` executable every 10 seconds, either on the system `PATH` or at a custom location specified with the `--ffmpeg` flag. If FFmate cannot find the executable at startup, a warning message appears in both the logs and the web interface. ## Dashboard The Dashboard provides a real-time overview of all `FFmpeg` tasks—letting you monitor progress, manage jobs, and review task details at a glance. ### Monitoring Tasks View all active and completed tasks in real time, including their status and progress. ### Filtering Task Statuses You can filter tasks by their current status to quickly focus on specific groups, such as **running**, **failed**, or **completed** jobs. To filter the list, click the **cogwheel icon** in the status column header and select a status from the dropdown menu. * **`QUEUED`** – Task is waiting to be processed. * **`RUNNING`** – Task is currently being executed. * **`DONE_SUCCESSFUL`** – Task completed without errors. * **`DONE_ERROR`** – Task encountered an error. * **`DONE_CANCELED`** – Task was manually canceled. ### Canceling Tasks To stop a running task, hover over it to reveal the **cancel** icon on the right. Once clicked, the task will be halted immediately and marked as `DONE_CANCELED`. ### Restarting Tasks To re-run a completed or failed task, hover over it and click the **restart** icon. The task will be resubmitted with the same configuration and added back to the queue. ### Deleting Tasks To remove a task from the list, hover over it and click the **delete** icon. Deleting a task will permanently remove both the task and its logs from the database. ### Task Details Click on any task to see its full execution details, including progress, `FFmpeg` command, input/output paths, and pre/post-processing information. ## Watchfolders Watchfolders let you automate task creation by continuously monitoring specific folders and triggering jobs when new media files are detected. ### Creating a Watchfolder Click the **plus (+) button** in the bottom-right corner of the Watchfolders page to create a new watchfolder. Specify the folder path, preset, scan interval, growth check duration, and optional file extension filters. ### Checking Configured Watchfolders The watchfolder list displays all configured watchfolders along with their current status, assigned preset, and monitored folder path. ### Checking Watchfolder Details Click on any watchfolder to view its full configuration, including assigned preset, filter rules, scan settings, and monitored folder path. ### Updating a Watchfolder Hover over a watchfolder in Watchfolders, click the **pencil** icon, adjust any field in the Edit Watchfolder form (path, preset, scan interval, growth check, filters), then click Save. The watchfolder will restart with the new configuration shortly after the update. ### Deleting Watchfolders Hover over a preset in Presets, click the **delete** icon next to a watchfolder to remove it. FFmate will immediately stop monitoring the associated folder. ## Presets Presets in FFmate are reusable templates that simplify task creation by letting you predefine `FFmpeg` commands, output naming patterns, priorities, and optional pre/post-processing scripts. ### Creating a Preset Click the **plus (+) button** in the bottom-right corner of the Presets page to create a new Preset. You can create your own custom preset or choose from a set of predefined, ready-to-use presets provided by the FFmate team. ### List of Active Presets View all configured presets along with their name, description, priority, and output file pattern. ### Checking Preset Details Click on any preset to view its full configuration, including the `FFmpeg` command, output pattern, priority, and any pre/post-processing settings. ### Updating a Preset Hover over a preset in Presets, click the **pencil** icon, modify any fields in the Edit Preset form (name, `FFmpeg` command, output pattern, priority, scripts), then click Save. ### Removing a Preset Hover over a preset in Presets, Click the **delete** icon next to a preset to remove it. ## Webhooks Webhooks let you integrate FFmate with other systems by sending real-time event notifications whenever something happens in your workflow — for example, when a task starts, finishes, or fails. ### Creating a Webhook Click the **plus (+) button** in the bottom-right corner of the Webhooks page to create a new webhook. Specify the **event** you want to subscribe to and the target **URL** where notifications should be delivered. ### Checking Configured Webhooks The Webhooks list displays all configured webhooks with their subscribed event and target URL. ### Updating a Webhook Hover over a webhook in the list, click the **pencil** icon, adjust any field in the Edit Webhook form (event, url), then click Save. Changes take effect immediately, and new events will be delivered according to the updated configuration. ### Deleting Webhooks Hover over a webhook in the list and click the **delete** icon to remove it. FFmate will immediately stop sending notifications to that URL. ## Accessing Real-Time Logs Click the **Logs** icon in the top-right navigation bar to open a real-time log window at the bottom of the screen. This view shows live FFmate activity, including task execution, watchfolder events, and system messages. --- --- url: /docs/webhooks.md description: >- Integrate external systems with FFmate using webhooks. Get instant notifications for task updates, batch processing, preset changes and more --- # Webhooks **Webhooks** in FFmate let you plug real-time event notifications into your workflows—making it easier to trigger external processes, connect third-party tools, and monitor `FFmpeg` jobs without constantly polling the API. When you add webhooks, FFmate can `notify` your external systems whenever events occur—whether it’s tasks, presets, watchfolders, or other changes. FFmate supports two kinds of webhooks: ### Global Webhooks Global webhooks let you define a **single target endpoint per webhook** [event](#task-events). They can be configured through the **/webhooks** [api](#creating-a-webhook) endpoint or the Web UI. ### Direct Webhooks **Direct webhooks** are for cases where you need more fine-grained notifications with additional target endpoints. You can add them **directly to tasks** when submitting via the [api](/docs/tasks.md#creating-a-task), or to an FFmate [preset](/docs/presets.md#creating-a-preset) so every task using that `preset` includes the direct webhooks. Direct webhooks are only available for the following events: ### Task Events | Event | Description | |-----------------|--------------------------------------------------| | `task.created` | Triggered when a new task is added | | `task.updated` | Triggered when a task’s status or details change | | `task.deleted` | Triggered when a task is deleted | ### Preset Events | Event | Description | |------------------|-----------------------------------------------| | `preset.created` | Triggered when a new preset is created | | `preset.updated` | Triggered when an existing preset is modified | | `preset.deleted` | Triggered when a preset is removed | Global and direct webhooks can work together. For example: * You might configure a global webhook for `task.created`, `task.updated`, and `task.deleted` that points to a central endpoint, e.g. `https://ffmate.io/webhooks/global`. * For certain tasks submitted via the API, you can attach extra direct webhooks for those same events, e.g. `https://welovemedia.io/hooks/task-events`. * Direct webhooks can be set when you create the task, or added later in the pre-processing step using the [sidecar re-import feature](/docs/pre-post-prcessing.md#importing-a-task-s-sidecar). ## Creating a Webhook To create a webhook, send a `POST` request to the FFmate API specifying the event you want to subscribe to and the URL where FFmate should deliver the notification. ```sh curl -X POST http://localhost:3000/api/v1/webhooks \ -H "Content-Type: application/json" \ -d '{ "event": "task.created", "url": "https://yourserver.com/webhook-handler" }' ``` After you create a webhook, FFmate responds with a JSON object containing the `id` of the newly created webhook. A `webhook.created` event is also fired via [webhooks](#webhook-events) 💡 Tip: Creating a new webhook? You can define and save webhooks directly in the [FFmate Web UI](/docs/web-ui.md#creating-a-webhook) without writing any API requests ## Global Webhook Events FFmate supports a range of webhook events, organized into categories based on what they track. ### Task Events: | Event | Description | |--------------------|-------------| | `task.created` | Triggered when a new task is added | | `task.updated` | Triggered when a task's status or details are updated | | `task.deleted` | Triggered when a task is deleted | *** ### Batch Events: | Event | Description | |--------------------|-------------| | `batch.created` | Triggered when a new batch of tasks is created | | `batch.finished` | Triggered when a batch of tasks is completed | *** ### Preset Events: | Event | Description | |--------------------|-------------| | `preset.created` | Triggered when a new preset is created | | `preset.updated` | Triggered when an existing preset is modified | | `preset.deleted` | Triggered when a preset is removed | *** ### Watchfolder Events: | Event | Description | |------------------------|-------------| | `watchfolder.created` | Triggered when a new watchfolder is created | | `watchfolder.updated` | Triggered when an existing watchfolder is modified | | `watchfolder.deleted` | Triggered when a watchfolder is removed | *** ### Webhook Events | Event | Description | |--------------------|-----------------------------------------------| | `webhook.created` | Triggered when a new webhook is registered | | `webhook.updated` | Triggered when an existing webhook is updated | | `webhook.deleted` | Triggered when a webhook is removed | ### Webhook Payload: When the event is triggered, FFmate sends a `POST` request to your specified URL, containing all relevant data about the event in the request body. ```json { "event": "task.created", "timestamp": "2025-02-13T14:05:32Z", "data": { "taskId": "550e8400-e29b-41d4-a716-446655440000", "inputFile": "/source/video.mp4", "outputFile": "/destination/video_converted.mp4", "status": "queued" } } ``` ## Listing all Webhooks To get a list of all available webhooks, send a `GET` request to the FFmate API ```sh curl -X GET 'http://localhost:3000/api/v1/webhooks?page=0&perPage=10' ``` **Query Parameters:** * **`page`** *\[optional]* – Specifies which page of results to retrieve. Default: `0`. * **`perPage`** *\[optional]* – Defines how many webhooks should be included in each page. Default: `100`. FFmate returns a JSON array with all configured webhooks. The `X-Total` response header provides the total number of webhooks available. 💡 Tip: Need an overview of all webhooks? You can browse and manage them easily in the [FFmate Web UI](/docs/web-ui.md#checking-configured-webhooks). ## Getting a Single Webhook To retrieve the details of a specific webhook, send a `GET` request to the FFmate API using its unique ID. ```sh curl -X GET http://localhost:3000/api/v1/webhooks/{webhookId} ``` FFmate returns a JSON object containing the details of the requested webhook. 💡 Tip: Want a quick way to check the webhook details? You can view webhook configurations directly in the [FFmate Web UI](/docs/web-ui.md#checking-configured-webhooks) without using the API. ## Updating a Webhook To modify an existing webhook, such as changing its **target URL** or the **event** it subscribes to, send a `PUT` request o the FFmate API with the **webhook's ID** in the URL and the new configuration in the request body. The request body should **contain the same fields** as when creating a new webhook. ```sh curl -X PUT http://localhost:3000/api/v1/webhooks/{webhookId} \ -H "Content-Type: application/json" \ -d '{ "event": "task.updated", "url": "https://your-new-server.com/updated-handler" }' ``` FFmate returns the updated webhook object in JSON format. A `webhook.updated` event is also fired via [webhooks](#webhook-events) 💡 Tip: Making changes to a webhook? You can update settings like name and url directly in the [FFmate Web UI](/docs/web-ui.md#updating-a-webhook). ## Deleting a Webhook To remove a webhook, send a `DELETE` request with its ID: ```sh curl -X DELETE http://localhost:3000/api/v1/webhooks/{webhookId} ``` FFmate responds with a `204` No Content status. The webhook will be removed from the system. A `webhook.deleted` event is also fired via [webhooks](#webhook-events) 💡 Tip: No need to send a delete request manually—you can remove webhooks instantly from the [FFmate Web UI](/docs/web-ui.md#deleting-webhooks). ## Setting Up Your Webhook Endpoint When FFmate sends a webhook, it expects your server to be ready to receive and respond to the event. Here's what your endpoint should do: 1. **Accept HTTP POST requests** FFmate sends events as `POST` requests with a JSON payload. Your endpoint should accept and correctly parse these requests. 2. **Return a 2xx status code** FFmate waits for your server to reply before considering the webhook delivered. If your server responds with an HTTP status in the `2xx` range, FFmate treats the webhook as successfully delivered. If your server times out or sends back a non-2xx (like `500 Internal Server Error`), FFmate will try again. It retries sending the webhook up to **three times**, with increasing delays: * After **3** seconds. * Then after **5** seconds. * Finally after **10** seconds. ## Webhook logs FFmate automatically records every webhook delivery attempt in the database. For each attempt, it stores: * the `event type` and `target URL`. * the exact `request headers` and `body sent`. * the HTTP status code, response headers, and response body returned by your server: You can fetch this full history through the API or UI: ```sh curl -X GET http://localhost:3000/api/v1/webhooks/executions ``` --- --- url: /README.md --- # ffmate-docs --- --- url: /docs/what-is-ffmate.md description: >- Discover FFmate, the modern and powerful API-powered FFmpeg automation layer. Automate media workflows with its queue system, webhooks, presets & watchfolders. Simplify transcoding at scale --- # What is FFmate? **FFmate is a modern and powerful automation layer built on top of [FFmpeg](https://ffmpeg.org/)—designed to make video and audio transcoding simpler, smarter, and easier to integrate.** While `FFmpeg` is the industry standard for media encoding and conversion, it can be complex to use directly—especially at scale. With FFmate, you get all the raw power of `FFmpeg`—plus the tools you need to automate, monitor, and scale your workflows with ease. Whether you’re a developer building a media pipeline, a workflow engineer managing a farm of agents, or a non-technical user needing simple batch conversions, FFmate is designed to work for you. ## 🚀 Key Features * **Queueing System** – Submit and manage multiple concurrent `FFmpeg` jobs efficiently. * **Cluster Support** – Run multiple FFmate instances together, sharing the same database for scaling and redundancy. * **Dynamic Filename Wildcards** – Enable smart and customizable output file naming. * **Webhook Notifications** – Receive real-time updates for seamless integration with external workflows. * **Watchfolder** – Automatically detect and process new files as they appear. * **Pre & Post Processing Actions** – Execute custom commands or scripts before and after transcoding. * **Preconfigured Presets** – Simplify common media conversion tasks with ready-to-use settings. * **Web UI** – Monitor and configure transcoding workflows with an intuitive interface. Want to see it in action? Skip to the [Getting started](/docs/getting-started.md) ## 📌 Use Cases ### 📽️ Automated Media Transcoding Easily automate common media processing tasks like video conversion, audio extraction, and thumbnail generation.\ FFmate allows you to submit multiple `FFmpeg` jobs at once and handles them efficiently through a built-in queueing system.\ Perfect for post-production pipelines, cloud workflows, or any scenario where repetitive transcoding needs to be streamlined. ### ⚙️ Workflow & Pipeline Automation Use FFmate’s webhook system to sync with: * Internal automation tools * Media asset management (MAM) platforms * Cloud-based production or publishing workflows No polling required—just plug in your endpoint and go. ### ☁️ Scalable FFmpeg Job Management Run FFmate as a centralized, API-first backend for `FFmpeg` job orchestration.\ You can scale the number of **simultaneous jobs** based on available resources—without needing to manage multiple agents.\ With full control over job priority, queuing, and task lifecycle, FFmate is ideal for high-volume transcoding environments where reliability and automation matter. Use it to power: * Cloud-based encoding workflows. * Media conversion microservices. * Internal development tools that need `FFmpeg` processing on demand. ### 🗂️ Drop Folder Ingest (Watchfolder) Set up a watchfolder to automatically detect new files and trigger predefined processing workflows—perfect for camera card offloads, shared storage, or ingest pipelines. --- --- url: /docs/ffmate-community.md description: >- Need help with FFmate or want to connect? Join our Discord community, get support, report bugs, or request features on GitHub. We'd love to hear from you! --- # How to Reach Out We’d love to hear from you—whether you have a question, want to share feedback, or just feel like connecting with other FFmate users. 💬 **Join the FFmate Community on Discord** Our Discord server is the best place to connect with the FFmate team and other users.\ Get help, share ideas, and stay up to date with the latest features and updates 👉 [Join our Discord](https://discord.gg/NzfeHn37jT) 🚀 **Feature Requests & Bug Reports** Have an idea for a new feature? Found a bug?\ Head over to our GitHub repository to open an issue or submit a pull request 👉 [FFmate on GitHub](https://github.com/welovemedia/ffmate) Your input helps shape the future of FFmate—thanks for being part of it! --- --- url: /docs/getting-started.md description: >- Your guide to getting started with FFmate. Learn to download, install, run the server, submit your first task, set up watchfolders, webhooks, and update easily --- # 🚀 Getting Started Setting up FFmate is quick and straightforward. Follow these steps to get up and running in no time. ## Installing FFmpeg FFmate relies on [FFmpeg](https://ffmpeg.org/) to handle all media processing behind the scenes. If you don’t have **FFmpeg** installed yet, no worries — just follow the steps below to get it set up on your system. ###  macOS #### Installing FFmpeg via Homebrew The easiest way to install FFmpeg on macOS is using [Homebrew](https://brew.sh): ```sh brew install ffmpeg ``` Homebrew installs FFmpeg and adds it to your system path automatically, so FFmate can find it and start processing tasks right away. #### Download and run the static build If Homebrew isn’t your thing, you can also install FFmpeg manually by downloading a static build. 1. Go to and click the **Apple** icon. 2. Choose a trusted static build provider like: * [evermeet.cx](https://evermeet.cx/ffmpeg/) * [Gyan.dev](https://www.gyan.dev/ffmpeg/builds/) 3. Download the build and unzip it. You’ll find an `ffmpeg` binary inside. 4. Move the binary to a directory in your system `PATH`, for example: ```sh sudo mv ~/Downloads/ffmpeg /usr/local/bin/ sudo chmod +x /usr/local/bin/ffmpeg ``` 5. The first time you run it, macOS may block it because it’s from an "unidentified developer" To allow it: * Open **System Settings → Privacy & Security** * Look for the FFmpeg block message and click **Allow Anyway** * Then run the binary again from your terminal Once that's done, **FFmpeg** will be available system-wide, and FFmate will be able to use it automatically. ### 🖥️ Windows #### Install via Windows Package Manager (winget) If you're on Windows 10 or 11, you can install **FFmpeg** via the built-in package manager: ```powershell winget install FFmpeg ``` This installs **FFmpeg** and automatically adds it to your system PATH, so FFmate can detect it and start processing tasks right away #### Download and run the static build Want full control? Here’s how to install FFmpeg manually with a static build 1. Go to and download a static build (e.g., `ffmpeg-release-essentials.zip`). 2. Extract the archive to a folder — for example: `C:\ffmpeg`. 3. Add `C:\ffmpeg\bin` to your system `PATH`: * Press `Win + S`, search for **Environment Variables**, and select **Edit the system environment variables** * In the **System Properties** window, click **Environment Variables…** * Under **System variables**, find and select the `Path` variable, then click **Edit** * Click **New** and enter: `C:\ffmpeg\bin` * Click **OK** to save and close all windows 4. Open a new terminal (Command Prompt or PowerShell) and verify the installation: ```cmd ffmpeg -version ``` Once installed and added to your path, **FFmpeg** will be available system-wide — and FFmate will be ready to use it automatically. ### 🐧 Linux On Ubuntu or Debian-based systems: ```sh sudo apt update sudo apt install ffmpeg ``` ### 🐳 Docker Running FFmate with Docker? FFmpeg is already included in the image, so there’s nothing else to install. Just run and go 🚀 > 💡 If FFmpeg is installed in a non-standard location, you can tell FFmate where to find it using the `--ffmpeg` flag. > Learn more 👉 [Flags Reference](/docs/flags/#server-command-flags) ## Downloading & Installing FFmate FFmate is available for Windows, macOS, and Linux, with multiple installation options: ###  macOS via Homebrew Install FFmate easily using Homebrew: ```bash brew install ffmate ``` To update FFmate installed via Homebrew, run the following command: ```bash brew update brew upgrade ffmate ``` ### 🖥️ Windows (Manual Download) * [Windows – AMD64](https://github.com/welovemedia/ffmate/releases/latest/download/ffmate-windows-amd64.zip) * [Windows – ARM64](https://github.com/welovemedia/ffmate/releases/latest/download/ffmate-windows-arm64.zip) ###  macOS (Manual Download) * [macOS – Apple Silicon (arm64)](https://github.com/welovemedia/ffmate/releases/latest/download/ffmate-darwin-arm64.gz) * [macOS – Intel (x86\_64)](https://github.com/welovemedia/ffmate/releases/latest/download/ffmate-darwin-amd64.gz) ### 🐧 Linux (Manual Download) * [Linux – ARM64](https://github.com/welovemedia/ffmate/releases/latest/download/ffmate-linux-arm64.gz) * [Linux – x86\_64](https://github.com/welovemedia/ffmate/releases/latest/download/ffmate-linux-amd64.gz) ### 🐳 Docker * [Run FFmate via Docker](https://github.com/welovemedia/ffmate/pkgs/container/ffmate) ## Running FFmate You can run FFmate in one of two ways: natively on Windows, macOS, or Linux, or via a Docker container. Whichever best fits your environment ### Windows After downloading FFmate, open your terminal, navigate to the folder where you saved it, and start the server with: ```cmd ffmate server ``` 💡 Tip: For easy access to FFmate’s features, start it with a tray icon using the following command: ```cmd ffmate server --tray ``` ### macOS & Linux After downloading FFmate, open your terminal, navigate to the folder where you saved it, and start the server with: ```sh ffmate server ``` 💡 Tip: For easy access to FFmate’s features, start it with a tray icon using the following command: ```sh ffmate server --tray ``` By default, FFmate runs on ****. If port 3000 is already in use or you prefer a different one, you can easily change it. Learn how to change the port here 👉 [Learn more](/docs/flags/#server-command-flags). > \[!NOTE] > FFmate requires `FFmpeg` to be installed on **Windows**, **macOS**, or **Linux**. Make sure `FFmpeg` is available in your system’s `PATH` before launching FFmate. If `FFmpeg` is installed in a custom location, use the `--ffmpeg` flag to specify its path. [Learn more](/docs/flags/#server-command-flags) ### Running FFmate with Docker FFmate is also available as a Docker image hosted on GitHub Container Registry. The Docker image comes bundled with `FFmpeg`, making it much easier to get started. You can pull and run FFmate using Docker with a single command: ```sh docker run -it --rm \ -p 3000:3000 \ ghcr.io/welovemedia/ffmate:latest ``` This will start FFmate and expose the web interface at http://localhost:3000 > \[!NOTE] > By default, data won't persist after the container stops. > To preserve your database, map a local folder to `**/app/db**`. > Example: `**-v $(pwd)/ffmate-data:/app/db**`. ### Optional Environment Variables You can customize FFmate’s behavior using the following environment variables: | Variable | Description | |-----------------------|-----------------------------------------------------------------------------| | `PORT` | The port FFmate will run on (default: `3000`) | | `DATABASE` | Path to the internal SQLite database (default: `/app/db/sqlite.db`) | | `LOGLEVEL` | Logging level (`info`, `warn`, `error`, `debug`) | | `MAX_CONCURRENT_TASKS`| Maximum number of FFmpeg tasks to run at the same time (default: `3`) | | `DEBUGO` | Enables verbose debug output (e.g., `ffmate:*`) | ### Example: Run FFmate with all environment variables set in a single command: ```sh docker run -it --rm \ -p 3000:3000 \ -v $(pwd)/ffmate-data:/app/db \ -e PORT=3000 \ -e LOGLEVEL=debug \ -e MAX_CONCURRENT_TASKS=5 \ ghcr.io/welovemedia/ffmate:latest ``` ### Docker Compose Prefer using Docker Compose? Here's a ready-to-use docker-compose.yml to get FFmate up and running quickly: ```yaml version: "3.8" services: ffmate: image: ghcr.io/welovemedia/ffmate:latest ports: - "3000:3000" volumes: - ./ffmate-data:/app/db environment: - PORT=3000 - DB=/app/db/sqlite.db - LOGLEVEL=info - MAX_CONCURRENT_TASKS=3 ``` Start FFmate using your `docker-compose.yml` file: ```sh docker compose up -d ``` ## Submitting your first task To submit a new transcoding task, make a `POST` request to the API: ```sh curl -X POST http://localhost:3000/api/v1/tasks \ -H "Content-Type: application/json" \ -d '{ "command": "-y -i ${INPUT_FILE} -c:v libx264 -preset fast -crf 23 ${OUTPUT_FILE}", "inputFile": "videos/input.mp4", "outputFile": "videos/output.mp4", "priority": 2 }' ``` ### Monitoring the Task Check the status of your task by making a `GET` request: ```sh curl -X GET http://localhost:3000/api/v1/tasks/{taskId} ``` Replace `{taskId}` with the actual ID returned when submitting the task. You can track the status and progress of your FFmate tasks directly in the Web UI. 👉 [Learn more](/docs/web-ui.md) ## Watchfolders FFmate can automatically detect and process new files in a **watchfolder**. To configure a watchfolder, make a `POST` request to the API: ```sh curl -X POST http://localhost:3000/api/v1/watchfolders \ -H "Content-Type: application/json" \ -d '{ "name": "My Watchfolder", "description": "Automatically processes new media files", "interval": 5, "growthChecks": 3, "preset": "preset-id", "path": "/path/to/watchfolder", "filter": { "extensions": { "include": ["mp4", "mov"], "exclude": ["tmp", "log"] } } }' ``` Once configured, any new file matching the criteria will be automatically processed when added to the watchfolder. Are you more in the mood to configure your watchfolder in a more visual way? No problem! Learn how to configure your first watchfolder using our Web UI 👉 [Check it out](/docs/web-ui.md) ## Real-Time updates with Webhook notifications FFmate can notify external systems about task progress, completion, or failure using webhooks. To configure a webhook, make a `POST` request to the API: ```sh curl -X POST http://localhost:3000/api/v1/webhooks \ -H "Content-Type: application/json" \ -d '{ "event": "task.created", "url": "https://myserver.com/ffmate/webhook.create" }' ``` FFmate will send a `POST` request to the specified URL when the event occurs. FFmate supports webhook notifications for tasks, batches, presets, watchfolders. You can react to new events, keep external systems in sync, or trigger automations in real time. Learn how to make the most of FFmate’s webhooks 👉 [Learn more](/docs/webhooks.md) ## Updating FFmate Keeping FFmate up to date ensures you have the latest features, bug fixes, and performance improvements. ### Update FFmate via CLI To update FFmate to the latest version, run the following command in your terminal: ```sh ffmate update ``` This command will check for the latest release and install the update automatically. ### Verify the Installed Version After updating, you can confirm that FFmate is running the latest version: ```sh ffmate --version ``` --- --- url: /docs/clustering.md description: >- Set up FFmate clustering with PostgreSQL to scale FFmpeg transcoding across servers. Distribute jobs, manage watchfolders, add redundancy, and boost throughput. --- # Clustering **Clustering** in FFmate lets you run several instances connected to the same **PostgreSQL** database. They share a common queue, distribute jobs across nodes, and handle more tasks in parallel. It lets you go beyond the limits of a single machine while keeping the system resilient if one or more nodes in the cluster go down. ## When to Use Clustering Clustering is useful when: * You need to scale task throughput across multiple servers or containers. * You need redundancy, if one node fails, others keep working. At its core, clustering ensures that all nodes: * Share a single source of truth for the job queue. * Broadcast real-time updates to connected users, no matter which node runs the job. ::: info FFmate clusters aren’t limited to one platform. Windows, macOS, Linux, and Docker instances can all run side by side in the same cluster, as long as they connect to the same PostgreSQL database ::: ## Requirements * FFmate **v2.0 or later**. You can check your version with the [version command](/docs/flags.md#version-command). * A running **PostgreSQL database** that every node can access. See [Setting up PostgreSQL](#setting-up-postgresql) for details and options. * **Shared storage** (recommended) if nodes need access to the same media files. ## Setup and Configuration All it takes to create a cluster of FFmate instances are three simple steps: 1. **Provision a PostgreSQL database** that all nodes can reach. 2. **Create a user and database** inside PostgreSQL for FFmate. 3. **Start each FFmate instance** with the same [--database](/docs/flags.md#server-command-flags) URI and a unique [--identifier](/docs/flags.md#server-command-flags): ```bash # Node A ffmate server \ --database="postgresql://user:pass@db_host:db_port/ffmate_db" \ --identifier="node-a" ``` ```bash # Node B ffmate server \ --database="postgresql://user:pass@db_host:db_port/ffmate_db" \ --identifier="node-b" ``` ::: info If you don’t set `--identifier`, FFmate defaults to the machine hostname. That works fine across machines, but it’s best practice to set an explicit identifier — especially if you run multiple nodes on the same host. ::: # How Clustering Works When you run multiple FFmate instances against the same **PostgreSQL** database, they **automatically** form a cluster and split the work between them. There’s **no master node**, you submit [tasks](/docs/tasks.md#creating-a-task) and [task batches](/docs/tasks.md#submitting-multiple-tasks-as-a-batch) exactly as you would in a non-cluster setup. The database makes sure each task is picked up by **only one node**, so jobs **aren’t duplicated**. Updates are shared with all nodes over `WebSockets`, so every UI shows the same state. FFmate’s clustering is built on PostgreSQL’s `LISTEN/NOTIFY`: nodes publish with `pg_notify`; peers `LISTEN` and react. Simple and built-in — no separate broker needed. ```mermaid sequenceDiagram participant A as FFmate Node A participant PG as PostgreSQL participant B as FFmate Node B participant UI as Web UI Note over A: FFmpeg task progress A->>PG: pg_notify(TASK_UPDATED) Note over PG: Fan-out to listeners (LISTEN/NOTIFY) PG-->>B: NOTIFY TASK_UPDATED B->>UI: WebSocket update ``` ## Watchfolders in a Cluster FFmate clustering uses PostgreSQL transactions to make sure watchfolders don’t get processed twice. Here’s how it works: * At each watchfolder **interval**, every node **queries** the database for watchfolders. The first node to claim one **locks it** and starts working. While it’s locked, other nodes see it’s locked and skip it. * When the **lock is released**, the next interval begins and the **cycle repeats**. This guarantees that only one node processes a watchfolder at a time, even if many are watching. ## Heartbeats Every node sends a small “`I’m alive`” signal to the cluster about **every 15 seconds**. FFmate uses these heartbeats to show active nodes and flag any that have gone quiet in the Web UI. ## Node Failures Clustering improves scalability and resilience, but it **isn’t a full high-availability setup**. If a node goes down mid-transcode, the task stays in `RUNNING`. There’s no built-in automatic failover or requeue. To recover, **restart** the task in the Web UI or via the API. That moves it back to `QUEUED` for another node to pick up. ## Cluster Debugging FFmate comes with advanced debug options that are especially useful when **troubleshooting** cluster setups. If nodes aren’t joining or events aren’t flowing, enable the cluster namespaces: `info:cluster`, `debug:cluster`, `warn:cluster`, and `error:cluster`. For more details on how debugging works in FFmate, see [Debugging](/docs/debugging.md). ## Setting up PostgreSQL **Postgres** is one of the most powerful battle tested and used object-relational database in the world. There are various options to provision or deploy postgres and while this section is not meant to give an indeepth section, we want to highlight the various options you have to get a Postgres db up and running ### Deployment Options FFmate needs a **PostgreSQL** instance that all nodes can reach. You’ve got a few ways to get there, depending on your environment and comfort level. * **For local development**, Docker is usually the quickest route. Pull the official image, run a container, and you’ll have a database ready in minutes. [Postgres on Docker Hub](https://hub.docker.com/_/postgres) * **If you prefer installing directly on your machine**, PostgreSQL provides native installers for Windows, macOS, and Linux. This is handy if you want a bare-metal setup. [Download PostgreSQL](https://www.postgresql.org/download/)\ [Installation Guide](https://www.postgresql.org/docs/current/tutorial-install.html) * **In production**, you can run a single PostgreSQL instance, but for more resilient setups it’s better to use a **high-availability cluster**. PostgreSQL has excellent built-in tools for this. [Creating a Database Cluster](https://www.postgresql.org/docs/current/creating-cluster.html) If you don’t want to install and run Postgres yourself, no problem! Services like [Supabase](https://supabase.com/database) and [Neon](https://neon.com) give you managed PostgreSQL with generous free tiers. You’ll have a database ready in minutes, without the low-level configuration or the headache of maintenance. Once PostgreSQL is running—whether `self-hosted` or `managed`—you only need two extra steps: 1. **Create a user** with permissions to `CONNECT, CREATE, SELECT, UPDATE, DELETE, and LISTEN/NOTIFY`. [Create User docs](https://www.postgresql.org/docs/current/sql-createuser.html) 2. **Create a dedicated database** for FFmate. [Create Database docs](https://www.postgresql.org/docs/current/sql-createdatabase.html) ::: warning Cluster performance depends on **network latency** between your nodes and the PostgreSQL server. Keep the database **close to your nodes whenever possible**. ::: --- --- url: /docs/watchfolder.md description: >- Configure FFmate watchfolders to auto-detect & transcode files. Guide to directory scanning, file growth checks, preset usage, filters & API for FFmpeg automation --- # Watchfolders **Watchfolders** in FFmate allow you to automatically detect and process new files in a specified directory. Once a watchfolder is configured, FFmate will **continuously scan** the folder for new or modified files and create **tasks** to process them based on a task preset. The watchfolder feature is useful for **automatically transcoding** footage from a camera SD card dropped into a network share or creating low-resolution versions of high-resolution files exported from an NLE for review. ## How Watchfolders Work 1. **Monitor a Folder** – FFmate scans the specified directory at a **set interval** to watch for new files. 2. **Detect New Files** – When a new file appears, FFmate doesn’t process it immediately. Instead, it checks the file’s **size** over time. * If the size continues to change, the file is still being copied or written. * If the size remains the same for a number of consecutive checks (controlled by the `growthChecks` setting), FFmate considers the file as finished and creates a task for it. By waiting until the file stops growing, FFmate ensures that partially copied or incomplete files aren’t processed too early. This is especially important for large media files being uploaded over a network or transferred from external systems. 3. **Create Tasks** – Each finished file results in a **new [task](/docs/tasks.md)** that FFmate processes automatically. For each processed file, FFmate creates an empty `.lock` file next to it (e.g., `movie.mp4` → `movie.mp4.lock`). This special file ensures the file isn’t picked up again, even after a restart. If the `.lock` file is removed while the original is still in the folder, the watchfolder will see it as new and process it again. ### Watchfolder metadata Tasks created by a watchfolder always include a specific `metadata` object populated with file information about the item that triggered the task. This includes: * `path` — the absolute path to the watchfolder * `relativeDir` — the relative directory of the file inside the watchfolder * `relativePath` — the relative path to the file inside the watchfolder * `uuid` — the unique identifier of the watchfolder that generated the task Example: ```json "metadata": { "ffmate": { "watchfolder": { "path": "/volumes/ffmate/wf", "relativeDir": "parent/subfolder1", "relativePath": "parent/subfolder1/18moo.mov", "uuid": "06bbbe21-8003-41b3-94f4-62508486c482" } } } ``` ### Watchfolder Task Flow The diagram below shows how a file dropped into a watchfolder becomes a [task](/docs/tasks.md) in FFmate. ```mermaid flowchart LR %% Styles classDef monitor fill:#99d6ff,stroke:#2060a0,stroke-width:1.2px,color:#000; classDef detect fill:#ffff99,stroke:#2060a0,stroke-width:1.2px,color:#000; classDef create fill:#99ff99,stroke:#2d7a2d,stroke-width:1.2px,color:#000; classDef lock fill:#ffcc99,stroke:#a65c00,stroke-width:1.2px,color:#000; %% Nodes A["Monitor Folder
Scan directory at set interval
 "]:::monitor B["Detect New Files
Wait until file copy completes
 "]:::detect C["Create Tasks
Create FFmate task for each file
 "]:::create D["Write .lock File
Prevents file from being processed again
 "]:::lock %% Flow A --> B --> C --> D ``` ## Creating a Watchfolder To create a watchfolder, send a `POST` request to the FFmate API: ```sh curl -X POST http://localhost:3000/api/v1/watchfolders \ -H "Content-Type: application/json" \ -d '{ "name": "Camera Card Watch", "description": "Automatically processes camera footage", "interval": 10, "growthChecks": 3, "preset": "cabfad2c-70d1-4df6-9267-f549a376301f", "path": "/volumes/media/camera_cards", "suspended": false "filter": { "extensions": { "exclude": ["tmp", "log"] } } }' ``` After you create a preset, FFmate responds with a JSON object that includes the `ID` of the newly created watchfolder. A `watchfolder.created` event is also fired via [webhooks](/docs/webhooks#watchfolder-events) 💡 Tip: Creating a new preset? You can define and save presets directly in the [FFmate Web UI](/docs/web-ui.md) without writing any API requests ## Watchfolder Properties * **`name`** – A unique name for the watchfolder. * **`description`** – Optional description of what this watchfolder does. * **`interval`** – How often (in seconds) FFmate scans the folder for new files. * **`growthChecks`** – The number of checks FFmate performs to ensure a file is fully copied before processing. * **`preset`** – The ID of a predefined transcoding **preset** that will be applied to detected files. * **`path`** – The **absolute path** of the directory to monitor. * **`suspended`** – A boolean flag that pauses watchfolder scanning. When set to `true`, FFmate temporarily stops detecting and processing files in the folder. * **`filter`** – Rules for file selection: * **`include`** – Only process files with these extensions (e.g., `mp4`, `mov`). * **`exclude`** – Ignore files with these extensions (e.g., `tmp`, `log`). ::: tip How filters work\ FFmate always checks the `exclude` list **first**.\ If a file’s extension matches anything in `exclude`, the file will be skipped—**even if it also matches an extension in `include`**. To keep things simple and predictable, it's best to use **either** `include` or `exclude`, not both at the same time. ::: ## Listing Watchfolders Send a `GET` request to the FFmate API to list all configured watchfolders. ```sh curl -X GET 'http://localhost:3000/api/v1/watchfolders?page=0&perPage=10' ``` FFmate rreturns a JSON array containing all configured watchfolders. The `X-Total` response headers provides the total number of presets available. **Query Parameters:** * **`page`** *\[optional]* – Specifies which page of results to retrieve. Default: `0`. * **`perPage`** *\[optional]* – Defines how many watchfolders should be included in each page. Default: `100`. 💡 Tip: Need an overview of all watchfolders? You can browse and manage them easily in the [FFmate Web UI](/docs/web-ui.md). ## Getting a Single Watchfolder To retrieve the details of a specific watchfolder, send a `GET` request to the FFmate API, including the watchfolder's `ID` in the path. ```sh curl -X GET http://localhost:3000/api/v1/watchfolders/{watchfolderId} ``` FFmate responds with a JSON object containing the full details of the specified watchfolder. 💡 Tip: Want a quick way to check the watchfolder details? You can view watchfolder configurations directly in the [FFmate Web UI](/docs/web-ui.md) without using the API. ## Updating a Watchfolder You can update an existing watchfolder's configuration by sending a `PUT` request to the FFmate API, including the watchfolder's `ID` in the path. The request body should contain the complete, updated definition of the watchfolder. You can find a list of all available properties in the [Watchfolder Properties](#watchfolder-properties) section above. ```sh curl -X PUT http://localhost:3000/api/v1/watchfolders/{watchfolderId} \ -H "Content-Type: application/json" \ -d '{ "name": "Camera Card Watch", "description": "Processes high-res camera footage", "interval": 15, "growthChecks": 5, "preset": "uuid-of-updated-preset", "path": "/volumes/media/camera_cards_archive", "suspended": false "filter": { "extensions": { "include": ["mov", "mp4", "mxf"] } } }' ``` FFmate responds with the full JSON object representing the updated watchfolder. The watchfolder will restart with the new configuration shortly after the update. A `watchfolder.updated` event is also fired via [webhooks](/docs/webhooks#watchfolder-events) 💡 Tip: Making changes to a watchfolder? You can update settings like filters and intervals directly in the [FFmate Web UI](/docs/web-ui.md). ## Suspending a Watchfolder The `suspended` flag lets you temporarily stop FFmate from detecting and processing files in a watchfolder. This is especially useful in production environments when you need to pause file processing during ingest operations, workflow changes, system maintenance. It also enables external applications or schedulers to programmatically start or stop a watchfolder as needed. To suspend a watchfolder, send a `PUT` request to the FFmate API with the watchfolder’s `ID` in the path and the `suspended` flag set to `true`.\ For example: ```sh curl -X PUT http://localhost:3000/api/v1/watchfolders/{watchfolderId} \ -H "Content-Type: application/json" \ -d '{ "name": "Camera Card Watch", "description": "Processes high-res camera footage", "interval": 15, "growthChecks": 5, "preset": "uuid-of-updated-preset", "path": "/volumes/media/camera_cards_archive", "suspended": true "filter": { "extensions": { "include": ["mov", "mp4", "mxf"] } } }' ``` FFmate responds with the full JSON object representing the updated watchfolder. When `suspended` is set to `true`, FFmate temporarily halts scanning and file processing in that folder. To resume scanning, send another `PUT` request with `suspended` set to `false`. Updating the `suspended` state counts as a watchfolder update, so it will also trigger a `watchfolder.updated` via [webhooks](/docs/webhooks#watchfolder-events). 💡 Tip: You can also suspend and resume watchfolder scanning directly in the [FFmate Web UI](/docs/web-ui.md). ## Deleting a Watchfolder Send a `DELETE` request to the FFmate API to remove a watchfolder by including the watchfolder's `ID` in the path. ```sh curl -X DELETE http://localhost:3000/api/v1/watchfolders/{watchfolderId} ``` FFmate responds with a `204` No Content status. The watchfolder will be **removed** from the system, and any monitoring for that folder will **stop**. A `watchfolder.deleted` event is also fired via [webhooks](/docs/webhooks#watchfolder-events) 💡 Tip: No need to send a delete request manually—you can remove watchfolders instantly from the [FFmate Web UI](/docs/web-ui.md). --- --- url: /docs/wildcards.md description: >- Learn how to use wildcards in FFmate to generate dynamic file and folder names, automate output paths, insert timestamps, and adapt processing logic based on task sources like the API or watchfolders --- # Wildcards **Wildcards** in FFmate act as placeholders that are **automatically replaced** with actual values when a FFmate [task](/docs/tasks.md#task-flow) runs. You can use wildcards in: * [Tasks](/docs/tasks.md#task-properties): `inputFile`, `outputFile`, and `command` * [Pre- and post-processing](/docs/pre-post-prcessing.md) `script`, and `sidecard` ## Input and Output File Information ### Full File Path: These wildcards return the **complete file path**, including the directory, filename, and extension. | Wildcard | Description | Example Output | |-----------------|----------------------------------|-------------------------| | `${INPUT_FILE}` | Full path of the input file | `/source/input.mp4` | | `${OUTPUT_FILE}` | Full path of the output file | `/destination/output.mp4` | #### Example: ```sh curl -X POST http://localhost:3000/api/v1/tasks \ -H "Content-Type: application/json" \ -d '{ "command": "-y -i ${INPUT_FILE} -c:v libx264 -preset fast -crf 23 ${OUTPUT_FILE}", "inputFile": "/volumes/ffmate/source/input.mp4", "outputFile": "/volumes/ffmate/destination/output.mp4" }' ``` ### Filename Information: These wildcards return the **filename** from the full path, either with or without the extension. | Wildcard | Description | Example Output | |------------------------|-----------------------------------------------------|-------------------| | `${INPUT_FILE_BASE}` | Filename with extension (without the path) | `input.mp4` | | `${OUTPUT_FILE_BASE}` | Filename with extension (without the path) | `output.mp4` | | `${INPUT_FILE_BASENAME}` | Filename without extension | `input` | | `${OUTPUT_FILE_BASENAME}` | Filename without extension | `output` | #### Example: ```sh curl -X POST http://localhost:3000/api/v1/tasks \ -H "Content-Type: application/json" \ -d '{ "command": "-y -i ${INPUT_FILE} -c:v libx264 -preset fast -crf 23 ${OUTPUT_FILE}.mkv", "inputFile": "/volumes/ffmate/videos/original_movie.mp4", "outputFile": "/volumes/ffmate/converted/${INPUT_FILE_BASENAME}" }' ``` #### Output Path: ```sh /volumes/ffmate/converted/input.mkv ``` *** ### File Extensions and Directory Path: These wildcards return **the file extension** and the **directory path**. | Wildcard | Description | Example Output | |---------------------------|-------------------------------------------|-------------------| | `${INPUT_FILE_EXTENSION}` | File extension of the input file | `.mp4` | | `${OUTPUT_FILE_EXTENSION}` | File extension of the output file | `.mp4` | | `${INPUT_FILE_DIR}` | Directory path of the input file | `/source` | | `${OUTPUT_FILE_DIR}` | Directory path of the output file | `/destination` | #### Example: ```sh curl -X POST http://localhost:3000/api/v1/tasks \ -H "Content-Type: application/json" \ -d '{ "command": "-y -i ${INPUT_FILE} -c:v libx264 -preset fast -crf 23 ${OUTPUT_FILE}", "inputFile": "/volumes/ffmate/source/video.mp4", "outputFile": "/volumes/ffmate/destination/${INPUT_FILE_BASENAME}_converted${INPUT_FILE_EXTENSION}" }' ``` #### Output Path: ```sh /volumes/ffmate/destination/input_converted.mp4 ``` ## Date & Time These wildcards return the **current date and time** values when the task runs. | Wildcard | Description | Example Output | |----------------------------|--------------------------------------------|------------------| | `${DATE_YEAR}` | Full year (4 digits) | `2024` | | `${DATE_SHORTYEAR}` | Short year (last 2 digits) | `24` | | `${DATE_MONTH}` | Month number (01-12) | `01` | | `${DATE_DAY}` | Day of the month (01-31) | `15` | | `${DATE_WEEK}` | Week number (01-52) | `03` | | `${TIME_HOUR}` | Hour (24-hour format, 00-23) | `14` | | `${TIME_MINUTE}` | Minute (00-59) | `05` | | `${TIME_SECOND}` | Second (00-59) | `32` | #### Example: ```sh curl -X POST http://localhost:3000/api/v1/tasks \ -H "Content-Type: application/json" \ -d '{ "command": "-y -i ${INPUT_FILE} -c:v libx264 -preset fast -crf 23 ${OUTPUT_FILE}", "inputFile": "/volumes/ffmate/source/video.mp4", "outputFile": "/volumes/ffmate/destination/${DATE_YEAR}/${DATE_MONTH}/${DATE_DAY}/video_${TIME_HOUR}-${TIME_MINUTE}-${TIME_SECOND}.mp4", "priority": 2 }' ``` #### Output Path: ```sh /volumes/ffmate/destination/2024/02/15/video_14-30-45.mp4 ``` ## Timestamps These wildcards return **Unix timestamps** based on the current system time. | Wildcard | Description | Example Output | |--------------------------------|--------------------------------------------|-------------------------| | `${TIMESTAMP_SECONDS}` | Unix timestamp in seconds | `1705318712` | | `${TIMESTAMP_MILLISECONDS}` | Unix timestamp with milliseconds precision | `1705318712123` | | `${TIMESTAMP_MICROSECONDS}` | Unix timestamp with microseconds precision | `1705318712123456` | | `${TIMESTAMP_NANOSECONDS}` | Unix timestamp with nanoseconds precision | `1705318712123456789` | #### Example: ```sh curl -X POST http://localhost:3000/api/v1/tasks \ -H "Content-Type: application/json" \ -d '{ "command": "-y -i ${INPUT_FILE} -c:v libx264 -preset fast -crf 23 ${OUTPUT_FILE}", "inputFile": "/volumes/ffmate/source/video.mp4", "outputFile": "/volumes/ffmate/destination/video_${TIMESTAMP_SECONDS}.mp4" }' ``` #### Output Path: ```sh /volumes/ffmate/destination/video_1705318712.mp4 ``` ## Task Metadata This wildcard lets you insert values from the task’s `metadata` object. This works in **any field** where wildcards are supported, including [task](/docs/tasks.md#task-properties) input and output paths, as well as [pre- and post-processing](/docs/pre-post-prcessing.md) actions. You can reference any key that was: * **Provided during task creation** via the `metadata` object, or * **Automatically populated** by FFmate (for example, when a task is triggered by a watchfolder). | Wildcard Pattern | Description | |-----------------------------|-------------------------------------------------| | `${METADATA_}` | Inserts the value from the `metadata` object at the given JSON path | *** #### Example: Recreating Watchfolder Structure When a task is created from a watchfolder, FFmate automatically adds **watchfolder file metadata** about the file that triggered the task. This includes fields like `relativeDir`, which you can use to recreate the original folder structure in your output. Here’s an example `metadata` object for a file dropped into `/volumes/ffmate/wf/parent/subfolder1/18moo.mov`: ```json "metadata": { "ffmate": { "watchfolder": { "path": "/volumes/ffmate/wf", "relativeDir": "parent/subfolder1", "relativePath": "parent/subfolder1/18moo.mov", "uuid": "06bbbe21-8003-41b3-94f4-62508486c482" } } } ``` With `${METADATA_}`, you can reference `relativeDir` and automatically recreate the same folder structure from the watchfolder in your output. ```sh curl -X POST http://localhost:3000/api/v1/tasks \ -H "Content-Type: application/json" \ -d '{ "command": "-y -i ${INPUT_FILE} -c:v libx264 -preset fast -crf 23 ${OUTPUT_FILE}", "inputFile": "/volumes/ffmate/wf/parent/subfolder1/18moo.mov", "outputFile": "/volumes/ffmate/processed/${METADATA_ffmate.watchfolder.relativeDir}/${INPUT_FILE_BASENAME}.mp4" } ' ``` #### Output Path: ```sh /volumes/ffmate/processed/parent/subfolder1/18moo.mp4 ``` ## Task Source This wildcard returns the **source** of the task: either `api` or `watchfolder`. | Wildcard | Description | Example Output | |-------------|------------------------------------------------------------|------------------------| | `${SOURCE}` | Returns the source that triggered the task (either API or watchfolder) | `api` or `watchfolder` | *** ### Example Use `${SOURCE}` in a Bash script to apply different behavior depending on the task’s origin. ```bash #!/usr/bin/env bash # Pre-processing script example # Adjusts logic based on the source of the task case "$SOURCE" in api) echo "Task originated from API. Applying API-specific logic." # Add API-specific pre-processing commands here ;; watchfolder) echo "Task originated from Watchfolder. Applying Watchfolder-specific logic." # Add Watchfolder-specific pre-processing commands here ;; *) echo "Unknown task source. Applying default logic." # Add fallback logic here ;; esac ``` ## FFmpeg Path This wildcard returns the full, resolved path to the `FFmpeg` executable as configured in FFmate (see [command-line flags](/docs/flags.md#server-command-flags)). It is particularly useful for advanced workflows that require chaining multiple `ffmpeg` calls within a single command, such as **two-pass encoding**. | Wildcard | Description | Example Output | |-------------|----------------------------------------------|---------------------| | `${FFMPEG}` | Returns the full path to the FFmpeg executable | `/usr/bin/ffmpeg` | #### Example: Two-Pass VP9 Encoding ```sh curl -X POST http://localhost:3000/api/v1/tasks \ -H "Content-Type: application/json" \ -d '{ "command": "-i ${INPUT_FILE} -c:v libvpx-vp9 -b:v 2M -pass 1 -an -f null - && ${FFMPEG} -i ${INPUT_FILE} -c:v libvpx-vp9 -b:v 2M -pass 2 -c:a libopus ${OUTPUT_FILE}", "inputFile": "/volumes/ffmate/source/video.mp4", "outputFile": "/volumes/ffmate/destination/video.webm" }' ``` This command performs a two-pass VP9 encode. FFmate **automatically** prepends the configured `ffmpeg` path to the beginning of the `command` for the first pass. When chaining commands with `&&`, you must explicitly use the `${FFMPEG}` wildcard for any subsequent `ffmpeg` calls to ensure the correct executable is used in each chained command. ## Unique Identifier This wildcard generates **random unique identifiers**. | Wildcard | Description | Example Output | |---------------|------------------------------------|------------------------------------------------| | `${UUID}` | Randomly generated UUID (v4) | `550e8400-e29b-41d4-a716-446655440000` | #### Example: ```sh curl -X POST http://localhost:3000/api/v1/tasks \ -H "Content-Type: application/json" \ -d '{ "command": "-y -i ${INPUT_FILE} -c:v libx264 -preset fast -crf 23 ${OUTPUT_FILE}", "inputFile": "/volumes/ffmate/source/video.mp4", "outputFile": "/volumes/ffmate/processed/${UUID}_video.mp4" }' ``` #### Output Path: ```sh /volumes/ffmate/processed/550e8400-e29b-41d4-a716-446655440000_video.mp4 ``` ## System Information These wildcards return the **operating system name** and **CPU architecture**. | Wildcard | Description | Example Output | |---------------|------------------------------------|----------------| | `${OS_NAME}` | Operating system name | `linux` | | `${OS_ARCH}` | CPU architecture | `amd64` | #### Example: ```sh curl -X POST http://localhost:3000/api/v1/tasks \ -H "Content-Type: application/json" \ -d '{ "command": "-y -i ${INPUT_FILE} -c:v libx264 -preset fast -crf 23 ${OUTPUT_FILE}", "inputFile": "/volumes/ffmate/source/video.mp4", "outputFile": "/volumes/ffmate/processed/${OS_NAME}/${OS_ARCH}/video.mp4" }' ``` #### Output Path: ```sh /volumes/ffmate/processed/linux/amd64/video.mp4 ```