From 7a4e9b6662d00be08644fa0ebe01c4ee6f8b3ca2 Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 30 Dec 2025 15:53:09 -0700 Subject: [PATCH] versioned name handling more accurate --- ...-19_18-52Z-blend-file-path-prefix-logic.md | 3719 ++++++++++++----- organize_textures.ps1 | 19 +- 2 files changed, 2621 insertions(+), 1117 deletions(-) diff --git a/.specstory/history/2025-12-19_18-52Z-blend-file-path-prefix-logic.md b/.specstory/history/2025-12-19_18-52Z-blend-file-path-prefix-logic.md index 62c138a..c349010 100644 --- a/.specstory/history/2025-12-19_18-52Z-blend-file-path-prefix-logic.md +++ b/.specstory/history/2025-12-19_18-52Z-blend-file-path-prefix-logic.md @@ -5610,29 +5610,328 @@ Rewriting the script to implement the two-pass approach: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: +```powershell +# Script to organize texture files by checksum with two-level duplicate detection +# Pass 1: Intra-blendfile duplicates → [blendfile]\common +# Pass 2: Inter-blendfile duplicates → \textures\common +# Usage: .\organize_textures.ps1 -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" +# Prompt user for texture folder path +$textureFolderPath = Read-Host "Enter texture folder path" + +# Validate the input path +if ([string]::IsNullOrWhiteSpace($textureFolderPath)) { + Write-Host "Error: No path provided." -ForegroundColor Red + exit } -``` -Additional data: -```json -{ - "codeblockId": "c8fbb5f1-d63f-475e-8d67-0e199fa93b99" +if (-not (Test-Path -Path $textureFolderPath -PathType Container)) { + Write-Host "Error: Path does not exist or is not a directory: $textureFolderPath" -ForegroundColor Red + exit } -``` -Status: **completed** +# Resolve the full path +$textureFolderPath = (Resolve-Path $textureFolderPath).ProviderPath +Write-Host "Processing texture folder: $textureFolderPath" -ForegroundColor Cyan + +# Function to calculate checksums for files +function Get-FilesWithChecksums { + param( + [array]$Files + ) + + $throttleLimit = [Math]::Max(1, [Environment]::ProcessorCount) + $parallelScriptBlock = { + try { + $hash = Get-FileHash -Path $_.FullName -Algorithm SHA256 + [PSCustomObject]@{ + File = $_ + Hash = $hash.Hash + } + } catch { + Write-Warning "Failed to calculate checksum for: $($_.FullName) - $($_.Exception.Message)" + $null + } + } + + return $Files | ForEach-Object -Parallel $parallelScriptBlock -ThrottleLimit $throttleLimit | Where-Object { $null -ne $_ } +} + +# Function to move files to common folder +function Move-FilesToCommon { + param( + [array]$Files, + [string]$CommonPath, + [string]$DuplicatesPath, + [hashtable]$FilesInCommon + ) + + $movedCount = 0 + $duplicateCount = 0 + + foreach ($fileObj in $Files) { + $fileName = $fileObj.Name + $destinationPath = Join-Path -Path $CommonPath -ChildPath $fileName + + # Handle name conflicts + if ($FilesInCommon.ContainsKey($fileName)) { + $baseName = [System.IO.Path]::GetFileNameWithoutExtension($fileName) + $extension = [System.IO.Path]::GetExtension($fileName) + $counter = 1 + do { + $newFileName = "${baseName}_${counter}${extension}" + $destinationPath = Join-Path -Path $CommonPath -ChildPath $newFileName + $counter++ + } while ($FilesInCommon.ContainsKey($newFileName) -or (Test-Path -Path $destinationPath)) + + $fileName = $newFileName + } + + try { + Move-Item -Path $fileObj.FullName -Destination $destinationPath -Force + $FilesInCommon[$fileName] = $true + $movedCount++ + } catch { + Write-Warning "Failed to move file: $($fileObj.FullName) - $($_.Exception.Message)" + } + } + + return @{ + MovedCount = $movedCount + DuplicateCount = $duplicateCount + } +} + +# Function to process duplicate group +function Process-DuplicateGroup { + param( + [array]$Files, + [string]$CommonPath, + [string]$DuplicatesPath, + [hashtable]$FilesInCommon + ) + + $movedCount = 0 + $duplicateCount = 0 + + if ($Files.Count -eq 1) { + # Single file - leave in place (will be processed in Pass 2) + return @{ + MovedCount = 0 + DuplicateCount = 0 + } + } + + # Multiple files with same checksum (duplicates) + # Move first file to \common + $firstFile = $Files[0].File + $fileName = $firstFile.Name + $destinationPath = Join-Path -Path $CommonPath -ChildPath $fileName + + # Handle name conflicts for the first file + if ($FilesInCommon.ContainsKey($fileName)) { + $baseName = [System.IO.Path]::GetFileNameWithoutExtension($fileName) + $extension = [System.IO.Path]::GetExtension($fileName) + $counter = 1 + do { + $newFileName = "${baseName}_${counter}${extension}" + $destinationPath = Join-Path -Path $CommonPath -ChildPath $newFileName + $counter++ + } while ($FilesInCommon.ContainsKey($newFileName) -or (Test-Path -Path $destinationPath)) + + $fileName = $newFileName + } + + try { + Move-Item -Path $firstFile.FullName -Destination $destinationPath -Force + $FilesInCommon[$fileName] = $true + $movedCount++ + } catch { + Write-Warning "Failed to move first duplicate file: $($firstFile.FullName) - $($_.Exception.Message)" + } + + # Move remaining files to \common\duplicates with numbered suffixes + for ($i = 1; $i -lt $Files.Count; $i++) { + $fileObj = $Files[$i].File + $baseName = [System.IO.Path]::GetFileNameWithoutExtension($fileObj.Name) + $extension = [System.IO.Path]::GetExtension($fileObj.Name) + $numberedFileName = "${baseName}.$($i.ToString('000'))${extension}" + $duplicateDestinationPath = Join-Path -Path $DuplicatesPath -ChildPath $numberedFileName + + # Handle name conflicts in duplicates folder + $conflictCounter = 1 + while (Test-Path -Path $duplicateDestinationPath) { + $numberedFileName = "${baseName}.$($i.ToString('000'))_${conflictCounter}${extension}" + $duplicateDestinationPath = Join-Path -Path $DuplicatesPath -ChildPath $numberedFileName + $conflictCounter++ + } + + try { + Move-Item -Path $fileObj.FullName -Destination $duplicateDestinationPath -Force + $duplicateCount++ + } catch { + Write-Warning "Failed to move duplicate file: $($fileObj.FullName) - $($_.Exception.Message)" + } + } + + return @{ + MovedCount = $movedCount + DuplicateCount = $duplicateCount + } +} + +# ============================================================================ +# PASS 1: Intra-Blendfile Processing +# ============================================================================ +Write-Host "" +Write-Host "=== PASS 1: Intra-Blendfile Processing ===" -ForegroundColor Cyan + +# Get all direct subdirectories of texture folder (blendfile folders) +$blendfileFolders = Get-ChildItem -Path $textureFolderPath -Directory | Where-Object { $_.Name -ne "common" } + +if ($null -eq $blendfileFolders -or $blendfileFolders.Count -eq 0) { + Write-Host "No blendfile folders found. Skipping Pass 1." -ForegroundColor Yellow +} else { + Write-Host "Found $($blendfileFolders.Count) blendfile folder(s) to process." -ForegroundColor Green + + $totalPass1Moved = 0 + $totalPass1Duplicates = 0 + + foreach ($blendfileFolder in $blendfileFolders) { + Write-Host "" + Write-Host "Processing blendfile: $($blendfileFolder.Name)" -ForegroundColor Yellow + + # Get all files in this blendfile folder, excluding \common folders + $blendfileFiles = Get-ChildItem -Path $blendfileFolder.FullName -Recurse -File | Where-Object { $_.FullName -notlike "*\common\*" } + + if ($null -eq $blendfileFiles -or $blendfileFiles.Count -eq 0) { + Write-Host " No files found in this blendfile folder." -ForegroundColor Gray + continue + } + + Write-Host " Found $($blendfileFiles.Count) files." -ForegroundColor Gray + + # Calculate checksums + Write-Host " Calculating checksums..." -ForegroundColor Gray + $filesWithChecksums = Get-FilesWithChecksums -Files $blendfileFiles + + # Group by checksum + $groupedByChecksum = $filesWithChecksums | Group-Object -Property Hash + + Write-Host " Found $($groupedByChecksum.Count) unique checksums." -ForegroundColor Gray + + # Create [blendfile]\common and [blendfile]\common\duplicates directories + $blendfileCommonPath = Join-Path -Path $blendfileFolder.FullName -ChildPath "common" + $blendfileDuplicatesPath = Join-Path -Path $blendfileCommonPath -ChildPath "duplicates" + + if (-not (Test-Path -Path $blendfileCommonPath -PathType Container)) { + New-Item -ItemType Directory -Path $blendfileCommonPath | Out-Null + } + + if (-not (Test-Path -Path $blendfileDuplicatesPath -PathType Container)) { + New-Item -ItemType Directory -Path $blendfileDuplicatesPath | Out-Null + } + + # Track filenames already in [blendfile]\common + $filesInBlendfileCommon = @{} + + # Process each checksum group + $blendfileMoved = 0 + $blendfileDuplicates = 0 + + foreach ($group in $groupedByChecksum) { + $result = Process-DuplicateGroup -Files $group.Group -CommonPath $blendfileCommonPath -DuplicatesPath $blendfileDuplicatesPath -FilesInCommon $filesInBlendfileCommon + $blendfileMoved += $result.MovedCount + $blendfileDuplicates += $result.DuplicateCount + } + + Write-Host " Moved $blendfileMoved file(s) to \common, $blendfileDuplicates duplicate(s) to \common\duplicates" -ForegroundColor Green + $totalPass1Moved += $blendfileMoved + $totalPass1Duplicates += $blendfileDuplicates + } + + Write-Host "" + Write-Host "Pass 1 complete: $totalPass1Moved file(s) moved, $totalPass1Duplicates duplicate(s) moved" -ForegroundColor Green +} + +# ============================================================================ +# PASS 2: Inter-Blendfile Processing +# ============================================================================ +Write-Host "" +Write-Host "=== PASS 2: Inter-Blendfile Processing ===" -ForegroundColor Cyan + +# Get all remaining files (excluding all \common folders) +Write-Host "Collecting remaining files..." -ForegroundColor Yellow +$remainingFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object { $_.FullName -notlike "*\common\*" } + +if ($null -eq $remainingFiles -or $remainingFiles.Count -eq 0) { + Write-Host "No remaining files found to process." -ForegroundColor Yellow +} else { + Write-Host "Found $($remainingFiles.Count) remaining files to process." -ForegroundColor Green + + # Calculate checksums + Write-Host "Calculating checksums using parallel processing (this may take a while)..." -ForegroundColor Yellow + $filesWithChecksums = Get-FilesWithChecksums -Files $remainingFiles + + Write-Host "Checksum calculation complete." -ForegroundColor Green + + # Group files by checksum + Write-Host "Grouping files by checksum..." -ForegroundColor Yellow + $groupedByChecksum = $filesWithChecksums | Group-Object -Property Hash + + Write-Host "Found $($groupedByChecksum.Count) unique checksums." -ForegroundColor Green + + # Create \textures\common and \textures\common\duplicates directories + $rootCommonPath = Join-Path -Path $textureFolderPath -ChildPath "common" + $rootDuplicatesPath = Join-Path -Path $rootCommonPath -ChildPath "duplicates" + + if (-not (Test-Path -Path $rootCommonPath -PathType Container)) { + New-Item -ItemType Directory -Path $rootCommonPath | Out-Null + Write-Host "Created directory: $rootCommonPath" -ForegroundColor Green + } + + if (-not (Test-Path -Path $rootDuplicatesPath -PathType Container)) { + New-Item -ItemType Directory -Path $rootDuplicatesPath | Out-Null + Write-Host "Created directory: $rootDuplicatesPath" -ForegroundColor Green + } + + # Track filenames already in \textures\common + $filesInRootCommon = @{} + + # Process each checksum group + Write-Host "Moving files to \common and \common\duplicates..." -ForegroundColor Yellow + $pass2Moved = 0 + $pass2Duplicates = 0 + + foreach ($group in $groupedByChecksum) { + $files = $group.Group + + if ($files.Count -eq 1) { + # Single file - leave in place (unique file) + continue + } + + # Multiple files with same checksum (duplicates across blendfiles) + $result = Process-DuplicateGroup -Files $files -CommonPath $rootCommonPath -DuplicatesPath $rootDuplicatesPath -FilesInCommon $filesInRootCommon + $pass2Moved += $result.MovedCount + $pass2Duplicates += $result.DuplicateCount + } + + Write-Host "" + Write-Host "Pass 2 complete: $pass2Moved file(s) moved to \common, $pass2Duplicates duplicate(s) moved to \common\duplicates" -ForegroundColor Green +} + +Write-Host "" +Write-Host "File organization complete!" -ForegroundColor Green + +```
+
--- @@ -5766,56 +6065,151 @@ Adding prefix detection and stripping for inter-blendfile commonalities: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: +```powershell +# Function to extract suffix after blendfile prefix (e.g., "Demarco_Std_Teeth_ao.jpg" -> "Std_Teeth_ao.jpg") +function Get-FileNameWithoutPrefix { + param( + [string]$FileName + ) + + # Check if filename contains underscore (potential prefix separator) + if ($FileName -match '^([^_]+)_(.+)$') { + return $matches[2] + } + + # No prefix found, return original filename + return $FileName +} -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" +# Function to process duplicate group +function Process-DuplicateGroup { + param( + [array]$Files, + [string]$CommonPath, + [string]$DuplicatesPath, + [hashtable]$FilesInCommon, + [switch]$StripPrefix + ) + + $movedCount = 0 + $duplicateCount = 0 + + if ($Files.Count -eq 1) { + # Single file - leave in place (will be processed in Pass 2) + return @{ + MovedCount = 0 + DuplicateCount = 0 + } + } + + # Multiple files with same checksum (duplicates) + # Determine the filename to use + $firstFile = $Files[0].File + $fileName = $firstFile.Name + + # If StripPrefix is enabled, try to extract common suffix + if ($StripPrefix) { + $suffixes = @() + $allHavePrefix = $true + + foreach ($fileObj in $Files) { + $suffix = Get-FileNameWithoutPrefix -FileName $fileObj.Name + $suffixes += $suffix + + # Check if this file had a prefix (suffix is different from original) + if ($suffix -eq $fileObj.Name) { + $allHavePrefix = $false + } + } + + # If all files have prefixes and they all have the same suffix, use the suffix + if ($allHavePrefix) { + $uniqueSuffixes = $suffixes | Select-Object -Unique + if ($uniqueSuffixes.Count -eq 1) { + $fileName = $uniqueSuffixes[0] + } + } + } + + $destinationPath = Join-Path -Path $CommonPath -ChildPath $fileName + + # Handle name conflicts for the first file + if ($FilesInCommon.ContainsKey($fileName)) { + $baseName = [System.IO.Path]::GetFileNameWithoutExtension($fileName) + $extension = [System.IO.Path]::GetExtension($fileName) + $counter = 1 + do { + $newFileName = "${baseName}_${counter}${extension}" + $destinationPath = Join-Path -Path $CommonPath -ChildPath $newFileName + $counter++ + } while ($FilesInCommon.ContainsKey($newFileName) -or (Test-Path -Path $destinationPath)) + + $fileName = $newFileName + } + + try { + Move-Item -Path $firstFile.FullName -Destination $destinationPath -Force + $FilesInCommon[$fileName] = $true + $movedCount++ + } catch { + Write-Warning "Failed to move first duplicate file: $($firstFile.FullName) - $($_.Exception.Message)" + } + + # Move remaining files to \common\duplicates with numbered suffixes + for ($i = 1; $i -lt $Files.Count; $i++) { + $fileObj = $Files[$i].File + $baseName = [System.IO.Path]::GetFileNameWithoutExtension($fileObj.Name) + $extension = [System.IO.Path]::GetExtension($fileObj.Name) + $numberedFileName = "${baseName}.$($i.ToString('000'))${extension}" + $duplicateDestinationPath = Join-Path -Path $DuplicatesPath -ChildPath $numberedFileName + + # Handle name conflicts in duplicates folder + $conflictCounter = 1 + while (Test-Path -Path $duplicateDestinationPath) { + $numberedFileName = "${baseName}.$($i.ToString('000'))_${conflictCounter}${extension}" + $duplicateDestinationPath = Join-Path -Path $DuplicatesPath -ChildPath $numberedFileName + $conflictCounter++ + } + + try { + Move-Item -Path $fileObj.FullName -Destination $duplicateDestinationPath -Force + $duplicateCount++ + } catch { + Write-Warning "Failed to move duplicate file: $($fileObj.FullName) - $($_.Exception.Message)" + } + } + + return @{ + MovedCount = $movedCount + DuplicateCount = $duplicateCount + } } ``` -Additional data: - -```json -{ - "codeblockId": "2956d080-871b-4e84-9c06-3e306eb1e9fa" -} -``` -Status: **completed** -
+
--- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # Multiple files with same checksum (duplicates across blendfiles) + # Use StripPrefix to remove blendfile prefixes (e.g., "Demarco_", "Chan_") when all files share the same suffix + $result = Process-DuplicateGroup -Files $files -CommonPath $rootCommonPath -DuplicatesPath $rootDuplicatesPath -FilesInCommon $filesInRootCommon -StripPrefix + $pass2Moved += $result.MovedCount + $pass2Duplicates += $result.DuplicateCount ``` -Additional data: - -```json -{ - "codeblockId": "6cd455f5-dc49-406f-9e9d-700b70d028e1" -} -``` -Status: **completed** -
+
--- @@ -5920,29 +6314,53 @@ Adding null/empty checks to prevent `$fileName` from being null: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # Multiple files with same checksum (duplicates) + # Determine the filename to use + $firstFile = $Files[0].File + $fileName = $firstFile.Name + + # If StripPrefix is enabled, try to extract common suffix + if ($StripPrefix) { + $suffixes = @() + $allHavePrefix = $true + + foreach ($fileObj in $Files) { + $suffix = Get-FileNameWithoutPrefix -FileName $fileObj.Name + $suffixes += $suffix + + # Check if this file had a prefix (suffix is different from original) + if ($suffix -eq $fileObj.Name) { + $allHavePrefix = $false + } + } + + # If all files have prefixes and they all have the same suffix, use the suffix + if ($allHavePrefix) { + $uniqueSuffixes = $suffixes | Select-Object -Unique + if ($uniqueSuffixes.Count -eq 1 -and -not [string]::IsNullOrWhiteSpace($uniqueSuffixes[0])) { + $fileName = $uniqueSuffixes[0] + } + } + } + + # Ensure fileName is never null or empty + if ([string]::IsNullOrWhiteSpace($fileName)) { + $fileName = $firstFile.Name + } + + $destinationPath = Join-Path -Path $CommonPath -ChildPath $fileName + + # Handle name conflicts for the first file + if ($FilesInCommon.ContainsKey($fileName)) { ``` -Additional data: - -```json -{ - "codeblockId": "8ffb06a6-9963-40a9-9ce5-f1cb0de9cd4c" -} -``` -Status: **completed** -
+
--- @@ -5967,29 +6385,38 @@ Adding validation to `Get-FileNameWithoutPrefix`: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" +```powershell +# Function to extract suffix after blendfile prefix (e.g., "Demarco_Std_Teeth_ao.jpg" -> "Std_Teeth_ao.jpg") +function Get-FileNameWithoutPrefix { + param( + [string]$FileName + ) + + # Validate input + if ([string]::IsNullOrWhiteSpace($FileName)) { + return $FileName + } + + # Check if filename contains underscore (potential prefix separator) + if ($FileName -match '^([^_]+)_(.+)$') { + $suffix = $matches[2] + # Only return suffix if it's not empty + if (-not [string]::IsNullOrWhiteSpace($suffix)) { + return $suffix + } + } + + # No prefix found or suffix is empty, return original filename + return $FileName } ``` -Additional data: - -```json -{ - "codeblockId": "3c5527f6-8ce9-4db0-9842-00c698aa79b0" -} -``` -Status: **completed** -
+
--- @@ -6000,29 +6427,43 @@ Adding validation to ensure files exist before processing: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + if ($Files.Count -eq 1) { + # Single file - leave in place (will be processed in Pass 2) + return @{ + MovedCount = 0 + DuplicateCount = 0 + } + } + + # Validate files array + if ($null -eq $Files -or $Files.Count -eq 0) { + return @{ + MovedCount = 0 + DuplicateCount = 0 + } + } + + # Multiple files with same checksum (duplicates) + # Determine the filename to use + $firstFile = $Files[0].File + if ($null -eq $firstFile -or [string]::IsNullOrWhiteSpace($firstFile.Name)) { + Write-Warning "Invalid file object in duplicate group" + return @{ + MovedCount = 0 + DuplicateCount = 0 + } + } + + $fileName = $firstFile.Name ``` -Additional data: - -```json -{ - "codeblockId": "82818fbe-ac0b-4b72-8d29-0ffee85cdc5a" -} -``` -Status: **completed** -
+
--- @@ -6327,29 +6768,45 @@ Replacing the strict prefix stripping logic with a more aggressive approach: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # If StripPrefix is enabled, try to extract common suffix + if ($StripPrefix) { + $suffixes = @() + $suffixCounts = @{} + + foreach ($fileObj in $Files) { + $suffix = Get-FileNameWithoutPrefix -FileName $fileObj.Name + $suffixes += $suffix + + # Count occurrences of each suffix + if ($suffixCounts.ContainsKey($suffix)) { + $suffixCounts[$suffix]++ + } else { + $suffixCounts[$suffix] = 1 + } + } + + # Find the most common suffix (appears in at least 2 files) + $mostCommonSuffix = $suffixCounts.GetEnumerator() | + Where-Object { $_.Value -ge 2 } | + Sort-Object -Property Value -Descending | + Select-Object -First 1 + + if ($mostCommonSuffix) { + $fileName = $mostCommonSuffix.Key + } elseif ($suffixes.Count -gt 0) { + # Fallback: use the shortest suffix (likely already stripped) + $fileName = ($suffixes | Sort-Object Length | Select-Object -First 1) + } + } ``` -Additional data: - -```json -{ - "codeblockId": "6582c453-339b-4fde-8c48-ee4723a7e7f3" -} -``` -Status: **completed** -
+
--- @@ -6576,29 +7033,54 @@ The logic is too complex. Simplifying: always strip the prefix from any file tha --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # If StripPrefix is enabled, always strip prefix from the first file if it has one + if ($StripPrefix) { + # Try to strip prefix from the first file + $strippedName = Get-FileNameWithoutPrefix -FileName $firstFile.Name + + # Only use stripped name if it's different from original (meaning a prefix was found and removed) + if ($strippedName -ne $firstFile.Name) { + $fileName = $strippedName + } + + # If we have multiple files, try to find a common suffix pattern + if ($Files.Count -gt 1) { + $suffixes = @() + $suffixCounts = @{} + + foreach ($fileObj in $Files) { + $suffix = Get-FileNameWithoutPrefix -FileName $fileObj.Name + $suffixes += $suffix + + # Count occurrences of each suffix + if ($suffixCounts.ContainsKey($suffix)) { + $suffixCounts[$suffix]++ + } else { + $suffixCounts[$suffix] = 1 + } + } + + # Find the most common suffix (appears in at least 2 files) + $mostCommonSuffix = $suffixCounts.GetEnumerator() | + Where-Object { $_.Value -ge 2 } | + Sort-Object -Property Value -Descending | + Select-Object -First 1 + + # Use the most common suffix if found + if ($mostCommonSuffix) { + $fileName = $mostCommonSuffix.Key + } + } + } ``` -Additional data: - -```json -{ - "codeblockId": "a95e50f6-82ae-433a-935b-6e5819fced2e" -} -``` -Status: **completed** -
+
--- @@ -6657,29 +7139,42 @@ Simplifying: when `StripPrefix` is enabled, always strip the prefix from any fil --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # If StripPrefix is enabled, always strip prefix from the filename + if ($StripPrefix) { + # Always try to strip prefix - if file has a prefix, it will be removed + $strippedName = Get-FileNameWithoutPrefix -FileName $firstFile.Name + + # Use stripped name if it's different from original (prefix was removed) + # Otherwise keep original (file had no prefix to strip) + if ($strippedName -ne $firstFile.Name) { + $fileName = $strippedName + } + + # If we have multiple files with same checksum, try to find common suffix + # This handles cases where files from different blendfiles share the same texture + if ($Files.Count -gt 1) { + $allSuffixes = @() + foreach ($fileObj in $Files) { + $suffix = Get-FileNameWithoutPrefix -FileName $fileObj.Name + $allSuffixes += $suffix + } + + # If all files strip to the same suffix, use that + $uniqueSuffixes = $allSuffixes | Select-Object -Unique + if ($uniqueSuffixes.Count -eq 1 -and $uniqueSuffixes[0] -ne $firstFile.Name) { + $fileName = $uniqueSuffixes[0] + } + } + } ``` -Additional data: - -```json -{ - "codeblockId": "d202e0f7-f2a8-4add-89e9-99b52ab5432b" -} -``` -Status: **completed** -
+
--- @@ -6745,29 +7240,52 @@ Adding debug output to trace what's happening: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # If StripPrefix is enabled, always strip prefix from the filename + if ($StripPrefix) { + # Always try to strip prefix - if file has a prefix, it will be removed + $strippedName = Get-FileNameWithoutPrefix -FileName $firstFile.Name + + Write-Host " [DEBUG] Original: '$($firstFile.Name)' -> Stripped: '$strippedName'" -ForegroundColor Gray + + # Use stripped name if it's different from original (prefix was removed) + # Otherwise keep original (file had no prefix to strip) + if ($strippedName -ne $firstFile.Name) { + $fileName = $strippedName + Write-Host " [DEBUG] Using stripped name: '$fileName'" -ForegroundColor Green + } else { + Write-Host " [DEBUG] No prefix found, keeping original: '$fileName'" -ForegroundColor Yellow + } + + # If we have multiple files with same checksum, try to find common suffix + # This handles cases where files from different blendfiles share the same texture + if ($Files.Count -gt 1) { + $allSuffixes = @() + foreach ($fileObj in $Files) { + $suffix = Get-FileNameWithoutPrefix -FileName $fileObj.Name + $allSuffixes += $suffix + } + + Write-Host " [DEBUG] All suffixes: $($allSuffixes -join ', ')" -ForegroundColor Gray + + # If all files strip to the same suffix, use that + $uniqueSuffixes = $allSuffixes | Select-Object -Unique + if ($uniqueSuffixes.Count -eq 1 -and $uniqueSuffixes[0] -ne $firstFile.Name) { + $fileName = $uniqueSuffixes[0] + Write-Host " [DEBUG] All files share common suffix, using: '$fileName'" -ForegroundColor Green + } + } + + Write-Host " [DEBUG] Final filename: '$fileName'" -ForegroundColor Cyan + } ``` -Additional data: - -```json -{ - "codeblockId": "8ce87e3d-6ac3-4649-86c9-257fce047a4b" -} -``` -Status: **completed** -
+
--- @@ -6778,29 +7296,20 @@ Adding a debug statement at the start of the StripPrefix block to confirm it's b --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # If StripPrefix is enabled, always strip prefix from the filename + if ($StripPrefix) { + Write-Host " [DEBUG] StripPrefix enabled for group with $($Files.Count) file(s)" -ForegroundColor Magenta + # Always try to strip prefix - if file has a prefix, it will be removed + $strippedName = Get-FileNameWithoutPrefix -FileName $firstFile.Name ``` -Additional data: - -```json -{ - "codeblockId": "eaf03592-a913-4c54-a125-d3646a49eb17" -} -``` -Status: **completed** -
+
--- @@ -6849,29 +7358,41 @@ Replacing the regex-based approach with string splitting to avoid `$matches` iss --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" +```powershell +# Function to extract suffix after blendfile prefix (e.g., "Demarco_Std_Teeth_ao.jpg" -> "Std_Teeth_ao.jpg") +function Get-FileNameWithoutPrefix { + param( + [string]$FileName + ) + + # Validate input + if ([string]::IsNullOrWhiteSpace($FileName)) { + return $FileName + } + + # Use Split instead of regex for robustness (avoids $matches variable issues in loops) + # Split by the first underscore only (limit to 2 parts) + $parts = $FileName.Split('_', 2) + + if ($parts.Length -eq 2) { + $suffix = $parts[1] + # Only return suffix if it's not empty + if (-not [string]::IsNullOrWhiteSpace($suffix)) { + return $suffix + } + } + + # No prefix found or suffix is empty, return original filename + return $FileName } ``` -Additional data: - -```json -{ - "codeblockId": "7ecb1aac-113b-4599-821f-f8b104e21000" -} -``` -Status: **completed** -
+
--- @@ -6911,29 +7432,34 @@ The loop uses `$fileObj.Name`, but `$fileObj` is a PSCustomObject with a `.File` --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # If we have multiple files with same checksum, try to find common suffix + # This handles cases where files from different blendfiles share the same texture + if ($Files.Count -gt 1) { + $allSuffixes = @() + foreach ($fileObj in $Files) { + # $fileObj is a PSCustomObject with .File property, so access .File.Name + $suffix = Get-FileNameWithoutPrefix -FileName $fileObj.File.Name + $allSuffixes += $suffix + } + + Write-Host " [DEBUG] All suffixes: $($allSuffixes -join ', ')" -ForegroundColor Gray + + # If all files strip to the same suffix, use that + $uniqueSuffixes = $allSuffixes | Select-Object -Unique + if ($uniqueSuffixes.Count -eq 1 -and $uniqueSuffixes[0] -ne $firstFile.Name) { + $fileName = $uniqueSuffixes[0] + Write-Host " [DEBUG] All files share common suffix, using: '$fileName'" -ForegroundColor Green + } + } ``` -Additional data: - -```json -{ - "codeblockId": "ae71c763-16c9-4c3a-9c67-b7b6e8ea1903" -} -``` -Status: **completed** -
+
--- @@ -6977,29 +7503,23 @@ The issue is that `Select-Object -Unique` on a string array can return a collect --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + Write-Host " [DEBUG] All suffixes: $($allSuffixes -join ', ')" -ForegroundColor Gray + + # If all files strip to the same suffix, use that + $uniqueSuffixes = @($allSuffixes | Select-Object -Unique) + if ($uniqueSuffixes.Count -eq 1 -and $uniqueSuffixes[0] -ne $firstFile.Name) { + $fileName = [string]$uniqueSuffixes[0] + Write-Host " [DEBUG] All files share common suffix, using: '$fileName'" -ForegroundColor Green + } ``` -Additional data: - -```json -{ - "codeblockId": "ecc4b754-ecf0-4588-89f0-b5443f35e0c6" -} -``` -Status: **completed** -
+
--- @@ -7073,29 +7593,50 @@ Updating the function to only strip known blendfile prefixes. Modifying `Get-Fil --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" +```powershell +# Function to extract suffix after blendfile prefix (e.g., "Demarco_Std_Teeth_ao.jpg" -> "Std_Teeth_ao.jpg") +# Only strips prefixes that are in the $ValidPrefixes list +function Get-FileNameWithoutPrefix { + param( + [string]$FileName, + [string[]]$ValidPrefixes + ) + + # Validate input + if ([string]::IsNullOrWhiteSpace($FileName)) { + return $FileName + } + + # If no valid prefixes provided, return original filename + if ($null -eq $ValidPrefixes -or $ValidPrefixes.Count -eq 0) { + return $FileName + } + + # Use Split instead of regex for robustness (avoids $matches variable issues in loops) + # Split by the first underscore only (limit to 2 parts) + $parts = $FileName.Split('_', 2) + + if ($parts.Length -eq 2) { + $prefix = $parts[0] + $suffix = $parts[1] + + # Only strip if the prefix is in the valid prefixes list + if ($ValidPrefixes -contains $prefix -and -not [string]::IsNullOrWhiteSpace($suffix)) { + return $suffix + } + } + + # No valid prefix found or suffix is empty, return original filename + return $FileName } ``` -Additional data: - -```json -{ - "codeblockId": "d56bed0f-1611-4026-b349-1367f22a00f5" -} -``` -Status: **completed** -
+
--- @@ -7120,29 +7661,25 @@ Updating `Process-DuplicateGroup` to accept and use the valid prefixes: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell +# Function to process duplicate group +function Process-DuplicateGroup { + param( + [array]$Files, + [string]$CommonPath, + [string]$DuplicatesPath, + [hashtable]$FilesInCommon, + [switch]$StripPrefix, + [string[]]$ValidPrefixes = @() + ) ``` -Additional data: - -```json -{ - "codeblockId": "7e9cab73-2e6a-4c51-aa15-d9ddc71f8fb2" -} -``` -Status: **completed** -
+
--- @@ -7153,29 +7690,41 @@ Updating calls to `Get-FileNameWithoutPrefix` within `Process-DuplicateGroup`: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # If StripPrefix is enabled, always strip prefix from the filename + if ($StripPrefix) { + Write-Host " [DEBUG] StripPrefix enabled for group with $($Files.Count) file(s)" -ForegroundColor Magenta + # Always try to strip prefix - if file has a prefix, it will be removed + $strippedName = Get-FileNameWithoutPrefix -FileName $firstFile.Name -ValidPrefixes $ValidPrefixes + + Write-Host " [DEBUG] Original: '$($firstFile.Name)' -> Stripped: '$strippedName'" -ForegroundColor Gray + + # Use stripped name if it's different from original (prefix was removed) + # Otherwise keep original (file had no prefix to strip) + if ($strippedName -ne $firstFile.Name) { + $fileName = $strippedName + Write-Host " [DEBUG] Using stripped name: '$fileName'" -ForegroundColor Green + } else { + Write-Host " [DEBUG] No prefix found, keeping original: '$fileName'" -ForegroundColor Yellow + } + + # If we have multiple files with same checksum, try to find common suffix + # This handles cases where files from different blendfiles share the same texture + if ($Files.Count -gt 1) { + $allSuffixes = @() + foreach ($fileObj in $Files) { + # $fileObj is a PSCustomObject with .File property, so access .File.Name + $suffix = Get-FileNameWithoutPrefix -FileName $fileObj.File.Name -ValidPrefixes $ValidPrefixes + $allSuffixes += $suffix + } ``` -Additional data: - -```json -{ - "codeblockId": "50bf96a9-7c22-49e2-b1f6-6ee8fa110e7b" -} -``` -Status: **completed** -
+
--- @@ -7186,29 +7735,32 @@ Building the list of valid prefixes before Pass 2 and passing it to `Process-Dup --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: +```powershell +# ============================================================================ +# PASS 2: Inter-Blendfile Processing +# ============================================================================ +Write-Host "" +Write-Host "=== PASS 2: Inter-Blendfile Processing ===" -ForegroundColor Cyan -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" +# Build list of valid blendfile prefixes from folder names +$validBlendfilePrefixes = @() +$blendfileFoldersForPrefixes = Get-ChildItem -Path $textureFolderPath -Directory | Where-Object { $_.Name -ne "common" } +if ($null -ne $blendfileFoldersForPrefixes) { + $validBlendfilePrefixes = $blendfileFoldersForPrefixes | ForEach-Object { $_.Name } + Write-Host "Valid blendfile prefixes: $($validBlendfilePrefixes -join ', ')" -ForegroundColor Gray } -``` -Additional data: -```json -{ - "codeblockId": "67686096-d013-4c0a-bf48-a813ecc99452" -} +# Get all remaining files (excluding all \common folders) +Write-Host "Collecting remaining files..." -ForegroundColor Yellow +$remainingFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object { $_.FullName -notlike "*\common\*" } ``` -Status: **completed** -
+
--- @@ -7247,29 +7799,18 @@ Updating the call to include the valid prefixes: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # Multiple files with same checksum (duplicates across blendfiles) + # Use StripPrefix to remove blendfile prefixes (e.g., "Demarco_", "Chan_") when all files share the same suffix + $result = Process-DuplicateGroup -Files $files -CommonPath $rootCommonPath -DuplicatesPath $rootDuplicatesPath -FilesInCommon $filesInRootCommon -StripPrefix -ValidPrefixes $validBlendfilePrefixes ``` -Additional data: - -```json -{ - "codeblockId": "2bd83a67-0dd8-46fc-9588-07244da0e8a3" -} -``` -Status: **completed** -
+
--- @@ -7319,29 +7860,24 @@ Updating `Process-DuplicateGroup` to delete duplicates instead of moving them: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell +# Function to process duplicate group +function Process-DuplicateGroup { + param( + [array]$Files, + [string]$CommonPath, + [hashtable]$FilesInCommon, + [switch]$StripPrefix, + [string[]]$ValidPrefixes = @() + ) ``` -Additional data: - -```json -{ - "codeblockId": "2666bd10-59d4-4d2b-be5e-cb4f437c6266" -} -``` -Status: **completed** -
+
--- @@ -7352,29 +7888,33 @@ Replacing the code that moves duplicates with code that deletes them: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + try { + Move-Item -Path $firstFile.FullName -Destination $destinationPath -Force + $FilesInCommon[$fileName] = $true + $movedCount++ + } catch { + Write-Warning "Failed to move first duplicate file: $($firstFile.FullName) - $($_.Exception.Message)" + } + + # Delete remaining duplicate files (they're replaced by the common file) + for ($i = 1; $i -lt $Files.Count; $i++) { + $fileObj = $Files[$i].File + try { + Remove-Item -Path $fileObj.FullName -Force + $duplicateCount++ + } catch { + Write-Warning "Failed to delete duplicate file: $($fileObj.FullName) - $($_.Exception.Message)" + } + } ``` -Additional data: - -```json -{ - "codeblockId": "4847ba4f-4666-4d56-9eb5-fc4ea2aaabab" -} -``` -Status: **completed** -
+
--- @@ -7399,29 +7939,36 @@ Updating Pass 1 to remove duplicates folder creation and update the call: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # Create [blendfile]\common directory + $blendfileCommonPath = Join-Path -Path $blendfileFolder.FullName -ChildPath "common" + + if (-not (Test-Path -Path $blendfileCommonPath -PathType Container)) { + New-Item -ItemType Directory -Path $blendfileCommonPath | Out-Null + } + + # Track filenames already in [blendfile]\common + $filesInBlendfileCommon = @{} + + # Process each checksum group + $blendfileMoved = 0 + $blendfileDuplicates = 0 + + foreach ($group in $groupedByChecksum) { + $result = Process-DuplicateGroup -Files $group.Group -CommonPath $blendfileCommonPath -FilesInCommon $filesInBlendfileCommon + $blendfileMoved += $result.MovedCount + $blendfileDuplicates += $result.DuplicateCount + } + + Write-Host " Moved $blendfileMoved file(s) to \common, deleted $blendfileDuplicates duplicate(s)" -ForegroundColor Green ``` -Additional data: - -```json -{ - "codeblockId": "a5a4e114-b913-4fd7-9267-0f8d5461f422" -} -``` -Status: **completed** -
+
--- @@ -7432,29 +7979,17 @@ Updating the Pass 1 summary message: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + Write-Host "" + Write-Host "Pass 1 complete: $totalPass1Moved file(s) moved, $totalPass1Duplicates duplicate(s) deleted" -ForegroundColor Green ``` -Additional data: - -```json -{ - "codeblockId": "86dbaa71-f9dd-4877-92b9-a496350ac9cd" -} -``` -Status: **completed** -
+
--- @@ -7479,29 +8014,48 @@ Updating Pass 2: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # Create \textures\common directory + $rootCommonPath = Join-Path -Path $textureFolderPath -ChildPath "common" + + if (-not (Test-Path -Path $rootCommonPath -PathType Container)) { + New-Item -ItemType Directory -Path $rootCommonPath | Out-Null + Write-Host "Created directory: $rootCommonPath" -ForegroundColor Green + } + + # Track filenames already in \textures\common + $filesInRootCommon = @{} + + # Process each checksum group + Write-Host "Moving files to \common and deleting duplicates..." -ForegroundColor Yellow + $pass2Moved = 0 + $pass2Duplicates = 0 + + foreach ($group in $groupedByChecksum) { + $files = $group.Group + + if ($files.Count -eq 1) { + # Single file - leave in place (unique file) + continue + } + + # Multiple files with same checksum (duplicates across blendfiles) + # Use StripPrefix to remove blendfile prefixes (e.g., "Demarco_", "Chan_") when all files share the same suffix + $result = Process-DuplicateGroup -Files $files -CommonPath $rootCommonPath -FilesInCommon $filesInRootCommon -StripPrefix -ValidPrefixes $validBlendfilePrefixes + $pass2Moved += $result.MovedCount + $pass2Duplicates += $result.DuplicateCount + } + + Write-Host "" + Write-Host "Pass 2 complete: $pass2Moved file(s) moved to \common, $pass2Duplicates duplicate(s) deleted" -ForegroundColor Green ``` -Additional data: - -```json -{ - "codeblockId": "7f1a3f6b-71df-42b5-b1c1-0e321a0a7fe0" -} -``` -Status: **completed** -
+
--- @@ -7551,29 +8105,79 @@ Adding logic to move FlatColors files to the common folder after duplicate proce --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # Process each checksum group + Write-Host "Moving files to \common and deleting duplicates..." -ForegroundColor Yellow + $pass2Moved = 0 + $pass2Duplicates = 0 + + foreach ($group in $groupedByChecksum) { + $files = $group.Group + + if ($files.Count -eq 1) { + # Single file - leave in place (unique file) + continue + } + + # Multiple files with same checksum (duplicates across blendfiles) + # Use StripPrefix to remove blendfile prefixes (e.g., "Demarco_", "Chan_") when all files share the same suffix + $result = Process-DuplicateGroup -Files $files -CommonPath $rootCommonPath -FilesInCommon $filesInRootCommon -StripPrefix -ValidPrefixes $validBlendfilePrefixes + $pass2Moved += $result.MovedCount + $pass2Duplicates += $result.DuplicateCount + } + + # Also move all FlatColors files to \common (even if they're unique) + Write-Host "Moving FlatColors files to \common..." -ForegroundColor Yellow + $flatColorsFiles = $filesWithChecksums | Where-Object { $_.File.Name -like "*FlatColors*" } + + if ($null -ne $flatColorsFiles -and $flatColorsFiles.Count -gt 0) { + foreach ($fileObj in $flatColorsFiles) { + $file = $fileObj.File + $fileName = $file.Name + + # Strip blendfile prefix if present + $strippedName = Get-FileNameWithoutPrefix -FileName $fileName -ValidPrefixes $validBlendfilePrefixes + if ($strippedName -ne $fileName) { + $fileName = $strippedName + } + + $destinationPath = Join-Path -Path $rootCommonPath -ChildPath $fileName + + # Handle name conflicts + if ($FilesInRootCommon.ContainsKey($fileName)) { + $baseName = [System.IO.Path]::GetFileNameWithoutExtension($fileName) + $extension = [System.IO.Path]::GetExtension($fileName) + $counter = 1 + do { + $newFileName = "${baseName}_${counter}${extension}" + $destinationPath = Join-Path -Path $rootCommonPath -ChildPath $newFileName + $counter++ + } while ($FilesInRootCommon.ContainsKey($newFileName) -or (Test-Path -Path $destinationPath)) + + $fileName = $newFileName + } + + try { + Move-Item -Path $file.FullName -Destination $destinationPath -Force + $FilesInRootCommon[$fileName] = $true + $pass2Moved++ + } catch { + Write-Warning "Failed to move FlatColors file: $($file.FullName) - $($_.Exception.Message)" + } + } + Write-Host "Moved $($flatColorsFiles.Count) FlatColors file(s) to \common" -ForegroundColor Green + } + + Write-Host "" + Write-Host "Pass 2 complete: $pass2Moved file(s) moved to \common, $pass2Duplicates duplicate(s) deleted" -ForegroundColor Green ``` -Additional data: - -```json -{ - "codeblockId": "cffef2ad-0b31-4a38-9241-1080d28c6a86" -} -``` -Status: **completed** -
+
--- @@ -7598,29 +8202,36 @@ Fixing the variable name to match: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # Handle name conflicts + if ($filesInRootCommon.ContainsKey($fileName)) { + $baseName = [System.IO.Path]::GetFileNameWithoutExtension($fileName) + $extension = [System.IO.Path]::GetExtension($fileName) + $counter = 1 + do { + $newFileName = "${baseName}_${counter}${extension}" + $destinationPath = Join-Path -Path $rootCommonPath -ChildPath $newFileName + $counter++ + } while ($filesInRootCommon.ContainsKey($newFileName) -or (Test-Path -Path $destinationPath)) + + $fileName = $newFileName + } + + try { + Move-Item -Path $file.FullName -Destination $destinationPath -Force + $filesInRootCommon[$fileName] = $true + $pass2Moved++ + } catch { + Write-Warning "Failed to move FlatColors file: $($file.FullName) - $($_.Exception.Message)" + } ``` -Additional data: - -```json -{ - "codeblockId": "af40fe44-3e54-44ce-8f07-a694e52051f0" -} -``` -Status: **completed** -
+
--- @@ -7631,29 +8242,23 @@ Adding a check to ensure the file still exists before moving it (in case it was --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # Also move all FlatColors files to \common (even if they're unique) + Write-Host "Moving FlatColors files to \common..." -ForegroundColor Yellow + $flatColorsFiles = $filesWithChecksums | Where-Object { $_.File.Name -like "*FlatColors*" -and (Test-Path -Path $_.File.FullName) } + + if ($null -ne $flatColorsFiles -and $flatColorsFiles.Count -gt 0) { + foreach ($fileObj in $flatColorsFiles) { + $file = $fileObj.File + $fileName = $file.Name ``` -Additional data: - -```json -{ - "codeblockId": "cc15b99a-e2d7-4f52-8186-be98b4fb2162" -} -``` -Status: **completed** -
+
--- @@ -7698,29 +8303,66 @@ Updating the code to create a `\textures\common\FlatColors` subfolder and move F --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # Also move all FlatColors files to \common\FlatColors (even if they're unique) + Write-Host "Moving FlatColors files to \common\FlatColors..." -ForegroundColor Yellow + $flatColorsFiles = $filesWithChecksums | Where-Object { $_.File.Name -like "*FlatColors*" -and (Test-Path -Path $_.File.FullName) } + + if ($null -ne $flatColorsFiles -and $flatColorsFiles.Count -gt 0) { + # Create \textures\common\FlatColors directory + $flatColorsPath = Join-Path -Path $rootCommonPath -ChildPath "FlatColors" + if (-not (Test-Path -Path $flatColorsPath -PathType Container)) { + New-Item -ItemType Directory -Path $flatColorsPath | Out-Null + Write-Host "Created directory: $flatColorsPath" -ForegroundColor Green + } + + # Track filenames already in \common\FlatColors + $filesInFlatColors = @{} + + foreach ($fileObj in $flatColorsFiles) { + $file = $fileObj.File + $fileName = $file.Name + + # Strip blendfile prefix if present + $strippedName = Get-FileNameWithoutPrefix -FileName $fileName -ValidPrefixes $validBlendfilePrefixes + if ($strippedName -ne $fileName) { + $fileName = $strippedName + } + + $destinationPath = Join-Path -Path $flatColorsPath -ChildPath $fileName + + # Handle name conflicts + if ($filesInFlatColors.ContainsKey($fileName)) { + $baseName = [System.IO.Path]::GetFileNameWithoutExtension($fileName) + $extension = [System.IO.Path]::GetExtension($fileName) + $counter = 1 + do { + $newFileName = "${baseName}_${counter}${extension}" + $destinationPath = Join-Path -Path $flatColorsPath -ChildPath $newFileName + $counter++ + } while ($filesInFlatColors.ContainsKey($newFileName) -or (Test-Path -Path $destinationPath)) + + $fileName = $newFileName + } + + try { + Move-Item -Path $file.FullName -Destination $destinationPath -Force + $filesInFlatColors[$fileName] = $true + $pass2Moved++ + } catch { + Write-Warning "Failed to move FlatColors file: $($file.FullName) - $($_.Exception.Message)" + } + } + Write-Host "Moved $($flatColorsFiles.Count) FlatColors file(s) to \common\FlatColors" -ForegroundColor Green + } ``` -Additional data: - -```json -{ - "codeblockId": "ccca3757-4691-405a-8e37-53dd61be3fbb" -} -``` -Status: **completed** -
+
--- @@ -7771,29 +8413,19 @@ The issue is that we're checking `$filesWithChecksums` after duplicates are proc --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # Also move all FlatColors files to \common\FlatColors (even if they're unique) + Write-Host "Moving FlatColors files to \common\FlatColors..." -ForegroundColor Yellow + # Check remainingFiles directly to find FlatColors files that haven't been moved yet + $flatColorsFiles = $remainingFiles | Where-Object { $_.Name -like "*FlatColors*" -and (Test-Path -Path $_.FullName) } ``` -Additional data: - -```json -{ - "codeblockId": "b1e0cbb6-fa2a-4be0-b29b-59895d935281" -} -``` -Status: **completed** -
+
--- @@ -7818,29 +8450,20 @@ Updating the loop to use FileInfo objects directly: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # Track filenames already in \common\FlatColors + $filesInFlatColors = @{} + + foreach ($file in $flatColorsFiles) { + $fileName = $file.Name ``` -Additional data: - -```json -{ - "codeblockId": "c06058ea-80c8-4195-a6d5-c077447a6411" -} -``` -Status: **completed** -
+
--- @@ -7902,29 +8525,62 @@ Restructuring to handle FlatColors files before duplicate processing and exclude --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # Separate FlatColors files from other files before processing + Write-Host "Identifying FlatColors files..." -ForegroundColor Yellow + $flatColorsFiles = $remainingFiles | Where-Object { $_.Name -like "*FlatColors*" } + $nonFlatColorsFiles = $remainingFiles | Where-Object { $_.Name -notlike "*FlatColors*" } + + Write-Host "Found $($flatColorsFiles.Count) FlatColors file(s), $($nonFlatColorsFiles.Count) other file(s)" -ForegroundColor Gray + + # Group non-FlatColors files by checksum + Write-Host "Grouping files by checksum..." -ForegroundColor Yellow + $nonFlatColorsWithChecksums = $filesWithChecksums | Where-Object { $_.File.Name -notlike "*FlatColors*" } + $groupedByChecksum = $nonFlatColorsWithChecksums | Group-Object -Property Hash + + Write-Host "Found $($groupedByChecksum.Count) unique checksums." -ForegroundColor Green + + # Create \textures\common directory + $rootCommonPath = Join-Path -Path $textureFolderPath -ChildPath "common" + + if (-not (Test-Path -Path $rootCommonPath -PathType Container)) { + New-Item -ItemType Directory -Path $rootCommonPath | Out-Null + Write-Host "Created directory: $rootCommonPath" -ForegroundColor Green + } + + # Track filenames already in \textures\common + $filesInRootCommon = @{} + + # Process each checksum group (excluding FlatColors) + Write-Host "Moving files to \common and deleting duplicates..." -ForegroundColor Yellow + $pass2Moved = 0 + $pass2Duplicates = 0 + + foreach ($group in $groupedByChecksum) { + $files = $group.Group + + if ($files.Count -eq 1) { + # Single file - leave in place (unique file) + continue + } + + # Multiple files with same checksum (duplicates across blendfiles) + # Use StripPrefix to remove blendfile prefixes (e.g., "Demarco_", "Chan_") when all files share the same suffix + $result = Process-DuplicateGroup -Files $files -CommonPath $rootCommonPath -FilesInCommon $filesInRootCommon -StripPrefix -ValidPrefixes $validBlendfilePrefixes + $pass2Moved += $result.MovedCount + $pass2Duplicates += $result.DuplicateCount + } + + # Move all FlatColors files to \common\FlatColors (even if they're unique) + Write-Host "Moving FlatColors files to \common\FlatColors..." -ForegroundColor Yellow ``` -Additional data: - -```json -{ - "codeblockId": "79972c53-e0e2-4130-a3c9-a43564ffd3f1" -} -``` -Status: **completed** -
+
--- @@ -7949,29 +8605,20 @@ Adding debug output to see if FlatColors files are being found: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # Move all FlatColors files to \common\FlatColors (even if they're unique) + Write-Host "Moving FlatColors files to \common\FlatColors..." -ForegroundColor Yellow + + if ($null -ne $flatColorsFiles -and $flatColorsFiles.Count -gt 0) { + Write-Host "Found $($flatColorsFiles.Count) FlatColors file(s) to move" -ForegroundColor Gray ``` -Additional data: - -```json -{ - "codeblockId": "c620ec8a-a87c-4377-90ed-577acc15dceb" -} -``` -Status: **completed** -
+
--- @@ -7982,29 +8629,20 @@ Adding an else clause to show when no FlatColors files are found: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + } + Write-Host "Moved $($flatColorsFiles.Count) FlatColors file(s) to \common\FlatColors" -ForegroundColor Green + } else { + Write-Host "No FlatColors files found to move." -ForegroundColor Gray + } ``` -Additional data: - -```json -{ - "codeblockId": "90044f8c-d9a6-4a70-ba89-21085a56910c" -} -``` -Status: **completed** -
+
--- @@ -8068,29 +8706,38 @@ Updating the code to collect FlatColors files from anywhere, including those in --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: +```powershell +# Collect FlatColors files separately (including those in \common\FlatColors folders) +Write-Host "Collecting FlatColors files..." -ForegroundColor Yellow +$allFlatColorsFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object { $_.FullName -like "*\FlatColors\*" -or $_.Name -like "*FlatColors*" } -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +# Get all remaining files (excluding all \common folders, but we'll handle FlatColors separately) +Write-Host "Collecting remaining files..." -ForegroundColor Yellow +$remainingFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object { $_.FullName -notlike "*\common\*" } + +if ($null -eq $remainingFiles -or $remainingFiles.Count -eq 0) { + Write-Host "No remaining files found to process." -ForegroundColor Yellow +} else { + Write-Host "Found $($remainingFiles.Count) remaining files to process." -ForegroundColor Green + + # Calculate checksums + Write-Host "Calculating checksums using parallel processing (this may take a while)..." -ForegroundColor Yellow + $filesWithChecksums = Get-FilesWithChecksums -Files $remainingFiles + + Write-Host "Checksum calculation complete." -ForegroundColor Green + + # Separate FlatColors files from other files before processing + Write-Host "Identifying FlatColors files..." -ForegroundColor Yellow + $flatColorsFiles = $allFlatColorsFiles | Where-Object { (Test-Path -Path $_.FullName) } + $nonFlatColorsFiles = $remainingFiles | Where-Object { $_.Name -notlike "*FlatColors*" } ``` -Additional data: - -```json -{ - "codeblockId": "fea6d4a8-6d9b-40ce-8281-2f5aac7bc93e" -} -``` -Status: **completed** -
+
--- @@ -8101,29 +8748,21 @@ Updating the debug output to show how many FlatColors files were found: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # Separate FlatColors files from other files before processing + Write-Host "Identifying FlatColors files..." -ForegroundColor Yellow + $flatColorsFiles = $allFlatColorsFiles | Where-Object { (Test-Path -Path $_.FullName) } + $nonFlatColorsFiles = $remainingFiles | Where-Object { $_.Name -notlike "*FlatColors*" } + + Write-Host "Found $($flatColorsFiles.Count) FlatColors file(s) (including from \common\FlatColors folders), $($nonFlatColorsFiles.Count) other file(s)" -ForegroundColor Gray ``` -Additional data: - -```json -{ - "codeblockId": "60bb9a02-854d-418b-a45a-b91013a7944a" -} -``` -Status: **completed** -
+
--- @@ -8134,29 +8773,22 @@ Excluding files already in the root `\textures\common\FlatColors` folder: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" +```powershell +# Collect FlatColors files separately (including those in \common\FlatColors folders, but not from root \common\FlatColors) +Write-Host "Collecting FlatColors files..." -ForegroundColor Yellow +$rootCommonFlatColorsPath = Join-Path -Path $textureFolderPath -ChildPath "common\FlatColors" +$allFlatColorsFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object { + ($_.FullName -like "*\FlatColors\*" -or $_.Name -like "*FlatColors*") -and + $_.FullName -notlike "$([regex]::Escape($rootCommonFlatColorsPath))\*" } ``` -Additional data: - -```json -{ - "codeblockId": "b7cacb81-a662-40f7-9058-7cafe450291e" -} -``` -Status: **completed** -
+
--- @@ -8210,29 +8842,91 @@ Updating FlatColors processing to calculate checksums, group duplicates, and mer --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # Process FlatColors files: merge duplicates and move to \common\FlatColors + Write-Host "Processing FlatColors files (merging duplicates)..." -ForegroundColor Yellow + + if ($null -ne $flatColorsFiles -and $flatColorsFiles.Count -gt 0) { + Write-Host "Found $($flatColorsFiles.Count) FlatColors file(s) to process" -ForegroundColor Gray + + # Calculate checksums for FlatColors files + Write-Host "Calculating checksums for FlatColors files..." -ForegroundColor Yellow + $flatColorsWithChecksums = Get-FilesWithChecksums -Files $flatColorsFiles + + # Group by checksum to find duplicates + $flatColorsGroupedByChecksum = $flatColorsWithChecksums | Group-Object -Property Hash + + Write-Host "Found $($flatColorsGroupedByChecksum.Count) unique FlatColors file(s)" -ForegroundColor Gray + + # Create \textures\common\FlatColors directory + $flatColorsPath = Join-Path -Path $rootCommonPath -ChildPath "FlatColors" + if (-not (Test-Path -Path $flatColorsPath -PathType Container)) { + New-Item -ItemType Directory -Path $flatColorsPath | Out-Null + Write-Host "Created directory: $flatColorsPath" -ForegroundColor Green + } + + # Track filenames already in \common\FlatColors + $filesInFlatColors = @{} + $flatColorsMoved = 0 + $flatColorsDuplicates = 0 + + foreach ($group in $flatColorsGroupedByChecksum) { + $files = $group.Group + + if ($files.Count -eq 1) { + # Single file - move to FlatColors folder + $fileObj = $files[0].File + $fileName = $fileObj.Name + + # Strip blendfile prefix if present + $strippedName = Get-FileNameWithoutPrefix -FileName $fileName -ValidPrefixes $validBlendfilePrefixes + if ($strippedName -ne $fileName) { + $fileName = $strippedName + } + + $destinationPath = Join-Path -Path $flatColorsPath -ChildPath $fileName + + # Handle name conflicts (shouldn't happen for unique files, but just in case) + if ($filesInFlatColors.ContainsKey($fileName) -or (Test-Path -Path $destinationPath)) { + $baseName = [System.IO.Path]::GetFileNameWithoutExtension($fileName) + $extension = [System.IO.Path]::GetExtension($fileName) + $counter = 1 + do { + $newFileName = "${baseName}_${counter}${extension}" + $destinationPath = Join-Path -Path $flatColorsPath -ChildPath $newFileName + $counter++ + } while ($filesInFlatColors.ContainsKey($newFileName) -or (Test-Path -Path $destinationPath)) + $fileName = $newFileName + } + + try { + Move-Item -Path $fileObj.FullName -Destination $destinationPath -Force + $filesInFlatColors[$fileName] = $true + $flatColorsMoved++ + } catch { + Write-Warning "Failed to move FlatColors file: $($fileObj.FullName) - $($_.Exception.Message)" + } + } else { + # Multiple files with same checksum (duplicates) - merge them + # Use Process-DuplicateGroup to handle merging + $result = Process-DuplicateGroup -Files $files -CommonPath $flatColorsPath -FilesInCommon $filesInFlatColors -StripPrefix -ValidPrefixes $validBlendfilePrefixes + $flatColorsMoved += $result.MovedCount + $flatColorsDuplicates += $result.DuplicateCount + } + } + + Write-Host "Moved $flatColorsMoved unique FlatColors file(s) to \common\FlatColors, deleted $flatColorsDuplicates duplicate(s)" -ForegroundColor Green + } else { + Write-Host "No FlatColors files found to process." -ForegroundColor Gray + } ``` -Additional data: - -```json -{ - "codeblockId": "385c5b5b-de3b-4166-b1ca-4cde1fe2e62b" -} -``` -Status: **completed** -
+
--- @@ -8312,29 +9006,67 @@ Adding a function to remove empty folders after the helper functions, then calli --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" +```powershell + Write-Host "" + Write-Host "Pass 2 complete: $pass2Moved file(s) moved to \common, $pass2Duplicates duplicate(s) deleted" -ForegroundColor Green } -``` -Additional data: -```json -{ - "codeblockId": "5ad7abd3-af49-44de-8265-ffa35a44e317" +# Function to remove empty folders recursively +function Remove-EmptyFolders { + param( + [string]$Path, + [string]$RootPath + ) + + $removedCount = 0 + + # Get all subdirectories + $subdirs = Get-ChildItem -Path $Path -Directory -ErrorAction SilentlyContinue + + if ($null -ne $subdirs) { + foreach ($subdir in $subdirs) { + # Recursively process subdirectories first + $removedCount += Remove-EmptyFolders -Path $subdir.FullName -RootPath $RootPath + + # Check if this directory is now empty (after processing subdirectories) + $items = Get-ChildItem -Path $subdir.FullName -ErrorAction SilentlyContinue + if ($null -eq $items -or $items.Count -eq 0) { + # Don't remove the root path + if ($subdir.FullName -ne $RootPath) { + try { + Remove-Item -Path $subdir.FullName -Force -ErrorAction Stop + $removedCount++ + } catch { + Write-Warning "Failed to remove empty folder: $($subdir.FullName) - $($_.Exception.Message)" + } + } + } + } + } + + return $removedCount } -``` -Status: **completed** +# Remove empty folders +Write-Host "" +Write-Host "Removing empty folders..." -ForegroundColor Yellow +$emptyFoldersRemoved = Remove-EmptyFolders -Path $textureFolderPath -RootPath $textureFolderPath +if ($emptyFoldersRemoved -gt 0) { + Write-Host "Removed $emptyFoldersRemoved empty folder(s)" -ForegroundColor Green +} else { + Write-Host "No empty folders found to remove." -ForegroundColor Gray +} + +Write-Host "" +Write-Host "File organization complete!" -ForegroundColor Green +```
+
--- @@ -8457,29 +9189,43 @@ Removing all debug statements: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # If StripPrefix is enabled, always strip prefix from the filename + if ($StripPrefix) { + # Always try to strip prefix - if file has a prefix, it will be removed + $strippedName = Get-FileNameWithoutPrefix -FileName $firstFile.Name -ValidPrefixes $ValidPrefixes + + # Use stripped name if it's different from original (prefix was removed) + # Otherwise keep original (file had no prefix to strip) + if ($strippedName -ne $firstFile.Name) { + $fileName = $strippedName + } + + # If we have multiple files with same checksum, try to find common suffix + # This handles cases where files from different blendfiles share the same texture + if ($Files.Count -gt 1) { + $allSuffixes = @() + foreach ($fileObj in $Files) { + # $fileObj is a PSCustomObject with .File property, so access .File.Name + $suffix = Get-FileNameWithoutPrefix -FileName $fileObj.File.Name -ValidPrefixes $ValidPrefixes + $allSuffixes += $suffix + } + + # If all files strip to the same suffix, use that + $uniqueSuffixes = @($allSuffixes | Select-Object -Unique) + if ($uniqueSuffixes.Count -eq 1 -and $uniqueSuffixes[0] -ne $firstFile.Name) { + $fileName = [string]$uniqueSuffixes[0] + } + } + } ``` -Additional data: - -```json -{ - "codeblockId": "bc2633e5-4947-44a4-b04c-2129bf7ebe97" -} -``` -Status: **completed** -
+
--- @@ -15897,29 +16643,28 @@ Modifying `Process-DuplicateGroup` to track file moves: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell +# Function to process duplicate group +function Process-DuplicateGroup { + param( + [array]$Files, + [string]$CommonPath, + [hashtable]$FilesInCommon, + [switch]$StripPrefix, + [string[]]$ValidPrefixes = @(), + [System.Collections.ArrayList]$MoveLog = $null + ) + + $movedCount = 0 + $duplicateCount = 0 ``` -Additional data: - -```json -{ - "codeblockId": "d7ca200d-9c2b-4710-8108-d6733b495306" -} -``` -Status: **completed** -
+
--- @@ -15930,29 +16675,61 @@ Adding move logging when files are moved and deleted: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + try { + Move-Item -Path $firstFile.FullName -Destination $destinationPath -Force + $FilesInCommon[$fileName] = $true + $movedCount++ + + # Log the move + if ($null -ne $MoveLog) { + $normalizedOriginal = [System.IO.Path]::GetFullPath($firstFile.FullName) + $normalizedNew = [System.IO.Path]::GetFullPath($destinationPath) + $null = $MoveLog.Add([PSCustomObject]@{ + OriginalPath = $normalizedOriginal + NewPath = $normalizedNew + Type = "moved" + }) + } + } catch { + Write-Warning "Failed to move first duplicate file: $($firstFile.FullName) - $($_.Exception.Message)" + } + + # Delete remaining duplicate files (they're replaced by the common file) + for ($i = 1; $i -lt $Files.Count; $i++) { + $fileObj = $Files[$i].File + try { + $originalPath = $fileObj.FullName + Remove-Item -Path $originalPath -Force + $duplicateCount++ + + # Log the deletion (replaced by the moved file) + if ($null -ne $MoveLog) { + $normalizedOriginal = [System.IO.Path]::GetFullPath($originalPath) + $normalizedReplacement = [System.IO.Path]::GetFullPath($destinationPath) + $null = $MoveLog.Add([PSCustomObject]@{ + OriginalPath = $normalizedOriginal + ReplacedBy = $normalizedReplacement + Type = "deleted" + }) + } + } catch { + Write-Warning "Failed to delete duplicate file: $($fileObj.FullName) - $($_.Exception.Message)" + } + } + + return @{ + MovedCount = $movedCount + DuplicateCount = $duplicateCount + } ``` -Additional data: - -```json -{ - "codeblockId": "c68d46a8-b351-4974-9135-75342cd43f22" -} -``` -Status: **completed** -
+
--- @@ -15963,29 +16740,23 @@ Updating Pass 1 to track moves: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell +} else { + Write-Host "Found $($blendfileFolders.Count) blendfile folder(s) to process." -ForegroundColor Green + + $totalPass1Moved = 0 + $totalPass1Duplicates = 0 + $pass1MoveLog = [System.Collections.ArrayList]::new() + + foreach ($blendfileFolder in $blendfileFolders) { ``` -Additional data: - -```json -{ - "codeblockId": "31268d32-79a3-4ef9-937d-c0a6361a87ea" -} -``` -Status: **completed** -
+
--- @@ -15996,29 +16767,24 @@ Status: **completed** --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # Process each checksum group + $blendfileMoved = 0 + $blendfileDuplicates = 0 + + foreach ($group in $groupedByChecksum) { + $result = Process-DuplicateGroup -Files $group.Group -CommonPath $blendfileCommonPath -FilesInCommon $filesInBlendfileCommon -MoveLog $pass1MoveLog + $blendfileMoved += $result.MovedCount + $blendfileDuplicates += $result.DuplicateCount + } ``` -Additional data: - -```json -{ - "codeblockId": "3ddff8b5-05e9-4947-a76f-31621596f4bd" -} -``` -Status: **completed** -
+
--- @@ -16029,29 +16795,35 @@ Updating Pass 2 to track moves for regular files: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # Process each checksum group (excluding FlatColors) + Write-Host "Moving files to \common and deleting duplicates..." -ForegroundColor Yellow + $pass2Moved = 0 + $pass2Duplicates = 0 + $pass2MoveLog = [System.Collections.ArrayList]::new() + + foreach ($group in $groupedByChecksum) { + $files = $group.Group + + if ($files.Count -eq 1) { + # Single file - leave in place (unique file) + continue + } + + # Multiple files with same checksum (duplicates across blendfiles) + # Use StripPrefix to remove blendfile prefixes (e.g., "Demarco_", "Chan_") when all files share the same suffix + $result = Process-DuplicateGroup -Files $files -CommonPath $rootCommonPath -FilesInCommon $filesInRootCommon -StripPrefix -ValidPrefixes $validBlendfilePrefixes -MoveLog $pass2MoveLog + $pass2Moved += $result.MovedCount + $pass2Duplicates += $result.DuplicateCount + } ``` -Additional data: - -```json -{ - "codeblockId": "1ad7aad6-265d-4a01-8ffc-d7368fb598b2" -} -``` -Status: **completed** -
+
--- @@ -16062,29 +16834,75 @@ Updating FlatColors processing to track moves: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # Track filenames already in \common\FlatColors + $filesInFlatColors = @{} + $flatColorsMoved = 0 + $flatColorsDuplicates = 0 + $flatColorsMoveLog = [System.Collections.ArrayList]::new() + + foreach ($group in $flatColorsGroupedByChecksum) { + $files = $group.Group + + if ($files.Count -eq 1) { + # Single file - move to FlatColors folder + $fileObj = $files[0].File + $fileName = $fileObj.Name + + # Strip blendfile prefix if present + $strippedName = Get-FileNameWithoutPrefix -FileName $fileName -ValidPrefixes $validBlendfilePrefixes + if ($strippedName -ne $fileName) { + $fileName = $strippedName + } + + $destinationPath = Join-Path -Path $flatColorsPath -ChildPath $fileName + + # Handle name conflicts (shouldn't happen for unique files, but just in case) + if ($filesInFlatColors.ContainsKey($fileName) -or (Test-Path -Path $destinationPath)) { + $baseName = [System.IO.Path]::GetFileNameWithoutExtension($fileName) + $extension = [System.IO.Path]::GetExtension($fileName) + $counter = 1 + do { + $newFileName = "${baseName}_${counter}${extension}" + $destinationPath = Join-Path -Path $flatColorsPath -ChildPath $newFileName + $counter++ + } while ($filesInFlatColors.ContainsKey($newFileName) -or (Test-Path -Path $destinationPath)) + $fileName = $newFileName + } + + try { + $originalPath = $fileObj.FullName + Move-Item -Path $originalPath -Destination $destinationPath -Force + $filesInFlatColors[$fileName] = $true + $flatColorsMoved++ + + # Log the move + $normalizedOriginal = [System.IO.Path]::GetFullPath($originalPath) + $normalizedNew = [System.IO.Path]::GetFullPath($destinationPath) + $null = $flatColorsMoveLog.Add([PSCustomObject]@{ + OriginalPath = $normalizedOriginal + NewPath = $normalizedNew + Type = "moved" + }) + } catch { + Write-Warning "Failed to move FlatColors file: $($fileObj.FullName) - $($_.Exception.Message)" + } + } else { + # Multiple files with same checksum (duplicates) - merge them + # Use Process-DuplicateGroup to handle merging + $result = Process-DuplicateGroup -Files $files -CommonPath $flatColorsPath -FilesInCommon $filesInFlatColors -StripPrefix -ValidPrefixes $validBlendfilePrefixes -MoveLog $flatColorsMoveLog + $flatColorsMoved += $result.MovedCount + $flatColorsDuplicates += $result.DuplicateCount + } + } ``` -Additional data: - -```json -{ - "codeblockId": "949e8451-7768-4feb-8ce9-d61c53d06f08" -} -``` -Status: **completed** -
+
--- @@ -16095,29 +16913,90 @@ Adding code to save the move log and find matching blend files. Adding it before --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: +```powershell +# ============================================================================ +# Save Move Log and Find Blend Files +# ============================================================================ +Write-Host "" +Write-Host "Saving move log and finding blend files..." -ForegroundColor Yellow -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" +# Combine all move logs +$allMoves = @() +if ($null -ne $pass1MoveLog -and $pass1MoveLog.Count -gt 0) { + $allMoves += $pass1MoveLog } -``` -Additional data: - -```json -{ - "codeblockId": "9e1fd6e6-5bd7-4e40-8499-3f39b7c8fe84" +if ($null -ne $pass2MoveLog -and $pass2MoveLog.Count -gt 0) { + $allMoves += $pass2MoveLog +} +if ($null -ne $flatColorsMoveLog -and $flatColorsMoveLog.Count -gt 0) { + $allMoves += $flatColorsMoveLog } -``` -Status: **completed** +# Get parent directory of texture folder +$blendFileParentDir = Split-Path -Path $textureFolderPath -Parent + +# Find matching blend files +$blendFileMappings = @() +if ($null -ne $blendfileFolders -and $blendfileFolders.Count -gt 0) { + # Get blendfile folder names + $blendfileFolderNames = $blendfileFolders | ForEach-Object { $_.Name } + + # Find all .blend files in parent directory + $blendFiles = Get-ChildItem -Path $blendFileParentDir -Filter "*.blend" -File -ErrorAction SilentlyContinue + + if ($null -ne $blendFiles -and $blendFiles.Count -gt 0) { + foreach ($blendFile in $blendFiles) { + # Extract prefix from blend file name (e.g., "Chan_v4.3.blend" -> "Chan") + $blendFileName = $blendFile.BaseName + $parts = $blendFileName.Split('_', 2) + + if ($parts.Length -ge 1) { + $prefix = $parts[0] + + # Check if prefix matches any blendfile folder name + if ($blendfileFolderNames -contains $prefix) { + $blendFileMappings += [PSCustomObject]@{ + BlendFile = [System.IO.Path]::GetFullPath($blendFile.FullName) + BlendfileFolder = $prefix + } + Write-Host "Found matching blend file: $($blendFile.Name) -> $prefix" -ForegroundColor Gray + } + } + } + } +} + +# Create move log object +$moveLogData = [PSCustomObject]@{ + TextureFolderPath = $textureFolderPath + Timestamp = (Get-Date -Format "yyyy-MM-ddTHH:mm:ssZ") + TotalMoves = ($allMoves | Where-Object { $_.Type -eq "moved" }).Count + TotalDeletes = ($allMoves | Where-Object { $_.Type -eq "deleted" }).Count + Moves = $allMoves + BlendFileMappings = $blendFileMappings +} + +# Save to JSON file +$moveLogPath = Join-Path -Path $blendFileParentDir -ChildPath "texture_moves.json" +try { + $moveLogData | ConvertTo-Json -Depth 10 | Set-Content -Path $moveLogPath -Encoding UTF8 + Write-Host "Move log saved to: $moveLogPath" -ForegroundColor Green + Write-Host " Total moves: $($moveLogData.TotalMoves), Total deletes: $($moveLogData.TotalDeletes)" -ForegroundColor Gray + Write-Host " Blend files found: $($blendFileMappings.Count)" -ForegroundColor Gray +} catch { + Write-Warning "Failed to save move log: $($_.Exception.Message)" +} + +# Function to remove empty folders recursively +function Remove-EmptyFolders { +```
+
--- @@ -16140,7 +17019,6 @@ Continue _**Agent (model default, mode Agent)**_ - Adding the PowerShell wrapper to call Blender with the remapping script. Adding it to the end of `organize_textures.ps1`: @@ -16154,40 +17032,152 @@ Adding the PowerShell wrapper to call Blender with the remapping script. Adding --- - Adding the PowerShell wrapper to remap blend files after saving the move log: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" +```powershell +} catch { + Write-Warning "Failed to save move log: $($_.Exception.Message)" } -``` -Additional data: -```json -{ - "codeblockId": "7f52cdaf-ab52-4aa6-8c0b-d398de4d6593" +# ============================================================================ +# Remap Texture Paths in Blend Files +# ============================================================================ +if ($blendFileMappings.Count -gt 0 -and (Test-Path -Path $moveLogPath)) { + Write-Host "" + Write-Host "Remapping texture paths in blend files..." -ForegroundColor Yellow + + # Find Blender executable + $blenderExe = $null + + # Common Blender installation paths + $possiblePaths = @( + "C:\Program Files\Blender Foundation\Blender *\blender.exe", + "C:\Program Files (x86)\Blender Foundation\Blender *\blender.exe", + "$env:LOCALAPPDATA\Programs\Blender Foundation\Blender *\blender.exe" + ) + + foreach ($pathPattern in $possiblePaths) { + $found = Get-ChildItem -Path $pathPattern -ErrorAction SilentlyContinue | Sort-Object LastWriteTime -Descending | Select-Object -First 1 + if ($null -ne $found) { + $blenderExe = $found.FullName + break + } + } + + # Also check PATH + if ($null -eq $blenderExe) { + $blenderInPath = Get-Command blender -ErrorAction SilentlyContinue + if ($null -ne $blenderInPath) { + $blenderExe = $blenderInPath.Source + } + } + + if ($null -eq $blenderExe) { + Write-Warning "Blender executable not found. Skipping texture path remapping." + Write-Host " Please install Blender or add it to your PATH." -ForegroundColor Yellow + } else { + Write-Host "Found Blender: $blenderExe" -ForegroundColor Gray + + # Get the remap script path (should be in the same directory as this script) + $scriptDir = Split-Path -Path $MyInvocation.MyCommand.Path -Parent + $remapScriptPath = Join-Path -Path $scriptDir -ChildPath "remap_texture_paths.py" + + if (-not (Test-Path -Path $remapScriptPath)) { + Write-Warning "Remap script not found: $remapScriptPath" + Write-Warning "Skipping texture path remapping." + } else { + $processedCount = 0 + $failedCount = 0 + + foreach ($mapping in $blendFileMappings) { + $blendFilePath = $mapping.BlendFile + $blendFileName = Split-Path -Path $blendFilePath -Leaf + + Write-Host "" + Write-Host "Processing: $blendFileName" -ForegroundColor Cyan + + # Check if blend file exists + if (-not (Test-Path -Path $blendFilePath)) { + Write-Warning " Blend file not found: $blendFilePath" + $failedCount++ + continue + } + + # Run Blender with the remapping script + $blenderArgs = @( + "--background", + "--factory-startup", + "--python", $remapScriptPath, + "--", + $blendFilePath, + $moveLogPath + ) + + try { + $process = Start-Process -FilePath $blenderExe -ArgumentList $blenderArgs -Wait -NoNewWindow -PassThru -RedirectStandardOutput "blender_output.txt" -RedirectStandardError "blender_error.txt" + + if ($process.ExitCode -eq 0) { + Write-Host " Successfully remapped texture paths" -ForegroundColor Green + $processedCount++ + + # Show summary from output if available + if (Test-Path -Path "blender_output.txt") { + $output = Get-Content -Path "blender_output.txt" -ErrorAction SilentlyContinue + $summaryLine = $output | Select-String -Pattern "Paths remapped:" + if ($summaryLine) { + Write-Host " $summaryLine" -ForegroundColor Gray + } + } + } else { + Write-Warning " Failed to remap texture paths (exit code: $($process.ExitCode))" + $failedCount++ + + # Show error if available + if (Test-Path -Path "blender_error.txt") { + $errorContent = Get-Content -Path "blender_error.txt" -ErrorAction SilentlyContinue | Select-Object -Last 5 + if ($errorContent) { + Write-Host " Error output:" -ForegroundColor Red + $errorContent | ForEach-Object { Write-Host " $_" -ForegroundColor Red } + } + } + } + } catch { + Write-Warning " Exception while processing blend file: $($_.Exception.Message)" + $failedCount++ + } + } + + # Clean up temporary output files + Remove-Item -Path "blender_output.txt" -ErrorAction SilentlyContinue + Remove-Item -Path "blender_error.txt" -ErrorAction SilentlyContinue + + Write-Host "" + Write-Host "Blend file remapping complete: $processedCount succeeded, $failedCount failed" -ForegroundColor $(if ($failedCount -eq 0) { "Green" } else { "Yellow" }) + } + } +} else { + if ($blendFileMappings.Count -eq 0) { + Write-Host "" + Write-Host "No matching blend files found. Skipping texture path remapping." -ForegroundColor Gray + } } -``` -Status: **completed** +# Function to remove empty folders recursively +```
+
--- - Reviewing the Python script to fix path lookup issues: @@ -16201,106 +17191,139 @@ Reviewing the Python script to fix path lookup issues: --- - Simplifying the Python script's path lookup logic: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\remap_texture_paths.py -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\remap_texture_paths.py" -} +```python +def load_move_log(json_path): + """Load the move log JSON file and build lookup dictionaries""" + try: + with open(json_path, 'r', encoding='utf-8') as f: + data = json.load(f) + + moves = data.get('moves', []) + + # Build lookup dictionaries: normalized original path -> actual new path + original_to_new = {} + original_to_replacement = {} + + for move in moves: + move_type = move.get('type', '') + original = move.get('originalPath', '') + + if not original: + continue + + orig_norm = normalize_path(original) + + if move_type == 'moved': + new_path = move.get('newPath', '') + if new_path: + original_to_new[orig_norm] = new_path + + elif move_type == 'deleted': + replacement = move.get('replacedBy', '') + if replacement: + original_to_replacement[orig_norm] = replacement + + return original_to_new, original_to_replacement, data.get('textureFolderPath', '') + + except Exception as e: + print(f"ERROR: Failed to load move log: {e}") + return {}, {}, "" ``` -Additional data: - -```json -{ - "codeblockId": "c5de5c60-d004-4d25-9bac-f7381ba22680" -} -``` -Status: **completed** -
+
--- - Simplifying the remapping logic: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\remap_texture_paths.py -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\remap_texture_paths.py" -} +```python + abs_norm = normalize_path(abs_path) + was_relative = not os.path.isabs(image.filepath) + + # Check if this path needs remapping + new_path = None + + # First check moved files + if abs_norm in original_to_new: + new_path = original_to_new[abs_norm] + + # Then check deleted files (replaced by) + elif abs_norm in original_to_replacement: + new_path = original_to_replacement[abs_norm] + + if new_path: ``` -Additional data: - -```json -{ - "codeblockId": "d3842818-a68f-4257-85ba-b97b88f14c87" -} -``` -Status: **completed** -
+
--- - Fixing the material node remapping section: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\remap_texture_paths.py -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\remap_texture_paths.py" -} +```python + # Also check material node trees for image texture nodes + # Note: Most image texture nodes reference the image datablock (which we already remapped above), + # but we check node.filepath for completeness in case any nodes have direct file paths + print("\nRemapping material node texture paths...") + node_remapped_count = 0 + for material in bpy.data.materials: + if not material.use_nodes or not material.node_tree: + continue + + for node in material.node_tree.nodes: + if node.type == 'TEX_IMAGE' and hasattr(node, 'filepath') and node.filepath: + abs_path = bpy.path.abspath(node.filepath) + if abs_path: + abs_norm = normalize_path(abs_path) + + new_path = None + if abs_norm in original_to_new: + new_path = original_to_new[abs_norm] + elif abs_norm in original_to_replacement: + new_path = original_to_replacement[abs_norm] + + if new_path: + node.filepath = new_path + print(f" Remapped node texture: {os.path.basename(abs_path)} -> {os.path.basename(new_path)}") + node_remapped_count += 1 + + if node_remapped_count > 0: + remapped_count += node_remapped_count ``` -Additional data: - -```json -{ - "codeblockId": "981b6fc3-70c6-48bd-a7cd-824de4ee5dbb" -} -``` -Status: **completed** -
+
--- - Implementation complete. Summary: 1. **Move tracking**: Modified `Process-DuplicateGroup` to accept a `MoveLog` parameter and log moves/deletions @@ -16330,7 +17353,6 @@ _**User**_ _**Agent (model default, mode Agent)**_ - Restoring automatic remapping after texture organization, processing all blend files in batch like `compress_blend_files.bat`. Checking how that script handles batch processing: @@ -16344,7 +17366,6 @@ Restoring automatic remapping after texture organization, processing all blend f --- - Restoring automatic remapping in `organize_textures.ps1` to process all blend files in batch: @@ -16358,40 +17379,154 @@ Restoring automatic remapping in `organize_textures.ps1` to process all blend fi --- - Adding automatic remapping that processes all blend files: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" +```powershell +} catch { + Write-Warning "Failed to save move log: $($_.Exception.Message)" } -``` -Additional data: -```json -{ - "codeblockId": "273aa3fe-8a42-487f-93b9-90ec673955f3" +# ============================================================================ +# Remap Texture Paths in Blend Files +# ============================================================================ +if ($blendFileMappings.Count -gt 0 -and (Test-Path -Path $moveLogPath)) { + Write-Host "" + Write-Host "Remapping texture paths in blend files..." -ForegroundColor Yellow + + # Find Blender executable + $blenderExe = $null + + # Common Blender installation paths + $possiblePaths = @( + "C:\Program Files\Blender Foundation\Blender *\blender.exe", + "C:\Program Files (x86)\Blender Foundation\Blender *\blender.exe", + "$env:LOCALAPPDATA\Programs\Blender Foundation\Blender *\blender.exe" + ) + + foreach ($pathPattern in $possiblePaths) { + $found = Get-ChildItem -Path $pathPattern -ErrorAction SilentlyContinue | Sort-Object LastWriteTime -Descending | Select-Object -First 1 + if ($null -ne $found) { + $blenderExe = $found.FullName + break + } + } + + # Also check PATH + if ($null -eq $blenderExe) { + $blenderInPath = Get-Command blender -ErrorAction SilentlyContinue + if ($null -ne $blenderInPath) { + $blenderExe = $blenderInPath.Source + } + } + + if ($null -eq $blenderExe) { + Write-Warning "Blender executable not found. Skipping texture path remapping." + Write-Host " Please install Blender or add it to your PATH." -ForegroundColor Yellow + } else { + Write-Host "Found Blender: $blenderExe" -ForegroundColor Gray + + # Get the remap script path (should be in the same directory as this script) + $scriptDir = Split-Path -Path $MyInvocation.MyCommand.Path -Parent + $remapScriptPath = Join-Path -Path $scriptDir -ChildPath "remap_texture_paths.py" + + if (-not (Test-Path -Path $remapScriptPath)) { + Write-Warning "Remap script not found: $remapScriptPath" + Write-Warning "Skipping texture path remapping." + } else { + $processedCount = 0 + $failedCount = 0 + + Write-Host "Processing $($blendFileMappings.Count) blend file(s)..." -ForegroundColor Gray + + foreach ($mapping in $blendFileMappings) { + $blendFilePath = $mapping.BlendFile + $blendFileName = Split-Path -Path $blendFilePath -Leaf + + Write-Host " Processing: $blendFileName" -ForegroundColor Cyan + + # Check if blend file exists + if (-not (Test-Path -Path $blendFilePath)) { + Write-Warning " Blend file not found: $blendFilePath" + $failedCount++ + continue + } + + # Run Blender with the remapping script (one file at a time) + $blenderArgs = @( + "--background", + "--factory-startup", + "--python", $remapScriptPath, + "--", + $blendFilePath, + $moveLogPath + ) + + try { + $process = Start-Process -FilePath $blenderExe -ArgumentList $blenderArgs -Wait -NoNewWindow -PassThru -RedirectStandardOutput "blender_output.txt" -RedirectStandardError "blender_error.txt" + + if ($process.ExitCode -eq 0) { + Write-Host " Successfully remapped texture paths" -ForegroundColor Green + $processedCount++ + + # Show summary from output if available + if (Test-Path -Path "blender_output.txt") { + $output = Get-Content -Path "blender_output.txt" -ErrorAction SilentlyContinue + $summaryLine = $output | Select-String -Pattern "Paths remapped:" + if ($summaryLine) { + Write-Host " $summaryLine" -ForegroundColor Gray + } + } + } else { + Write-Warning " Failed to remap texture paths (exit code: $($process.ExitCode))" + $failedCount++ + + # Show error if available + if (Test-Path -Path "blender_error.txt") { + $errorContent = Get-Content -Path "blender_error.txt" -ErrorAction SilentlyContinue | Select-Object -Last 3 + if ($errorContent) { + $errorContent | ForEach-Object { Write-Host " $_" -ForegroundColor Red } + } + } + } + } catch { + Write-Warning " Exception while processing blend file: $($_.Exception.Message)" + $failedCount++ + } + } + + # Clean up temporary output files + Remove-Item -Path "blender_output.txt" -ErrorAction SilentlyContinue + Remove-Item -Path "blender_error.txt" -ErrorAction SilentlyContinue + + Write-Host "" + if ($processedCount -gt 0 -or $failedCount -gt 0) { + Write-Host "Blend file remapping complete: $processedCount succeeded, $failedCount failed" -ForegroundColor $(if ($failedCount -eq 0) { "Green" } else { "Yellow" }) + } + } + } +} else { + if ($blendFileMappings.Count -eq 0) { + Write-Host "" + Write-Host "No matching blend files found. Skipping texture path remapping." -ForegroundColor Gray + } } -``` -Status: **completed** +# Function to remove empty folders recursively +```
+
--- - Restored automatic remapping. After texture organization, it will: 1. **Automatically find all matching blend files** (by prefix matching) @@ -16413,7 +17548,6 @@ _**User**_ _**Agent (model default, mode Agent)**_ - Blender is receiving an unquoted script path with spaces, so it only sees "A:\1". Quoting the Python script path in the PowerShell arguments: @@ -16427,73 +17561,65 @@ Blender is receiving an unquoted script path with spaces, so it only sees "A:\1" --- - Fixing path quoting so paths with spaces are handled correctly: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # Run Blender with the remapping script (one file at a time) + # Quote paths that contain spaces to avoid argument parsing issues + $quotedRemapScript = if ($remapScriptPath -match ' ') { "`"$remapScriptPath`"" } else { $remapScriptPath } + $quotedBlendFile = if ($blendFilePath -match ' ') { "`"$blendFilePath`"" } else { $blendFilePath } + $quotedMoveLog = if ($moveLogPath -match ' ') { "`"$moveLogPath`"" } else { $moveLogPath } + + $blenderArgs = @( + "--background", + "--factory-startup", + "--python", $quotedRemapScript, + "--", + $quotedBlendFile, + $quotedMoveLog + ) + + try { + $process = Start-Process -FilePath $blenderExe -ArgumentList $blenderArgs -Wait -NoNewWindow -PassThru -RedirectStandardOutput "blender_output.txt" -RedirectStandardError "blender_error.txt" ``` -Additional data: - -```json -{ - "codeblockId": "f252e947-1fdf-4d48-bfa0-040a3a2fe751" -} -``` -Status: **completed** -
+
--- - Switching to a single argument string for better reliability with paths containing spaces: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # Run Blender with the remapping script (one file at a time) + # Build argument string with proper quoting for paths with spaces + $blenderArgs = "--background --factory-startup --python `"$remapScriptPath`" -- `"$blendFilePath`" `"$moveLogPath`"" + + try { + $process = Start-Process -FilePath $blenderExe -ArgumentList $blenderArgs -Wait -NoNewWindow -PassThru -RedirectStandardOutput "blender_output.txt" -RedirectStandardError "blender_error.txt" ``` -Additional data: - -```json -{ - "codeblockId": "2e630f98-e82b-4307-9f19-dd00ee441c50" -} -``` -Status: **completed** -
+
--- - Fixed the path quoting issue. The script now builds a single argument string with proper quotes around paths that contain spaces. This ensures Blender receives the full paths correctly. The fix: @@ -16513,7 +17639,6 @@ _**User**_ _**Agent (model default, mode Agent)**_ - Checking the Python script to see where it saves the blend files: @@ -16527,7 +17652,6 @@ Checking the Python script to see where it saves the blend files: --- - The script saves to the original blend file path, overwriting it. Checking what path is passed from PowerShell: @@ -16541,7 +17665,6 @@ The script saves to the original blend file path, overwriting it. Checking what --- - The script saves to the original blend file location, overwriting the files. It uses `$mapping.BlendFile`, which is the full path to each blend file (e.g., `T:\1 BlenderAssets\Amazon\Char\Cartoon1\Chan_v4.3.blend`). So the remapped blend files are saved in place: @@ -16563,7 +17686,6 @@ Let's have it use the same Blender that's on PATH. _**Agent (model default, mode Agent)**_ - Updating the script to use Blender from PATH and checking why the files aren't saving: @@ -16577,40 +17699,30 @@ Updating the script to use Blender from PATH and checking why the files aren't s --- - Simplifying Blender path finding to use PATH only, and checking the Python script for save issues: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # Find Blender executable from PATH + $blenderExe = $null + $blenderInPath = Get-Command blender -ErrorAction SilentlyContinue + if ($null -ne $blenderInPath) { + $blenderExe = $blenderInPath.Source + } ``` -Additional data: - -```json -{ - "codeblockId": "3fb276d3-ae18-4c24-8dc3-0a2e22471153" -} -``` -Status: **completed** -
+
--- - Checking the Python script to see why files aren't saving: @@ -16624,7 +17736,6 @@ Checking the Python script to see why files aren't saving: --- - Checking the save operation in the remap function and ensuring it completes: @@ -16638,40 +17749,46 @@ Checking the save operation in the remap function and ensuring it completes: --- - Ensuring the save uses an absolute path and adding error handling: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\remap_texture_paths.py -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\remap_texture_paths.py" -} +```python + # Save the blend file + try: + print(f"\nSaving blend file...") + # Ensure we use an absolute path + abs_blend_path = os.path.abspath(blend_file_path) + print(f" Saving to: {abs_blend_path}") + bpy.ops.wm.save_mainfile(filepath=abs_blend_path) + + # Verify the file was actually saved + if os.path.exists(abs_blend_path): + file_time = os.path.getmtime(abs_blend_path) + print(f"Successfully saved: {abs_blend_path}") + print(f" File modified time: {file_time}") + return remapped_count + else: + print(f"ERROR: File was not created at {abs_blend_path}") + return -1 + except Exception as e: + print(f"ERROR: Failed to save blend file: {e}") + import traceback + traceback.print_exc() + return -1 ``` -Additional data: - -```json -{ - "codeblockId": "21ba993f-041e-40e4-b94e-d437688a9769" -} -``` -Status: **completed** -
+
--- - Updating the PowerShell script to show more output from Blender to diagnose the issue: @@ -16685,40 +17802,58 @@ Updating the PowerShell script to show more output from Blender to diagnose the --- - Updating the script to show more Blender output to diagnose the save issue: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # Show output for debugging + if (Test-Path -Path "blender_output.txt") { + $output = Get-Content -Path "blender_output.txt" -ErrorAction SilentlyContinue + $saveLine = $output | Select-String -Pattern "Saving blend file|Successfully saved|ERROR.*save|File modified time" + if ($saveLine) { + $saveLine | ForEach-Object { Write-Host " $_" -ForegroundColor Gray } + } + } + + if ($process.ExitCode -eq 0) { + Write-Host " Successfully remapped texture paths" -ForegroundColor Green + $processedCount++ + + # Show summary from output if available + if (Test-Path -Path "blender_output.txt") { + $output = Get-Content -Path "blender_output.txt" -ErrorAction SilentlyContinue + $summaryLine = $output | Select-String -Pattern "Paths remapped:" + if ($summaryLine) { + Write-Host " $summaryLine" -ForegroundColor Gray + } + } + } else { + Write-Warning " Failed to remap texture paths (exit code: $($process.ExitCode))" + $failedCount++ + + # Show error if available + if (Test-Path -Path "blender_error.txt") { + $errorContent = Get-Content -Path "blender_error.txt" -ErrorAction SilentlyContinue | Select-Object -Last 5 + if ($errorContent) { + Write-Host " Error output:" -ForegroundColor Red + $errorContent | ForEach-Object { Write-Host " $_" -ForegroundColor Red } + } + } + } ``` -Additional data: - -```json -{ - "codeblockId": "a57b0186-85c8-4a2f-9358-885912d58afe" -} -``` -Status: **completed** -
+
--- - Made two changes: 1. **Simplified Blender path finding** — now uses only PATH (removed the search through common installation paths) @@ -16747,7 +17882,6 @@ _**User**_ _**Agent (model default, mode Agent)**_ - Checking how `compress_blend_files.bat` handles output, then updating the remapping section to show full Blender output: @@ -16761,7 +17895,6 @@ Checking how `compress_blend_files.bat` handles output, then updating the remapp --- - Updating the PowerShell script to display Blender output in real time, similar to `compress_blend_files.bat`: @@ -16775,106 +17908,160 @@ Updating the PowerShell script to display Blender output in real time, similar t --- - Updating the script to display Blender output in real time: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # Run Blender with the remapping script (one file at a time) + # Build argument string with proper quoting for paths with spaces + $blenderArgs = "--background --factory-startup --python `"$remapScriptPath`" -- `"$blendFilePath`" `"$moveLogPath`"" + + # Delete old output file + Remove-Item -Path "blender_output.txt" -ErrorAction SilentlyContinue + + try { + # Run Blender and capture output while displaying it (like compress_blend_files.bat) + $process = Start-Process -FilePath $blenderExe -ArgumentList $blenderArgs -Wait -NoNewWindow -PassThru -RedirectStandardOutput "blender_output.txt" -RedirectStandardError "blender_output.txt" + + # Display all output + if (Test-Path -Path "blender_output.txt") { + $output = Get-Content -Path "blender_output.txt" -ErrorAction SilentlyContinue + if ($output) { + $output | ForEach-Object { Write-Host " $_" } + } + } + + if ($process.ExitCode -eq 0) { + Write-Host " Successfully remapped texture paths" -ForegroundColor Green + $processedCount++ + } else { + Write-Warning " Failed to remap texture paths (exit code: $($process.ExitCode))" + $failedCount++ + } + } catch { + Write-Warning " Exception while processing blend file: $($_.Exception.Message)" + $failedCount++ + } ``` -Additional data: - -```json -{ - "codeblockId": "d1c2af27-1264-47c4-a06c-81aba2f3353f" -} -``` -Status: **completed** -
+
--- - Updating to stream output in real time, similar to `compress_blend_files.bat`: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # Run Blender with the remapping script (one file at a time) + # Build argument string with proper quoting for paths with spaces + $blenderArgs = "--background --factory-startup --python `"$remapScriptPath`" -- `"$blendFilePath`" `"$moveLogPath`"" + + # Delete old output file + Remove-Item -Path "blender_output.txt" -ErrorAction SilentlyContinue + + try { + # Run Blender and capture output while displaying it (like compress_blend_files.bat) + # Use & to invoke and pipe through Tee-Object to display and save simultaneously + $exitCode = 0 + & $blenderExe $blenderArgs.Split(' ') 2>&1 | Tee-Object -FilePath "blender_output.txt" | ForEach-Object { + Write-Host " $_" + # Check for error indicators in output + if ($_ -match "ERROR|Traceback|Exception") { + $script:exitCode = 1 + } + } + + # Check exit code from the last command + if ($LASTEXITCODE -ne 0) { + $exitCode = $LASTEXITCODE + } + + if ($exitCode -eq 0) { + Write-Host " Successfully remapped texture paths" -ForegroundColor Green + $processedCount++ + } else { + Write-Warning " Failed to remap texture paths (exit code: $exitCode)" + $failedCount++ + } + } catch { + Write-Warning " Exception while processing blend file: $($_.Exception.Message)" + $failedCount++ + } ``` -Additional data: - -```json -{ - "codeblockId": "7ead3d3c-669c-45b3-bb80-594af0d0253a" -} -``` -Status: **completed** -
+
--- - Fixing argument handling to preserve quotes: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.ps1" -} +```powershell + # Run Blender with the remapping script (one file at a time) + # Delete old output file + Remove-Item -Path "blender_output.txt" -ErrorAction SilentlyContinue + + try { + # Run Blender and capture output while displaying it (like compress_blend_files.bat) + # Build command with proper argument array + $blenderArgsArray = @( + "--background", + "--factory-startup", + "--python", $remapScriptPath, + "--", + $blendFilePath, + $moveLogPath + ) + + # Execute and pipe output through Tee-Object to display and save + & $blenderExe $blenderArgsArray 2>&1 | Tee-Object -FilePath "blender_output.txt" | ForEach-Object { + Write-Host " $_" + } + + # Check exit code + $exitCode = $LASTEXITCODE + + if ($exitCode -eq 0) { + Write-Host " Successfully remapped texture paths" -ForegroundColor Green + $processedCount++ + } else { + Write-Warning " Failed to remap texture paths (exit code: $exitCode)" + $failedCount++ + } + } catch { + Write-Warning " Exception while processing blend file: $($_.Exception.Message)" + $failedCount++ + } ``` -Additional data: - -```json -{ - "codeblockId": "169577e0-3e15-408e-a38b-34eaf9ee2591" -} -``` -Status: **completed** -
+
--- - Updated the script to display all Blender output in real time, similar to `compress_blend_files.bat`. It now: 1. Uses an argument array (handles paths with spaces) @@ -16924,29 +18111,67 @@ Adding debug output to the Python script to inspect the loaded JSON: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\remap_texture_paths.py -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\remap_texture_paths.py" -} +```python +def load_move_log(json_path): + """Load the move log JSON file and build lookup dictionaries""" + try: + with open(json_path, 'r', encoding='utf-8') as f: + data = json.load(f) + + # Debug: Check what keys are in the data + print(f" JSON keys: {list(data.keys())}") + + # PowerShell ConvertTo-Json uses PascalCase by default, so check both cases + moves = data.get('moves', []) or data.get('Moves', []) + + print(f" Found {len(moves)} move entries in JSON") + + if len(moves) > 0: + # Debug: Show first move entry structure + print(f" First move entry keys: {list(moves[0].keys())}") + print(f" First move entry: {moves[0]}") + + # Build lookup dictionaries: normalized original path -> actual new path + original_to_new = {} + original_to_replacement = {} + + for move in moves: + # Try both camelCase and PascalCase property names + move_type = move.get('type', '') or move.get('Type', '') + original = move.get('originalPath', '') or move.get('OriginalPath', '') + + if not original: + continue + + orig_norm = normalize_path(original) + + if move_type == 'moved' or move_type == 'Moved': + new_path = move.get('newPath', '') or move.get('NewPath', '') + if new_path: + original_to_new[orig_norm] = new_path + + elif move_type == 'deleted' or move_type == 'Deleted': + replacement = move.get('replacedBy', '') or move.get('ReplacedBy', '') + if replacement: + original_to_replacement[orig_norm] = replacement + + print(f" Built {len(original_to_new)} move mappings and {len(original_to_replacement)} replacement mappings") + + return original_to_new, original_to_replacement, data.get('textureFolderPath', '') or data.get('TextureFolderPath', '') + + except Exception as e: + print(f"ERROR: Failed to load move log: {e}") + import traceback + traceback.print_exc() + return {}, {}, "" ``` -Additional data: - -```json -{ - "codeblockId": "dfbcefe1-5f53-460d-b223-d89dccc9d572" -} -``` -Status: **completed** -
+
--- @@ -16970,7 +18195,6 @@ incredible! now we just need to make sure to run bpy.ops.file.make_paths_relativ _**Agent (model default, mode Agent)**_ - Adding `bpy.ops.file.make_paths_relative()` after remapping to convert absolute paths to relative: @@ -16986,38 +18210,40 @@ Adding `bpy.ops.file.make_paths_relative()` after remapping to convert absolute - - --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\remap_texture_paths.py -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\remap_texture_paths.py" -} +```python + print(f"\n=== REMAPPING SUMMARY ===") + print(f"Paths remapped: {remapped_count}") + print(f"Broken references (not found): {not_found_count}") + + # Make all paths relative after remapping + try: + print(f"\nMaking paths relative...") + bpy.ops.file.make_paths_relative() + print(f" Converted absolute paths to relative paths") + except Exception as e: + print(f" Warning: Failed to make paths relative: {e}") + + # Save the blend file + try: + print(f"\nSaving blend file...") + # Ensure we use an absolute path + abs_blend_path = os.path.abspath(blend_file_path) + print(f" Saving to: {abs_blend_path}") + bpy.ops.wm.save_mainfile(filepath=abs_blend_path) ``` -Additional data: - -```json -{ - "codeblockId": "cf7dff8c-38d3-4fab-8987-6fc7cd6438ac" -} -``` -Status: **completed** -
+
--- - Added `bpy.ops.file.make_paths_relative()` after remapping and before saving. The script will: 1. Remap all texture paths to their new locations @@ -17040,3 +18266,280 @@ _**Agent (model default, mode Agent)**_ --- +Updating the remapping script to convert absolute image texture paths to relative, ignoring paths from linked files. Checking the current script: + + +--- + + +
Tool use: **read_file_v2** • Read file: a:\1 Amazon_Active_Projects\3 ProjectStructure\remap_texture_paths.py + +
+
+ +--- + +Updating the script to convert absolute image texture paths to relative, skipping paths from linked files: + + +--- + + + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\remap_texture_paths.py + +```python + if node_remapped_count > 0: + remapped_count += node_remapped_count + + # Convert any remaining absolute paths in image datablocks to relative + # (ignoring images from linked files) + print("\nConverting absolute image paths to relative...") + abs_to_rel_count = 0 + for image in bpy.data.images: + # Skip images from linked files (library datablocks) + if image.library: + continue + + if not image.filepath: + continue + + # Check if path is absolute + if os.path.isabs(image.filepath): + try: + # Convert to relative path + rel_path = bpy.path.relpath(image.filepath, blend_file_dir) + if rel_path != image.filepath: + image.filepath = rel_path + print(f" Converted to relative: {os.path.basename(image.filepath)}") + abs_to_rel_count += 1 + except Exception as e: + # If conversion fails, skip it (might be a network path or other issue) + pass + + if abs_to_rel_count > 0: + remapped_count += abs_to_rel_count + + print(f"\n=== REMAPPING SUMMARY ===") + print(f"Paths remapped: {remapped_count}") + print(f"Broken references (not found): {not_found_count}") + + # Make all paths relative after remapping (this handles other datablock types) + try: + print(f"\nMaking paths relative...") + bpy.ops.file.make_paths_relative() + print(f" Converted absolute paths to relative paths") + except Exception as e: + print(f" Warning: Failed to make paths relative: {e}") +``` + +
+ +
+ +--- + +Updated the script to convert absolute image texture paths to relative. Changes: + +1. **After remapping from the move log**, it scans all image datablocks for remaining absolute paths. +2. **Skips images from linked files** by checking `image.library` (e.g., paths from `Cartoon1_006.blend`). +3. **Converts absolute paths to relative** using `bpy.path.relpath()`. + +This ensures absolute image paths (like in Kirk) are converted to relative, while ignoring linked file paths. The script still calls `bpy.ops.file.make_paths_relative()` at the end for other datablock types, but the explicit image path conversion happens first and handles the image textures specifically. + +When you run the script again, it should convert any absolute image paths to relative, even if they weren't in the move log. + +--- + +_**User**_ + +The texture folders don't have versioning, while the blendfiles do. It's ignoring the corresponding blendfiles due to their names. \\textures\Beth belongs to AM_Beth_v3.2.blend, etc. + +``` +Running texture organizer... +Enter texture folder path: T:\1 BlenderAssets\Amazon\Char\Cartoon2\AM +Processing texture folder: T:\1 BlenderAssets\Amazon\Char\Cartoon2\AM + +=== PASS 1: Intra-Blendfile Processing === +Found 1 blendfile folder(s) to process. + +Processing blendfile: textures + Found 330 files. + Calculating checksums... + Found 240 unique checksums. + Moved 51 file(s) to \common, deleted 90 duplicate(s) + +Pass 1 complete: 51 file(s) moved, 90 duplicate(s) deleted + +=== PASS 2: Inter-Blendfile Processing === +Valid blendfile prefixes: textures +Collecting FlatColors files... +Collecting remaining files... +Found 193 remaining files to process. +Calculating checksums using parallel processing (this may take a while)... +Checksum calculation complete. +Identifying FlatColors files... +Found 15 FlatColors file(s) (including from \common\FlatColors folders), 193 other file(s) +Grouping files by checksum... +Found 193 unique checksums. +Created directory: T:\1 BlenderAssets\Amazon\Char\Cartoon2\AM\common +Moving files to \common and deleting duplicates... +Processing FlatColors files (merging duplicates)... +Found 15 FlatColors file(s) to process +Calculating checksums for FlatColors files... +Found 6 unique FlatColors file(s) +Created directory: T:\1 BlenderAssets\Amazon\Char\Cartoon2\AM\common\FlatColors +Moved 6 unique FlatColors file(s) to \common\FlatColors, deleted 9 duplicate(s) + +Pass 2 complete: 0 file(s) moved to \common, 0 duplicate(s) deleted + +Saving move log and finding blend files... +Move log saved to: T:\1 BlenderAssets\Amazon\Char\Cartoon2\texture_moves.json + Total moves: 57, Total deletes: 99 + Blend files found: 0 + +No matching blend files found. Skipping texture path remapping. + +Removing empty folders... +Removed 43 empty folder(s) + +File organization complete! + +Press any key to continue . . . +``` + +--- + +_**Agent (model default, mode Agent)**_ + + +Updating the blend file matching logic to handle versioned blend files. Checking the current matching code: + + +--- + + +
Tool use: **read_file_v2** • Read file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 + +
+
+ +--- + + + + + +--- + + +
Tool use: **read_file_v2** • Read file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 + +
+
+ +--- + + +Updating the matching logic: instead of extracting a prefix from the blend file, check if the blend file name contains the blendfile folder name (e.g., `AM_Beth_v3.2.blend` contains `Beth`). + + +--- + + + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 + +```powershell +# Find matching blend files +# Match logic: blendfile folder name (e.g., "Beth") should appear in blend file name (e.g., "AM_Beth_v3.2.blend") +$blendFileMappings = @() +if ($null -ne $blendfileFolders -and $blendfileFolders.Count -gt 0) { + # Get blendfile folder names + $blendfileFolderNames = $blendfileFolders | ForEach-Object { $_.Name } + + # Find all .blend files in parent directory + $blendFiles = Get-ChildItem -Path $blendFileParentDir -Filter "*.blend" -File -ErrorAction SilentlyContinue + + if ($null -ne $blendFiles -and $blendFiles.Count -gt 0) { + foreach ($blendFile in $blendFiles) { + $blendFileName = $blendFile.BaseName + + # Check if any blendfile folder name appears in the blend file name + foreach ($folderName in $blendfileFolderNames) { + # Use word boundary matching to avoid partial matches (e.g., "Beth" in "Bethany") + # Check if folder name appears as a whole word in the blend file name + if ($blendFileName -match "\b$([regex]::Escape($folderName))\b") { + $blendFileMappings += [PSCustomObject]@{ + BlendFile = [System.IO.Path]::GetFullPath($blendFile.FullName) + BlendfileFolder = $folderName + } + Write-Host "Found matching blend file: $($blendFile.Name) -> $folderName" -ForegroundColor Gray + break # Only match once per blend file + } + } + } + } +} +``` + +
+ +
+ +--- + + +Fixing the regex: word boundaries don't match at underscores. Updating to match the folder name when surrounded by underscores, dots, or at the start/end: + + +--- + + + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 + +```powershell + # Check if any blendfile folder name appears in the blend file name + foreach ($folderName in $blendfileFolderNames) { + # Match folder name when surrounded by underscores, dots, hyphens, or at start/end + # This avoids partial matches (e.g., "Beth" in "Bethany") while allowing "Beth" in "AM_Beth_v3.2" + $escapedFolderName = [regex]::Escape($folderName) + if ($blendFileName -match "(^|[._-])$escapedFolderName([._-]|$)") { + $blendFileMappings += [PSCustomObject]@{ + BlendFile = [System.IO.Path]::GetFullPath($blendFile.FullName) + BlendfileFolder = $folderName + } + Write-Host "Found matching blend file: $($blendFile.Name) -> $folderName" -ForegroundColor Gray + break # Only match once per blend file + } + } +``` + +
+ +
+ +--- + + +Updated the blend file matching logic: + +1. **Reversed the matching approach**: Instead of extracting a prefix from the blend file and checking if it matches a folder, it checks if each blendfile folder name appears in the blend file name. + +2. **Uses word boundary matching**: The regex pattern `(^|[._-])$escapedFolderName([._-]|$)` matches the folder name when it's: + - At the start of the filename, OR + - Preceded by an underscore, dot, or hyphen, OR + - Followed by an underscore, dot, or hyphen, OR + - At the end of the filename + +This means: +- `AM_Beth_v3.2.blend` will match the `Beth` folder (because `Beth` appears between underscores) +- `Beth_v3.2.blend` will match the `Beth` folder (at the start) +- `AM_Beth.blend` will match the `Beth` folder (at the end) +- `Bethany_v3.2.blend` will NOT match the `Beth` folder (to avoid partial matches) + +The script should now correctly find blend files like `AM_Beth_v3.2.blend` that correspond to texture folders like `\textures\Beth`. + +--- + diff --git a/organize_textures.ps1 b/organize_textures.ps1 index 488e3f2..e3af864 100644 --- a/organize_textures.ps1 +++ b/organize_textures.ps1 @@ -533,6 +533,7 @@ if ($null -ne $flatColorsMoveLog -and $flatColorsMoveLog.Count -gt 0) { $blendFileParentDir = Split-Path -Path $textureFolderPath -Parent # Find matching blend files +# Match logic: blendfile folder name (e.g., "Beth") should appear in blend file name (e.g., "AM_Beth_v3.2.blend") $blendFileMappings = @() if ($null -ne $blendfileFolders -and $blendfileFolders.Count -gt 0) { # Get blendfile folder names @@ -543,20 +544,20 @@ if ($null -ne $blendfileFolders -and $blendfileFolders.Count -gt 0) { if ($null -ne $blendFiles -and $blendFiles.Count -gt 0) { foreach ($blendFile in $blendFiles) { - # Extract prefix from blend file name (e.g., "Chan_v4.3.blend" -> "Chan") $blendFileName = $blendFile.BaseName - $parts = $blendFileName.Split('_', 2) - if ($parts.Length -ge 1) { - $prefix = $parts[0] - - # Check if prefix matches any blendfile folder name - if ($blendfileFolderNames -contains $prefix) { + # Check if any blendfile folder name appears in the blend file name + foreach ($folderName in $blendfileFolderNames) { + # Match folder name when surrounded by underscores, dots, hyphens, or at start/end + # This avoids partial matches (e.g., "Beth" in "Bethany") while allowing "Beth" in "AM_Beth_v3.2" + $escapedFolderName = [regex]::Escape($folderName) + if ($blendFileName -match "(^|[._-])$escapedFolderName([._-]|$)") { $blendFileMappings += [PSCustomObject]@{ BlendFile = [System.IO.Path]::GetFullPath($blendFile.FullName) - BlendfileFolder = $prefix + BlendfileFolder = $folderName } - Write-Host "Found matching blend file: $($blendFile.Name) -> $prefix" -ForegroundColor Gray + Write-Host "Found matching blend file: $($blendFile.Name) -> $folderName" -ForegroundColor Gray + break # Only match once per blend file } } }