Create an FFmpeg Automated Watch Folder Script

Automating your media workflow with a watch folder saves time by automatically transcoding new video or audio files as soon as they are saved to a specific directory. This article demonstrates how to build a lightweight, cross-platform automation script using FFmpeg, utilizing Bash for Linux and macOS systems, and PowerShell for Windows environments.

Prerequisites

Before starting, ensure you have the following installed on your system: * FFmpeg: Must be installed and added to your system’s PATH. * Inotify-tools (for Linux): Required to monitor file system events. Install it via your package manager (e.g., sudo apt install inotify-tools on Ubuntu/Debian).

Note: Always set your watch folder and output folder to different directories to prevent the script from entering an infinite loop of transcoding its own output.


Method 1: Linux and macOS (Bash Script)

On Unix-like systems, the most efficient way to monitor a directory is by using inotifywait (Linux) or fswatch (macOS). This method triggers the transcoding process only when a file write operation is fully completed.

Create a file named watch_folder.sh and paste the following script:

#!/bin/bash

# Define directories (use absolute paths)
WATCH_DIR="/path/to/watch_folder"
OUTPUT_DIR="/path/to/output_folder"

# Ensure output directory exists
mkdir -p "$OUTPUT_DIR"

echo "Watching directory: $WATCH_DIR"

# Monitor for newly closed (written) files
inotifywait -m "$WATCH_DIR" -e close_write | while read -r path action file; do
    # Check if the file has a video extension
    if [[ "$file" =~ \.(mp4|mkv|mov|avi)$ ]]; then
        echo "New file detected: $file"
        
        INPUT_FILE="$WATCH_DIR/$file"
        OUTPUT_FILE="$OUTPUT_DIR/${file%.*}.mp4"
        
        echo "Transcoding $file to MP4..."
        
        # Run FFmpeg transcoding (H.264 video and AAC audio)
        ffmpeg -i "$INPUT_FILE" -c:v libx264 -crf 23 -c:a aac -b:a 128k "$OUTPUT_FILE" -y
        
        if [ $? -eq 0 ]; then
            echo "Successfully transcoded: $file"
            # Optional: Delete the source file after successful transcoding
            # rm "$INPUT_FILE"
        else
            echo "Error transcoding: $file"
        fi
    fi
done

To run this script, make it executable and run it in the background:

chmod +x watch_folder.sh
./watch_folder.sh &

Method 2: Windows (PowerShell Script)

On Windows, you can utilize the .NET FileSystemWatcher class within PowerShell to monitor directory changes in real-time.

Create a file named watch_folder.ps1 and paste the following script:

# Define directories
$WatchDir = "C:\path\to\watch_folder"
$OutputDir = "C:\path\to\output_folder"

# Ensure output directory exists
if (!(Test-Path $OutputDir)) {
    New-Item -ItemType Directory -Force -Path $OutputDir
}

# Create FileSystemWatcher object
$Watcher = New-Object System.IO.FileSystemWatcher
$Watcher.Path = $WatchDir
$Watcher.Filter = "*.*" # Filters can be specified here, e.g., "*.mkv"
$Watcher.EnableRaisingEvents = $true

Write-Host "Watching directory: $WatchDir"

# Action to take when a file is created
$Action = {
    $Path = $Event.SourceEventArgs.FullPath
    $Name = $Event.SourceEventArgs.Name
    $Extension = [System.IO.Path]::GetExtension($Path)
    
    # Process only specific video extensions
    if ($Extension -match '\.(mp4|mkv|mov|avi)$') {
        Write-Host "New file detected: $Name"
        
        # Wait briefly to ensure the file is completely written to disk
        Start-Sleep -Seconds 3
        
        $OutputFile = Join-Path $OutputDir ([System.IO.Path]::GetFileNameWithoutExtension($Name) + ".mp4")
        
        Write-Host "Transcoding $Name..."
        
        # Run FFmpeg
        & ffmpeg -i $Path -c:v libx264 -crf 23 -c:a aac -b:a 128k $OutputFile -y
        
        if ($LASTEXITCODE -eq 0) {
            Write-Host "Successfully transcoded: $Name"
            # Optional: Remove source file
            # Remove-Item $Path
        } else {
            Write-Host "Error transcoding: $Name"
        }
    }
}

# Bind event
Register-ObjectEvent $Watcher "Created" -Action $Action

# Keep the script running
while ($true) {
    Start-Sleep -Seconds 1
}

To run this script on Windows, open PowerShell and execute:

Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
.\watch_folder.ps1