From adafff58f02ffe14e713b35fa96485a2721e0bda Mon Sep 17 00:00:00 2001 From: Nathan Date: Fri, 19 Dec 2025 11:26:50 -0700 Subject: [PATCH] begin reconfig orgtxt --- organize_textures.bat | 22 +++++ organize_textures.ps1 | 202 +++++++++++++++++++++++++++++++++--------- 2 files changed, 184 insertions(+), 40 deletions(-) create mode 100644 organize_textures.bat diff --git a/organize_textures.bat b/organize_textures.bat new file mode 100644 index 0000000..d68fa5c --- /dev/null +++ b/organize_textures.bat @@ -0,0 +1,22 @@ +@echo off +setlocal EnableExtensions + +set "script_dir=%~dp0" +set "ps1_path=%script_dir%organize_textures.ps1" + +if not exist "%ps1_path%" ( + echo [ERROR] organize_textures.ps1 not found at %ps1_path% + exit /b 1 +) + +echo Running texture organizer... +powershell -NoProfile -ExecutionPolicy Bypass -File "%ps1_path%" +set "rc=%errorlevel%" + +if %rc% neq 0 ( + echo. + echo Script exited with error code %rc% + pause +) + +exit /b %rc% \ No newline at end of file diff --git a/organize_textures.ps1 b/organize_textures.ps1 index 649f53b..9b86cf7 100644 --- a/organize_textures.ps1 +++ b/organize_textures.ps1 @@ -1,53 +1,175 @@ -# Script to organize texture files into subdirectories based on their prefix (e.g., Regina_, Martha_) -# Usage: .\organize_textures.ps1 (Run from the directory containing the texture files) +# Script to organize texture files by checksum, moving all files to \common and duplicates to \common\duplicates +# Usage: .\organize_textures.ps1 -# Get all files (excluding hidden files like .cursorindexingignore) -$files = Get-ChildItem -File | Where-Object { $_.Name -notmatch '^\.' }; +# Prompt user for texture folder path +$textureFolderPath = Read-Host "Enter texture folder path (e.g., A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Char\Cartoon1\textures)" -# Check if any files were found -if ($null -eq $files -or $files.Count -eq 0) { - Write-Host "No files found to process (excluding hidden files)."; - exit; +# Validate the input path +if ([string]::IsNullOrWhiteSpace($textureFolderPath)) { + Write-Host "Error: No path provided." -ForegroundColor Red + exit } -# Group files by their prefix (the part before the first underscore) -$groupedFiles = $files | Group-Object { ($_.Name -split '_')[0] }; +if (-not (Test-Path -Path $textureFolderPath -PathType Container)) { + Write-Host "Error: Path does not exist or is not a directory: $textureFolderPath" -ForegroundColor Red + exit +} -# Iterate through each group (prefix) -foreach ($group in $groupedFiles) { - $prefix = $group.Name; +# Resolve the full path +$textureFolderPath = (Resolve-Path $textureFolderPath).ProviderPath +Write-Host "Processing texture folder: $textureFolderPath" -ForegroundColor Cyan - # Skip if the prefix is empty or whitespace (shouldn't happen normally, but just in case) - if ([string]::IsNullOrWhiteSpace($prefix)) { - Write-Warning "Skipping files that result in an empty or whitespace prefix."; - foreach ($file in $group.Group) { - Write-Warning " Problematic file: $($file.Name)" - } - continue; +# Get all files recursively, excluding the \common folder to avoid processing already-moved files +Write-Host "Collecting files..." -ForegroundColor Yellow +$allFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object { $_.FullName -notlike "*\common\*" } + +if ($null -eq $allFiles -or $allFiles.Count -eq 0) { + Write-Host "No files found to process (excluding \common folder)." -ForegroundColor Yellow + exit +} + +Write-Host "Found $($allFiles.Count) files to process." -ForegroundColor Green + +# Calculate checksums for all files +Write-Host "Calculating checksums (this may take a while)..." -ForegroundColor Yellow +$filesWithChecksums = @() +$fileCount = 0 +foreach ($file in $allFiles) { + $fileCount++ + if ($fileCount % 50 -eq 0) { + Write-Host " Processed $fileCount / $($allFiles.Count) files..." -ForegroundColor Gray } + + try { + $hash = Get-FileHash -Path $file.FullName -Algorithm SHA256 + $filesWithChecksums += [PSCustomObject]@{ + File = $file + Hash = $hash.Hash + } + } catch { + Write-Warning "Failed to calculate checksum for: $($file.FullName) - $($_.Exception.Message)" + } +} - # Create the subdirectory for this prefix if it doesn't exist - if (-not (Test-Path -Path $prefix -PathType Container)) { - New-Item -ItemType Directory -Path $prefix | Out-Null; - Write-Host "Created directory: $prefix" +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 \common and \common\duplicates directories +$commonPath = Join-Path -Path $textureFolderPath -ChildPath "common" +$duplicatesPath = Join-Path -Path $commonPath -ChildPath "duplicates" + +if (-not (Test-Path -Path $commonPath -PathType Container)) { + New-Item -ItemType Directory -Path $commonPath | Out-Null + Write-Host "Created directory: $commonPath" -ForegroundColor Green +} + +if (-not (Test-Path -Path $duplicatesPath -PathType Container)) { + New-Item -ItemType Directory -Path $duplicatesPath | Out-Null + Write-Host "Created directory: $duplicatesPath" -ForegroundColor Green +} + +# Track filenames already in \common to handle name conflicts +$filesInCommon = @{} + +# Process each checksum group +Write-Host "Moving files to \common and \common\duplicates..." -ForegroundColor Yellow +$movedCount = 0 +$duplicateCount = 0 + +foreach ($group in $groupedByChecksum) { + $files = $group.Group + + if ($files.Count -eq 1) { + # Single file - move to \common + $fileObj = $files[0].File + $fileName = $fileObj.Name + $destinationPath = Join-Path -Path $commonPath -ChildPath $fileName + + # Handle name conflicts + if ($filesInCommon.ContainsKey($fileName)) { + # File with same name but different checksum already exists + $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 + Write-Host " Name conflict resolved: renamed to '$fileName'" -ForegroundColor Yellow + } + + try { + Move-Item -Path $fileObj.FullName -Destination $destinationPath -Force + $filesInCommon[$fileName] = $true + $movedCount++ + } catch { + Write-Warning "Failed to move file: $($fileObj.FullName) - $($_.Exception.Message)" + } } else { - Write-Host "Directory '$prefix' already exists." - } - - # Move each file in the group into the corresponding subdirectory - # (Skip if the file is already in the correct directory) - foreach ($file in $group.Group) { - $destinationDirPath = (Resolve-Path $prefix).ProviderPath; - $currentFileDirPath = $file.DirectoryName; - - if ($currentFileDirPath -ne $destinationDirPath) { - $destinationPath = Join-Path -Path $prefix -ChildPath $file.Name; - Move-Item -Path $file.FullName -Destination $destinationPath -Force; - Write-Host "Moved '$($file.Name)' to '$prefix\'" - } else { - Write-Host "File '$($file.Name)' is already in '$prefix\'" + # 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 + Write-Host " Name conflict resolved for duplicate group: renamed to '$fileName'" -ForegroundColor Yellow + } + + 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)" + } } } } -Write-Host "File organization complete." \ No newline at end of file +Write-Host "" +Write-Host "File organization complete!" -ForegroundColor Green +Write-Host " Files moved to \common: $movedCount" -ForegroundColor Cyan +Write-Host " Duplicate files moved to \common\duplicates: $duplicateCount" -ForegroundColor Cyan