Files
ProjectStructure_HOME/UpdateSequences.ps1

305 lines
12 KiB
PowerShell
Raw Permalink Normal View History

[CmdletBinding()]
param(
[switch]$DebugMode
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
2025-11-08 02:36:20 -07:00
if (-not $PSScriptRoot) {
$PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
}
$configLoader = Join-Path -Path $PSScriptRoot -ChildPath 'ConfigLoader.ps1'
if (-not (Test-Path -LiteralPath $configLoader)) {
throw "Missing ConfigLoader.ps1 in $PSScriptRoot"
}
. $configLoader
$useIsoDailyFormat = Use-IsoDailyFormat
function Sync-SequenceFilenames {
param(
[Parameter(Mandatory)] [string]$SequenceFolderPath,
[Parameter(Mandatory)] [string]$SequenceName,
[string]$LogFile,
[string[]]$Extensions = @('.png','.jpg','.jpeg','.exr','.tif','.tiff','.bmp','.tga')
)
$renamed = 0
$collisions = 0
$errors = 0
$checked = 0
2025-10-23 10:33:23 -06:00
$minFrame = [int]::MaxValue
$maxFrame = -1
$frameCount = 0
if ($LogFile) { "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] RENAME CHECK in '$SequenceFolderPath' (seq='$SequenceName')" | Add-Content -LiteralPath $LogFile }
$files = Get-ChildItem -LiteralPath $SequenceFolderPath -File -Recurse -ErrorAction SilentlyContinue |
Where-Object { $_.FullName -notlike '*\_archive\*' -and ($Extensions -contains $_.Extension.ToLower()) }
foreach ($f in $files) {
$checked++
$base = [System.IO.Path]::GetFileNameWithoutExtension($f.Name)
$ext = $f.Extension
$digits = $null
if ($base -match '_(\d{6})$') {
$digits = $Matches[1]
}
elseif ($base -match '(?<!_)\b(\d{6})$') {
$digits = $Matches[1]
}
elseif ($base -match '(\d{4})$') {
$digits = ('00' + $Matches[1])
}
else {
continue
}
2025-10-23 10:33:23 -06:00
try {
$n = [int]$digits
if ($n -lt $minFrame) { $minFrame = $n }
if ($n -gt $maxFrame) { $maxFrame = $n }
$frameCount++
} catch {}
$targetBase = "$SequenceName" + '_' + $digits
if ($base -eq $targetBase) { continue }
$newName = $targetBase + $ext
$newPath = Join-Path $SequenceFolderPath $newName
try {
if (Test-Path -LiteralPath $newPath) {
2025-11-06 14:38:35 -07:00
$existing = Get-Item -LiteralPath $newPath -ErrorAction Stop
$sameSize = ($existing.Length -eq $f.Length)
$sameTime = ([math]::Abs(($existing.LastWriteTimeUtc - $f.LastWriteTimeUtc).TotalSeconds) -le 1)
if ($sameSize -and $sameTime) {
Remove-Item -LiteralPath $f.FullName -Force -ErrorAction Stop
$collisions++
if ($LogFile) { "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] RENAME DROP duplicate: '$($f.Name)' (matches '$newName')" | Add-Content -LiteralPath $LogFile }
continue
}
$archiveDir = Join-Path $SequenceFolderPath '_archive'
if (-not (Test-Path -LiteralPath $archiveDir)) {
New-Item -ItemType Directory -Path $archiveDir -Force | Out-Null
}
$archiveName = $existing.Name
$archivePath = Join-Path $archiveDir $archiveName
if (Test-Path -LiteralPath $archivePath) {
$stamp = Get-Date -Format 'yyyyMMdd_HHmmss'
$baseName = [System.IO.Path]::GetFileNameWithoutExtension($archiveName)
$archivePath = Join-Path $archiveDir ("{0}_{1}{2}" -f $baseName, $stamp, $existing.Extension)
}
Move-Item -LiteralPath $existing.FullName -Destination $archivePath -Force -ErrorAction Stop
$collisions++
2025-11-06 14:38:35 -07:00
if ($LogFile) { "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] RENAME ARCHIVE existing '$($existing.Name)' -> '$archivePath'" | Add-Content -LiteralPath $LogFile }
}
Rename-Item -LiteralPath $f.FullName -NewName $newName -ErrorAction Stop
$renamed++
if ($LogFile) { "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] RENAME: '$($f.Name)' -> '$newName'" | Add-Content -LiteralPath $LogFile }
}
catch {
$errors++
if ($LogFile) { "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] RENAME ERROR for '$($f.Name)': $($_.Exception.Message)" | Add-Content -LiteralPath $LogFile }
}
}
2025-10-23 10:33:23 -06:00
$minOut = $null
$maxOut = $null
if ($frameCount -gt 0) {
$minOut = $minFrame
$maxOut = $maxFrame
}
return [pscustomobject]@{
Renamed = $renamed
Collisions = $collisions
Errors = $errors
Checked = $checked
MinFrame = $minOut
MaxFrame = $maxOut
FrameCount = $frameCount
}
}
function Rename-SequencePreviewMp4 {
param(
[Parameter(Mandatory)] [string]$SequenceFolderPath,
[Parameter(Mandatory)] [string]$SequenceName,
[Parameter(Mandatory)] [int]$StartFrame,
[Parameter(Mandatory)] [int]$EndFrame,
[string]$LogFile
)
$renamed = 0
$collisions = 0
$errors = 0
$checked = 0
$targetName = "$SequenceName-$StartFrame-$EndFrame.mp4"
$targetPath = Join-Path $SequenceFolderPath $targetName
$mp4s = Get-ChildItem -LiteralPath $SequenceFolderPath -File -Filter '*.mp4' -ErrorAction SilentlyContinue |
Where-Object { $_.FullName -notlike '*\_archive\*' }
foreach ($m in $mp4s) {
$checked++
if ($m.Name -eq $targetName) { continue }
try {
if (Test-Path -LiteralPath $targetPath) {
$collisions++
if ($LogFile) { "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] MP4 RENAME SKIP collision: '$($m.Name)' -> '$targetName'" | Add-Content -LiteralPath $LogFile }
continue
}
Rename-Item -LiteralPath $m.FullName -NewName $targetName -ErrorAction Stop
$renamed++
if ($LogFile) { "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] MP4 RENAME: '$($m.Name)' -> '$targetName'" | Add-Content -LiteralPath $LogFile }
break
}
catch {
$errors++
if ($LogFile) { "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] MP4 RENAME ERROR for '$($m.Name)': $($_.Exception.Message)" | Add-Content -LiteralPath $LogFile }
}
}
return [pscustomobject]@{
Renamed = $renamed
Collisions = $collisions
Errors = $errors
Checked = $checked
}
}
2025-11-06 14:38:35 -07:00
function Resolve-SequenceName {
param(
[Parameter(Mandatory)] [System.IO.DirectoryInfo]$Directory
)
if ($Directory.Name -eq '_CURRENT' -and $Directory.Parent) {
return $Directory.Parent.Name
}
return $Directory.Name
}
function Add-SequenceFolder {
param(
[Parameter(Mandatory)] [System.IO.DirectoryInfo]$Directory,
[Parameter(Mandatory)] [hashtable]$Map
)
if ($Directory.Name -eq '_archive') { return }
$fullPath = $Directory.FullName
if ($Map.ContainsKey($fullPath)) { return }
$Map[$fullPath] = Resolve-SequenceName -Directory $Directory
}
try {
$root = (Get-Location).ProviderPath
2025-11-06 10:47:19 -07:00
$logFile = $null
if ($DebugMode) {
$logFile = Join-Path $root ("UpdateSequences_{0}.log" -f (Get-Date -Format 'yyyyMMdd_HHmmss'))
"[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] === UpdateSequences started in '$root' ===" | Out-File -LiteralPath $logFile -Encoding UTF8
}
2025-11-06 14:38:35 -07:00
$sequenceMap = @{}
2025-11-08 02:36:20 -07:00
$primaryPattern = if ($useIsoDailyFormat) { '????-??-??' } else { 'daily_*' }
$secondaryPattern = if ($useIsoDailyFormat) { 'daily_*' } else { '????-??-??' }
$primaryDirs = Get-ChildItem -LiteralPath $root -Directory -Filter $primaryPattern -ErrorAction SilentlyContinue |
2025-11-06 10:47:19 -07:00
Where-Object { $_.Name -ne '_archive' }
2025-11-08 02:36:20 -07:00
foreach ($d in $primaryDirs) {
2025-11-06 10:47:19 -07:00
$seqDirs = @(Get-ChildItem -LiteralPath $d.FullName -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -ne '_archive' })
if ($seqDirs.Count -eq 0) {
2025-11-06 14:38:35 -07:00
Add-SequenceFolder -Directory $d -Map $sequenceMap
2025-11-06 10:47:19 -07:00
} else {
2025-11-06 14:38:35 -07:00
foreach ($s in $seqDirs) {
Add-SequenceFolder -Directory $s -Map $sequenceMap
}
2025-11-06 10:47:19 -07:00
}
}
2025-11-08 02:36:20 -07:00
$secondaryDirs = Get-ChildItem -LiteralPath $root -Directory -Filter $secondaryPattern -ErrorAction SilentlyContinue |
2025-11-08 01:44:26 -07:00
Where-Object { $_.Name -ne '_archive' }
2025-11-08 02:36:20 -07:00
foreach ($d in $secondaryDirs) {
2025-11-08 01:44:26 -07:00
$seqDirs = @(Get-ChildItem -LiteralPath $d.FullName -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -ne '_archive' })
if ($seqDirs.Count -eq 0) {
Add-SequenceFolder -Directory $d -Map $sequenceMap
} else {
foreach ($s in $seqDirs) {
Add-SequenceFolder -Directory $s -Map $sequenceMap
}
}
}
2025-11-06 10:47:19 -07:00
$directSeqs = Get-ChildItem -LiteralPath $root -Directory -ErrorAction SilentlyContinue |
2025-11-08 02:36:20 -07:00
Where-Object {
$_.Name -ne '_archive' -and
$_.Name -notlike 'daily_*' -and
$_.Name -notmatch '^\d{4}-\d{2}-\d{2}$'
}
2025-11-06 14:38:35 -07:00
foreach ($seq in $directSeqs) {
Add-SequenceFolder -Directory $seq -Map $sequenceMap
}
2025-11-06 14:38:35 -07:00
$sequenceFolders = $sequenceMap.GetEnumerator() | ForEach-Object {
[pscustomobject]@{
Path = $_.Key
Name = $_.Value
}
} | Sort-Object -Property Path
2025-11-06 10:47:19 -07:00
if (-not $sequenceFolders) {
Write-Host "No sequence folders found." -ForegroundColor Yellow
if ($logFile) { "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] No sequence folders found." | Add-Content -LiteralPath $logFile }
exit 0
}
$totalSequences = 0
$filesRenamedTotal = 0
$renameCollisions = 0
$renameErrors = 0
2025-10-23 10:33:23 -06:00
$mp4RenamedTotal = 0
$mp4Collisions = 0
$mp4Errors = 0
2025-11-06 10:47:19 -07:00
foreach ($seq in $sequenceFolders) {
$totalSequences++
2025-11-06 14:38:35 -07:00
$renameResult = Sync-SequenceFilenames -SequenceFolderPath $seq.Path -SequenceName $seq.Name -LogFile $logFile
2025-11-06 10:47:19 -07:00
if ($DebugMode -or $renameResult.Renamed -gt 0 -or $renameResult.Collisions -gt 0 -or $renameResult.Errors -gt 0) {
2025-11-06 14:38:35 -07:00
Write-Host "[RENAME]|$($seq.Path)|$($seq.Name)|checked=$($renameResult.Checked)|renamed=$($renameResult.Renamed)|collisions=$($renameResult.Collisions)|errors=$($renameResult.Errors)" -ForegroundColor Cyan
}
2025-11-06 10:47:19 -07:00
$filesRenamedTotal += $renameResult.Renamed
$renameCollisions += $renameResult.Collisions
$renameErrors += $renameResult.Errors
2025-09-16 22:11:55 -06:00
2025-11-08 01:44:26 -07:00
if ($renameResult.FrameCount -gt 0 -and $null -ne $renameResult.MinFrame -and $null -ne $renameResult.MaxFrame) {
2025-11-06 14:38:35 -07:00
$mp4Result = Rename-SequencePreviewMp4 -SequenceFolderPath $seq.Path -SequenceName $seq.Name -StartFrame $renameResult.MinFrame -EndFrame $renameResult.MaxFrame -LogFile $logFile
2025-11-06 10:47:19 -07:00
if ($DebugMode -or $mp4Result.Renamed -gt 0 -or $mp4Result.Collisions -gt 0 -or $mp4Result.Errors -gt 0) {
2025-11-06 14:38:35 -07:00
Write-Host "[MP4]|$($seq.Path)|$($seq.Name)|renamed=$($mp4Result.Renamed)|collisions=$($mp4Result.Collisions)|errors=$($mp4Result.Errors)" -ForegroundColor Cyan
}
2025-11-06 10:47:19 -07:00
$mp4RenamedTotal += $mp4Result.Renamed
$mp4Collisions += $mp4Result.Collisions
$mp4Errors += $mp4Result.Errors
}
}
Write-Host "=== SUMMARY REPORT ===" -ForegroundColor Magenta
2025-11-06 10:47:19 -07:00
Write-Host "Sequences scanned: $totalSequences" -ForegroundColor White
Write-Host "Files renamed: $filesRenamedTotal (collisions: $renameCollisions, errors: $renameErrors)" -ForegroundColor White
2025-10-23 10:33:23 -06:00
Write-Host "Preview MP4s renamed: $mp4RenamedTotal (collisions: $mp4Collisions, errors: $mp4Errors)" -ForegroundColor White
2025-09-16 22:11:55 -06:00
Write-Host "=====================" -ForegroundColor Magenta
2025-11-06 10:47:19 -07:00
if ($logFile) {
"[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] === UpdateSequences completed (seq=$totalSequences renamed=$filesRenamedTotal mp4=$mp4RenamedTotal) ===" | Add-Content -LiteralPath $logFile
}
exit 0
}
catch {
2025-11-06 10:47:19 -07:00
if ($logFile) {
"[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] ERROR: $($_.Exception.Message)" | Add-Content -LiteralPath $logFile
}
2025-11-06 10:47:19 -07:00
Write-Host "ERROR: $_" -ForegroundColor Red
exit 1
2025-09-16 22:11:55 -06:00
}