Media Dimension Adder Script

[CmdletBinding(SupportsShouldProcess = $true)]
param(
    [string]$RootPath
)

$ErrorActionPreference = 'Stop'

if IsNullOrWhiteSpace($RootPath) {
    $RootPath = Join-Path (Split-Path $PSScriptRoot -Parent) 'media'
}

if (-not (Get-Command ffprobe -ErrorAction SilentlyContinue)) {
    throw 'ffprobe was not found on PATH. Install ffprobe or add it to PATH before running this script.'
}

$mediaExtensions = @(
    '.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.heic', '.heif', '.avif', '.tif', '.tiff',
    '.mp4', '.mov', '.m4v', '.webm', '.mkv', '.avi', '.wmv', '.mpeg', '.mpg', '.3gp', '.mts', '.m2ts'
)

function Get-MediaDimensions {
    param(
        [Parameter(Mandatory)]
        [string]$Path
    )

    $probeOutput = & ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=p=0:s=x $Path 2>$null
    $dimensions = $probeOutput | Where-Object { $_ -match '^\d+x\d+ } | Select-Object -First 1

    if (-not $dimensions) {
        return $null
    }

    if ($dimensions -match '^(\d+)x(\d+)) {
        return [pscustomobject]@{
            Width = [int]$matches[1]
            Height = [int]$matches[2]
        }
    }

    return $null
}

try {
    $resolvedRoot = (Resolve-Path -LiteralPath $RootPath).Path
} catch {
    throw "Root path not found: $RootPath"
}

$files = Get-ChildItem -LiteralPath $resolvedRoot -File -Recurse |
    Where-Object {
        $mediaExtensions -contains $_.Extension.ToLowerInvariant()
    } |
    Sort-Object FullName

foreach ($file in $files) {
    if ($file.BaseName -match '(?:^|[_-])\d+x\d+) {
        Write-Host "Skipped: $($file.FullName) (already tagged)"
        continue
    }

    $dimensions = Get-MediaDimensions -Path $file.FullName

    if (-not $dimensions) {
        Write-Warning "Could not read dimensions: $($file.FullName)"
        continue
    }

    $newName = '{0}_{1}x{2}{3}' -f $file.BaseName, $dimensions.Width, $dimensions.Height, $file.Extension
    $targetPath = Join-Path $file.DirectoryName $newName

    if (Test-Path -LiteralPath $targetPath) {
        Write-Warning "Skipping because target exists: $targetPath"
        continue
    }

    if ($PSCmdlet.ShouldProcess($file.FullName, "Rename to $newName")) {
        Rename-Item -LiteralPath $file.FullName -NewName $newName
        Write-Host "Renamed: $($file.Name) -> $newName"
    }
}