diff --git a/.specstory/history/2025-12-19_17-59Z-texture-folder-commonality-script.md b/.specstory/history/2025-12-19_17-59Z-texture-folder-commonality-script.md index 730c249..1ee4ce2 100644 --- a/.specstory/history/2025-12-19_17-59Z-texture-folder-commonality-script.md +++ b/.specstory/history/2025-12-19_17-59Z-texture-folder-commonality-script.md @@ -2246,35 +2246,29 @@ Updating the plan with the clarified requirements: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: c:\Users\Nathan\.cursor\plans\update_organize_textures_script_6f224239.plan.md -Parameters: +```markdown +**Considerations:** -```json -{ - "relativeWorkspacePath": "c:\\Users\\Nathan\\.cursor\\plans\\update_organize_textures_script_6f224239.plan.md" -} +- Flatten all files into `\common` (consolidating from multiple blendfile texture folders) +- Skip the `\common` folder itself when processing files to avoid recursion +- Handle name conflicts when multiple files have the same name but different checksums (append unique identifier) +- Provide progress feedback for large directories +- For duplicates: first file keeps original name in `\common`, subsequent files go to `\common\duplicates` with numbered suffixes (.001, .002, etc.) + +**Workflow Context:** + +- AutoMat Extractor creates material-specific folders (e.g., `Regina\Regina_Hair\`, `Regina\common\`) +- This script consolidates textures from multiple blendfiles into a single `\common` folder +- After consolidation, user will relink textures using FMT +- Duplicates in `\common\duplicates` are for debugging purposes only ``` -Additional data: - -```json -{ - "codeblockId": "4774826a-ca76-4d99-bbb3-e6d7eb7fab3f", - "reviewData": { - "status": "None", - "selectedOption": "accept", - "isShowingInput": false, - "firstTimeReviewMode": false - } -} -``` -Status: **completed** -
+
--- @@ -2295,35 +2289,26 @@ The string to replace was not found in the file. --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: c:\Users\Nathan\.cursor\plans\update_organize_textures_script_6f224239.plan.md -Parameters: +```markdown +9. For each checksum group: + - If only one file: move it to `\common` (flattened, using original filename) + - If multiple files (duplicates): + - Move the first file to `\common` (keep original filename) + - Move remaining files to `\common\duplicates` with numbered suffixes (.001, .002, etc.) + - Format: `[original_name].001[extension]`, `[original_name].002[extension]`, etc. -```json -{ - "relativeWorkspacePath": "c:\\Users\\Nathan\\.cursor\\plans\\update_organize_textures_script_6f224239.plan.md" -} +10. Handle file name conflicts: + - Track filenames already moved to `\common` + - If a file with the same name but different checksum exists, append a unique suffix (e.g., `_1`, `_2`) before extension + - This ensures no overwrites when consolidating from multiple sources ``` -Additional data: - -```json -{ - "codeblockId": "0de8e761-04de-4791-aba6-c6df3d744717", - "reviewData": { - "status": "None", - "selectedOption": "accept", - "isShowingInput": false, - "firstTimeReviewMode": false - } -} -``` -Status: **completed** -
+
--- @@ -2334,35 +2319,21 @@ Adding an algorithm flow section: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: c:\Users\Nathan\.cursor\plans\update_organize_textures_script_6f224239.plan.md -Parameters: +```markdown +4. Use `Get-ChildItem -Recurse -File` to get all files recursively + - Exclude files in `\common` folder to avoid processing already-moved files + - Use `Where-Object { $_.FullName -notlike "*\common\*" }` filter -```json -{ - "relativeWorkspacePath": "c:\\Users\\Nathan\\.cursor\\plans\\update_organize_textures_script_6f224239.plan.md" -} +5. Calculate SHA256 checksum for each file using `Get-FileHash -Algorithm SHA256` +6. Group files by checksum value using `Group-Object` ``` -Additional data: - -```json -{ - "codeblockId": "a51dd69b-eb2b-4cd2-826d-06a9548764fe", - "reviewData": { - "status": "None", - "selectedOption": "accept", - "isShowingInput": false, - "firstTimeReviewMode": false - } -} -``` -Status: **completed** -
+
--- @@ -2428,35 +2399,191 @@ Rewriting the script according to the plan: --- - -
-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, moving all files to \common and duplicates to \common\duplicates +# 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 (e.g., A:\1 Amazon_Active_Projects\1 BlenderAssets\Amazon\Char\Cartoon1\textures)" + +# Validate the input path +if ([string]::IsNullOrWhiteSpace($textureFolderPath)) { + Write-Host "Error: No path provided." -ForegroundColor Red + exit } -``` -Additional data: -```json -{ - "codeblockId": "381bbd99-41a2-428f-a35b-76bac947f896", - "reviewData": { - "status": "None", - "selectedOption": "accept", - "isShowingInput": false, - "firstTimeReviewMode": false - } +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 + +# 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)" + } +} + +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 { + # 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 "" +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 + +```
+
--- @@ -2589,35 +2716,23 @@ Adding a pause at the end so the window stays open on success. Updating the batc --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.bat -Parameters: +```bat +if %rc% neq 0 ( + echo. + echo Script exited with error code %rc% +) -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.bat" -} +echo. +pause +exit /b %rc% ``` -Additional data: - -```json -{ - "codeblockId": "855d0c6a-f1cb-41f6-9920-57ac63e537e0", - "reviewData": { - "status": "None", - "selectedOption": "accept", - "isShowingInput": false, - "firstTimeReviewMode": false - } -} -``` -Status: **completed** -
+
--- @@ -2657,35 +2772,17 @@ Removing the example path from the prompt: --- - -
-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 +# Prompt user for texture folder path +$textureFolderPath = Read-Host "Enter texture folder path" ``` -Additional data: - -```json -{ - "codeblockId": "da996a06-6cad-45b0-8103-8c865d2cf6dc", - "reviewData": { - "status": "None", - "selectedOption": "accept", - "isShowingInput": false, - "firstTimeReviewMode": false - } -} -``` -Status: **completed** -
+
--- @@ -2725,35 +2822,18 @@ Updating the batch file to set the execution policy properly: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.bat -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.bat" -} +```bat +echo Running texture organizer... +powershell -NoProfile -Command "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -Force; & '%ps1_path%'" +set "rc=%errorlevel%" ``` -Additional data: - -```json -{ - "codeblockId": "62340c40-576d-41f2-9ad8-86a073e36d56", - "reviewData": { - "status": "None", - "selectedOption": "accept", - "isShowingInput": false, - "firstTimeReviewMode": false - } -} -``` -Status: **completed** -
+
--- @@ -2764,35 +2844,18 @@ Updating the batch file to set the execution policy only if needed: --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.bat -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.bat" -} +```bat +echo Running texture organizer... +powershell -NoProfile -Command "$policy = Get-ExecutionPolicy -Scope CurrentUser; if ($policy -eq 'Restricted') { Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -Force }; & '%ps1_path%'" +set "rc=%errorlevel%" ``` -Additional data: - -```json -{ - "codeblockId": "828ef4e1-65ea-4738-9ac8-507e09ec852c", - "reviewData": { - "status": "None", - "selectedOption": "accept", - "isShowingInput": false, - "firstTimeReviewMode": false - } -} -``` -Status: **completed** -
+
--- @@ -2834,35 +2897,18 @@ Switching the batch file to use `pwsh` (PowerShell Core) instead of `powershell` --- - -
-Tool use: **edit_file_v2** + +
Tool use: **edit_file_v2** • Edit file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.bat -Parameters: - -```json -{ - "relativeWorkspacePath": "a:\\1 Amazon_Active_Projects\\3 ProjectStructure\\organize_textures.bat" -} +```bat +echo Running texture organizer... +pwsh -NoProfile -ExecutionPolicy Bypass -File "%ps1_path%" +set "rc=%errorlevel%" ``` -Additional data: - -```json -{ - "codeblockId": "010230dd-6631-4101-9f7f-46bff8a218b2", - "reviewData": { - "status": "None", - "selectedOption": "accept", - "isShowingInput": false, - "firstTimeReviewMode": false - } -} -``` -Status: **completed** -
+
--- @@ -2902,35 +2948,29 @@ The script runs sequentially. Adding parallel processing for checksum calculatio --- - -
-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 +# Calculate checksums for all files using parallel processing +Write-Host "Calculating checksums using parallel processing (this may take a while)..." -ForegroundColor Yellow +$filesWithChecksums = $allFiles | ForEach-Object -Parallel { + 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 + } +} -ThrottleLimit ([Math]::Max(1, [Environment]::ProcessorCount)) ``` -Additional data: - -```json -{ - "codeblockId": "3df1eea1-d4e4-4d55-ab45-a20155aecff3", - "reviewData": { - "status": "None", - "selectedOption": "accept", - "isShowingInput": false, - "firstTimeReviewMode": false - } -} -``` -Status: **completed** -
+
--- @@ -2941,35 +2981,29 @@ 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 +# Calculate checksums for all files using parallel processing +Write-Host "Calculating checksums using parallel processing (this may take a while)..." -ForegroundColor Yellow +$filesWithChecksums = $allFiles | ForEach-Object -Parallel { + 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 + } +} -ThrottleLimit ([Math]::Max(1, [Environment]::ProcessorCount)) | Where-Object { $null -ne $_ } ``` -Additional data: - -```json -{ - "codeblockId": "3c9f96be-6177-43b2-85a0-86f792edf83c", - "reviewData": { - "status": "None", - "selectedOption": "accept", - "isShowingInput": false, - "firstTimeReviewMode": false - } -} -``` -Status: **completed** -
+
--- @@ -3055,29 +3089,30 @@ Storing the throttle limit in a variable to resolve the linter 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 +# Calculate checksums for all files using parallel processing +Write-Host "Calculating checksums using parallel processing (this may take a while)..." -ForegroundColor Yellow +$throttleLimit = [Math]::Max(1, [Environment]::ProcessorCount) +$filesWithChecksums = $allFiles | ForEach-Object -Parallel { + 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 + } +} -ThrottleLimit $throttleLimit | Where-Object { $null -ne $_ } ``` -Additional data: - -```json -{ - "codeblockId": "21b2309a-af4e-40f3-95c7-4355a1bc042a" -} -``` -Status: **completed** -
+
--- @@ -3148,29 +3183,31 @@ The syntax is correct. The linter likely uses an older PowerShell parser that do --- - -
-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 +# Calculate checksums for all files using parallel processing +Write-Host "Calculating checksums using parallel processing (this may take a while)..." -ForegroundColor Yellow +$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 + } } +$filesWithChecksums = $allFiles | ForEach-Object -Parallel $parallelScriptBlock -ThrottleLimit $throttleLimit | Where-Object { $null -ne $_ } ``` -Additional data: - -```json -{ - "codeblockId": "d8e8f9ee-ebc0-4c37-acc6-e7eafe64f737" -} -``` -Status: **completed** -
+
--- @@ -3312,7 +3349,6 @@ Fix it, verify, and then give a concise explanation. @c:\Users\Nathan\AppData\Ro _**Agent (model default, mode Agent)**_ - Fixing the deprecated setting. Reading the settings file: @@ -3326,7 +3362,6 @@ Fixing the deprecated setting. Reading the settings file: --- - Updating the settings to use the new format: @@ -3348,7 +3383,6 @@ Fix it, verify, and then give a concise explanation. @c:\Users\Nathan\AppData\Ro _**Agent (model default, mode Agent)**_ - Reading the settings file to check the structure: @@ -3362,7 +3396,6 @@ Reading the settings file to check the structure: --- - Fixing the structure: `powerShellAdditionalExePaths` expects an object (key-value pairs), not an array. @@ -3437,16 +3470,10921 @@ Cancelled _**User**_ -Got it, no more problems detected. +let's make sure that universally, the FlatColors are all saved as 16x16 jpgs, unless they're .tga. also, duplicate flatcolors can and absolutely should be merged. --- -next issue: let's make sure it scans each folder separately. it goes \\textures\[Blendfile]\[Material] +_**Agent (model default, mode Agent)**_ -Intra-blendfile commonalities should go to `\\textures\[blendfile]\common` -Inter-blendfile commonalities should go to `\\textures\common` -sound good? +Exploring the project structure to locate FlatColors and check for existing scripts that handle them. + + +--- + + +
+Tool use: **semantic_search_full** + + +Parameters: + +```json +{ + "query": "Where are FlatColors stored or processed?", + "topK": 10, + "explanation": "" +} +``` +Result: + +```json +{ + "codeResults": [ + { + "codeBlock": { + "relativeWorkspacePath": ".\\organize_textures.ps1", + "range": { + "startPosition": { + "line": 355 + }, + "endPosition": { + "line": 390 + } + }, + "contents": "$allFlatColorsFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object { \n ($_.FullName -like \"*\\FlatColors\\*\" -or $_.Name -like \"*FlatColors*\") -and \n $_.FullName -notlike \"$([regex]::Escape($rootCommonFlatColorsPath))\\*\" \n}\n\n# Get all remaining files (excluding all \\common folders, but we'll handle FlatColors separately)\nWrite-Host \"Collecting remaining files...\" -ForegroundColor Yellow\n$remainingFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object { $_.FullName -notlike \"*\\common\\*\" }\n\nif ($null -eq $remainingFiles -or $remainingFiles.Count -eq 0) {\n Write-Host \"No remaining files found to process.\" -ForegroundColor Yellow\n} else {\n Write-Host \"Found $($remainingFiles.Count) remaining files to process.\" -ForegroundColor Green\n \n # Calculate checksums\n Write-Host \"Calculating checksums using parallel processing (this may take a while)...\" -ForegroundColor Yellow\n $filesWithChecksums = Get-FilesWithChecksums -Files $remainingFiles\n \n Write-Host \"Checksum calculation complete.\" -ForegroundColor Green\n \n # Separate FlatColors files from other files before processing\n Write-Host \"Identifying FlatColors files...\" -ForegroundColor Yellow\n $flatColorsFiles = $allFlatColorsFiles | Where-Object { (Test-Path -Path $_.FullName) }\n $nonFlatColorsFiles = $remainingFiles | Where-Object { $_.Name -notlike \"*FlatColors*\" }\n \n Write-Host \"Found $($flatColorsFiles.Count) FlatColors file(s) (including from \\common\\FlatColors folders), $($nonFlatColorsFiles.Count) other file(s)\" -ForegroundColor Gray\n \n # Group non-FlatColors files by checksum\n Write-Host \"Grouping files by checksum...\" -ForegroundColor Yellow\n $nonFlatColorsWithChecksums = $filesWithChecksums | Where-Object { $_.File.Name -notlike \"*FlatColors*\" }\n $groupedByChecksum = $nonFlatColorsWithChecksums | Group-Object -Property Hash\n \n Write-Host \"Found $($groupedByChecksum.Count) unique checksums.\" -ForegroundColor Green\n \n # Create \\textures\\common directory", + "signatures": {}, + "detailedLines": [ + { + "text": "$allFlatColorsFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object { ", + "lineNumber": 356 + }, + { + "text": " ($_.FullName -like \"*\\FlatColors\\*\" -or $_.Name -like \"*FlatColors*\") -and ", + "lineNumber": 357 + }, + { + "text": " $_.FullName -notlike \"$([regex]::Escape($rootCommonFlatColorsPath))\\*\" ", + "lineNumber": 358 + }, + { + "text": "}", + "lineNumber": 359 + }, + { + "lineNumber": 360 + }, + { + "text": "# Get all remaining files (excluding all \\common folders, but we'll handle FlatColors separately)", + "lineNumber": 361 + }, + { + "text": "Write-Host \"Collecting remaining files...\" -ForegroundColor Yellow", + "lineNumber": 362 + }, + { + "text": "$remainingFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object { $_.FullName -notlike \"*\\common\\*\" }", + "lineNumber": 363 + }, + { + "lineNumber": 364 + }, + { + "text": "if ($null -eq $remainingFiles -or $remainingFiles.Count -eq 0) {", + "lineNumber": 365 + }, + { + "text": " Write-Host \"No remaining files found to process.\" -ForegroundColor Yellow", + "lineNumber": 366 + }, + { + "text": "} else {", + "lineNumber": 367 + }, + { + "text": " Write-Host \"Found $($remainingFiles.Count) remaining files to process.\" -ForegroundColor Green", + "lineNumber": 368 + }, + { + "text": " ", + "lineNumber": 369 + }, + { + "text": " # Calculate checksums", + "lineNumber": 370 + }, + { + "text": " Write-Host \"Calculating checksums using parallel processing (this may take a while)...\" -ForegroundColor Yellow", + "lineNumber": 371 + }, + { + "text": " $filesWithChecksums = Get-FilesWithChecksums -Files $remainingFiles", + "lineNumber": 372 + }, + { + "text": " ", + "lineNumber": 373 + }, + { + "text": " Write-Host \"Checksum calculation complete.\" -ForegroundColor Green", + "lineNumber": 374 + }, + { + "text": " ", + "lineNumber": 375 + }, + { + "text": " # Separate FlatColors files from other files before processing", + "lineNumber": 376 + }, + { + "text": " Write-Host \"Identifying FlatColors files...\" -ForegroundColor Yellow", + "lineNumber": 377 + }, + { + "text": " $flatColorsFiles = $allFlatColorsFiles | Where-Object { (Test-Path -Path $_.FullName) }", + "lineNumber": 378 + }, + { + "text": " $nonFlatColorsFiles = $remainingFiles | Where-Object { $_.Name -notlike \"*FlatColors*\" }", + "lineNumber": 379 + }, + { + "text": " ", + "lineNumber": 380 + }, + { + "text": " Write-Host \"Found $($flatColorsFiles.Count) FlatColors file(s) (including from \\common\\FlatColors folders), $($nonFlatColorsFiles.Count) other file(s)\" -ForegroundColor Gray", + "lineNumber": 381 + }, + { + "text": " ", + "lineNumber": 382 + }, + { + "text": " # Group non-FlatColors files by checksum", + "lineNumber": 383 + }, + { + "text": " Write-Host \"Grouping files by checksum...\" -ForegroundColor Yellow", + "lineNumber": 384 + }, + { + "text": " $nonFlatColorsWithChecksums = $filesWithChecksums | Where-Object { $_.File.Name -notlike \"*FlatColors*\" }", + "lineNumber": 385 + }, + { + "text": " $groupedByChecksum = $nonFlatColorsWithChecksums | Group-Object -Property Hash", + "lineNumber": 386 + }, + { + "text": " ", + "lineNumber": 387 + }, + { + "text": " Write-Host \"Found $($groupedByChecksum.Count) unique checksums.\" -ForegroundColor Green", + "lineNumber": 388 + }, + { + "text": " ", + "lineNumber": 389 + }, + { + "text": " # Create \\textures\\common directory", + "lineNumber": 390 + } + ] + }, + "score": 0.3292612135410309 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\organize_textures.ps1", + "range": { + "startPosition": { + "line": 423 + }, + "endPosition": { + "line": 453, + "column": 16 + } + }, + "contents": " \n if ($null -ne $flatColorsFiles -and $flatColorsFiles.Count -gt 0) {\n Write-Host \"Found $($flatColorsFiles.Count) FlatColors file(s) to process\" -ForegroundColor Gray\n \n # Calculate checksums for FlatColors files\n Write-Host \"Calculating checksums for FlatColors files...\" -ForegroundColor Yellow\n $flatColorsWithChecksums = Get-FilesWithChecksums -Files $flatColorsFiles\n \n # Group by checksum to find duplicates\n $flatColorsGroupedByChecksum = $flatColorsWithChecksums | Group-Object -Property Hash\n \n Write-Host \"Found $($flatColorsGroupedByChecksum.Count) unique FlatColors file(s)\" -ForegroundColor Gray\n \n # Create \\textures\\common\\FlatColors directory\n $flatColorsPath = Join-Path -Path $rootCommonPath -ChildPath \"FlatColors\"\n if (-not (Test-Path -Path $flatColorsPath -PathType Container)) {\n New-Item -ItemType Directory -Path $flatColorsPath | Out-Null\n Write-Host \"Created directory: $flatColorsPath\" -ForegroundColor Green\n }\n \n # Track filenames already in \\common\\FlatColors\n $filesInFlatColors = @{}\n $flatColorsMoved = 0\n $flatColorsDuplicates = 0\n $flatColorsMoveLog = [System.Collections.ArrayList]::new()\n \n foreach ($group in $flatColorsGroupedByChecksum) {\n $files = $group.Group\n \n if ($files.Count -eq 1) {\n ", + "signatures": {}, + "detailedLines": [ + { + "text": " ", + "lineNumber": 424 + }, + { + "text": " if ($null -ne $flatColorsFiles -and $flatColorsFiles.Count -gt 0) {", + "lineNumber": 425 + }, + { + "text": " Write-Host \"Found $($flatColorsFiles.Count) FlatColors file(s) to process\" -ForegroundColor Gray", + "lineNumber": 426 + }, + { + "text": " ", + "lineNumber": 427 + }, + { + "text": " # Calculate checksums for FlatColors files", + "lineNumber": 428 + }, + { + "text": " Write-Host \"Calculating checksums for FlatColors files...\" -ForegroundColor Yellow", + "lineNumber": 429 + }, + { + "text": " $flatColorsWithChecksums = Get-FilesWithChecksums -Files $flatColorsFiles", + "lineNumber": 430 + }, + { + "text": " ", + "lineNumber": 431 + }, + { + "text": " # Group by checksum to find duplicates", + "lineNumber": 432 + }, + { + "text": " $flatColorsGroupedByChecksum = $flatColorsWithChecksums | Group-Object -Property Hash", + "lineNumber": 433 + }, + { + "text": " ", + "lineNumber": 434 + }, + { + "text": " Write-Host \"Found $($flatColorsGroupedByChecksum.Count) unique FlatColors file(s)\" -ForegroundColor Gray", + "lineNumber": 435 + }, + { + "text": " ", + "lineNumber": 436 + }, + { + "text": " # Create \\textures\\common\\FlatColors directory", + "lineNumber": 437 + }, + { + "text": " $flatColorsPath = Join-Path -Path $rootCommonPath -ChildPath \"FlatColors\"", + "lineNumber": 438 + }, + { + "text": " if (-not (Test-Path -Path $flatColorsPath -PathType Container)) {", + "lineNumber": 439 + }, + { + "text": " New-Item -ItemType Directory -Path $flatColorsPath | Out-Null", + "lineNumber": 440 + }, + { + "text": " Write-Host \"Created directory: $flatColorsPath\" -ForegroundColor Green", + "lineNumber": 441 + }, + { + "text": " }", + "lineNumber": 442 + }, + { + "text": " ", + "lineNumber": 443 + }, + { + "text": " # Track filenames already in \\common\\FlatColors", + "lineNumber": 444 + }, + { + "text": " $filesInFlatColors = @{}", + "lineNumber": 445 + }, + { + "text": " $flatColorsMoved = 0", + "lineNumber": 446 + }, + { + "text": " $flatColorsDuplicates = 0", + "lineNumber": 447 + }, + { + "text": " $flatColorsMoveLog = [System.Collections.ArrayList]::new()", + "lineNumber": 448 + }, + { + "text": " ", + "lineNumber": 449 + }, + { + "text": " foreach ($group in $flatColorsGroupedByChecksum) {", + "lineNumber": 450 + }, + { + "text": " $files = $group.Group", + "lineNumber": 451 + }, + { + "text": " ", + "lineNumber": 452 + }, + { + "text": " if ($files.Count -eq 1) {", + "lineNumber": 453 + }, + { + "text": " ", + "lineNumber": 454 + } + ] + }, + "score": 0.3252905607223511 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\organize_textures.ps1", + "range": { + "startPosition": { + "line": 477 + }, + "endPosition": { + "line": 518 + } + }, + "contents": " \n try {\n $originalPath = $fileObj.FullName\n Move-Item -Path $originalPath -Destination $destinationPath -Force\n $filesInFlatColors[$fileName] = $true\n $flatColorsMoved++\n \n # Log the move\n $normalizedOriginal = [System.IO.Path]::GetFullPath($originalPath)\n $normalizedNew = [System.IO.Path]::GetFullPath($destinationPath)\n $null = $flatColorsMoveLog.Add([PSCustomObject]@{\n OriginalPath = $normalizedOriginal\n NewPath = $normalizedNew\n Type = \"moved\"\n })\n } catch {\n Write-Warning \"Failed to move FlatColors file: $($fileObj.FullName) - $($_.Exception.Message)\"\n }\n } else {\n # Multiple files with same checksum (duplicates) - merge them\n # Use Process-DuplicateGroup to handle merging\n $result = Process-DuplicateGroup -Files $files -CommonPath $flatColorsPath -FilesInCommon $filesInFlatColors -StripPrefix -ValidPrefixes $validBlendfilePrefixes -MoveLog $flatColorsMoveLog\n $flatColorsMoved += $result.MovedCount\n $flatColorsDuplicates += $result.DuplicateCount\n }\n }\n \n Write-Host \"Moved $flatColorsMoved unique FlatColors file(s) to \\common\\FlatColors, deleted $flatColorsDuplicates duplicate(s)\" -ForegroundColor Green\n } else {\n Write-Host \"No FlatColors files found to process.\" -ForegroundColor Gray\n }\n \n Write-Host \"\"\n Write-Host \"Pass 2 complete: $pass2Moved file(s) moved to \\common, $pass2Duplicates duplicate(s) deleted\" -ForegroundColor Green\n}\n\n# ============================================================================\n# Save Move Log and Find Blend Files\n# ============================================================================\nWrite-Host \"\"\nWrite-Host \"Saving move log and finding blend files...\" -ForegroundColor Yellow", + "signatures": {}, + "detailedLines": [ + { + "text": " ", + "lineNumber": 478 + }, + { + "text": " try {", + "lineNumber": 479 + }, + { + "text": " $originalPath = $fileObj.FullName", + "lineNumber": 480 + }, + { + "text": " Move-Item -Path $originalPath -Destination $destinationPath -Force", + "lineNumber": 481 + }, + { + "text": " $filesInFlatColors[$fileName] = $true", + "lineNumber": 482 + }, + { + "text": " $flatColorsMoved++", + "lineNumber": 483 + }, + { + "text": " ", + "lineNumber": 484 + }, + { + "text": " # Log the move", + "lineNumber": 485 + }, + { + "text": " $normalizedOriginal = [System.IO.Path]::GetFullPath($originalPath)", + "lineNumber": 486 + }, + { + "text": " $normalizedNew = [System.IO.Path]::GetFullPath($destinationPath)", + "lineNumber": 487 + }, + { + "text": " $null = $flatColorsMoveLog.Add([PSCustomObject]@{", + "lineNumber": 488 + }, + { + "text": " OriginalPath = $normalizedOriginal", + "lineNumber": 489 + }, + { + "text": " NewPath = $normalizedNew", + "lineNumber": 490 + }, + { + "text": " Type = \"moved\"", + "lineNumber": 491 + }, + { + "text": " })", + "lineNumber": 492 + }, + { + "text": " } catch {", + "lineNumber": 493 + }, + { + "text": " Write-Warning \"Failed to move FlatColors file: $($fileObj.FullName) - $($_.Exception.Message)\"", + "lineNumber": 494 + }, + { + "text": " }", + "lineNumber": 495 + }, + { + "text": " } else {", + "lineNumber": 496 + }, + { + "text": " # Multiple files with same checksum (duplicates) - merge them", + "lineNumber": 497 + }, + { + "text": " # Use Process-DuplicateGroup to handle merging", + "lineNumber": 498 + }, + { + "text": " $result = Process-DuplicateGroup -Files $files -CommonPath $flatColorsPath -FilesInCommon $filesInFlatColors -StripPrefix -ValidPrefixes $validBlendfilePrefixes -MoveLog $flatColorsMoveLog", + "lineNumber": 499 + }, + { + "text": " $flatColorsMoved += $result.MovedCount", + "lineNumber": 500 + }, + { + "text": " $flatColorsDuplicates += $result.DuplicateCount", + "lineNumber": 501 + }, + { + "text": " }", + "lineNumber": 502 + }, + { + "text": " }", + "lineNumber": 503 + }, + { + "text": " ", + "lineNumber": 504 + }, + { + "text": " Write-Host \"Moved $flatColorsMoved unique FlatColors file(s) to \\common\\FlatColors, deleted $flatColorsDuplicates duplicate(s)\" -ForegroundColor Green", + "lineNumber": 505 + }, + { + "text": " } else {", + "lineNumber": 506 + }, + { + "text": " Write-Host \"No FlatColors files found to process.\" -ForegroundColor Gray", + "lineNumber": 507 + }, + { + "text": " }", + "lineNumber": 508 + }, + { + "text": " ", + "lineNumber": 509 + }, + { + "text": " Write-Host \"\"", + "lineNumber": 510 + }, + { + "text": " Write-Host \"Pass 2 complete: $pass2Moved file(s) moved to \\common, $pass2Duplicates duplicate(s) deleted\" -ForegroundColor Green", + "lineNumber": 511 + }, + { + "text": "}", + "lineNumber": 512 + }, + { + "lineNumber": 513 + }, + { + "text": "# ============================================================================", + "lineNumber": 514 + }, + { + "text": "# Save Move Log and Find Blend Files", + "lineNumber": 515 + }, + { + "text": "# ============================================================================", + "lineNumber": 516 + }, + { + "text": "Write-Host \"\"", + "lineNumber": 517 + }, + { + "text": "Write-Host \"Saving move log and finding blend files...\" -ForegroundColor Yellow", + "lineNumber": 518 + } + ] + }, + "score": 0.29058343172073364 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\organize_textures.ps1", + "range": { + "startPosition": { + "line": 448 + }, + "endPosition": { + "line": 481 + } + }, + "contents": " \n foreach ($group in $flatColorsGroupedByChecksum) {\n $files = $group.Group\n \n if ($files.Count -eq 1) {\n # Single file - move to FlatColors folder\n $fileObj = $files[0].File\n $fileName = $fileObj.Name\n \n # Strip blendfile prefix if present\n $strippedName = Get-FileNameWithoutPrefix -FileName $fileName -ValidPrefixes $validBlendfilePrefixes\n if ($strippedName -ne $fileName) {\n $fileName = $strippedName\n }\n \n $destinationPath = Join-Path -Path $flatColorsPath -ChildPath $fileName\n \n # Handle name conflicts (shouldn't happen for unique files, but just in case)\n if ($filesInFlatColors.ContainsKey($fileName) -or (Test-Path -Path $destinationPath)) {\n $baseName = [System.IO.Path]::GetFileNameWithoutExtension($fileName)\n $extension = [System.IO.Path]::GetExtension($fileName)\n $counter = 1\n do {\n $newFileName = \"${baseName}_${counter}${extension}\"\n $destinationPath = Join-Path -Path $flatColorsPath -ChildPath $newFileName\n $counter++\n } while ($filesInFlatColors.ContainsKey($newFileName) -or (Test-Path -Path $destinationPath))\n $fileName = $newFileName\n }\n \n try {\n $originalPath = $fileObj.FullName\n Move-Item -Path $originalPath -Destination $destinationPath -Force", + "signatures": {}, + "detailedLines": [ + { + "text": " ", + "lineNumber": 449 + }, + { + "text": " foreach ($group in $flatColorsGroupedByChecksum) {", + "lineNumber": 450 + }, + { + "text": " $files = $group.Group", + "lineNumber": 451 + }, + { + "text": " ", + "lineNumber": 452 + }, + { + "text": " if ($files.Count -eq 1) {", + "lineNumber": 453 + }, + { + "text": " # Single file - move to FlatColors folder", + "lineNumber": 454 + }, + { + "text": " $fileObj = $files[0].File", + "lineNumber": 455 + }, + { + "text": " $fileName = $fileObj.Name", + "lineNumber": 456 + }, + { + "text": " ", + "lineNumber": 457 + }, + { + "text": " # Strip blendfile prefix if present", + "lineNumber": 458 + }, + { + "text": " $strippedName = Get-FileNameWithoutPrefix -FileName $fileName -ValidPrefixes $validBlendfilePrefixes", + "lineNumber": 459 + }, + { + "text": " if ($strippedName -ne $fileName) {", + "lineNumber": 460 + }, + { + "text": " $fileName = $strippedName", + "lineNumber": 461 + }, + { + "text": " }", + "lineNumber": 462 + }, + { + "text": " ", + "lineNumber": 463 + }, + { + "text": " $destinationPath = Join-Path -Path $flatColorsPath -ChildPath $fileName", + "lineNumber": 464 + }, + { + "text": " ", + "lineNumber": 465 + }, + { + "text": " # Handle name conflicts (shouldn't happen for unique files, but just in case)", + "lineNumber": 466 + }, + { + "text": " if ($filesInFlatColors.ContainsKey($fileName) -or (Test-Path -Path $destinationPath)) {", + "lineNumber": 467 + }, + { + "text": " $baseName = [System.IO.Path]::GetFileNameWithoutExtension($fileName)", + "lineNumber": 468 + }, + { + "text": " $extension = [System.IO.Path]::GetExtension($fileName)", + "lineNumber": 469 + }, + { + "text": " $counter = 1", + "lineNumber": 470 + }, + { + "text": " do {", + "lineNumber": 471 + }, + { + "text": " $newFileName = \"${baseName}_${counter}${extension}\"", + "lineNumber": 472 + }, + { + "text": " $destinationPath = Join-Path -Path $flatColorsPath -ChildPath $newFileName", + "lineNumber": 473 + }, + { + "text": " $counter++", + "lineNumber": 474 + }, + { + "text": " } while ($filesInFlatColors.ContainsKey($newFileName) -or (Test-Path -Path $destinationPath))", + "lineNumber": 475 + }, + { + "text": " $fileName = $newFileName", + "lineNumber": 476 + }, + { + "text": " }", + "lineNumber": 477 + }, + { + "text": " ", + "lineNumber": 478 + }, + { + "text": " try {", + "lineNumber": 479 + }, + { + "text": " $originalPath = $fileObj.FullName", + "lineNumber": 480 + }, + { + "text": " Move-Item -Path $originalPath -Destination $destinationPath -Force", + "lineNumber": 481 + } + ] + }, + "score": 0.2869645357131958 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\organize_textures.ps1", + "range": { + "startPosition": { + "line": 323 + }, + "endPosition": { + "line": 357 + } + }, + "contents": " foreach ($group in $groupedByChecksum) {\n $result = Process-DuplicateGroup -Files $group.Group -CommonPath $blendfileCommonPath -FilesInCommon $filesInBlendfileCommon -MoveLog $pass1MoveLog\n $blendfileMoved += $result.MovedCount\n $blendfileDuplicates += $result.DuplicateCount\n }\n \n Write-Host \" Moved $blendfileMoved file(s) to \\common, deleted $blendfileDuplicates duplicate(s)\" -ForegroundColor Green\n $totalPass1Moved += $blendfileMoved\n $totalPass1Duplicates += $blendfileDuplicates\n }\n \n Write-Host \"\"\n Write-Host \"Pass 1 complete: $totalPass1Moved file(s) moved, $totalPass1Duplicates duplicate(s) deleted\" -ForegroundColor Green\n}\n\n# ============================================================================\n# PASS 2: Inter-Blendfile Processing\n# ============================================================================\nWrite-Host \"\"\nWrite-Host \"=== PASS 2: Inter-Blendfile Processing ===\" -ForegroundColor Cyan\n\n# Build list of valid blendfile prefixes from folder names\n$validBlendfilePrefixes = @()\n$blendfileFoldersForPrefixes = Get-ChildItem -Path $textureFolderPath -Directory | Where-Object { $_.Name -ne \"common\" }\nif ($null -ne $blendfileFoldersForPrefixes) {\n $validBlendfilePrefixes = $blendfileFoldersForPrefixes | ForEach-Object { $_.Name }\n Write-Host \"Valid blendfile prefixes: $($validBlendfilePrefixes -join ', ')\" -ForegroundColor Gray\n}\n\n# Collect FlatColors files separately (including those in \\common\\FlatColors folders, but not from root \\common\\FlatColors)\nWrite-Host \"Collecting FlatColors files...\" -ForegroundColor Yellow\n$rootCommonFlatColorsPath = Join-Path -Path $textureFolderPath -ChildPath \"common\\FlatColors\"\n$allFlatColorsFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object { \n ($_.FullName -like \"*\\FlatColors\\*\" -or $_.Name -like \"*FlatColors*\") -and ", + "signatures": {}, + "detailedLines": [ + { + "text": " foreach ($group in $groupedByChecksum) {", + "lineNumber": 324 + }, + { + "text": " $result = Process-DuplicateGroup -Files $group.Group -CommonPath $blendfileCommonPath -FilesInCommon $filesInBlendfileCommon -MoveLog $pass1MoveLog", + "lineNumber": 325 + }, + { + "text": " $blendfileMoved += $result.MovedCount", + "lineNumber": 326 + }, + { + "text": " $blendfileDuplicates += $result.DuplicateCount", + "lineNumber": 327 + }, + { + "text": " }", + "lineNumber": 328 + }, + { + "text": " ", + "lineNumber": 329 + }, + { + "text": " Write-Host \" Moved $blendfileMoved file(s) to \\common, deleted $blendfileDuplicates duplicate(s)\" -ForegroundColor Green", + "lineNumber": 330 + }, + { + "text": " $totalPass1Moved += $blendfileMoved", + "lineNumber": 331 + }, + { + "text": " $totalPass1Duplicates += $blendfileDuplicates", + "lineNumber": 332 + }, + { + "text": " }", + "lineNumber": 333 + }, + { + "text": " ", + "lineNumber": 334 + }, + { + "text": " Write-Host \"\"", + "lineNumber": 335 + }, + { + "text": " Write-Host \"Pass 1 complete: $totalPass1Moved file(s) moved, $totalPass1Duplicates duplicate(s) deleted\" -ForegroundColor Green", + "lineNumber": 336 + }, + { + "text": "}", + "lineNumber": 337 + }, + { + "lineNumber": 338 + }, + { + "text": "# ============================================================================", + "lineNumber": 339 + }, + { + "text": "# PASS 2: Inter-Blendfile Processing", + "lineNumber": 340 + }, + { + "text": "# ============================================================================", + "lineNumber": 341 + }, + { + "text": "Write-Host \"\"", + "lineNumber": 342 + }, + { + "text": "Write-Host \"=== PASS 2: Inter-Blendfile Processing ===\" -ForegroundColor Cyan", + "lineNumber": 343 + }, + { + "lineNumber": 344 + }, + { + "text": "# Build list of valid blendfile prefixes from folder names", + "lineNumber": 345 + }, + { + "text": "$validBlendfilePrefixes = @()", + "lineNumber": 346 + }, + { + "text": "$blendfileFoldersForPrefixes = Get-ChildItem -Path $textureFolderPath -Directory | Where-Object { $_.Name -ne \"common\" }", + "lineNumber": 347 + }, + { + "text": "if ($null -ne $blendfileFoldersForPrefixes) {", + "lineNumber": 348 + }, + { + "text": " $validBlendfilePrefixes = $blendfileFoldersForPrefixes | ForEach-Object { $_.Name }", + "lineNumber": 349 + }, + { + "text": " Write-Host \"Valid blendfile prefixes: $($validBlendfilePrefixes -join ', ')\" -ForegroundColor Gray", + "lineNumber": 350 + }, + { + "text": "}", + "lineNumber": 351 + }, + { + "lineNumber": 352 + }, + { + "text": "# Collect FlatColors files separately (including those in \\common\\FlatColors folders, but not from root \\common\\FlatColors)", + "lineNumber": 353 + }, + { + "text": "Write-Host \"Collecting FlatColors files...\" -ForegroundColor Yellow", + "lineNumber": 354 + }, + { + "text": "$rootCommonFlatColorsPath = Join-Path -Path $textureFolderPath -ChildPath \"common\\FlatColors\"", + "lineNumber": 355 + }, + { + "text": "$allFlatColorsFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object { ", + "lineNumber": 356 + }, + { + "text": " ($_.FullName -like \"*\\FlatColors\\*\" -or $_.Name -like \"*FlatColors*\") -and ", + "lineNumber": 357 + } + ] + }, + "score": 0.2548561990261078 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\organize_textures.ps1", + "range": { + "startPosition": { + "line": 386 + }, + "endPosition": { + "line": 426 + } + }, + "contents": " \n Write-Host \"Found $($groupedByChecksum.Count) unique checksums.\" -ForegroundColor Green\n \n # Create \\textures\\common directory\n $rootCommonPath = Join-Path -Path $textureFolderPath -ChildPath \"common\"\n \n if (-not (Test-Path -Path $rootCommonPath -PathType Container)) {\n New-Item -ItemType Directory -Path $rootCommonPath | Out-Null\n Write-Host \"Created directory: $rootCommonPath\" -ForegroundColor Green\n }\n \n # Track filenames already in \\textures\\common\n $filesInRootCommon = @{}\n \n # Process each checksum group (excluding FlatColors)\n Write-Host \"Moving files to \\common and deleting duplicates...\" -ForegroundColor Yellow\n $pass2Moved = 0\n $pass2Duplicates = 0\n $pass2MoveLog = [System.Collections.ArrayList]::new()\n \n foreach ($group in $groupedByChecksum) {\n $files = $group.Group\n \n if ($files.Count -eq 1) {\n # Single file - leave in place (unique file)\n continue\n }\n \n # Multiple files with same checksum (duplicates across blendfiles)\n # Use StripPrefix to remove blendfile prefixes (e.g., \"Demarco_\", \"Chan_\") when all files share the same suffix\n $result = Process-DuplicateGroup -Files $files -CommonPath $rootCommonPath -FilesInCommon $filesInRootCommon -StripPrefix -ValidPrefixes $validBlendfilePrefixes -MoveLog $pass2MoveLog\n $pass2Moved += $result.MovedCount\n $pass2Duplicates += $result.DuplicateCount\n }\n \n # Process FlatColors files: merge duplicates and move to \\common\\FlatColors\n Write-Host \"Processing FlatColors files (merging duplicates)...\" -ForegroundColor Yellow\n \n if ($null -ne $flatColorsFiles -and $flatColorsFiles.Count -gt 0) {\n Write-Host \"Found $($flatColorsFiles.Count) FlatColors file(s) to process\" -ForegroundColor Gray", + "signatures": {}, + "detailedLines": [ + { + "text": " ", + "lineNumber": 387 + }, + { + "text": " Write-Host \"Found $($groupedByChecksum.Count) unique checksums.\" -ForegroundColor Green", + "lineNumber": 388 + }, + { + "text": " ", + "lineNumber": 389 + }, + { + "text": " # Create \\textures\\common directory", + "lineNumber": 390 + }, + { + "text": " $rootCommonPath = Join-Path -Path $textureFolderPath -ChildPath \"common\"", + "lineNumber": 391 + }, + { + "text": " ", + "lineNumber": 392 + }, + { + "text": " if (-not (Test-Path -Path $rootCommonPath -PathType Container)) {", + "lineNumber": 393 + }, + { + "text": " New-Item -ItemType Directory -Path $rootCommonPath | Out-Null", + "lineNumber": 394 + }, + { + "text": " Write-Host \"Created directory: $rootCommonPath\" -ForegroundColor Green", + "lineNumber": 395 + }, + { + "text": " }", + "lineNumber": 396 + }, + { + "text": " ", + "lineNumber": 397 + }, + { + "text": " # Track filenames already in \\textures\\common", + "lineNumber": 398 + }, + { + "text": " $filesInRootCommon = @{}", + "lineNumber": 399 + }, + { + "text": " ", + "lineNumber": 400 + }, + { + "text": " # Process each checksum group (excluding FlatColors)", + "lineNumber": 401 + }, + { + "text": " Write-Host \"Moving files to \\common and deleting duplicates...\" -ForegroundColor Yellow", + "lineNumber": 402 + }, + { + "text": " $pass2Moved = 0", + "lineNumber": 403 + }, + { + "text": " $pass2Duplicates = 0", + "lineNumber": 404 + }, + { + "text": " $pass2MoveLog = [System.Collections.ArrayList]::new()", + "lineNumber": 405 + }, + { + "text": " ", + "lineNumber": 406 + }, + { + "text": " foreach ($group in $groupedByChecksum) {", + "lineNumber": 407 + }, + { + "text": " $files = $group.Group", + "lineNumber": 408 + }, + { + "text": " ", + "lineNumber": 409 + }, + { + "text": " if ($files.Count -eq 1) {", + "lineNumber": 410 + }, + { + "text": " # Single file - leave in place (unique file)", + "lineNumber": 411 + }, + { + "text": " continue", + "lineNumber": 412 + }, + { + "text": " }", + "lineNumber": 413 + }, + { + "text": " ", + "lineNumber": 414 + }, + { + "text": " # Multiple files with same checksum (duplicates across blendfiles)", + "lineNumber": 415 + }, + { + "text": " # Use StripPrefix to remove blendfile prefixes (e.g., \"Demarco_\", \"Chan_\") when all files share the same suffix", + "lineNumber": 416 + }, + { + "text": " $result = Process-DuplicateGroup -Files $files -CommonPath $rootCommonPath -FilesInCommon $filesInRootCommon -StripPrefix -ValidPrefixes $validBlendfilePrefixes -MoveLog $pass2MoveLog", + "lineNumber": 417 + }, + { + "text": " $pass2Moved += $result.MovedCount", + "lineNumber": 418 + }, + { + "text": " $pass2Duplicates += $result.DuplicateCount", + "lineNumber": 419 + }, + { + "text": " }", + "lineNumber": 420 + }, + { + "text": " ", + "lineNumber": 421 + }, + { + "text": " # Process FlatColors files: merge duplicates and move to \\common\\FlatColors", + "lineNumber": 422 + }, + { + "text": " Write-Host \"Processing FlatColors files (merging duplicates)...\" -ForegroundColor Yellow", + "lineNumber": 423 + }, + { + "text": " ", + "lineNumber": 424 + }, + { + "text": " if ($null -ne $flatColorsFiles -and $flatColorsFiles.Count -gt 0) {", + "lineNumber": 425 + }, + { + "text": " Write-Host \"Found $($flatColorsFiles.Count) FlatColors file(s) to process\" -ForegroundColor Gray", + "lineNumber": 426 + } + ] + }, + "score": 0.2526206374168396 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\zip_sequences.py", + "range": { + "startPosition": {}, + "endPosition": { + "line": 102 + } + }, + "contents": "#!/usr/bin/env python3\n\"\"\"Maintain zipped render sequences for Git hooks.\n\nDefault mode scans `Renders/`, produces ZIP archives under `Renders/_zipped/`,\nand stages any updated archives so commits only track compact files. Switch to\n`--mode expand` to inflate the tracked archives back into the ignored working\ndirectories after checkouts or pulls.\n\"\"\"\n\nfrom __future__ import annotations\n\nimport argparse\nimport json\nimport os\nimport platform\nimport shutil\nimport subprocess\nimport sys\nimport tempfile\nimport time\nimport traceback\nfrom concurrent.futures import ThreadPoolExecutor, as_completed\nfrom pathlib import Path\nfrom typing import Iterator, Sequence\n\n# Try to import psutil for cross-platform RAM detection\ntry:\n import psutil\n HAS_PSUTIL = True\nexcept ImportError:\n HAS_PSUTIL = False\n # For Windows fallback\n if platform.system() == \"Windows\":\n try:\n import ctypes\n HAS_CTYPES = True\n except ImportError:\n HAS_CTYPES = False\n else:\n HAS_CTYPES = False\n\n\nRENDER_ROOT = Path(\"Renders\")\nARCHIVE_ROOT = RENDER_ROOT / \"_zipped\"\nSEQUENCE_EXTENSIONS = {\n \".png\",\n \".jpg\",\n \".jpeg\",\n \".tif\",\n \".tiff\",\n \".exr\",\n}\nSTATE_SUFFIX = \".meta.json\"\nDEFAULT_CONFIG = {\n \"zipper\": \"7z\",\n \"compression\": 9,\n \"compressionMethod\": \"LZMA2\", # Compression method: LZMA2 (multi-threaded), PPMd (single-threaded), BZip2, Deflate\n \"dailyFormat\": \"daily_YYMMDD\",\n \"Max7zInst\": 0, # Maximum concurrent 7z instances (0 = auto-calculate)\n}\n\n\ndef log(mode: str, message: str, *, verbose_only: bool = False, verbose: bool = False) -> None:\n if verbose_only and not verbose:\n return\n print(f\"[{mode}] {message}\", flush=True)\n\n\ndef load_config() -> dict:\n # First try to load from project's .config folder (current working directory)\n # Then fall back to ProjectStructure repo config (next to zip_sequences.py)\n ", + "signatures": {}, + "detailedLines": [ + { + "text": "#!/usr/bin/env python3", + "lineNumber": 1 + }, + { + "text": "\"\"\"Maintain zipped render sequences for Git hooks.", + "lineNumber": 2 + }, + { + "lineNumber": 3 + }, + { + "text": "Default mode scans `Renders/`, produces ZIP archives under `Renders/_zipped/`,", + "lineNumber": 4 + }, + { + "text": "and stages any updated archives so commits only track compact files. Switch to", + "lineNumber": 5 + }, + { + "text": "`--mode expand` to inflate the tracked archives back into the ignored working", + "lineNumber": 6 + }, + { + "text": "directories after checkouts or pulls.", + "lineNumber": 7 + }, + { + "text": "\"\"\"", + "lineNumber": 8 + }, + { + "lineNumber": 9 + }, + { + "text": "from __future__ import annotations", + "lineNumber": 10 + }, + { + "lineNumber": 11 + }, + { + "text": "import argparse", + "lineNumber": 12 + }, + { + "text": "import json", + "lineNumber": 13 + }, + { + "text": "import os", + "lineNumber": 14 + }, + { + "text": "import platform", + "lineNumber": 15 + }, + { + "text": "import shutil", + "lineNumber": 16 + }, + { + "text": "import subprocess", + "lineNumber": 17 + }, + { + "text": "import sys", + "lineNumber": 18 + }, + { + "text": "import tempfile", + "lineNumber": 19 + }, + { + "text": "import time", + "lineNumber": 20 + }, + { + "text": "import traceback", + "lineNumber": 21 + }, + { + "text": "from concurrent.futures import ThreadPoolExecutor, as_completed", + "lineNumber": 22 + }, + { + "text": "from pathlib import Path", + "lineNumber": 23 + }, + { + "text": "from typing import Iterator, Sequence", + "lineNumber": 24 + }, + { + "lineNumber": 25 + }, + { + "text": "# Try to import psutil for cross-platform RAM detection", + "lineNumber": 26 + }, + { + "text": "try:", + "lineNumber": 27 + }, + { + "text": " import psutil", + "lineNumber": 28 + }, + { + "text": " HAS_PSUTIL = True", + "lineNumber": 29 + }, + { + "text": "except ImportError:", + "lineNumber": 30 + }, + { + "text": " HAS_PSUTIL = False", + "lineNumber": 31 + }, + { + "text": " # For Windows fallback", + "lineNumber": 32 + }, + { + "text": " if platform.system() == \"Windows\":", + "lineNumber": 33 + }, + { + "text": " try:", + "lineNumber": 34 + }, + { + "text": " import ctypes", + "lineNumber": 35 + }, + { + "text": " HAS_CTYPES = True", + "lineNumber": 36 + }, + { + "text": " except ImportError:", + "lineNumber": 37 + }, + { + "text": " HAS_CTYPES = False", + "lineNumber": 38 + }, + { + "text": " else:", + "lineNumber": 39 + }, + { + "text": " HAS_CTYPES = False", + "lineNumber": 40 + }, + { + "lineNumber": 41 + }, + { + "lineNumber": 42 + }, + { + "text": "RENDER_ROOT = Path(\"Renders\")", + "lineNumber": 43 + }, + { + "text": "ARCHIVE_ROOT = RENDER_ROOT / \"_zipped\"", + "lineNumber": 44 + }, + { + "text": "SEQUENCE_EXTENSIONS = {", + "lineNumber": 45 + }, + { + "text": " \".png\",", + "lineNumber": 46 + }, + { + "text": " \".jpg\",", + "lineNumber": 47 + }, + { + "text": " \".jpeg\",", + "lineNumber": 48 + }, + { + "text": " \".tif\",", + "lineNumber": 49 + }, + { + "text": " \".tiff\",", + "lineNumber": 50 + }, + { + "text": " \".exr\",", + "lineNumber": 51 + }, + { + "text": "}", + "lineNumber": 52 + }, + { + "text": "STATE_SUFFIX = \".meta.json\"", + "lineNumber": 53 + }, + { + "text": "DEFAULT_CONFIG = {", + "lineNumber": 54 + }, + { + "text": " \"zipper\": \"7z\",", + "lineNumber": 55 + }, + { + "text": " \"compression\": 9,", + "lineNumber": 56 + }, + { + "text": " \"compressionMethod\": \"LZMA2\", # Compression method: LZMA2 (multi-threaded), PPMd (single-threaded), BZip2, Deflate", + "lineNumber": 57 + }, + { + "text": " \"dailyFormat\": \"daily_YYMMDD\",", + "lineNumber": 58 + }, + { + "text": " \"Max7zInst\": 0, # Maximum concurrent 7z instances (0 = auto-calculate)", + "lineNumber": 59 + }, + { + "text": "}", + "lineNumber": 60 + }, + { + "lineNumber": 61 + }, + { + "lineNumber": 62 + }, + { + "text": "def log(mode: str, message: str, *, verbose_only: bool = False, verbose: bool = False) -> None:", + "lineNumber": 63, + "isSignature": true + }, + { + "text": " if verbose_only and not verbose:", + "lineNumber": 64 + }, + { + "text": " return", + "lineNumber": 65 + }, + { + "text": " print(f\"[{mode}] {message}\", flush=True)", + "lineNumber": 66, + "isSignature": true + }, + { + "lineNumber": 67 + }, + { + "lineNumber": 68 + }, + { + "text": "def load_config() -> dict:", + "lineNumber": 69, + "isSignature": true + }, + { + "text": " # First try to load from project's .config folder (current working directory)", + "lineNumber": 70, + "isSignature": true + }, + { + "text": " # Then fall back to ProjectStructure repo config (next to zip_sequences.py)", + "lineNumber": 71, + "isSignature": true + }, + { + "text": " ", + "lineNumber": 72 + } + ] + }, + "score": 0.16568893194198608 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\replace_cel_with_bsdf.py", + "range": { + "startPosition": { + "line": 186, + "column": 26 + }, + "endPosition": { + "line": 355 + } + }, + "contents": "def replace_cel_materials():\n \"\"\"Replace all CEL materials with their BSDF counterparts using Blender's user remapping\"\"\"\n \n # First, link BSDF materials from library\n linked_materials = link_bsdf_materials()\n \n # Then, remap any missing datablocks\n missing_remaps = remap_missing_datablocks()\n \n # Then, remap any appended BSDF materials to linked versions\n appended_remaps = remap_appended_to_linked()\n \n print(f\"\\n=== STARTING MATERIAL REPLACEMENT ===\")\n \n # Custom material mappings (source -> target)\n custom_mappings = {\n \"bag BLACK (squid ink)\": \"BSDF_black_SQUID-INK\",\n \"bag WHITE\": \"BSDF_WHITE\",\n \"Wheel-White\": \"BSDF_WHITE\",\n \"Bag Colors\": \"BSDF_Bag Colors\",\n \"cardboard\": \"Package_Cardboard\",\n \"blue (triton)\": \"BSDF_blue-2_TRITON\",\n \"gray (snow)\": \"BSDF_gray-6_SNOW\",\n \"gray (storm)\": \"BSDF_gray-2_STORM\",\n \"gray (summit)\": \"BSDF_gray-5_SUMMIT\",\n \"light blue (prime)\": \"BSDF_blue-4_PRIME\",\n \"yellow (summer)\": \"BSDF_orange-5_SUMMER\",\n \"Accessory_CEL_gray-6_SNOW\": \"BSDF_gray-6_SNOW\",\n \"Accessory_CEL_SquidInk\": \"BSDF_black_SQUID-INK\",\n \"FingerScanner\": \"BSDF_black_SQUID-INK\",\n \"cel BLACK (squid ink)\": \"BSDF_black_SQUID-INK\",\n \"cel WHITE\": \"BSDF_WHITE\",\n \"gray (stone)\": \"BSDF_gray-3_STONE\",\n \"green (oxygen)\": \"BSDF_green-3_OXYGEN\",\n \"orange (smile)\": \"BSDF_orange-3_SMILE\",\n \"orange (blaze)\": \"BSDF_orange-1_BLAZE\"\n }\n \n # Get all materials in the scene\n materials = bpy.data.materials\n \n # Dictionary to store source -> target material mapping\n material_mapping = {}\n \n # Replace all CEL materials with their BSDF counterparts, ignoring numeric suffixes\n cel_pattern = re.compile(r\"^(CEL_.+?)(\\.\\d{3})?$\")\n bsdf_pattern = re.compile(r\"^(BSDF_.+?)(\\.\\d{3})?$\")\n \n # Build a mapping from base BSDF name to BSDF material (without suffix)", + "signatures": {}, + "detailedLines": [ + { + "text": "def replace_cel_materials():", + "lineNumber": 189, + "isSignature": true + }, + { + "text": " \"\"\"Replace all CEL materials with their BSDF counterparts using Blender's user remapping\"\"\"", + "lineNumber": 190 + }, + { + "text": " ", + "lineNumber": 191 + }, + { + "text": " # First, link BSDF materials from library", + "lineNumber": 192 + }, + { + "text": " linked_materials = link_bsdf_materials()", + "lineNumber": 193 + }, + { + "text": " ", + "lineNumber": 194 + }, + { + "text": " # Then, remap any missing datablocks", + "lineNumber": 195 + }, + { + "text": " missing_remaps = remap_missing_datablocks()", + "lineNumber": 196 + }, + { + "text": " ", + "lineNumber": 197 + }, + { + "text": " # Then, remap any appended BSDF materials to linked versions", + "lineNumber": 198 + }, + { + "text": " appended_remaps = remap_appended_to_linked()", + "lineNumber": 199 + }, + { + "text": " ", + "lineNumber": 200 + }, + { + "text": " print(f\"\\n=== STARTING MATERIAL REPLACEMENT ===\")", + "lineNumber": 201 + }, + { + "text": " ", + "lineNumber": 202 + }, + { + "text": " # Custom material mappings (source -> target)", + "lineNumber": 203 + }, + { + "text": " custom_mappings = {", + "lineNumber": 204 + }, + { + "text": " \"bag BLACK (squid ink)\": \"BSDF_black_SQUID-INK\",", + "lineNumber": 205 + }, + { + "text": " \"bag WHITE\": \"BSDF_WHITE\",", + "lineNumber": 206 + }, + { + "text": " \"Wheel-White\": \"BSDF_WHITE\",", + "lineNumber": 207 + }, + { + "text": " \"Bag Colors\": \"BSDF_Bag Colors\",", + "lineNumber": 208 + }, + { + "text": " \"cardboard\": \"Package_Cardboard\",", + "lineNumber": 209 + }, + { + "text": " \"blue (triton)\": \"BSDF_blue-2_TRITON\",", + "lineNumber": 210 + }, + { + "text": " \"gray (snow)\": \"BSDF_gray-6_SNOW\",", + "lineNumber": 211 + }, + { + "text": " \"gray (storm)\": \"BSDF_gray-2_STORM\",", + "lineNumber": 212 + }, + { + "text": " \"gray (summit)\": \"BSDF_gray-5_SUMMIT\",", + "lineNumber": 213 + }, + { + "text": " \"light blue (prime)\": \"BSDF_blue-4_PRIME\",", + "lineNumber": 214 + }, + { + "text": " \"yellow (summer)\": \"BSDF_orange-5_SUMMER\",", + "lineNumber": 215 + }, + { + "text": " \"Accessory_CEL_gray-6_SNOW\": \"BSDF_gray-6_SNOW\",", + "lineNumber": 216 + }, + { + "text": " \"Accessory_CEL_SquidInk\": \"BSDF_black_SQUID-INK\",", + "lineNumber": 217 + }, + { + "text": " \"FingerScanner\": \"BSDF_black_SQUID-INK\",", + "lineNumber": 218 + }, + { + "text": " \"cel BLACK (squid ink)\": \"BSDF_black_SQUID-INK\",", + "lineNumber": 219 + }, + { + "text": " \"cel WHITE\": \"BSDF_WHITE\",", + "lineNumber": 220 + }, + { + "text": " \"gray (stone)\": \"BSDF_gray-3_STONE\",", + "lineNumber": 221 + }, + { + "text": " \"green (oxygen)\": \"BSDF_green-3_OXYGEN\",", + "lineNumber": 222 + }, + { + "text": " \"orange (smile)\": \"BSDF_orange-3_SMILE\",", + "lineNumber": 223 + }, + { + "text": " \"orange (blaze)\": \"BSDF_orange-1_BLAZE\"", + "lineNumber": 224 + }, + { + "text": " }", + "lineNumber": 225 + }, + { + "text": " ", + "lineNumber": 226 + }, + { + "text": " # Get all materials in the scene", + "lineNumber": 227 + }, + { + "text": " materials = bpy.data.materials", + "lineNumber": 228 + }, + { + "text": " ", + "lineNumber": 229 + }, + { + "text": " # Dictionary to store source -> target material mapping", + "lineNumber": 230 + }, + { + "text": " material_mapping = {}", + "lineNumber": 231 + }, + { + "text": " ", + "lineNumber": 232 + }, + { + "text": " # Replace all CEL materials with their BSDF counterparts, ignoring numeric suffixes", + "lineNumber": 233 + }, + { + "text": " cel_pattern = re.compile(r\"^(CEL_.+?)(\\.\\d{3})?$\")", + "lineNumber": 234 + }, + { + "text": " bsdf_pattern = re.compile(r\"^(BSDF_.+?)(\\.\\d{3})?$\")", + "lineNumber": 235 + }, + { + "text": " ", + "lineNumber": 236 + }, + { + "text": " # Build a mapping from base BSDF name to BSDF material (without suffix)", + "lineNumber": 237 + } + ] + }, + "score": 0.15942895412445068 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\remap_texture_paths.py", + "range": { + "startPosition": { + "line": 18, + "column": 29 + }, + "endPosition": { + "line": 71 + } + }, + "contents": "def load_move_log(json_path):\n \"\"\"Load the move log JSON file and build lookup dictionaries\"\"\"\n try:\n with open(json_path, 'r', encoding='utf-8') as f:\n data = json.load(f)\n \n # Debug: Check what keys are in the data\n print(f\" JSON keys: {list(data.keys())}\")\n \n # PowerShell ConvertTo-Json uses PascalCase by default, so check both cases\n moves = data.get('moves', []) or data.get('Moves', [])\n \n print(f\" Found {len(moves)} move entries in JSON\")\n \n if len(moves) > 0:\n # Debug: Show first move entry structure\n print(f\" First move entry keys: {list(moves[0].keys())}\")\n print(f\" First move entry: {moves[0]}\")\n \n # Build lookup dictionaries: normalized original path -> actual new path\n original_to_new = {}\n original_to_replacement = {}\n \n for move in moves:\n # Try both camelCase and PascalCase property names\n move_type = move.get('type', '') or move.get('Type', '')\n original = move.get('originalPath', '') or move.get('OriginalPath', '')\n \n if not original:\n continue\n \n orig_norm = normalize_path(original)\n \n if move_type == 'moved' or move_type == 'Moved':\n new_path = move.get('newPath', '') or move.get('NewPath', '')\n if new_path:\n original_to_new[orig_norm] = new_path\n \n elif move_type == 'deleted' or move_type == 'Deleted':\n replacement = move.get('replacedBy', '') or move.get('ReplacedBy', '')\n if replacement:\n original_to_replacement[orig_norm] = replacement\n \n print(f\" Built {len(original_to_new)} move mappings and {len(original_to_replacement)} replacement mappings\")\n \n return original_to_new, original_to_replacement,", + "signatures": {}, + "detailedLines": [ + { + "text": "def load_move_log(json_path):", + "lineNumber": 21, + "isSignature": true + }, + { + "text": " \"\"\"Load the move log JSON file and build lookup dictionaries\"\"\"", + "lineNumber": 22 + }, + { + "text": " try:", + "lineNumber": 23 + }, + { + "text": " with open(json_path, 'r', encoding='utf-8') as f:", + "lineNumber": 24 + }, + { + "text": " data = json.load(f)", + "lineNumber": 25 + }, + { + "text": " ", + "lineNumber": 26 + }, + { + "text": " # Debug: Check what keys are in the data", + "lineNumber": 27 + }, + { + "text": " print(f\" JSON keys: {list(data.keys())}\")", + "lineNumber": 28 + }, + { + "text": " ", + "lineNumber": 29 + }, + { + "text": " # PowerShell ConvertTo-Json uses PascalCase by default, so check both cases", + "lineNumber": 30 + }, + { + "text": " moves = data.get('moves', []) or data.get('Moves', [])", + "lineNumber": 31 + }, + { + "text": " ", + "lineNumber": 32 + }, + { + "text": " print(f\" Found {len(moves)} move entries in JSON\")", + "lineNumber": 33 + }, + { + "text": " ", + "lineNumber": 34 + }, + { + "text": " if len(moves) > 0:", + "lineNumber": 35 + }, + { + "text": " # Debug: Show first move entry structure", + "lineNumber": 36 + }, + { + "text": " print(f\" First move entry keys: {list(moves[0].keys())}\")", + "lineNumber": 37 + }, + { + "text": " print(f\" First move entry: {moves[0]}\")", + "lineNumber": 38 + }, + { + "text": " ", + "lineNumber": 39 + }, + { + "text": " # Build lookup dictionaries: normalized original path -> actual new path", + "lineNumber": 40 + }, + { + "text": " original_to_new = {}", + "lineNumber": 41 + }, + { + "text": " original_to_replacement = {}", + "lineNumber": 42 + }, + { + "text": " ", + "lineNumber": 43 + }, + { + "text": " for move in moves:", + "lineNumber": 44 + }, + { + "text": " # Try both camelCase and PascalCase property names", + "lineNumber": 45 + }, + { + "text": " move_type = move.get('type', '') or move.get('Type', '')", + "lineNumber": 46 + }, + { + "text": " original = move.get('originalPath', '') or move.get('OriginalPath', '')", + "lineNumber": 47 + }, + { + "text": " ", + "lineNumber": 48 + }, + { + "text": " if not original:", + "lineNumber": 49 + }, + { + "text": " continue", + "lineNumber": 50 + }, + { + "text": " ", + "lineNumber": 51 + }, + { + "text": " orig_norm = normalize_path(original)", + "lineNumber": 52 + }, + { + "text": " ", + "lineNumber": 53 + }, + { + "text": " if move_type == 'moved' or move_type == 'Moved':", + "lineNumber": 54 + }, + { + "text": " new_path = move.get('newPath', '') or move.get('NewPath', '')", + "lineNumber": 55 + }, + { + "text": " if new_path:", + "lineNumber": 56 + }, + { + "text": " original_to_new[orig_norm] = new_path", + "lineNumber": 57 + }, + { + "text": " ", + "lineNumber": 58 + }, + { + "text": " elif move_type == 'deleted' or move_type == 'Deleted':", + "lineNumber": 59 + }, + { + "text": " replacement = move.get('replacedBy', '') or move.get('ReplacedBy', '')", + "lineNumber": 60 + }, + { + "text": " if replacement:", + "lineNumber": 61 + }, + { + "text": " original_to_replacement[orig_norm] = replacement", + "lineNumber": 62 + }, + { + "text": " ", + "lineNumber": 63 + }, + { + "text": " print(f\" Built {len(original_to_new)} move mappings and {len(original_to_replacement)} replacement mappings\")", + "lineNumber": 64 + }, + { + "text": " ", + "lineNumber": 65 + }, + { + "text": " return original_to_new, original_to_replacement,", + "lineNumber": 66 + } + ] + }, + "score": 0.14390915632247925 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\zip_sequences.py", + "range": { + "startPosition": { + "line": 65, + "column": 44 + }, + "endPosition": { + "line": 106, + "column": 39 + } + }, + "contents": "def load_config() -> dict:\n # First try to load from project's .config folder (current working directory)\n # Then fall back to ProjectStructure repo config (next to zip_sequences.py)\n cwd = Path.cwd()\n project_config = cwd / \".config\" / \"config.json\"\n repo_config = Path(__file__).resolve().with_name(\"config.json\")\n \n config_paths = [\n (\"project\", project_config),\n (\"repo\", repo_config),\n ]\n \n log(\"init\", \"Loading configuration sources...\")\n for source, config_path in config_paths:\n try:\n if config_path.exists():\n log(\"init\", f\"Reading {source} config at {config_path}\")\n text = config_path.read_text(encoding=\"utf-8\")\n try:\n data = json.loads(text)\n if isinstance(data, dict):\n merged = DEFAULT_CONFIG.copy()\n merged.update(data)\n log(\"init\", f\"Configuration loaded from {source}\")\n return merged\n except json.JSONDecodeError:\n log(\"init\", f\"Config file at {config_path} is invalid JSON; skipping\")\n continue\n except OSError:\n log(\"init\", f\"Unable to read config at {config_path}; skipping\")\n continue\n \n # If no config found, return defaults\n log(\"init\", \"No config files found; using default settings\")\n return DEFAULT_CONFIG.copy()\n\n\nCONFIG = load_config()\nzipper_val = CONFIG.get(\"zipper\", \"7z\")", + "signatures": {}, + "detailedLines": [ + { + "text": "def load_config() -> dict:", + "lineNumber": 69, + "isSignature": true + }, + { + "text": " # First try to load from project's .config folder (current working directory)", + "lineNumber": 70, + "isSignature": true + }, + { + "text": " # Then fall back to ProjectStructure repo config (next to zip_sequences.py)", + "lineNumber": 71, + "isSignature": true + }, + { + "text": " cwd = Path.cwd()", + "lineNumber": 72 + }, + { + "text": " project_config = cwd / \".config\" / \"config.json\"", + "lineNumber": 73 + }, + { + "text": " repo_config = Path(__file__).resolve().with_name(\"config.json\")", + "lineNumber": 74 + }, + { + "text": " ", + "lineNumber": 75 + }, + { + "text": " config_paths = [", + "lineNumber": 76 + }, + { + "text": " (\"project\", project_config),", + "lineNumber": 77 + }, + { + "text": " (\"repo\", repo_config),", + "lineNumber": 78 + }, + { + "text": " ]", + "lineNumber": 79 + }, + { + "text": " ", + "lineNumber": 80 + }, + { + "text": " log(\"init\", \"Loading configuration sources...\")", + "lineNumber": 81 + }, + { + "text": " for source, config_path in config_paths:", + "lineNumber": 82 + }, + { + "text": " try:", + "lineNumber": 83 + }, + { + "text": " if config_path.exists():", + "lineNumber": 84 + }, + { + "text": " log(\"init\", f\"Reading {source} config at {config_path}\")", + "lineNumber": 85 + }, + { + "text": " text = config_path.read_text(encoding=\"utf-8\")", + "lineNumber": 86 + }, + { + "text": " try:", + "lineNumber": 87 + }, + { + "text": " data = json.loads(text)", + "lineNumber": 88 + }, + { + "text": " if isinstance(data, dict):", + "lineNumber": 89 + }, + { + "text": " merged = DEFAULT_CONFIG.copy()", + "lineNumber": 90 + }, + { + "text": " merged.update(data)", + "lineNumber": 91 + }, + { + "text": " log(\"init\", f\"Configuration loaded from {source}\")", + "lineNumber": 92 + }, + { + "text": " return merged", + "lineNumber": 93 + }, + { + "text": " except json.JSONDecodeError:", + "lineNumber": 94 + }, + { + "text": " log(\"init\", f\"Config file at {config_path} is invalid JSON; skipping\")", + "lineNumber": 95 + }, + { + "text": " continue", + "lineNumber": 96 + }, + { + "text": " except OSError:", + "lineNumber": 97 + }, + { + "text": " log(\"init\", f\"Unable to read config at {config_path}; skipping\")", + "lineNumber": 98 + }, + { + "text": " continue", + "lineNumber": 99 + }, + { + "text": " ", + "lineNumber": 100 + }, + { + "text": " # If no config found, return defaults", + "lineNumber": 101 + }, + { + "text": " log(\"init\", \"No config files found; using default settings\")", + "lineNumber": 102 + }, + { + "text": " return DEFAULT_CONFIG.copy()", + "lineNumber": 103, + "isSignature": true + }, + { + "lineNumber": 104 + }, + { + "lineNumber": 105 + }, + { + "text": "CONFIG = load_config()", + "lineNumber": 106 + }, + { + "text": "zipper_val = CONFIG.get(\"zipper\", \"7z\")", + "lineNumber": 107 + } + ] + }, + "score": 0.14383095502853394 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\organize_textures.ps1", + "range": { + "startPosition": { + "line": 514 + }, + "endPosition": { + "line": 546, + "column": 12 + } + }, + "contents": "# Save Move Log and Find Blend Files\n# ============================================================================\nWrite-Host \"\"\nWrite-Host \"Saving move log and finding blend files...\" -ForegroundColor Yellow\n\n# Combine all move logs\n$allMoves = @()\nif ($null -ne $pass1MoveLog -and $pass1MoveLog.Count -gt 0) {\n $allMoves += $pass1MoveLog\n}\nif ($null -ne $pass2MoveLog -and $pass2MoveLog.Count -gt 0) {\n $allMoves += $pass2MoveLog\n}\nif ($null -ne $flatColorsMoveLog -and $flatColorsMoveLog.Count -gt 0) {\n $allMoves += $flatColorsMoveLog\n}\n\n# Get parent directory of texture folder\n$blendFileParentDir = Split-Path -Path $textureFolderPath -Parent\n\n# Find matching blend files\n# Match logic: blendfile folder name (e.g., \"Beth\") should appear in blend file name (e.g., \"AM_Beth_v3.2.blend\")\n$blendFileMappings = @()\nif ($null -ne $blendfileFolders -and $blendfileFolders.Count -gt 0) {\n # Get blendfile folder names\n $blendfileFolderNames = $blendfileFolders | ForEach-Object { $_.Name }\n \n # Find all .blend files in parent directory\n $blendFiles = Get-ChildItem -Path $blendFileParentDir -Filter \"*.blend\" -File -ErrorAction SilentlyContinue\n \n if ($null -ne $blendFiles -and $blendFiles.Count -gt 0) {\n foreach ($blendFile in $blendFiles) {\n ", + "signatures": {}, + "detailedLines": [ + { + "text": "# Save Move Log and Find Blend Files", + "lineNumber": 515 + }, + { + "text": "# ============================================================================", + "lineNumber": 516 + }, + { + "text": "Write-Host \"\"", + "lineNumber": 517 + }, + { + "text": "Write-Host \"Saving move log and finding blend files...\" -ForegroundColor Yellow", + "lineNumber": 518 + }, + { + "lineNumber": 519 + }, + { + "text": "# Combine all move logs", + "lineNumber": 520 + }, + { + "text": "$allMoves = @()", + "lineNumber": 521 + }, + { + "text": "if ($null -ne $pass1MoveLog -and $pass1MoveLog.Count -gt 0) {", + "lineNumber": 522 + }, + { + "text": " $allMoves += $pass1MoveLog", + "lineNumber": 523 + }, + { + "text": "}", + "lineNumber": 524 + }, + { + "text": "if ($null -ne $pass2MoveLog -and $pass2MoveLog.Count -gt 0) {", + "lineNumber": 525 + }, + { + "text": " $allMoves += $pass2MoveLog", + "lineNumber": 526 + }, + { + "text": "}", + "lineNumber": 527 + }, + { + "text": "if ($null -ne $flatColorsMoveLog -and $flatColorsMoveLog.Count -gt 0) {", + "lineNumber": 528 + }, + { + "text": " $allMoves += $flatColorsMoveLog", + "lineNumber": 529 + }, + { + "text": "}", + "lineNumber": 530 + }, + { + "lineNumber": 531 + }, + { + "text": "# Get parent directory of texture folder", + "lineNumber": 532 + }, + { + "text": "$blendFileParentDir = Split-Path -Path $textureFolderPath -Parent", + "lineNumber": 533 + }, + { + "lineNumber": 534 + }, + { + "text": "# Find matching blend files", + "lineNumber": 535 + }, + { + "text": "# Match logic: blendfile folder name (e.g., \"Beth\") should appear in blend file name (e.g., \"AM_Beth_v3.2.blend\")", + "lineNumber": 536 + }, + { + "text": "$blendFileMappings = @()", + "lineNumber": 537 + }, + { + "text": "if ($null -ne $blendfileFolders -and $blendfileFolders.Count -gt 0) {", + "lineNumber": 538 + }, + { + "text": " # Get blendfile folder names", + "lineNumber": 539 + }, + { + "text": " $blendfileFolderNames = $blendfileFolders | ForEach-Object { $_.Name }", + "lineNumber": 540 + }, + { + "text": " ", + "lineNumber": 541 + }, + { + "text": " # Find all .blend files in parent directory", + "lineNumber": 542 + }, + { + "text": " $blendFiles = Get-ChildItem -Path $blendFileParentDir -Filter \"*.blend\" -File -ErrorAction SilentlyContinue", + "lineNumber": 543 + }, + { + "text": " ", + "lineNumber": 544 + }, + { + "text": " if ($null -ne $blendFiles -and $blendFiles.Count -gt 0) {", + "lineNumber": 545 + }, + { + "text": " foreach ($blendFile in $blendFiles) {", + "lineNumber": 546 + }, + { + "text": " ", + "lineNumber": 547 + } + ] + }, + "score": 0.1407375931739807 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\components\\gitattributes", + "range": { + "startPosition": { + "line": 51 + }, + "endPosition": { + "line": 115 + } + }, + "contents": "*.hiplc filter=lfs diff=lfs merge=lfs -text\n*.bgeo filter=lfs diff=lfs merge=lfs -text\n*.bgeo.sc filter=lfs diff=lfs merge=lfs -text\n\n# Flip Fluids cache files\n*.data filter=lfs diff=lfs merge=lfs -text\n*.sqlite3 filter=lfs diff=lfs merge=lfs -text\n*.ffp3 filter=lfs diff=lfs merge=lfs -text\n\n# Substance files\n*.sbs filter=lfs diff=lfs merge=lfs -text\n*.sbsar filter=lfs diff=lfs merge=lfs -text\n*.spp filter=lfs diff=lfs merge=lfs -text\n\n# Audio files\n*.mp3 filter=lfs diff=lfs merge=lfs -text\n*.wav filter=lfs diff=lfs merge=lfs -text\n*.m4a filter=lfs diff=lfs merge=lfs -text\n*.aac filter=lfs diff=lfs merge=lfs -text\n*.ogg filter=lfs diff=lfs merge=lfs -text\n*.flac filter=lfs diff=lfs merge=lfs -text\n\n# Archive/Compression files\n*.7z filter=lfs diff=lfs merge=lfs -text\n*.bz2 filter=lfs diff=lfs merge=lfs -text\n*.gz filter=lfs diff=lfs merge=lfs -text\n*.rar filter=lfs diff=lfs merge=lfs -text\n*.tar filter=lfs diff=lfs merge=lfs -text\n*.zip filter=lfs diff=lfs merge=lfs -text\n\n# Documents\n*.docx filter=lfs diff=lfs merge=lfs -text\n*.xlsx filter=lfs diff=lfs merge=lfs -text\n*.eps filter=lfs diff=lfs merge=lfs -text\n*.pdf filter=lfs diff=lfs merge=lfs -text\n\n# Adobe files\n*.aegraphic filter=lfs diff=lfs merge=lfs -text\n*.aep filter=lfs diff=lfs merge=lfs -text\n*.prel filter=lfs diff=lfs merge=lfs -text\n*.prin filter=lfs diff=lfs merge=lfs -text\n*.prmf filter=lfs diff=lfs merge=lfs -text\n*.prproj filter=lfs diff=lfs merge=lfs -text\n*.ai filter=lfs diff=lfs merge=lfs -text\n*.psd filter=lfs diff=lfs merge=lfs -text\n\n# Davinci Resolve files\n*.dpx filter=lfs diff=lfs merge=lfs -text\n*.drp filter=lfs diff=lfs merge=lfs -text\n\n# Data files\n*.h5 filter=lfs diff=lfs merge=lfs -text\n*.hdf5 filter=lfs diff=lfs merge=lfs -text\n\n# Other\n*.uni filter=lfs diff=lfs merge=lfs -text\n*.pdn filter=lfs diff=lfs merge=lfs -text\n*.pur filter=lfs diff=lfs merge=lfs -text\n*.db filter=lfs diff=lfs merge=lfs -text\n\n# Python files\n*.npz filter=lfs diff=lfs merge=lfs -text\n\n# Adobe Alternatives", + "signatures": {}, + "detailedLines": [ + { + "text": "*.hiplc filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 52 + }, + { + "text": "*.bgeo filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 53 + }, + { + "text": "*.bgeo.sc filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 54 + }, + { + "lineNumber": 55 + }, + { + "text": "# Flip Fluids cache files", + "lineNumber": 56 + }, + { + "text": "*.data filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 57 + }, + { + "text": "*.sqlite3 filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 58 + }, + { + "text": "*.ffp3 filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 59 + }, + { + "lineNumber": 60 + }, + { + "text": "# Substance files", + "lineNumber": 61 + }, + { + "text": "*.sbs filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 62 + }, + { + "text": "*.sbsar filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 63 + }, + { + "text": "*.spp filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 64 + }, + { + "lineNumber": 65 + }, + { + "text": "# Audio files", + "lineNumber": 66 + }, + { + "text": "*.mp3 filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 67 + }, + { + "text": "*.wav filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 68 + }, + { + "text": "*.m4a filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 69 + }, + { + "text": "*.aac filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 70 + }, + { + "text": "*.ogg filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 71 + }, + { + "text": "*.flac filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 72 + }, + { + "lineNumber": 73 + }, + { + "text": "# Archive/Compression files", + "lineNumber": 74 + }, + { + "text": "*.7z filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 75 + }, + { + "text": "*.bz2 filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 76 + }, + { + "text": "*.gz filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 77 + }, + { + "text": "*.rar filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 78 + }, + { + "text": "*.tar filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 79 + }, + { + "text": "*.zip filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 80 + }, + { + "lineNumber": 81 + }, + { + "text": "# Documents", + "lineNumber": 82 + }, + { + "text": "*.docx filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 83 + }, + { + "text": "*.xlsx filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 84 + }, + { + "text": "*.eps filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 85 + }, + { + "text": "*.pdf filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 86 + }, + { + "lineNumber": 87 + }, + { + "text": "# Adobe files", + "lineNumber": 88 + }, + { + "text": "*.aegraphic filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 89 + }, + { + "text": "*.aep filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 90 + }, + { + "text": "*.prel filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 91 + }, + { + "text": "*.prin filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 92 + }, + { + "text": "*.prmf filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 93 + }, + { + "text": "*.prproj filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 94 + }, + { + "text": "*.ai filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 95 + }, + { + "text": "*.psd filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 96 + }, + { + "lineNumber": 97 + }, + { + "text": "# Davinci Resolve files", + "lineNumber": 98 + }, + { + "text": "*.dpx filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 99 + }, + { + "text": "*.drp filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 100 + }, + { + "lineNumber": 101 + }, + { + "text": "# Data files", + "lineNumber": 102 + }, + { + "text": "*.h5 filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 103 + }, + { + "text": "*.hdf5 filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 104 + }, + { + "lineNumber": 105 + }, + { + "text": "# Other", + "lineNumber": 106 + }, + { + "text": "*.uni filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 107 + }, + { + "text": "*.pdn filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 108 + }, + { + "text": "*.pur filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 109 + }, + { + "text": "*.db filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 110 + }, + { + "lineNumber": 111 + }, + { + "text": "# Python files", + "lineNumber": 112 + }, + { + "text": "*.npz filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 113 + }, + { + "lineNumber": 114 + }, + { + "text": "# Adobe Alternatives", + "lineNumber": 115 + } + ] + }, + "score": 0.13852763175964355 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\ConfigLoader.ps1", + "range": { + "startPosition": {}, + "endPosition": { + "line": 54 + } + }, + "contents": "[CmdletBinding()]\nparam(\n [Parameter(Mandatory=$false)]\n [string]$ProjectPath\n)\n\nSet-StrictMode -Version Latest\n$ErrorActionPreference = 'Stop'\n\n$script:LoaderRoot = Split-Path -Parent $MyInvocation.MyCommand.Path\n$script:ConfigPath = Join-Path -Path $script:LoaderRoot -ChildPath 'config.json'\n$script:ConfigCache = $null\n\nfunction Get-ProjectStructureConfig {\n if ($null -ne $script:ConfigCache) {\n return $script:ConfigCache\n }\n\n if (Test-Path -LiteralPath $script:ConfigPath) {\n try {\n $raw = Get-Content -LiteralPath $script:ConfigPath -Raw -ErrorAction Stop\n if ($raw.Trim().Length -gt 0) {\n $script:ConfigCache = $raw | ConvertFrom-Json\n return $script:ConfigCache\n }\n }\n catch {\n Write-Warning \"Failed to parse config.json: $($_.Exception.Message)\"\n }\n }\n\n $script:ConfigCache = [pscustomobject]@{}\n return $script:ConfigCache\n}\n\nfunction Get-ConfigValue {\n param(\n [Parameter(Mandatory)] [string]$Name,\n $Default = $null\n )\n\n $config = Get-ProjectStructureConfig\n if ($config.PSObject.Properties.Name -contains $Name) {\n $value = $config.$Name\n if ($null -ne $value -and ($value -isnot [string] -or $value.Trim().Length -gt 0)) {\n return $value\n }\n }\n\n return $Default\n}\n\nfunction Get-StructDirectory {\n # When script is run directly (not dot-sourced), always use script's directory for portability", + "signatures": {}, + "detailedLines": [ + { + "text": "[CmdletBinding()]", + "lineNumber": 1 + }, + { + "text": "param(", + "lineNumber": 2 + }, + { + "text": " [Parameter(Mandatory=$false)]", + "lineNumber": 3 + }, + { + "text": " [string]$ProjectPath", + "lineNumber": 4 + }, + { + "text": ")", + "lineNumber": 5 + }, + { + "lineNumber": 6 + }, + { + "text": "Set-StrictMode -Version Latest", + "lineNumber": 7 + }, + { + "text": "$ErrorActionPreference = 'Stop'", + "lineNumber": 8 + }, + { + "lineNumber": 9 + }, + { + "text": "$script:LoaderRoot = Split-Path -Parent $MyInvocation.MyCommand.Path", + "lineNumber": 10 + }, + { + "text": "$script:ConfigPath = Join-Path -Path $script:LoaderRoot -ChildPath 'config.json'", + "lineNumber": 11 + }, + { + "text": "$script:ConfigCache = $null", + "lineNumber": 12 + }, + { + "lineNumber": 13 + }, + { + "text": "function Get-ProjectStructureConfig {", + "lineNumber": 14 + }, + { + "text": " if ($null -ne $script:ConfigCache) {", + "lineNumber": 15 + }, + { + "text": " return $script:ConfigCache", + "lineNumber": 16 + }, + { + "text": " }", + "lineNumber": 17 + }, + { + "lineNumber": 18 + }, + { + "text": " if (Test-Path -LiteralPath $script:ConfigPath) {", + "lineNumber": 19 + }, + { + "text": " try {", + "lineNumber": 20 + }, + { + "text": " $raw = Get-Content -LiteralPath $script:ConfigPath -Raw -ErrorAction Stop", + "lineNumber": 21 + }, + { + "text": " if ($raw.Trim().Length -gt 0) {", + "lineNumber": 22 + }, + { + "text": " $script:ConfigCache = $raw | ConvertFrom-Json", + "lineNumber": 23 + }, + { + "text": " return $script:ConfigCache", + "lineNumber": 24 + }, + { + "text": " }", + "lineNumber": 25 + }, + { + "text": " }", + "lineNumber": 26 + }, + { + "text": " catch {", + "lineNumber": 27 + }, + { + "text": " Write-Warning \"Failed to parse config.json: $($_.Exception.Message)\"", + "lineNumber": 28 + }, + { + "text": " }", + "lineNumber": 29 + }, + { + "text": " }", + "lineNumber": 30 + }, + { + "lineNumber": 31 + }, + { + "text": " $script:ConfigCache = [pscustomobject]@{}", + "lineNumber": 32 + }, + { + "text": " return $script:ConfigCache", + "lineNumber": 33 + }, + { + "text": "}", + "lineNumber": 34 + }, + { + "lineNumber": 35 + }, + { + "text": "function Get-ConfigValue {", + "lineNumber": 36 + }, + { + "text": " param(", + "lineNumber": 37 + }, + { + "text": " [Parameter(Mandatory)] [string]$Name,", + "lineNumber": 38 + }, + { + "text": " $Default = $null", + "lineNumber": 39 + }, + { + "text": " )", + "lineNumber": 40 + }, + { + "lineNumber": 41 + }, + { + "text": " $config = Get-ProjectStructureConfig", + "lineNumber": 42 + }, + { + "text": " if ($config.PSObject.Properties.Name -contains $Name) {", + "lineNumber": 43 + }, + { + "text": " $value = $config.$Name", + "lineNumber": 44 + }, + { + "text": " if ($null -ne $value -and ($value -isnot [string] -or $value.Trim().Length -gt 0)) {", + "lineNumber": 45 + }, + { + "text": " return $value", + "lineNumber": 46 + }, + { + "text": " }", + "lineNumber": 47 + }, + { + "text": " }", + "lineNumber": 48 + }, + { + "lineNumber": 49 + }, + { + "text": " return $Default", + "lineNumber": 50 + }, + { + "text": "}", + "lineNumber": 51 + }, + { + "lineNumber": 52 + }, + { + "text": "function Get-StructDirectory {", + "lineNumber": 53 + }, + { + "text": " # When script is run directly (not dot-sourced), always use script's directory for portability", + "lineNumber": 54 + } + ] + }, + "score": 0.13009920716285706 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\replace_cel_with_bsdf.py", + "range": { + "startPosition": {}, + "endPosition": { + "line": 106 + } + }, + "contents": "import bpy\nimport re\nimport os\n\ndef link_bsdf_materials():\n \"\"\"Link all materials from the BSDF library file\"\"\"\n \n library_path = r\"R:\\Creative\\artsy\\maya\\0 ProjectStructure\\1 BlenderAssets\\Amazon\\MATERIALS_BSDF_pallette_v1.0.blend\"\n \n if not os.path.exists(library_path):\n print(f\"Warning: Library file not found at {library_path}\")\n return []\n \n print(f\"Linking materials from: {library_path}\")\n \n # Get list of materials before linking\n materials_before = set(bpy.data.materials.keys())\n \n # Link all materials from the library file\n with bpy.data.libraries.load(library_path, link=True) as (data_from, data_to):\n # Link all materials\n data_to.materials = data_from.materials\n \n # Get list of newly linked materials\n materials_after = set(bpy.data.materials.keys())\n newly_linked = materials_after - materials_before\n \n print(f\"Linked {len(newly_linked)} materials from library\")\n for mat_name in sorted(newly_linked):\n print(f\" - {mat_name}\")\n \n return list(newly_linked)\n\ndef remap_appended_to_linked():\n \"\"\"Remap any appended BSDF materials to their linked counterparts\"\"\"", + "signatures": {}, + "detailedLines": [ + { + "text": "import bpy", + "lineNumber": 1 + }, + { + "text": "import re", + "lineNumber": 2 + }, + { + "text": "import os", + "lineNumber": 3 + }, + { + "lineNumber": 4 + }, + { + "text": "def link_bsdf_materials():", + "lineNumber": 5, + "isSignature": true + }, + { + "text": " \"\"\"Link all materials from the BSDF library file\"\"\"", + "lineNumber": 6 + }, + { + "text": " ", + "lineNumber": 7 + }, + { + "text": " library_path = r\"R:\\Creative\\artsy\\maya\\0 ProjectStructure\\1 BlenderAssets\\Amazon\\MATERIALS_BSDF_pallette_v1.0.blend\"", + "lineNumber": 8 + }, + { + "text": " ", + "lineNumber": 9 + }, + { + "text": " if not os.path.exists(library_path):", + "lineNumber": 10 + }, + { + "text": " print(f\"Warning: Library file not found at {library_path}\")", + "lineNumber": 11 + }, + { + "text": " return []", + "lineNumber": 12 + }, + { + "text": " ", + "lineNumber": 13 + }, + { + "text": " print(f\"Linking materials from: {library_path}\")", + "lineNumber": 14 + }, + { + "text": " ", + "lineNumber": 15 + }, + { + "text": " # Get list of materials before linking", + "lineNumber": 16 + }, + { + "text": " materials_before = set(bpy.data.materials.keys())", + "lineNumber": 17 + }, + { + "text": " ", + "lineNumber": 18 + }, + { + "text": " # Link all materials from the library file", + "lineNumber": 19 + }, + { + "text": " with bpy.data.libraries.load(library_path, link=True) as (data_from, data_to):", + "lineNumber": 20 + }, + { + "text": " # Link all materials", + "lineNumber": 21 + }, + { + "text": " data_to.materials = data_from.materials", + "lineNumber": 22 + }, + { + "text": " ", + "lineNumber": 23 + }, + { + "text": " # Get list of newly linked materials", + "lineNumber": 24 + }, + { + "text": " materials_after = set(bpy.data.materials.keys())", + "lineNumber": 25 + }, + { + "text": " newly_linked = materials_after - materials_before", + "lineNumber": 26 + }, + { + "text": " ", + "lineNumber": 27 + }, + { + "text": " print(f\"Linked {len(newly_linked)} materials from library\")", + "lineNumber": 28 + }, + { + "text": " for mat_name in sorted(newly_linked):", + "lineNumber": 29 + }, + { + "text": " print(f\" - {mat_name}\")", + "lineNumber": 30 + }, + { + "text": " ", + "lineNumber": 31 + }, + { + "text": " return list(newly_linked)", + "lineNumber": 32, + "isSignature": true + }, + { + "lineNumber": 33 + }, + { + "text": "def remap_appended_to_linked():", + "lineNumber": 34, + "isSignature": true + }, + { + "text": " \"\"\"Remap any appended BSDF materials to their linked counterparts\"\"\"", + "lineNumber": 35 + } + ] + }, + "score": 0.1130639985203743 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\organize_textures.ps1", + "range": { + "startPosition": { + "line": 543 + }, + "endPosition": { + "line": 585 + } + }, + "contents": " \n if ($null -ne $blendFiles -and $blendFiles.Count -gt 0) {\n foreach ($blendFile in $blendFiles) {\n $blendFileName = $blendFile.BaseName\n \n # Check if any blendfile folder name appears in the blend file name\n foreach ($folderName in $blendfileFolderNames) {\n # Match folder name when surrounded by underscores, dots, hyphens, or at start/end\n # This avoids partial matches (e.g., \"Beth\" in \"Bethany\") while allowing \"Beth\" in \"AM_Beth_v3.2\"\n $escapedFolderName = [regex]::Escape($folderName)\n if ($blendFileName -match \"(^|[._-])$escapedFolderName([._-]|$)\") {\n $blendFileMappings += [PSCustomObject]@{\n BlendFile = [System.IO.Path]::GetFullPath($blendFile.FullName)\n BlendfileFolder = $folderName\n }\n Write-Host \"Found matching blend file: $($blendFile.Name) -> $folderName\" -ForegroundColor Gray\n break # Only match once per blend file\n }\n }\n }\n }\n}\n\n# Create move log object\n$moveLogData = [PSCustomObject]@{\n TextureFolderPath = $textureFolderPath\n Timestamp = (Get-Date -Format \"yyyy-MM-ddTHH:mm:ssZ\")\n TotalMoves = ($allMoves | Where-Object { $_.Type -eq \"moved\" }).Count\n TotalDeletes = ($allMoves | Where-Object { $_.Type -eq \"deleted\" }).Count\n Moves = $allMoves\n BlendFileMappings = $blendFileMappings\n}\n\n# Save to JSON file\n$moveLogPath = Join-Path -Path $blendFileParentDir -ChildPath \"texture_moves.json\"\ntry {\n $moveLogData | ConvertTo-Json -Depth 10 | Set-Content -Path $moveLogPath -Encoding UTF8\n Write-Host \"Move log saved to: $moveLogPath\" -ForegroundColor Green\n Write-Host \" Total moves: $($moveLogData.TotalMoves), Total deletes: $($moveLogData.TotalDeletes)\" -ForegroundColor Gray\n Write-Host \" Blend files found: $($blendFileMappings.Count)\" -ForegroundColor Gray\n} catch {\n Write-Warning \"Failed to save move log: $($_.Exception.Message)\"", + "signatures": {}, + "detailedLines": [ + { + "text": " ", + "lineNumber": 544 + }, + { + "text": " if ($null -ne $blendFiles -and $blendFiles.Count -gt 0) {", + "lineNumber": 545 + }, + { + "text": " foreach ($blendFile in $blendFiles) {", + "lineNumber": 546 + }, + { + "text": " $blendFileName = $blendFile.BaseName", + "lineNumber": 547 + }, + { + "text": " ", + "lineNumber": 548 + }, + { + "text": " # Check if any blendfile folder name appears in the blend file name", + "lineNumber": 549 + }, + { + "text": " foreach ($folderName in $blendfileFolderNames) {", + "lineNumber": 550 + }, + { + "text": " # Match folder name when surrounded by underscores, dots, hyphens, or at start/end", + "lineNumber": 551 + }, + { + "text": " # This avoids partial matches (e.g., \"Beth\" in \"Bethany\") while allowing \"Beth\" in \"AM_Beth_v3.2\"", + "lineNumber": 552 + }, + { + "text": " $escapedFolderName = [regex]::Escape($folderName)", + "lineNumber": 553 + }, + { + "text": " if ($blendFileName -match \"(^|[._-])$escapedFolderName([._-]|$)\") {", + "lineNumber": 554 + }, + { + "text": " $blendFileMappings += [PSCustomObject]@{", + "lineNumber": 555 + }, + { + "text": " BlendFile = [System.IO.Path]::GetFullPath($blendFile.FullName)", + "lineNumber": 556 + }, + { + "text": " BlendfileFolder = $folderName", + "lineNumber": 557 + }, + { + "text": " }", + "lineNumber": 558 + }, + { + "text": " Write-Host \"Found matching blend file: $($blendFile.Name) -> $folderName\" -ForegroundColor Gray", + "lineNumber": 559 + }, + { + "text": " break # Only match once per blend file", + "lineNumber": 560 + }, + { + "text": " }", + "lineNumber": 561 + }, + { + "text": " }", + "lineNumber": 562 + }, + { + "text": " }", + "lineNumber": 563 + }, + { + "text": " }", + "lineNumber": 564 + }, + { + "text": "}", + "lineNumber": 565 + }, + { + "lineNumber": 566 + }, + { + "text": "# Create move log object", + "lineNumber": 567 + }, + { + "text": "$moveLogData = [PSCustomObject]@{", + "lineNumber": 568 + }, + { + "text": " TextureFolderPath = $textureFolderPath", + "lineNumber": 569 + }, + { + "text": " Timestamp = (Get-Date -Format \"yyyy-MM-ddTHH:mm:ssZ\")", + "lineNumber": 570 + }, + { + "text": " TotalMoves = ($allMoves | Where-Object { $_.Type -eq \"moved\" }).Count", + "lineNumber": 571 + }, + { + "text": " TotalDeletes = ($allMoves | Where-Object { $_.Type -eq \"deleted\" }).Count", + "lineNumber": 572 + }, + { + "text": " Moves = $allMoves", + "lineNumber": 573 + }, + { + "text": " BlendFileMappings = $blendFileMappings", + "lineNumber": 574 + }, + { + "text": "}", + "lineNumber": 575 + }, + { + "lineNumber": 576 + }, + { + "text": "# Save to JSON file", + "lineNumber": 577 + }, + { + "text": "$moveLogPath = Join-Path -Path $blendFileParentDir -ChildPath \"texture_moves.json\"", + "lineNumber": 578 + }, + { + "text": "try {", + "lineNumber": 579 + }, + { + "text": " $moveLogData | ConvertTo-Json -Depth 10 | Set-Content -Path $moveLogPath -Encoding UTF8", + "lineNumber": 580 + }, + { + "text": " Write-Host \"Move log saved to: $moveLogPath\" -ForegroundColor Green", + "lineNumber": 581 + }, + { + "text": " Write-Host \" Total moves: $($moveLogData.TotalMoves), Total deletes: $($moveLogData.TotalDeletes)\" -ForegroundColor Gray", + "lineNumber": 582 + }, + { + "text": " Write-Host \" Blend files found: $($blendFileMappings.Count)\" -ForegroundColor Gray", + "lineNumber": 583 + }, + { + "text": "} catch {", + "lineNumber": 584 + }, + { + "text": " Write-Warning \"Failed to save move log: $($_.Exception.Message)\"", + "lineNumber": 585 + } + ] + }, + "score": 0.11181569844484329 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\zip_sequences.py", + "range": { + "startPosition": { + "line": 102, + "column": 32 + }, + "endPosition": { + "line": 202 + } + }, + "contents": "CONFIG = load_config()\nzipper_val = CONFIG.get(\"zipper\", \"7z\")\n# Handle both old boolean format and new string format\nif isinstance(zipper_val, bool):\n ZIPPER_TYPE = \"7z\" if zipper_val else \"zip\"\nelse:\n ZIPPER_TYPE = str(zipper_val).lower()\n\nCOMPRESSION_LEVEL = CONFIG.get(\"compression\", 9)\nif isinstance(COMPRESSION_LEVEL, str):\n try:\n COMPRESSION_LEVEL = int(COMPRESSION_LEVEL)\n except ValueError:\n COMPRESSION_LEVEL = 9\nif not isinstance(COMPRESSION_LEVEL, int):\n COMPRESSION_LEVEL = 9\nCOMPRESSION_LEVEL = max(0, min(9, COMPRESSION_LEVEL))\n\nCOMPRESSION_METHOD = CONFIG.get(\"compressionMethod\", \"LZMA2\")\n# Validate compression method\nvalid_methods = {\"LZMA2\", \"PPMd\", \"BZip2\", \"Deflate\"}\nif COMPRESSION_METHOD not in valid_methods:\n COMPRESSION_METHOD = \"LZMA2\" # Default to LZMA2 for multi-threading support\n\nMAX_7Z_INSTANCES = CONFIG.get(\"Max7zInst\", 0)\nif MAX_7Z_INSTANCES is not None:\n if isinstance(MAX_7Z_INSTANCES, str):\n try:\n MAX_7Z_INSTANCES = int(MAX_7Z_INSTANCES)\n except ValueError:\n MAX_7Z_INSTANCES = 0\n if not isinstance(MAX_7Z_INSTANCES, int) or MAX_7Z_INSTANCES < 1:\n MAX_7Z_INSTANCES = 0\n# Treat 0 as None (auto-calculate)\nif MAX_7Z_INSTANCES == 0:\n MAX_7Z_INSTANCES = None\n\nSEVEN_Z_EXE: str | None = None\nif ZIPPER_TYPE == \"7z\":\n SEVEN_Z_EXE = shutil.which(\"7z\") or shutil.which(\"7za\")\n\n\ndef parse_args() -> argparse.Namespace:\n parser = argparse.ArgumentParser(description=\"Sync render sequences with zipped archives.\")\n parser.add_argument(\n \"--mode\",\n choices=(\"zip\", \"expand\"),\n default=\"zip\",\n help=\"zip sequences for commit (default) or expand tracked archives\",\n )\n parser.add_argument(\"--jobs\", type=int, help=\"max parallel workers\")\n parser.add_argument(\"--verbose\", action=\"store_true\", help=\"print extra progress details\")\n return parser.parse_args()\n\n\ndef get_available_ram() -> int | None:\n \"\"\"", + "signatures": {}, + "detailedLines": [ + { + "text": "CONFIG = load_config()", + "lineNumber": 106 + }, + { + "text": "zipper_val = CONFIG.get(\"zipper\", \"7z\")", + "lineNumber": 107 + }, + { + "text": "# Handle both old boolean format and new string format", + "lineNumber": 108 + }, + { + "text": "if isinstance(zipper_val, bool):", + "lineNumber": 109 + }, + { + "text": " ZIPPER_TYPE = \"7z\" if zipper_val else \"zip\"", + "lineNumber": 110 + }, + { + "text": "else:", + "lineNumber": 111 + }, + { + "text": " ZIPPER_TYPE = str(zipper_val).lower()", + "lineNumber": 112 + }, + { + "lineNumber": 113 + }, + { + "text": "COMPRESSION_LEVEL = CONFIG.get(\"compression\", 9)", + "lineNumber": 114 + }, + { + "text": "if isinstance(COMPRESSION_LEVEL, str):", + "lineNumber": 115 + }, + { + "text": " try:", + "lineNumber": 116 + }, + { + "text": " COMPRESSION_LEVEL = int(COMPRESSION_LEVEL)", + "lineNumber": 117 + }, + { + "text": " except ValueError:", + "lineNumber": 118 + }, + { + "text": " COMPRESSION_LEVEL = 9", + "lineNumber": 119 + }, + { + "text": "if not isinstance(COMPRESSION_LEVEL, int):", + "lineNumber": 120 + }, + { + "text": " COMPRESSION_LEVEL = 9", + "lineNumber": 121 + }, + { + "text": "COMPRESSION_LEVEL = max(0, min(9, COMPRESSION_LEVEL))", + "lineNumber": 122 + }, + { + "lineNumber": 123 + }, + { + "text": "COMPRESSION_METHOD = CONFIG.get(\"compressionMethod\", \"LZMA2\")", + "lineNumber": 124 + }, + { + "text": "# Validate compression method", + "lineNumber": 125 + }, + { + "text": "valid_methods = {\"LZMA2\", \"PPMd\", \"BZip2\", \"Deflate\"}", + "lineNumber": 126 + }, + { + "text": "if COMPRESSION_METHOD not in valid_methods:", + "lineNumber": 127 + }, + { + "text": " COMPRESSION_METHOD = \"LZMA2\" # Default to LZMA2 for multi-threading support", + "lineNumber": 128 + }, + { + "lineNumber": 129 + }, + { + "text": "MAX_7Z_INSTANCES = CONFIG.get(\"Max7zInst\", 0)", + "lineNumber": 130 + }, + { + "text": "if MAX_7Z_INSTANCES is not None:", + "lineNumber": 131 + }, + { + "text": " if isinstance(MAX_7Z_INSTANCES, str):", + "lineNumber": 132 + }, + { + "text": " try:", + "lineNumber": 133 + }, + { + "text": " MAX_7Z_INSTANCES = int(MAX_7Z_INSTANCES)", + "lineNumber": 134 + }, + { + "text": " except ValueError:", + "lineNumber": 135 + }, + { + "text": " MAX_7Z_INSTANCES = 0", + "lineNumber": 136 + }, + { + "text": " if not isinstance(MAX_7Z_INSTANCES, int) or MAX_7Z_INSTANCES < 1:", + "lineNumber": 137 + }, + { + "text": " MAX_7Z_INSTANCES = 0", + "lineNumber": 138 + }, + { + "text": "# Treat 0 as None (auto-calculate)", + "lineNumber": 139 + }, + { + "text": "if MAX_7Z_INSTANCES == 0:", + "lineNumber": 140 + }, + { + "text": " MAX_7Z_INSTANCES = None", + "lineNumber": 141 + }, + { + "lineNumber": 142 + }, + { + "text": "SEVEN_Z_EXE: str | None = None", + "lineNumber": 143 + }, + { + "text": "if ZIPPER_TYPE == \"7z\":", + "lineNumber": 144 + }, + { + "text": " SEVEN_Z_EXE = shutil.which(\"7z\") or shutil.which(\"7za\")", + "lineNumber": 145 + }, + { + "lineNumber": 146 + }, + { + "lineNumber": 147 + }, + { + "text": "def parse_args() -> argparse.Namespace:", + "lineNumber": 148, + "isSignature": true + }, + { + "text": " parser = argparse.ArgumentParser(description=\"Sync render sequences with zipped archives.\")", + "lineNumber": 149 + }, + { + "text": " parser.add_argument(", + "lineNumber": 150 + }, + { + "text": " \"--mode\",", + "lineNumber": 151 + }, + { + "text": " choices=(\"zip\", \"expand\"),", + "lineNumber": 152 + }, + { + "text": " default=\"zip\",", + "lineNumber": 153 + }, + { + "text": " help=\"zip sequences for commit (default) or expand tracked archives\",", + "lineNumber": 154 + }, + { + "text": " )", + "lineNumber": 155 + }, + { + "text": " parser.add_argument(\"--jobs\", type=int, help=\"max parallel workers\")", + "lineNumber": 156 + }, + { + "text": " parser.add_argument(\"--verbose\", action=\"store_true\", help=\"print extra progress details\")", + "lineNumber": 157 + }, + { + "text": " return parser.parse_args()", + "lineNumber": 158, + "isSignature": true + }, + { + "lineNumber": 159 + }, + { + "lineNumber": 160 + }, + { + "text": "def get_available_ram() -> int | None:", + "lineNumber": 161, + "isSignature": true + }, + { + "text": " \"\"\"", + "lineNumber": 162 + } + ] + }, + "score": 0.10932300239801407 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\organize_textures.ps1", + "range": { + "startPosition": {}, + "endPosition": { + "line": 50 + } + }, + "contents": "# Script to organize texture files by checksum with two-level duplicate detection\n# Pass 1: Intra-blendfile duplicates → [blendfile]\\common\n# Pass 2: Inter-blendfile duplicates → \\textures\\common\n# Usage: .\\organize_textures.ps1\n\n# Prompt user for texture folder path\n$textureFolderPath = Read-Host \"Enter texture folder path\"\n\n# Validate the input path\nif ([string]::IsNullOrWhiteSpace($textureFolderPath)) {\n Write-Host \"Error: No path provided.\" -ForegroundColor Red\n exit\n}\n\nif (-not (Test-Path -Path $textureFolderPath -PathType Container)) {\n Write-Host \"Error: Path does not exist or is not a directory: $textureFolderPath\" -ForegroundColor Red\n exit\n}\n\n# Resolve the full path\n$textureFolderPath = (Resolve-Path $textureFolderPath).ProviderPath\nWrite-Host \"Processing texture folder: $textureFolderPath\" -ForegroundColor Cyan\n\n# Function to calculate checksums for files\nfunction Get-FilesWithChecksums {\n param(\n [array]$Files\n )\n \n $throttleLimit = [Math]::Max(1, [Environment]::ProcessorCount)\n $parallelScriptBlock = {\n try {\n $hash = Get-FileHash -Path $_.FullName -Algorithm SHA256\n [PSCustomObject]@{\n File = $_\n Hash = $hash.Hash\n }\n } catch {\n Write-Warning \"Failed to calculate checksum for: $($_.FullName) - $($_.Exception.Message)\"\n $null\n }\n }\n \n return $Files | ForEach-Object -Parallel $parallelScriptBlock -ThrottleLimit $throttleLimit | Where-Object { $null -ne $_ }\n}\n\n# Function to move files to common folder\nfunction Move-FilesToCommon {\n param(\n [array]$Files,", + "signatures": {}, + "detailedLines": [ + { + "text": "# Script to organize texture files by checksum with two-level duplicate detection", + "lineNumber": 1 + }, + { + "text": "# Pass 1: Intra-blendfile duplicates → [blendfile]\\common", + "lineNumber": 2 + }, + { + "text": "# Pass 2: Inter-blendfile duplicates → \\textures\\common", + "lineNumber": 3 + }, + { + "text": "# Usage: .\\organize_textures.ps1", + "lineNumber": 4 + }, + { + "lineNumber": 5 + }, + { + "text": "# Prompt user for texture folder path", + "lineNumber": 6 + }, + { + "text": "$textureFolderPath = Read-Host \"Enter texture folder path\"", + "lineNumber": 7 + }, + { + "lineNumber": 8 + }, + { + "text": "# Validate the input path", + "lineNumber": 9 + }, + { + "text": "if ([string]::IsNullOrWhiteSpace($textureFolderPath)) {", + "lineNumber": 10 + }, + { + "text": " Write-Host \"Error: No path provided.\" -ForegroundColor Red", + "lineNumber": 11 + }, + { + "text": " exit", + "lineNumber": 12 + }, + { + "text": "}", + "lineNumber": 13 + }, + { + "lineNumber": 14 + }, + { + "text": "if (-not (Test-Path -Path $textureFolderPath -PathType Container)) {", + "lineNumber": 15 + }, + { + "text": " Write-Host \"Error: Path does not exist or is not a directory: $textureFolderPath\" -ForegroundColor Red", + "lineNumber": 16 + }, + { + "text": " exit", + "lineNumber": 17 + }, + { + "text": "}", + "lineNumber": 18 + }, + { + "lineNumber": 19 + }, + { + "text": "# Resolve the full path", + "lineNumber": 20 + }, + { + "text": "$textureFolderPath = (Resolve-Path $textureFolderPath).ProviderPath", + "lineNumber": 21 + }, + { + "text": "Write-Host \"Processing texture folder: $textureFolderPath\" -ForegroundColor Cyan", + "lineNumber": 22 + }, + { + "lineNumber": 23 + }, + { + "text": "# Function to calculate checksums for files", + "lineNumber": 24 + }, + { + "text": "function Get-FilesWithChecksums {", + "lineNumber": 25 + }, + { + "text": " param(", + "lineNumber": 26 + }, + { + "text": " [array]$Files", + "lineNumber": 27 + }, + { + "text": " )", + "lineNumber": 28 + }, + { + "text": " ", + "lineNumber": 29 + }, + { + "text": " $throttleLimit = [Math]::Max(1, [Environment]::ProcessorCount)", + "lineNumber": 30 + }, + { + "text": " $parallelScriptBlock = {", + "lineNumber": 31 + }, + { + "text": " try {", + "lineNumber": 32 + }, + { + "text": " $hash = Get-FileHash -Path $_.FullName -Algorithm SHA256", + "lineNumber": 33 + }, + { + "text": " [PSCustomObject]@{", + "lineNumber": 34 + }, + { + "text": " File = $_", + "lineNumber": 35 + }, + { + "text": " Hash = $hash.Hash", + "lineNumber": 36 + }, + { + "text": " }", + "lineNumber": 37 + }, + { + "text": " } catch {", + "lineNumber": 38 + }, + { + "text": " Write-Warning \"Failed to calculate checksum for: $($_.FullName) - $($_.Exception.Message)\"", + "lineNumber": 39 + }, + { + "text": " $null", + "lineNumber": 40 + }, + { + "text": " }", + "lineNumber": 41 + }, + { + "text": " }", + "lineNumber": 42 + }, + { + "text": " ", + "lineNumber": 43 + }, + { + "text": " return $Files | ForEach-Object -Parallel $parallelScriptBlock -ThrottleLimit $throttleLimit | Where-Object { $null -ne $_ }", + "lineNumber": 44 + }, + { + "text": "}", + "lineNumber": 45 + }, + { + "lineNumber": 46 + }, + { + "text": "# Function to move files to common folder", + "lineNumber": 47 + }, + { + "text": "function Move-FilesToCommon {", + "lineNumber": 48 + }, + { + "text": " param(", + "lineNumber": 49 + }, + { + "text": " [array]$Files,", + "lineNumber": 50 + } + ] + }, + "score": 0.10515463352203369 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\zip_sequences.py", + "range": { + "startPosition": { + "line": 560, + "column": 33 + }, + "endPosition": { + "line": 650 + } + }, + "contents": "def load_state(state_path: Path) -> dict | None:\n if not state_path.exists():\n return None\n try:\n state = json.loads(state_path.read_text())\n # Remove Thumbs.db entries from loaded state\n if \"files\" in state:\n state[\"files\"] = [\n entry for entry in state.get(\"files\", [])\n if Path(entry.get(\"path\", \"\")).name.lower() != \"thumbs.db\"\n ]\n # Normalize timestamps in loaded state to ensure consistency\n # This handles state files created before normalization was added\n is_windows = platform.system() == \"Windows\"\n if is_windows and \"files\" in state:\n for entry in state.get(\"files\", []):\n if \"mtime_ns\" in entry:\n # Normalize to 100-nanosecond boundaries (NTFS precision)\n entry[\"mtime_ns\"] = (entry[\"mtime_ns\"] // 100) * 100\n return state\n except json.JSONDecodeError:\n return None\n\n\ndef state_changed(seq_state: dict, stored_state: dict | None, *, verbose: bool = False) -> bool:\n ", + "signatures": {}, + "detailedLines": [ + { + "text": "def load_state(state_path: Path) -> dict | None:", + "lineNumber": 564, + "isSignature": true + }, + { + "text": " if not state_path.exists():", + "lineNumber": 565 + }, + { + "text": " return None", + "lineNumber": 566 + }, + { + "text": " try:", + "lineNumber": 567 + }, + { + "text": " state = json.loads(state_path.read_text())", + "lineNumber": 568 + }, + { + "text": " # Remove Thumbs.db entries from loaded state", + "lineNumber": 569 + }, + { + "text": " if \"files\" in state:", + "lineNumber": 570 + }, + { + "text": " state[\"files\"] = [", + "lineNumber": 571 + }, + { + "text": " entry for entry in state.get(\"files\", [])", + "lineNumber": 572 + }, + { + "text": " if Path(entry.get(\"path\", \"\")).name.lower() != \"thumbs.db\"", + "lineNumber": 573 + }, + { + "text": " ]", + "lineNumber": 574 + }, + { + "text": " # Normalize timestamps in loaded state to ensure consistency", + "lineNumber": 575 + }, + { + "text": " # This handles state files created before normalization was added", + "lineNumber": 576 + }, + { + "text": " is_windows = platform.system() == \"Windows\"", + "lineNumber": 577 + }, + { + "text": " if is_windows and \"files\" in state:", + "lineNumber": 578 + }, + { + "text": " for entry in state.get(\"files\", []):", + "lineNumber": 579 + }, + { + "text": " if \"mtime_ns\" in entry:", + "lineNumber": 580 + }, + { + "text": " # Normalize to 100-nanosecond boundaries (NTFS precision)", + "lineNumber": 581 + }, + { + "text": " entry[\"mtime_ns\"] = (entry[\"mtime_ns\"] // 100) * 100", + "lineNumber": 582 + }, + { + "text": " return state", + "lineNumber": 583 + }, + { + "text": " except json.JSONDecodeError:", + "lineNumber": 584 + }, + { + "text": " return None", + "lineNumber": 585, + "isSignature": true + }, + { + "lineNumber": 586 + }, + { + "lineNumber": 587 + }, + { + "text": "def state_changed(seq_state: dict, stored_state: dict | None, *, verbose: bool = False) -> bool:", + "lineNumber": 588, + "isSignature": true + }, + { + "text": " ", + "lineNumber": 589 + } + ] + }, + "score": 0.10263250023126602 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\CONFIG.md", + "range": { + "startPosition": {}, + "endPosition": { + "line": 24 + } + }, + "contents": "# ProjectStructure Configuration\n\nThe repository reads user preferences from `config.json` in the ProjectStructure\nroot (copied alongside helper batches when they are deployed to projects).\n\n## Keys\n\n| Key | Type | Meaning |\n| --- | --- | --- |\n| `dailyFormat` | bool | `true` → daily folders named `YYYY-MM-DD`; `false` → `daily_*` style. |\n| `structDir` | string | Absolute or relative path to the canonical ProjectStructure directory. Blank values default to the folder containing `config.json`. |\n| `projectsRoot` | string (optional) | Override for the root directory scanned by `UpgradeSeqBatches.ps1`. Defaults to the parent of `structDir`. |\n| `zipper` | bool | `true` → use 7‑Zip (if available); `false` → use Python’s built-in zipfile module. |\n| `compression` | int | Compression level `0-9` (0 = store only, 9 = max). Applies to both zipfile and 7‑Zip. |\n\n## Notes\n\n- `UpdateProjectBatches.ps1` copies `config.json` and `ConfigLoader.ps1` to the\n target project so the helper `.bat` launchers can resolve script locations.\n- When `zipper` is `true`, the tool searches for `7z`/`7za` on `PATH`. If neither\n is found it logs a warning and falls back to `zipfile`.\n- Leaving `structDir` empty is safe—the scripts fall back to the directory that\n contains `config.json`.", + "signatures": {}, + "detailedLines": [ + { + "text": "# ProjectStructure Configuration", + "lineNumber": 1 + }, + { + "lineNumber": 2 + }, + { + "text": "The repository reads user preferences from `config.json` in the ProjectStructure", + "lineNumber": 3 + }, + { + "text": "root (copied alongside helper batches when they are deployed to projects).", + "lineNumber": 4 + }, + { + "lineNumber": 5 + }, + { + "text": "## Keys", + "lineNumber": 6 + }, + { + "lineNumber": 7 + }, + { + "text": "| Key | Type | Meaning |", + "lineNumber": 8 + }, + { + "text": "| --- | --- | --- |", + "lineNumber": 9 + }, + { + "text": "| `dailyFormat` | bool | `true` → daily folders named `YYYY-MM-DD`; `false` → `daily_*` style. |", + "lineNumber": 10 + }, + { + "text": "| `structDir` | string | Absolute or relative path to the canonical ProjectStructure directory. Blank values default to the folder containing `config.json`. |", + "lineNumber": 11 + }, + { + "text": "| `projectsRoot` | string (optional) | Override for the root directory scanned by `UpgradeSeqBatches.ps1`. Defaults to the parent of `structDir`. |", + "lineNumber": 12 + }, + { + "text": "| `zipper` | bool | `true` → use 7‑Zip (if available); `false` → use Python’s built-in zipfile module. |", + "lineNumber": 13 + }, + { + "text": "| `compression` | int | Compression level `0-9` (0 = store only, 9 = max). Applies to both zipfile and 7‑Zip. |", + "lineNumber": 14 + }, + { + "lineNumber": 15 + }, + { + "text": "## Notes", + "lineNumber": 16 + }, + { + "lineNumber": 17 + }, + { + "text": "- `UpdateProjectBatches.ps1` copies `config.json` and `ConfigLoader.ps1` to the", + "lineNumber": 18 + }, + { + "text": " target project so the helper `.bat` launchers can resolve script locations.", + "lineNumber": 19 + }, + { + "text": "- When `zipper` is `true`, the tool searches for `7z`/`7za` on `PATH`. If neither", + "lineNumber": 20 + }, + { + "text": " is found it logs a warning and falls back to `zipfile`.", + "lineNumber": 21 + }, + { + "text": "- Leaving `structDir` empty is safe—the scripts fall back to the directory that", + "lineNumber": 22 + }, + { + "text": " contains `config.json`.", + "lineNumber": 23 + } + ] + }, + "score": 0.1001589298248291 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\zip_sequences.py", + "range": { + "startPosition": { + "line": 981, + "column": 53 + }, + "endPosition": { + "line": 1170 + } + }, + "contents": "def run_zip(requested_workers: int | None, *, verbose: bool) -> int:\n work_items: list[tuple[Path, Path, Path, dict]] = []\n log(\"init\", f\"Scanning sequences under {RENDER_ROOT.resolve()}\")\n total_scanned = 0\n quick_skipped = 0\n state_skipped = 0\n empty_dirs = 0\n queued = 0\n\n if RENDER_ROOT.exists():\n for seq_dir in find_sequence_dirs(RENDER_ROOT, verbose=verbose):\n total_scanned += 1\n rel = seq_dir.relative_to(RENDER_ROOT)\n if total_scanned <= 5 or total_scanned % 10 == 0:\n log(\"scan\", f\"[{total_scanned}] Inspecting {rel}\")\n\n # Get the target archive path (will be .7z if ZIPPER_TYPE is \"7z\")\n zip_path = archive_path_for(seq_dir)\n state_path = state_path_for(zip_path)\n \n # Quick check: if archive exists, load stored state first (fast)\n stored_state = load_state(state_path)\n \n # Debug: log if stored state is missing\n if stored_state is None:\n if zip_path.exists():\n if verbose:\n log(\"scan\", f\"Warning: {rel} archive exists but no stored state file found at {state_path}\", verbose_only=True, verbose=verbose)\n else:\n if verbose:\n log(\"scan\", f\"Info: {rel} no archive or state file (will create new)\", verbose_only=True, verbose=verbose)\n \n # Check if we need to upgrade from .zip to .7z\n old_zip_path = None\n old_stored_state = None\n if ZIPPER_TYPE == \"7z\":\n old_zip_path = zip_path.with_suffix(\".zip\")", + "signatures": {}, + "detailedLines": [ + { + "text": "def run_zip(requested_workers: int | None, *, verbose: bool) -> int:", + "lineNumber": 985, + "isSignature": true + }, + { + "text": " work_items: list[tuple[Path, Path, Path, dict]] = []", + "lineNumber": 986 + }, + { + "text": " log(\"init\", f\"Scanning sequences under {RENDER_ROOT.resolve()}\")", + "lineNumber": 987 + }, + { + "text": " total_scanned = 0", + "lineNumber": 988 + }, + { + "text": " quick_skipped = 0", + "lineNumber": 989 + }, + { + "text": " state_skipped = 0", + "lineNumber": 990 + }, + { + "text": " empty_dirs = 0", + "lineNumber": 991 + }, + { + "text": " queued = 0", + "lineNumber": 992 + }, + { + "lineNumber": 993 + }, + { + "text": " if RENDER_ROOT.exists():", + "lineNumber": 994 + }, + { + "text": " for seq_dir in find_sequence_dirs(RENDER_ROOT, verbose=verbose):", + "lineNumber": 995 + }, + { + "text": " total_scanned += 1", + "lineNumber": 996 + }, + { + "text": " rel = seq_dir.relative_to(RENDER_ROOT)", + "lineNumber": 997 + }, + { + "text": " if total_scanned <= 5 or total_scanned % 10 == 0:", + "lineNumber": 998 + }, + { + "text": " log(\"scan\", f\"[{total_scanned}] Inspecting {rel}\")", + "lineNumber": 999 + }, + { + "lineNumber": 1000 + }, + { + "text": " # Get the target archive path (will be .7z if ZIPPER_TYPE is \"7z\")", + "lineNumber": 1001 + }, + { + "text": " zip_path = archive_path_for(seq_dir)", + "lineNumber": 1002 + }, + { + "text": " state_path = state_path_for(zip_path)", + "lineNumber": 1003 + }, + { + "text": " ", + "lineNumber": 1004 + }, + { + "text": " # Quick check: if archive exists, load stored state first (fast)", + "lineNumber": 1005 + }, + { + "text": " stored_state = load_state(state_path)", + "lineNumber": 1006 + }, + { + "text": " ", + "lineNumber": 1007 + }, + { + "text": " # Debug: log if stored state is missing", + "lineNumber": 1008 + }, + { + "text": " if stored_state is None:", + "lineNumber": 1009 + }, + { + "text": " if zip_path.exists():", + "lineNumber": 1010 + }, + { + "text": " if verbose:", + "lineNumber": 1011 + }, + { + "text": " log(\"scan\", f\"Warning: {rel} archive exists but no stored state file found at {state_path}\", verbose_only=True, verbose=verbose)", + "lineNumber": 1012 + }, + { + "text": " else:", + "lineNumber": 1013 + }, + { + "text": " if verbose:", + "lineNumber": 1014 + }, + { + "text": " log(\"scan\", f\"Info: {rel} no archive or state file (will create new)\", verbose_only=True, verbose=verbose)", + "lineNumber": 1015 + }, + { + "text": " ", + "lineNumber": 1016 + }, + { + "text": " # Check if we need to upgrade from .zip to .7z", + "lineNumber": 1017 + }, + { + "text": " old_zip_path = None", + "lineNumber": 1018 + }, + { + "text": " old_stored_state = None", + "lineNumber": 1019 + }, + { + "text": " if ZIPPER_TYPE == \"7z\":", + "lineNumber": 1020 + }, + { + "text": " old_zip_path = zip_path.with_suffix(\".zip\")", + "lineNumber": 1021 + } + ] + }, + "score": 0.1000261977314949 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\organize_textures.ps1", + "range": { + "startPosition": { + "line": 279 + }, + "endPosition": { + "line": 325 + } + }, + "contents": "} else {\n Write-Host \"Found $($blendfileFolders.Count) blendfile folder(s) to process.\" -ForegroundColor Green\n \n $totalPass1Moved = 0\n $totalPass1Duplicates = 0\n $pass1MoveLog = [System.Collections.ArrayList]::new()\n \n foreach ($blendfileFolder in $blendfileFolders) {\n Write-Host \"\"\n Write-Host \"Processing blendfile: $($blendfileFolder.Name)\" -ForegroundColor Yellow\n \n # Get all files in this blendfile folder, excluding \\common folders\n $blendfileFiles = Get-ChildItem -Path $blendfileFolder.FullName -Recurse -File | Where-Object { $_.FullName -notlike \"*\\common\\*\" }\n \n if ($null -eq $blendfileFiles -or $blendfileFiles.Count -eq 0) {\n Write-Host \" No files found in this blendfile folder.\" -ForegroundColor Gray\n continue\n }\n \n Write-Host \" Found $($blendfileFiles.Count) files.\" -ForegroundColor Gray\n \n # Calculate checksums\n Write-Host \" Calculating checksums...\" -ForegroundColor Gray\n $filesWithChecksums = Get-FilesWithChecksums -Files $blendfileFiles\n \n # Group by checksum\n $groupedByChecksum = $filesWithChecksums | Group-Object -Property Hash\n \n Write-Host \" Found $($groupedByChecksum.Count) unique checksums.\" -ForegroundColor Gray\n \n # Create [blendfile]\\common directory\n $blendfileCommonPath = Join-Path -Path $blendfileFolder.FullName -ChildPath \"common\"\n \n if (-not (Test-Path -Path $blendfileCommonPath -PathType Container)) {\n New-Item -ItemType Directory -Path $blendfileCommonPath | Out-Null\n }\n \n # Track filenames already in [blendfile]\\common\n $filesInBlendfileCommon = @{}\n \n # Process each checksum group\n $blendfileMoved = 0\n $blendfileDuplicates = 0\n \n foreach ($group in $groupedByChecksum) {\n $result = Process-DuplicateGroup -Files $group.Group -CommonPath $blendfileCommonPath -FilesInCommon $filesInBlendfileCommon -MoveLog $pass1MoveLog", + "signatures": {}, + "detailedLines": [ + { + "text": "} else {", + "lineNumber": 280 + }, + { + "text": " Write-Host \"Found $($blendfileFolders.Count) blendfile folder(s) to process.\" -ForegroundColor Green", + "lineNumber": 281 + }, + { + "text": " ", + "lineNumber": 282 + }, + { + "text": " $totalPass1Moved = 0", + "lineNumber": 283 + }, + { + "text": " $totalPass1Duplicates = 0", + "lineNumber": 284 + }, + { + "text": " $pass1MoveLog = [System.Collections.ArrayList]::new()", + "lineNumber": 285 + }, + { + "text": " ", + "lineNumber": 286 + }, + { + "text": " foreach ($blendfileFolder in $blendfileFolders) {", + "lineNumber": 287 + }, + { + "text": " Write-Host \"\"", + "lineNumber": 288 + }, + { + "text": " Write-Host \"Processing blendfile: $($blendfileFolder.Name)\" -ForegroundColor Yellow", + "lineNumber": 289 + }, + { + "text": " ", + "lineNumber": 290 + }, + { + "text": " # Get all files in this blendfile folder, excluding \\common folders", + "lineNumber": 291 + }, + { + "text": " $blendfileFiles = Get-ChildItem -Path $blendfileFolder.FullName -Recurse -File | Where-Object { $_.FullName -notlike \"*\\common\\*\" }", + "lineNumber": 292 + }, + { + "text": " ", + "lineNumber": 293 + }, + { + "text": " if ($null -eq $blendfileFiles -or $blendfileFiles.Count -eq 0) {", + "lineNumber": 294 + }, + { + "text": " Write-Host \" No files found in this blendfile folder.\" -ForegroundColor Gray", + "lineNumber": 295 + }, + { + "text": " continue", + "lineNumber": 296 + }, + { + "text": " }", + "lineNumber": 297 + }, + { + "text": " ", + "lineNumber": 298 + }, + { + "text": " Write-Host \" Found $($blendfileFiles.Count) files.\" -ForegroundColor Gray", + "lineNumber": 299 + }, + { + "text": " ", + "lineNumber": 300 + }, + { + "text": " # Calculate checksums", + "lineNumber": 301 + }, + { + "text": " Write-Host \" Calculating checksums...\" -ForegroundColor Gray", + "lineNumber": 302 + }, + { + "text": " $filesWithChecksums = Get-FilesWithChecksums -Files $blendfileFiles", + "lineNumber": 303 + }, + { + "text": " ", + "lineNumber": 304 + }, + { + "text": " # Group by checksum", + "lineNumber": 305 + }, + { + "text": " $groupedByChecksum = $filesWithChecksums | Group-Object -Property Hash", + "lineNumber": 306 + }, + { + "text": " ", + "lineNumber": 307 + }, + { + "text": " Write-Host \" Found $($groupedByChecksum.Count) unique checksums.\" -ForegroundColor Gray", + "lineNumber": 308 + }, + { + "text": " ", + "lineNumber": 309 + }, + { + "text": " # Create [blendfile]\\common directory", + "lineNumber": 310 + }, + { + "text": " $blendfileCommonPath = Join-Path -Path $blendfileFolder.FullName -ChildPath \"common\"", + "lineNumber": 311 + }, + { + "text": " ", + "lineNumber": 312 + }, + { + "text": " if (-not (Test-Path -Path $blendfileCommonPath -PathType Container)) {", + "lineNumber": 313 + }, + { + "text": " New-Item -ItemType Directory -Path $blendfileCommonPath | Out-Null", + "lineNumber": 314 + }, + { + "text": " }", + "lineNumber": 315 + }, + { + "text": " ", + "lineNumber": 316 + }, + { + "text": " # Track filenames already in [blendfile]\\common", + "lineNumber": 317 + }, + { + "text": " $filesInBlendfileCommon = @{}", + "lineNumber": 318 + }, + { + "text": " ", + "lineNumber": 319 + }, + { + "text": " # Process each checksum group", + "lineNumber": 320 + }, + { + "text": " $blendfileMoved = 0", + "lineNumber": 321 + }, + { + "text": " $blendfileDuplicates = 0", + "lineNumber": 322 + }, + { + "text": " ", + "lineNumber": 323 + }, + { + "text": " foreach ($group in $groupedByChecksum) {", + "lineNumber": 324 + }, + { + "text": " $result = Process-DuplicateGroup -Files $group.Group -CommonPath $blendfileCommonPath -FilesInCommon $filesInBlendfileCommon -MoveLog $pass1MoveLog", + "lineNumber": 325 + } + ] + }, + "score": 0.09988240152597427 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\zip_sequences.py", + "range": { + "startPosition": { + "line": 584, + "column": 19 + }, + "endPosition": { + "line": 650 + } + }, + "contents": "def state_changed(seq_state: dict, stored_state: dict | None, *, verbose: bool = False) -> bool:\n if stored_state is None:\n if verbose:\n log(\"scan\", \"State changed: no stored state found\", verbose_only=True, verbose=verbose)\n return True\n \n # Normalize timestamps in both states for comparison\n # On Windows, normalize to 100-nanosecond boundaries (NTFS precision)\n is_windows = platform.system() == \"Windows\"\n \n def normalize_state(state: dict) -> dict:\n \"\"\"Normalize timestamps in state to filesystem precision and filter out Thumbs.db.\"\"\"\n normalized = {\"files\": []}\n for entry in state.get(\"files\", []):\n # Ignore Thumbs.db files in state comparison\n if Path(entry.get(\"path\", \"\")).name.lower() == \"thumbs.db\":\n continue\n mtime_ns = entry[\"mtime_ns\"]\n if is_windows:\n mtime_ns = (mtime_ns // 100) * 100\n normalized[\"files\"].append({\n \"path\": entry[\"path\"],\n \"size\": entry[\"size\"],\n \"mtime_ns\": mtime_ns,\n })\n return normalized\n \n # Compare normalized states (Thumbs.db already filtered out)\n normalized_seq = normalize_state(seq_state)\n normalized_stored = normalize_state(stored_state)\n \n if normalized_seq == normalized_stored:\n return False\n \n # States differ - log diagnostic info if verbose\n if verbose:", + "signatures": {}, + "detailedLines": [ + { + "text": "def state_changed(seq_state: dict, stored_state: dict | None, *, verbose: bool = False) -> bool:", + "lineNumber": 588, + "isSignature": true + }, + { + "text": " if stored_state is None:", + "lineNumber": 589 + }, + { + "text": " if verbose:", + "lineNumber": 590 + }, + { + "text": " log(\"scan\", \"State changed: no stored state found\", verbose_only=True, verbose=verbose)", + "lineNumber": 591 + }, + { + "text": " return True", + "lineNumber": 592 + }, + { + "text": " ", + "lineNumber": 593 + }, + { + "text": " # Normalize timestamps in both states for comparison", + "lineNumber": 594 + }, + { + "text": " # On Windows, normalize to 100-nanosecond boundaries (NTFS precision)", + "lineNumber": 595 + }, + { + "text": " is_windows = platform.system() == \"Windows\"", + "lineNumber": 596 + }, + { + "text": " ", + "lineNumber": 597 + }, + { + "text": " def normalize_state(state: dict) -> dict:", + "lineNumber": 598 + }, + { + "text": " \"\"\"Normalize timestamps in state to filesystem precision and filter out Thumbs.db.\"\"\"", + "lineNumber": 599 + }, + { + "text": " normalized = {\"files\": []}", + "lineNumber": 600 + }, + { + "text": " for entry in state.get(\"files\", []):", + "lineNumber": 601 + }, + { + "text": " # Ignore Thumbs.db files in state comparison", + "lineNumber": 602 + }, + { + "text": " if Path(entry.get(\"path\", \"\")).name.lower() == \"thumbs.db\":", + "lineNumber": 603 + }, + { + "text": " continue", + "lineNumber": 604 + }, + { + "text": " mtime_ns = entry[\"mtime_ns\"]", + "lineNumber": 605 + }, + { + "text": " if is_windows:", + "lineNumber": 606 + }, + { + "text": " mtime_ns = (mtime_ns // 100) * 100", + "lineNumber": 607 + }, + { + "text": " normalized[\"files\"].append({", + "lineNumber": 608 + }, + { + "text": " \"path\": entry[\"path\"],", + "lineNumber": 609 + }, + { + "text": " \"size\": entry[\"size\"],", + "lineNumber": 610 + }, + { + "text": " \"mtime_ns\": mtime_ns,", + "lineNumber": 611 + }, + { + "text": " })", + "lineNumber": 612 + }, + { + "text": " return normalized", + "lineNumber": 613 + }, + { + "text": " ", + "lineNumber": 614 + }, + { + "text": " # Compare normalized states (Thumbs.db already filtered out)", + "lineNumber": 615 + }, + { + "text": " normalized_seq = normalize_state(seq_state)", + "lineNumber": 616 + }, + { + "text": " normalized_stored = normalize_state(stored_state)", + "lineNumber": 617 + }, + { + "text": " ", + "lineNumber": 618 + }, + { + "text": " if normalized_seq == normalized_stored:", + "lineNumber": 619 + }, + { + "text": " return False", + "lineNumber": 620 + }, + { + "text": " ", + "lineNumber": 621 + }, + { + "text": " # States differ - log diagnostic info if verbose", + "lineNumber": 622 + }, + { + "text": " if verbose:", + "lineNumber": 623 + } + ] + }, + "score": 0.09323669970035553 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\remove_action_fake_users.bat", + "range": { + "startPosition": {}, + "endPosition": { + "line": 66 + } + }, + "contents": "@echo off\nsetlocal enabledelayedexpansion\n\necho Starting fake user removal for actions...\n\nREM Check if files were dragged onto the batch file\nif \"%~1\"==\"\" (\n\techo.\n\techo Usage: Drag .blend files onto this batch file to remove fake users from actions.\n\techo Output will be saved to the \\output folder.\n\techo.\n\tpause\n\texit /b 1\n)\n\nREM Create output directory if it doesn't exist\nif not exist \"output\" mkdir \"output\"\n\nREM Initialize counters and tracking\nset \"processed=0\"\nset \"crashed=0\"\nset \"skipped=0\"\nset \"deleted_similar=0\"\nset \"threshold_percent=10\"\nset \"updated_total=0\"\n\nREM Create a temporary Python script for processing\nset \"TEMP_SCRIPT=remove_action_fake_users_temp.py\"\necho Creating Python script: !TEMP_SCRIPT!\n\n(\necho import bpy\necho import os\necho import sys\necho.\necho # Create output directory if it doesn't exist\necho if not os.path.exists^(\"output\"^):\necho \tos.makedirs^(\"output\"^)\necho.\necho # Get command line arguments ^(the dragged files^)\necho blend_files = sys.argv[sys.argv.index^(\"--\"^) + 1:] if \"--\" in sys.argv else []\necho.\necho print^(\"Found \" + str^(len^(blend_files^)^) + \" .blend files to process\"^)\necho.\necho for blend_file in blend_files:\necho ^\tif blend_file.lower^(^).endswith^(\".blend\"^):\necho ^\t\ttry:\necho ^\t\t\t# Create output path in output folder\necho ^\t\t\tfilename = os.path.basename^(blend_file^)\necho ^\t\t\toutput_file = os.path.join^(\"output\", filename^)\necho ^\t\t\t# Check if output file already exists\necho ^\t\t\tif os.path.exists^(output_file^):\necho ^\t\t\t\tprint^(\"SKIP_EXISTING:\" + blend_file^)\necho ^\t\t\t\tcontinue\necho ^\t\t\tprint^(\"PROCESSING:\" + blend_file^)\necho ^\t\t\t# Load the blend file\necho ^\t\t\tbpy.ops.wm.open_mainfile^(filepath=blend_file^)\necho ^\t\t\t# Remove fake users from all actions\necho ^\t\t\tchanged = 0\necho ^\t\t\tfor action in bpy.data.actions:\necho ^\t\t\t\tif getattr^(action, \"use_fake_user\", False^):\necho ^\t\t\t\t\taction.use_fake_user = False\necho ^\t\t\t\t\tchanged += 1\necho ^\t\t\tprint^(\"UPDATED:\" + blend_file + \":\" + str^(changed^)^)\necho ^\t\t\t# Save to output folder\necho ^\t\t\tbpy.ops.wm.save_mainfile^(filepath=output_file, compress=True^)", + "signatures": {}, + "detailedLines": [ + { + "text": "@echo off", + "lineNumber": 1 + }, + { + "text": "setlocal enabledelayedexpansion", + "lineNumber": 2 + }, + { + "lineNumber": 3 + }, + { + "text": "echo Starting fake user removal for actions...", + "lineNumber": 4 + }, + { + "lineNumber": 5 + }, + { + "text": "REM Check if files were dragged onto the batch file", + "lineNumber": 6 + }, + { + "text": "if \"%~1\"==\"\" (", + "lineNumber": 7 + }, + { + "text": "\techo.", + "lineNumber": 8 + }, + { + "text": "\techo Usage: Drag .blend files onto this batch file to remove fake users from actions.", + "lineNumber": 9 + }, + { + "text": "\techo Output will be saved to the \\output folder.", + "lineNumber": 10 + }, + { + "text": "\techo.", + "lineNumber": 11 + }, + { + "text": "\tpause", + "lineNumber": 12 + }, + { + "text": "\texit /b 1", + "lineNumber": 13 + }, + { + "text": ")", + "lineNumber": 14 + }, + { + "lineNumber": 15 + }, + { + "text": "REM Create output directory if it doesn't exist", + "lineNumber": 16 + }, + { + "text": "if not exist \"output\" mkdir \"output\"", + "lineNumber": 17 + }, + { + "lineNumber": 18 + }, + { + "text": "REM Initialize counters and tracking", + "lineNumber": 19 + }, + { + "text": "set \"processed=0\"", + "lineNumber": 20 + }, + { + "text": "set \"crashed=0\"", + "lineNumber": 21 + }, + { + "text": "set \"skipped=0\"", + "lineNumber": 22 + }, + { + "text": "set \"deleted_similar=0\"", + "lineNumber": 23 + }, + { + "text": "set \"threshold_percent=10\"", + "lineNumber": 24 + }, + { + "text": "set \"updated_total=0\"", + "lineNumber": 25 + }, + { + "lineNumber": 26 + }, + { + "text": "REM Create a temporary Python script for processing", + "lineNumber": 27 + }, + { + "text": "set \"TEMP_SCRIPT=remove_action_fake_users_temp.py\"", + "lineNumber": 28 + }, + { + "text": "echo Creating Python script: !TEMP_SCRIPT!", + "lineNumber": 29 + }, + { + "lineNumber": 30 + }, + { + "text": "(", + "lineNumber": 31 + }, + { + "text": "echo import bpy", + "lineNumber": 32 + }, + { + "text": "echo import os", + "lineNumber": 33 + }, + { + "text": "echo import sys", + "lineNumber": 34 + }, + { + "text": "echo.", + "lineNumber": 35 + }, + { + "text": "echo # Create output directory if it doesn't exist", + "lineNumber": 36 + }, + { + "text": "echo if not os.path.exists^(\"output\"^):", + "lineNumber": 37 + }, + { + "text": "echo \tos.makedirs^(\"output\"^)", + "lineNumber": 38 + }, + { + "text": "echo.", + "lineNumber": 39 + }, + { + "text": "echo # Get command line arguments ^(the dragged files^)", + "lineNumber": 40 + }, + { + "text": "echo blend_files = sys.argv[sys.argv.index^(\"--\"^) + 1:] if \"--\" in sys.argv else []", + "lineNumber": 41 + }, + { + "text": "echo.", + "lineNumber": 42 + }, + { + "text": "echo print^(\"Found \" + str^(len^(blend_files^)^) + \" .blend files to process\"^)", + "lineNumber": 43 + }, + { + "text": "echo.", + "lineNumber": 44 + }, + { + "text": "echo for blend_file in blend_files:", + "lineNumber": 45 + }, + { + "text": "echo ^\tif blend_file.lower^(^).endswith^(\".blend\"^):", + "lineNumber": 46 + }, + { + "text": "echo ^\t\ttry:", + "lineNumber": 47 + }, + { + "text": "echo ^\t\t\t# Create output path in output folder", + "lineNumber": 48 + }, + { + "text": "echo ^\t\t\tfilename = os.path.basename^(blend_file^)", + "lineNumber": 49 + }, + { + "text": "echo ^\t\t\toutput_file = os.path.join^(\"output\", filename^)", + "lineNumber": 50 + }, + { + "text": "echo ^\t\t\t# Check if output file already exists", + "lineNumber": 51 + }, + { + "text": "echo ^\t\t\tif os.path.exists^(output_file^):", + "lineNumber": 52 + }, + { + "text": "echo ^\t\t\t\tprint^(\"SKIP_EXISTING:\" + blend_file^)", + "lineNumber": 53 + }, + { + "text": "echo ^\t\t\t\tcontinue", + "lineNumber": 54 + }, + { + "text": "echo ^\t\t\tprint^(\"PROCESSING:\" + blend_file^)", + "lineNumber": 55 + }, + { + "text": "echo ^\t\t\t# Load the blend file", + "lineNumber": 56 + }, + { + "text": "echo ^\t\t\tbpy.ops.wm.open_mainfile^(filepath=blend_file^)", + "lineNumber": 57 + }, + { + "text": "echo ^\t\t\t# Remove fake users from all actions", + "lineNumber": 58 + }, + { + "text": "echo ^\t\t\tchanged = 0", + "lineNumber": 59 + }, + { + "text": "echo ^\t\t\tfor action in bpy.data.actions:", + "lineNumber": 60 + }, + { + "text": "echo ^\t\t\t\tif getattr^(action, \"use_fake_user\", False^):", + "lineNumber": 61 + }, + { + "text": "echo ^\t\t\t\t\taction.use_fake_user = False", + "lineNumber": 62 + }, + { + "text": "echo ^\t\t\t\t\tchanged += 1", + "lineNumber": 63 + }, + { + "text": "echo ^\t\t\tprint^(\"UPDATED:\" + blend_file + \":\" + str^(changed^)^)", + "lineNumber": 64 + }, + { + "text": "echo ^\t\t\t# Save to output folder", + "lineNumber": 65 + }, + { + "text": "echo ^\t\t\tbpy.ops.wm.save_mainfile^(filepath=output_file, compress=True^)", + "lineNumber": 66 + } + ] + }, + "score": 0.09131913632154465 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\config.json", + "range": { + "startPosition": {}, + "endPosition": { + "line": 6, + "column": 1 + } + }, + "contents": "{\n \"dailyFormat\": \"YYYY-MM-DD\",\n \"structDir\": \"A:\\\\1 Amazon_Active_Projects\\\\3 ProjectStructure\",\n \"zipper\": \"7z\",\n \"compression\": 0,\n \"Max7zInst\": 0\n}", + "signatures": {}, + "detailedLines": [ + { + "text": "{", + "lineNumber": 1 + }, + { + "text": " \"dailyFormat\": \"YYYY-MM-DD\",", + "lineNumber": 2 + }, + { + "text": " \"structDir\": \"A:\\\\1 Amazon_Active_Projects\\\\3 ProjectStructure\",", + "lineNumber": 3 + }, + { + "text": " \"zipper\": \"7z\",", + "lineNumber": 4 + }, + { + "text": " \"compression\": 0,", + "lineNumber": 5 + }, + { + "text": " \"Max7zInst\": 0", + "lineNumber": 6 + }, + { + "text": "}", + "lineNumber": 7 + } + ] + }, + "score": 0.08737760037183762 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\NewProject.bat", + "range": { + "startPosition": { + "line": 26 + }, + "endPosition": { + "line": 88 + } + }, + "contents": "for /f \"tokens=2-4 delims=/ \" %%a in ('date /t') do (\n set mm=%%a\n set dd=%%b\n set yy=%%c\n)\nset yyyy=20%yy:~-2%\nset yymmdd=%yy:~-2%%mm%%dd%\n\n:: Ask for project name\nset /p projectName=\"Enter project name (press Enter for default 'NewProject'): \"\nif \"%projectName%\"==\"\" set projectName=NewProject\nset projectRoot=%yymmdd%_%projectName%\n\n:: Create main project directory\nmkdir \"%projectRoot%\"\n\n:: Create Assets structure\nmkdir \"%projectRoot%\\Assets\\ElevenLabs\"\nif exist \"%STRUCT_DIR%\\NewDaily.bat\" copy /Y \"%STRUCT_DIR%\\NewDaily.bat\" \"%projectRoot%\\Assets\\ElevenLabs\\NewDaily.bat\" >nul\nmkdir \"%projectRoot%\\Assets\\Blends\"\nmkdir \"%projectRoot%\\Assets\\Mocap\"\nmkdir \"%projectRoot%\\Assets\\VO\"\nif exist \"%~dp0NewDaily.bat\" copy /Y \"%~dp0NewDaily.bat\" \"%projectRoot%\\Assets\\VO\\NewDaily.bat\" >nul\n\n:: Create Blends structure\nmkdir \"%projectRoot%\\Blends\\animations\\\"\nmkdir \"%projectRoot%\\Blends\\stills\\img-BG\"\n\n:: Create Deliverable structure\nmkdir \"%projectRoot%\\Deliverable\\\"\n\n:: Create Pr structure\nmkdir \"%projectRoot%\\Pr\\RnR\\RIFE\"\n\n:: Add project root additions\nif not exist \"%projectRoot%\\Renders\" mkdir \"%projectRoot%\\Renders\"\n\n:: Place helper scripts into Renders\nset \"templateRoot=%STRUCT_DIR%\"\nfor %%F in (UpdateSequences.bat ZipSeqArchv.bat UnzipSeqArchv.bat ConfigLoader.ps1 config.json) do (\n if exist \"%templateRoot%\\%%F\" copy /Y \"%templateRoot%\\%%F\" \"%projectRoot%\\Renders\\%%F\" >nul\n)\n\n:: Use repo-provided templates for git config files\nif exist \"%~dp0components\\gitignore\" copy /Y \"%~dp0components\\gitignore\" \"%projectRoot%\\.gitignore\" >nul\nif exist \"%~dp0components\\gitattributes\" copy /Y \"%~dp0components\\gitattributes\" \"%projectRoot%\\.gitattributes\" >nul\n\n:: Initialize git and install Git LFS\npushd \"%projectRoot%\" >nul\ngit init\ngit lfs install\ngit add . -v\ngit commit -m \"init\"\npopd >nul\n\n:: Deploy config workflow using ConfigLoader.ps1\necho.\necho Deploying config workflow...\nfor %%P in (\"%projectRoot%\") do set \"PROJECT_ROOT_ABS=%%~fP\"\npowershell -NoProfile -ExecutionPolicy Bypass -Command \"& '%CONFIG_LOADER%' -ProjectPath '%PROJECT_ROOT_ABS%'\"\nif errorlevel 1 (\n echo [WARNING] Config workflow deployment failed. You may need to run ConfigLoader.ps1 manually.", + "signatures": {}, + "detailedLines": [ + { + "text": "for /f \"tokens=2-4 delims=/ \" %%a in ('date /t') do (", + "lineNumber": 27 + }, + { + "text": " set mm=%%a", + "lineNumber": 28 + }, + { + "text": " set dd=%%b", + "lineNumber": 29 + }, + { + "text": " set yy=%%c", + "lineNumber": 30 + }, + { + "text": ")", + "lineNumber": 31 + }, + { + "text": "set yyyy=20%yy:~-2%", + "lineNumber": 32 + }, + { + "text": "set yymmdd=%yy:~-2%%mm%%dd%", + "lineNumber": 33 + }, + { + "lineNumber": 34 + }, + { + "text": ":: Ask for project name", + "lineNumber": 35 + }, + { + "text": "set /p projectName=\"Enter project name (press Enter for default 'NewProject'): \"", + "lineNumber": 36 + }, + { + "text": "if \"%projectName%\"==\"\" set projectName=NewProject", + "lineNumber": 37 + }, + { + "text": "set projectRoot=%yymmdd%_%projectName%", + "lineNumber": 38 + }, + { + "lineNumber": 39 + }, + { + "text": ":: Create main project directory", + "lineNumber": 40 + }, + { + "text": "mkdir \"%projectRoot%\"", + "lineNumber": 41 + }, + { + "lineNumber": 42 + }, + { + "text": ":: Create Assets structure", + "lineNumber": 43 + }, + { + "text": "mkdir \"%projectRoot%\\Assets\\ElevenLabs\"", + "lineNumber": 44 + }, + { + "text": "if exist \"%STRUCT_DIR%\\NewDaily.bat\" copy /Y \"%STRUCT_DIR%\\NewDaily.bat\" \"%projectRoot%\\Assets\\ElevenLabs\\NewDaily.bat\" >nul", + "lineNumber": 45 + }, + { + "text": "mkdir \"%projectRoot%\\Assets\\Blends\"", + "lineNumber": 46 + }, + { + "text": "mkdir \"%projectRoot%\\Assets\\Mocap\"", + "lineNumber": 47 + }, + { + "text": "mkdir \"%projectRoot%\\Assets\\VO\"", + "lineNumber": 48 + }, + { + "text": "if exist \"%~dp0NewDaily.bat\" copy /Y \"%~dp0NewDaily.bat\" \"%projectRoot%\\Assets\\VO\\NewDaily.bat\" >nul", + "lineNumber": 49 + }, + { + "lineNumber": 50 + }, + { + "text": ":: Create Blends structure", + "lineNumber": 51 + }, + { + "text": "mkdir \"%projectRoot%\\Blends\\animations\\\"", + "lineNumber": 52 + }, + { + "text": "mkdir \"%projectRoot%\\Blends\\stills\\img-BG\"", + "lineNumber": 53 + }, + { + "lineNumber": 54 + }, + { + "text": ":: Create Deliverable structure", + "lineNumber": 55 + }, + { + "text": "mkdir \"%projectRoot%\\Deliverable\\\"", + "lineNumber": 56 + }, + { + "lineNumber": 57 + }, + { + "text": ":: Create Pr structure", + "lineNumber": 58 + }, + { + "text": "mkdir \"%projectRoot%\\Pr\\RnR\\RIFE\"", + "lineNumber": 59 + }, + { + "lineNumber": 60 + }, + { + "text": ":: Add project root additions", + "lineNumber": 61 + }, + { + "text": "if not exist \"%projectRoot%\\Renders\" mkdir \"%projectRoot%\\Renders\"", + "lineNumber": 62 + }, + { + "lineNumber": 63 + }, + { + "text": ":: Place helper scripts into Renders", + "lineNumber": 64 + }, + { + "text": "set \"templateRoot=%STRUCT_DIR%\"", + "lineNumber": 65 + }, + { + "text": "for %%F in (UpdateSequences.bat ZipSeqArchv.bat UnzipSeqArchv.bat ConfigLoader.ps1 config.json) do (", + "lineNumber": 66 + }, + { + "text": " if exist \"%templateRoot%\\%%F\" copy /Y \"%templateRoot%\\%%F\" \"%projectRoot%\\Renders\\%%F\" >nul", + "lineNumber": 67 + }, + { + "text": ")", + "lineNumber": 68 + }, + { + "lineNumber": 69 + }, + { + "text": ":: Use repo-provided templates for git config files", + "lineNumber": 70 + }, + { + "text": "if exist \"%~dp0components\\gitignore\" copy /Y \"%~dp0components\\gitignore\" \"%projectRoot%\\.gitignore\" >nul", + "lineNumber": 71 + }, + { + "text": "if exist \"%~dp0components\\gitattributes\" copy /Y \"%~dp0components\\gitattributes\" \"%projectRoot%\\.gitattributes\" >nul", + "lineNumber": 72 + }, + { + "lineNumber": 73 + }, + { + "text": ":: Initialize git and install Git LFS", + "lineNumber": 74 + }, + { + "text": "pushd \"%projectRoot%\" >nul", + "lineNumber": 75 + }, + { + "text": "git init", + "lineNumber": 76 + }, + { + "text": "git lfs install", + "lineNumber": 77 + }, + { + "text": "git add . -v", + "lineNumber": 78 + }, + { + "text": "git commit -m \"init\"", + "lineNumber": 79 + }, + { + "text": "popd >nul", + "lineNumber": 80 + }, + { + "lineNumber": 81 + }, + { + "text": ":: Deploy config workflow using ConfigLoader.ps1", + "lineNumber": 82 + }, + { + "text": "echo.", + "lineNumber": 83 + }, + { + "text": "echo Deploying config workflow...", + "lineNumber": 84 + }, + { + "text": "for %%P in (\"%projectRoot%\") do set \"PROJECT_ROOT_ABS=%%~fP\"", + "lineNumber": 85 + }, + { + "text": "powershell -NoProfile -ExecutionPolicy Bypass -Command \"& '%CONFIG_LOADER%' -ProjectPath '%PROJECT_ROOT_ABS%'\"", + "lineNumber": 86 + }, + { + "text": "if errorlevel 1 (", + "lineNumber": 87 + }, + { + "text": " echo [WARNING] Config workflow deployment failed. You may need to run ConfigLoader.ps1 manually.", + "lineNumber": 88 + } + ] + }, + "score": 0.08714190125465393 + } + ] +} +``` +Status: **completed** + + +
+
+ +--- + + +
Tool use: **read_file_v2** • Read file: config.json + +
+
+ +--- + + +
+Tool use: **ripgrep_raw_search** + + +Parameters: + +```json +{ + "pattern": "FlatColor", + "caseInsensitive": true +} +``` +Result: + +```json +{ + "success": { + "pattern": "FlatColor", + "outputMode": "content", + "workspaceResults": { + "A:\\1 Amazon_Active_Projects\\3 ProjectStructure": { + "content": { + "matches": [ + { + "file": "organize_textures.ps1", + "matches": [ + { + "lineNumber": 353, + "content": "# Collect FlatColors files separately (including those in \\common\\FlatColors folders, but not from root \\common\\FlatColors)" + }, + { + "lineNumber": 354, + "content": "Write-Host \"Collecting FlatColors files...\" -ForegroundColor Yellow" + }, + { + "lineNumber": 355, + "content": "$rootCommonFlatColorsPath = Join-Path -Path $textureFolderPath -ChildPath \"common\\FlatColors\"" + }, + { + "lineNumber": 356, + "content": "$allFlatColorsFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object {" + }, + { + "lineNumber": 357, + "content": " ($_.FullName -like \"*\\FlatColors\\*\" -or $_.Name -like \"*FlatColors*\") -and" + }, + { + "lineNumber": 358, + "content": " $_.FullName -notlike \"$([regex]::Escape($rootCommonFlatColorsPath))\\*\"" + }, + { + "lineNumber": 361, + "content": "# Get all remaining files (excluding all \\common folders, but we'll handle FlatColors separately)" + }, + { + "lineNumber": 376, + "content": " # Separate FlatColors files from other files before processing" + }, + { + "lineNumber": 377, + "content": " Write-Host \"Identifying FlatColors files...\" -ForegroundColor Yellow" + }, + { + "lineNumber": 378, + "content": " $flatColorsFiles = $allFlatColorsFiles | Where-Object { (Test-Path -Path $_.FullName) }" + }, + { + "lineNumber": 379, + "content": " $nonFlatColorsFiles = $remainingFiles | Where-Object { $_.Name -notlike \"*FlatColors*\" }" + }, + { + "lineNumber": 381, + "content": " Write-Host \"Found $($flatColorsFiles.Count) FlatColors file(s) (including from \\common\\FlatColors folders), $($nonFlatColorsFiles.Count) other file(s)\" -ForegroundColor Gray" + }, + { + "lineNumber": 383, + "content": " # Group non-FlatColors files by checksum" + }, + { + "lineNumber": 385, + "content": " $nonFlatColorsWithChecksums = $filesWithChecksums | Where-Object { $_.File.Name -notlike \"*FlatColors*\" }" + }, + { + "lineNumber": 386, + "content": " $groupedByChecksum = $nonFlatColorsWithChecksums | Group-Object -Property Hash" + }, + { + "lineNumber": 401, + "content": " # Process each checksum group (excluding FlatColors)" + }, + { + "lineNumber": 422, + "content": " # Process FlatColors files: merge duplicates and move to \\common\\FlatColors" + }, + { + "lineNumber": 423, + "content": " Write-Host \"Processing FlatColors files (merging duplicates)...\" -ForegroundColor Yellow" + }, + { + "lineNumber": 425, + "content": " if ($null -ne $flatColorsFiles -and $flatColorsFiles.Count -gt 0) {" + }, + { + "lineNumber": 426, + "content": " Write-Host \"Found $($flatColorsFiles.Count) FlatColors file(s) to process\" -ForegroundColor Gray" + }, + { + "lineNumber": 428, + "content": " # Calculate checksums for FlatColors files" + }, + { + "lineNumber": 429, + "content": " Write-Host \"Calculating checksums for FlatColors files...\" -ForegroundColor Yellow" + }, + { + "lineNumber": 430, + "content": " $flatColorsWithChecksums = Get-FilesWithChecksums -Files $flatColorsFiles" + }, + { + "lineNumber": 433, + "content": " $flatColorsGroupedByChecksum = $flatColorsWithChecksums | Group-Object -Property Hash" + }, + { + "lineNumber": 435, + "content": " Write-Host \"Found $($flatColorsGroupedByChecksum.Count) unique FlatColors file(s)\" -ForegroundColor Gray" + }, + { + "lineNumber": 437, + "content": " # Create \\textures\\common\\FlatColors directory" + }, + { + "lineNumber": 438, + "content": " $flatColorsPath = Join-Path -Path $rootCommonPath -ChildPath \"FlatColors\"" + }, + { + "lineNumber": 439, + "content": " if (-not (Test-Path -Path $flatColorsPath -PathType Container)) {" + }, + { + "lineNumber": 440, + "content": " New-Item -ItemType Directory -Path $flatColorsPath | Out-Null" + }, + { + "lineNumber": 441, + "content": " Write-Host \"Created directory: $flatColorsPath\" -ForegroundColor Green" + }, + { + "lineNumber": 444, + "content": " # Track filenames already in \\common\\FlatColors" + }, + { + "lineNumber": 445, + "content": " $filesInFlatColors = @{}" + }, + { + "lineNumber": 446, + "content": " $flatColorsMoved = 0" + }, + { + "lineNumber": 447, + "content": " $flatColorsDuplicates = 0" + }, + { + "lineNumber": 448, + "content": " $flatColorsMoveLog = [System.Collections.ArrayList]::new()" + }, + { + "lineNumber": 450, + "content": " foreach ($group in $flatColorsGroupedByChecksum) {" + }, + { + "lineNumber": 454, + "content": " # Single file - move to FlatColors folder" + }, + { + "lineNumber": 464, + "content": " $destinationPath = Join-Path -Path $flatColorsPath -ChildPath $fileName" + }, + { + "lineNumber": 467, + "content": " if ($filesInFlatColors.ContainsKey($fileName) -or (Test-Path -Path $destinationPath)) {" + }, + { + "lineNumber": 473, + "content": " $destinationPath = Join-Path -Path $flatColorsPath -ChildPath $newFileName" + }, + { + "lineNumber": 475, + "content": " } while ($filesInFlatColors.ContainsKey($newFileName) -or (Test-Path -Path $destinationPath))" + }, + { + "lineNumber": 482, + "content": " $filesInFlatColors[$fileName] = $true" + }, + { + "lineNumber": 483, + "content": " $flatColorsMoved++" + }, + { + "lineNumber": 488, + "content": " $null = $flatColorsMoveLog.Add([PSCustomObject]@{" + }, + { + "lineNumber": 494, + "content": " Write-Warning \"Failed to move FlatColors file: $($fileObj.FullName) - $($_.Exception.Message)\"" + }, + { + "lineNumber": 499, + "content": " $result = Process-DuplicateGroup -Files $files -CommonPath $flatColorsPath -FilesInCommon $filesInFlatColors -StripPrefix -ValidPrefixes $validBlendfilePrefixes -MoveLog $flatColorsMoveLog" + }, + { + "lineNumber": 500, + "content": " $flatColorsMoved += $result.MovedCount" + }, + { + "lineNumber": 501, + "content": " $flatColorsDuplicates += $result.DuplicateCount" + }, + { + "lineNumber": 505, + "content": " Write-Host \"Moved $flatColorsMoved unique FlatColors file(s) to \\common\\FlatColors, deleted $flatColorsDuplicates duplicate(s)\" -ForegroundColor Green" + }, + { + "lineNumber": 507, + "content": " Write-Host \"No FlatColors files found to process.\" -ForegroundColor Gray" + }, + { + "lineNumber": 528, + "content": "if ($null -ne $flatColorsMoveLog -and $flatColorsMoveLog.Count -gt 0) {" + }, + { + "lineNumber": 529, + "content": " $allMoves += $flatColorsMoveLog" + } + ] + }, + { + "file": ".specstory/history/2025-12-19_18-52Z-blend-file-path-prefix-logic.md", + "matches": [ + { + "lineNumber": 8082, + "content": "@pwsh (357-1075) ah, let's have it move all FlatColors to the inter-blendfile \\common folder as well." + }, + { + "lineNumber": 8089, + "content": "Updating Pass 2 to also move files containing \"FlatColors\" to the inter-blendfile `\\common` folder, even if they're not duplicates:" + }, + { + "lineNumber": 8103, + "content": "Adding logic to move FlatColors files to the common folder after duplicate processing:" + }, + { + "lineNumber": 8133, + "content": " # Also move all FlatColors files to \\common (even if they're unique)" + }, + { + "lineNumber": 8134, + "content": " Write-Host \"Moving FlatColors files to \\common...\" -ForegroundColor Yellow" + }, + { + "lineNumber": 8135, + "content": " $flatColorsFiles = $filesWithChecksums | Where-Object { $_.File.Name -like \"*FlatColors*\" }" + }, + { + "lineNumber": 8137, + "content": " if ($null -ne $flatColorsFiles -and $flatColorsFiles.Count -gt 0) {" + }, + { + "lineNumber": 8138, + "content": " foreach ($fileObj in $flatColorsFiles) {" + }, + { + "lineNumber": 8169, + "content": " Write-Warning \"Failed to move FlatColors file: $($file.FullName) - $($_.Exception.Message)\"" + }, + { + "lineNumber": 8172, + "content": " Write-Host \"Moved $($flatColorsFiles.Count) FlatColors file(s) to \\common\" -ForegroundColor Green" + }, + { + "lineNumber": 8229, + "content": " Write-Warning \"Failed to move FlatColors file: $($file.FullName) - $($_.Exception.Message)\"" + }, + { + "lineNumber": 8250, + "content": " # Also move all FlatColors files to \\common (even if they're unique)" + }, + { + "lineNumber": 8251, + "content": " Write-Host \"Moving FlatColors files to \\common...\" -ForegroundColor Yellow" + }, + { + "lineNumber": 8252, + "content": " $flatColorsFiles = $filesWithChecksums | Where-Object { $_.File.Name -like \"*FlatColors*\" -and (Test-Path -Path $_.File.FullName) }" + }, + { + "lineNumber": 8254, + "content": " if ($null -ne $flatColorsFiles -and $flatColorsFiles.Count -gt 0) {" + }, + { + "lineNumber": 8255, + "content": " foreach ($fileObj in $flatColorsFiles) {" + }, + { + "lineNumber": 8267, + "content": "Updated Pass 2 to also move all files containing \"FlatColors\" in their name to the inter-blendfile `\\common` folder, even if they're unique (not duplicates). The changes:" + }, + { + "lineNumber": 8269, + "content": "1. **Added FlatColors processing** - After processing duplicate groups, the script now finds all files with \"FlatColors\" in their name" + }, + { + "lineNumber": 8270, + "content": "2. **Strips blendfile prefixes** - FlatColors files also have their blendfile prefixes stripped (e.g., \"Demarco_FlatColors.jpg\" → \"FlatColors.jpg\")" + }, + { + "lineNumber": 8271, + "content": "3. **Handles name conflicts** - If multiple FlatColors files would have the same name after prefix stripping, they get numbered suffixes" + }, + { + "lineNumber": 8272, + "content": "4. **Checks file existence** - Only processes FlatColors files that still exist at their original location (in case they were already moved during duplicate processing)" + }, + { + "lineNumber": 8274, + "content": "When you run the script, all FlatColors files will be moved to `\\textures\\common` along with the duplicate files, with blendfile prefixes stripped." + }, + { + "lineNumber": 8280, + "content": "@pwsh (995-1075) it didn't add a `\\\\textures\\common\\FlatColors` folder and it didn't move any of the FlatColors there." + }, + { + "lineNumber": 8287, + "content": "Updating the code to create a `\\textures\\common\\FlatColors` subfolder and move FlatColors files there:" + }, + { + "lineNumber": 8301, + "content": "Updating the code to create a `\\textures\\common\\FlatColors` subfolder and move FlatColors files there:" + }, + { + "lineNumber": 8311, + "content": " # Also move all FlatColors files to \\common\\FlatColors (even if they're unique)" + }, + { + "lineNumber": 8312, + "content": " Write-Host \"Moving FlatColors files to \\common\\FlatColors...\" -ForegroundColor Yellow" + }, + { + "lineNumber": 8313, + "content": " $flatColorsFiles = $filesWithChecksums | Where-Object { $_.File.Name -like \"*FlatColors*\" -and (Test-Path -Path $_.File.FullName) }" + }, + { + "lineNumber": 8315, + "content": " if ($null -ne $flatColorsFiles -and $flatColorsFiles.Count -gt 0) {" + }, + { + "lineNumber": 8316, + "content": " # Create \\textures\\common\\FlatColors directory" + }, + { + "lineNumber": 8317, + "content": " $flatColorsPath = Join-Path -Path $rootCommonPath -ChildPath \"FlatColors\"" + }, + { + "lineNumber": 8318, + "content": " if (-not (Test-Path -Path $flatColorsPath -PathType Container)) {" + }, + { + "lineNumber": 8319, + "content": " New-Item -ItemType Directory -Path $flatColorsPath | Out-Null" + }, + { + "lineNumber": 8320, + "content": " Write-Host \"Created directory: $flatColorsPath\" -ForegroundColor Green" + }, + { + "lineNumber": 8323, + "content": " # Track filenames already in \\common\\FlatColors" + }, + { + "lineNumber": 8324, + "content": " $filesInFlatColors = @{}" + }, + { + "lineNumber": 8326, + "content": " foreach ($fileObj in $flatColorsFiles) {" + }, + { + "lineNumber": 8336, + "content": " $destinationPath = Join-Path -Path $flatColorsPath -ChildPath $fileName" + }, + { + "lineNumber": 8339, + "content": " if ($filesInFlatColors.ContainsKey($fileName)) {" + }, + { + "lineNumber": 8345, + "content": " $destinationPath = Join-Path -Path $flatColorsPath -ChildPath $newFileName" + }, + { + "lineNumber": 8347, + "content": " } while ($filesInFlatColors.ContainsKey($newFileName) -or (Test-Path -Path $destinationPath))" + }, + { + "lineNumber": 8354, + "content": " $filesInFlatColors[$fileName] = $true" + }, + { + "lineNumber": 8357, + "content": " Write-Warning \"Failed to move FlatColors file: $($file.FullName) - $($_.Exception.Message)\"" + }, + { + "lineNumber": 8360, + "content": " Write-Host \"Moved $($flatColorsFiles.Count) FlatColors file(s) to \\common\\FlatColors\" -ForegroundColor Green" + }, + { + "lineNumber": 8373, + "content": "1. **Create `\\textures\\common\\FlatColors` subfolder** - Creates the directory if it doesn't exist" + }, + { + "lineNumber": 8374, + "content": "2. **Use separate tracking** - Uses `$filesInFlatColors` hashtable to track files in the FlatColors folder (separate from the root common folder)" + }, + { + "lineNumber": 8375, + "content": "3. **Update destination paths** - All FlatColors files are moved to `\\textures\\common\\FlatColors` instead of directly to `\\textures\\common`" + }, + { + "lineNumber": 8379, + "content": "- Create the `\\textures\\common\\FlatColors` folder if it doesn't exist" + }, + { + "lineNumber": 8380, + "content": "- Move all files containing \"FlatColors\" in their name to that subfolder" + }, + { + "lineNumber": 8381, + "content": "- Strip blendfile prefixes from FlatColors filenames" + }, + { + "lineNumber": 8382, + "content": "- Handle name conflicts within the FlatColors folder" + }, + { + "lineNumber": 8384, + "content": "The FlatColors files will be organized in their own subfolder within the common directory." + }, + { + "lineNumber": 8390, + "content": "@pwsh (356-1075) i still see no FlatColors folder in \\\\textures\\common" + }, + { + "lineNumber": 8397, + "content": "Checking why FlatColors files aren't being found. The filter may be running after they're already moved, or the pattern isn't matching. Reviewing the code and adding debug output:" + }, + { + "lineNumber": 8421, + "content": " # Also move all FlatColors files to \\common\\FlatColors (even if they're unique)" + }, + { + "lineNumber": 8422, + "content": " Write-Host \"Moving FlatColors files to \\common\\FlatColors...\" -ForegroundColor Yellow" + }, + { + "lineNumber": 8423, + "content": " # Check remainingFiles directly to find FlatColors files that haven't been moved yet" + }, + { + "lineNumber": 8424, + "content": " $flatColorsFiles = $remainingFiles | Where-Object { $_.Name -like \"*FlatColors*\" -and (Test-Path -Path $_.FullName) }" + }, + { + "lineNumber": 8458, + "content": " # Track filenames already in \\common\\FlatColors" + }, + { + "lineNumber": 8459, + "content": " $filesInFlatColors = @{}" + }, + { + "lineNumber": 8461, + "content": " foreach ($file in $flatColorsFiles) {" + }, + { + "lineNumber": 8474, + "content": "1. **Check `$remainingFiles` directly** - This is the original file list before any processing, so it includes all FlatColors files that haven't been moved yet" + }, + { + "lineNumber": 8478, + "content": "- Find all FlatColors files from the original remaining files list" + }, + { + "lineNumber": 8479, + "content": "- Create the `\\textures\\common\\FlatColors` folder" + }, + { + "lineNumber": 8480, + "content": "- Move all FlatColors files there, stripping blendfile prefixes as needed" + }, + { + "lineNumber": 8482, + "content": "When you run the script, it should create the FlatColors folder and move the files there." + }, + { + "lineNumber": 8488, + "content": "@pwsh (1-698) still no FlatColors relocation." + }, + { + "lineNumber": 8495, + "content": "Adding debug output to see why FlatColors files aren't being found. Checking if they're being excluded or already moved:" + }, + { + "lineNumber": 8509, + "content": "FlatColors files may have already been moved during duplicate processing. Checking for them before duplicate processing and handling them separately. Updating the code:" + }, + { + "lineNumber": 8523, + "content": "Restructuring to handle FlatColors files before duplicate processing and exclude them from the duplicate loop:" + }, + { + "lineNumber": 8533, + "content": " # Separate FlatColors files from other files before processing" + }, + { + "lineNumber": 8534, + "content": " Write-Host \"Identifying FlatColors files...\" -ForegroundColor Yellow" + }, + { + "lineNumber": 8535, + "content": " $flatColorsFiles = $remainingFiles | Where-Object { $_.Name -like \"*FlatColors*\" }" + }, + { + "lineNumber": 8536, + "content": " $nonFlatColorsFiles = $remainingFiles | Where-Object { $_.Name -notlike \"*FlatColors*\" }" + }, + { + "lineNumber": 8538, + "content": " Write-Host \"Found $($flatColorsFiles.Count) FlatColors file(s), $($nonFlatColorsFiles.Count) other file(s)\" -ForegroundColor Gray" + }, + { + "lineNumber": 8540, + "content": " # Group non-FlatColors files by checksum" + }, + { + "lineNumber": 8542, + "content": " $nonFlatColorsWithChecksums = $filesWithChecksums | Where-Object { $_.File.Name -notlike \"*FlatColors*\" }" + }, + { + "lineNumber": 8543, + "content": " $groupedByChecksum = $nonFlatColorsWithChecksums | Group-Object -Property Hash" + }, + { + "lineNumber": 8558, + "content": " # Process each checksum group (excluding FlatColors)" + }, + { + "lineNumber": 8578, + "content": " # Move all FlatColors files to \\common\\FlatColors (even if they're unique)" + }, + { + "lineNumber": 8579, + "content": " Write-Host \"Moving FlatColors files to \\common\\FlatColors...\" -ForegroundColor Yellow" + }, + { + "lineNumber": 8589, + "content": "Updating the FlatColors processing to use the pre-filtered list:" + }, + { + "lineNumber": 8603, + "content": "Adding debug output to see if FlatColors files are being found:" + }, + { + "lineNumber": 8613, + "content": " # Move all FlatColors files to \\common\\FlatColors (even if they're unique)" + }, + { + "lineNumber": 8614, + "content": " Write-Host \"Moving FlatColors files to \\common\\FlatColors...\" -ForegroundColor Yellow" + }, + { + "lineNumber": 8616, + "content": " if ($null -ne $flatColorsFiles -and $flatColorsFiles.Count -gt 0) {" + }, + { + "lineNumber": 8617, + "content": " Write-Host \"Found $($flatColorsFiles.Count) FlatColors file(s) to move\" -ForegroundColor Gray" + }, + { + "lineNumber": 8627, + "content": "Adding an else clause to show when no FlatColors files are found:" + }, + { + "lineNumber": 8638, + "content": " Write-Host \"Moved $($flatColorsFiles.Count) FlatColors file(s) to \\common\\FlatColors\" -ForegroundColor Green" + }, + { + "lineNumber": 8640, + "content": " Write-Host \"No FlatColors files found to move.\" -ForegroundColor Gray" + }, + { + "lineNumber": 8653, + "content": "1. **Identify FlatColors files first** - Separates them from other files before duplicate processing" + }, + { + "lineNumber": 8654, + "content": "2. **Exclude from duplicate processing** - FlatColors files are filtered out of the checksum grouping so they aren't processed as duplicates" + }, + { + "lineNumber": 8655, + "content": "3. **Add debug output** - Shows how many FlatColors files were found" + }, + { + "lineNumber": 8656, + "content": "4. **Handle separately** - Moves all FlatColors files to `\\common\\FlatColors` regardless of whether they're duplicates" + }, + { + "lineNumber": 8659, + "content": "- Find all FlatColors files before any duplicate processing" + }, + { + "lineNumber": 8660, + "content": "- Process duplicates for non-FlatColors files" + }, + { + "lineNumber": 8661, + "content": "- Then move all FlatColors files to `\\textures\\common\\FlatColors` with prefixes stripped" + }, + { + "lineNumber": 8663, + "content": "When you run it, you should see messages indicating how many FlatColors files were found and moved." + }, + { + "lineNumber": 8669, + "content": "@pwsh (353-1075) how did it find no FlatColors?" + }, + { + "lineNumber": 8676, + "content": "The script matches filenames containing \"FlatColors\", but these files are in a `FlatColors` folder and named with hex codes (e.g., `#000000.png`). Updating the search to include files in a `FlatColors` folder path:" + }, + { + "lineNumber": 8690, + "content": "FlatColors files are in `[blendfile]\\common\\FlatColors`, so they're excluded by the `$remainingFiles` filter that excludes `*\\common\\*`. Collecting FlatColors files separately, including those in common folders:" + }, + { + "lineNumber": 8704, + "content": "Updating the code to collect FlatColors files from anywhere, including those in `\\common\\FlatColors` folders:" + }, + { + "lineNumber": 8714, + "content": "# Collect FlatColors files separately (including those in \\common\\FlatColors folders)" + }, + { + "lineNumber": 8715, + "content": "Write-Host \"Collecting FlatColors files...\" -ForegroundColor Yellow" + }, + { + "lineNumber": 8716, + "content": "$allFlatColorsFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object { $_.FullName -like \"*\\FlatColors\\*\" -or $_.Name -like \"*FlatColors*\" }" + }, + { + "lineNumber": 8718, + "content": "# Get all remaining files (excluding all \\common folders, but we'll handle FlatColors separately)" + }, + { + "lineNumber": 8733, + "content": " # Separate FlatColors files from other files before processing" + }, + { + "lineNumber": 8734, + "content": " Write-Host \"Identifying FlatColors files...\" -ForegroundColor Yellow" + }, + { + "lineNumber": 8735, + "content": " $flatColorsFiles = $allFlatColorsFiles | Where-Object { (Test-Path -Path $_.FullName) }" + }, + { + "lineNumber": 8736, + "content": " $nonFlatColorsFiles = $remainingFiles | Where-Object { $_.Name -notlike \"*FlatColors*\" }" + }, + { + "lineNumber": 8746, + "content": "Updating the debug output to show how many FlatColors files were found:" + }, + { + "lineNumber": 8756, + "content": " # Separate FlatColors files from other files before processing" + }, + { + "lineNumber": 8757, + "content": " Write-Host \"Identifying FlatColors files...\" -ForegroundColor Yellow" + }, + { + "lineNumber": 8758, + "content": " $flatColorsFiles = $allFlatColorsFiles | Where-Object { (Test-Path -Path $_.FullName) }" + }, + { + "lineNumber": 8759, + "content": " $nonFlatColorsFiles = $remainingFiles | Where-Object { $_.Name -notlike \"*FlatColors*\" }" + }, + { + "lineNumber": 8761, + "content": " Write-Host \"Found $($flatColorsFiles.Count) FlatColors file(s) (including from \\common\\FlatColors folders), $($nonFlatColorsFiles.Count) other file(s)\" -ForegroundColor Gray" + }, + { + "lineNumber": 8771, + "content": "Excluding files already in the root `\\textures\\common\\FlatColors` folder:" + }, + { + "lineNumber": 8781, + "content": "# Collect FlatColors files separately (including those in \\common\\FlatColors folders, but not from root \\common\\FlatColors)" + }, + { + "lineNumber": 8782, + "content": "Write-Host \"Collecting FlatColors files...\" -ForegroundColor Yellow" + }, + { + "lineNumber": 8783, + "content": "$rootCommonFlatColorsPath = Join-Path -Path $textureFolderPath -ChildPath \"common\\FlatColors\"" + }, + { + "lineNumber": 8784, + "content": "$allFlatColorsFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object {" + }, + { + "lineNumber": 8785, + "content": " ($_.FullName -like \"*\\FlatColors\\*\" -or $_.Name -like \"*FlatColors*\") -and" + }, + { + "lineNumber": 8786, + "content": " $_.FullName -notlike \"$([regex]::Escape($rootCommonFlatColorsPath))\\*\"" + }, + { + "lineNumber": 8799, + "content": "1. **Collects FlatColors files separately** - Searches for files in any `\\FlatColors\\` folder or with \"FlatColors\" in their name" + }, + { + "lineNumber": 8800, + "content": "2. **Excludes files already in the target** - Skips files already in `\\textures\\common\\FlatColors` to avoid moving files that are already in place" + }, + { + "lineNumber": 8801, + "content": "3. **Includes files from blendfile common folders** - Finds FlatColors files in `[blendfile]\\common\\FlatColors` folders that were excluded from `$remainingFiles`" + }, + { + "lineNumber": 8803, + "content": "When you run the script, it should find FlatColors files in folders like `Chan\\common\\FlatColors` and move them to `\\textures\\common\\FlatColors`. The debug output will show how many FlatColors files were found." + }, + { + "lineNumber": 8809, + "content": "@pwsh (350-1075) Good. Duplicate FlatColors should be merged, too, no _1 or _2 suffixes." + }, + { + "lineNumber": 8815, + "content": "Updating FlatColors processing to merge duplicates by checksum (keep one, delete the rest) instead of renaming with suffixes. Checking the current implementation:" + }, + { + "lineNumber": 8840, + "content": "Updating FlatColors processing to calculate checksums, group duplicates, and merge them (keep one, delete the rest) before moving:" + }, + { + "lineNumber": 8850, + "content": " # Process FlatColors files: merge duplicates and move to \\common\\FlatColors" + }, + { + "lineNumber": 8851, + "content": " Write-Host \"Processing FlatColors files (merging duplicates)...\" -ForegroundColor Yellow" + }, + { + "lineNumber": 8853, + "content": " if ($null -ne $flatColorsFiles -and $flatColorsFiles.Count -gt 0) {" + }, + { + "lineNumber": 8854, + "content": " Write-Host \"Found $($flatColorsFiles.Count) FlatColors file(s) to process\" -ForegroundColor Gray" + }, + { + "lineNumber": 8856, + "content": " # Calculate checksums for FlatColors files" + }, + { + "lineNumber": 8857, + "content": " Write-Host \"Calculating checksums for FlatColors files...\" -ForegroundColor Yellow" + }, + { + "lineNumber": 8858, + "content": " $flatColorsWithChecksums = Get-FilesWithChecksums -Files $flatColorsFiles" + }, + { + "lineNumber": 8861, + "content": " $flatColorsGroupedByChecksum = $flatColorsWithChecksums | Group-Object -Property Hash" + }, + { + "lineNumber": 8863, + "content": " Write-Host \"Found $($flatColorsGroupedByChecksum.Count) unique FlatColors file(s)\" -ForegroundColor Gray" + }, + { + "lineNumber": 8865, + "content": " # Create \\textures\\common\\FlatColors directory" + }, + { + "lineNumber": 8866, + "content": " $flatColorsPath = Join-Path -Path $rootCommonPath -ChildPath \"FlatColors\"" + }, + { + "lineNumber": 8867, + "content": " if (-not (Test-Path -Path $flatColorsPath -PathType Container)) {" + }, + { + "lineNumber": 8868, + "content": " New-Item -ItemType Directory -Path $flatColorsPath | Out-Null" + }, + { + "lineNumber": 8869, + "content": " Write-Host \"Created directory: $flatColorsPath\" -ForegroundColor Green" + }, + { + "lineNumber": 8872, + "content": " # Track filenames already in \\common\\FlatColors" + }, + { + "lineNumber": 8873, + "content": " $filesInFlatColors = @{}" + }, + { + "lineNumber": 8874, + "content": " $flatColorsMoved = 0" + }, + { + "lineNumber": 8875, + "content": " $flatColorsDuplicates = 0" + }, + { + "lineNumber": 8877, + "content": " foreach ($group in $flatColorsGroupedByChecksum) {" + }, + { + "lineNumber": 8881, + "content": " # Single file - move to FlatColors folder" + }, + { + "lineNumber": 8891, + "content": " $destinationPath = Join-Path -Path $flatColorsPath -ChildPath $fileName" + }, + { + "lineNumber": 8894, + "content": " if ($filesInFlatColors.ContainsKey($fileName) -or (Test-Path -Path $destinationPath)) {" + }, + { + "lineNumber": 8900, + "content": " $destinationPath = Join-Path -Path $flatColorsPath -ChildPath $newFileName" + }, + { + "lineNumber": 8902, + "content": " } while ($filesInFlatColors.ContainsKey($newFileName) -or (Test-Path -Path $destinationPath))" + }, + { + "lineNumber": 8908, + "content": " $filesInFlatColors[$fileName] = $true" + }, + { + "lineNumber": 8909, + "content": " $flatColorsMoved++" + }, + { + "lineNumber": 8911, + "content": " Write-Warning \"Failed to move FlatColors file: $($fileObj.FullName) - $($_.Exception.Message)\"" + }, + { + "lineNumber": 8916, + "content": " $result = Process-DuplicateGroup -Files $files -CommonPath $flatColorsPath -FilesInCommon $filesInFlatColors -StripPrefix -ValidPrefixes $validBlendfilePrefixes" + }, + { + "lineNumber": 8917, + "content": " $flatColorsMoved += $result.MovedCount" + }, + { + "lineNumber": 8918, + "content": " $flatColorsDuplicates += $result.DuplicateCount" + }, + { + "lineNumber": 8922, + "content": " Write-Host \"Moved $flatColorsMoved unique FlatColors file(s) to \\common\\FlatColors, deleted $flatColorsDuplicates duplicate(s)\" -ForegroundColor Green" + }, + { + "lineNumber": 8924, + "content": " Write-Host \"No FlatColors files found to process.\" -ForegroundColor Gray" + }, + { + "lineNumber": 8934, + "content": "Updated FlatColors processing to:" + }, + { + "lineNumber": 8936, + "content": "1. **Calculate checksums** for all FlatColors files" + }, + { + "lineNumber": 8939, + "content": "4. **Move unique files**: Single-file groups are moved to `\\common\\FlatColors`" + }, + { + "lineNumber": 8941, + "content": "This removes the `_1`, `_2` suffixes and merges duplicate FlatColors files, keeping one copy per unique checksum and deleting the rest. The script will report how many unique files were moved and how many duplicates were deleted." + }, + { + "lineNumber": 9875, + "content": " \"contents\": \" foreach ($group in $groupedByChecksum) {\\n $result = Process-DuplicateGroup -Files $group.Group -CommonPath $blendfileCommonPath -FilesInCommon $filesInBlendfileCommon\\n $blendfileMoved += $result.MovedCount\\n $blendfileDuplicates += $result.DuplicateCount\\n }\\n \\n Write-Host \\\" Moved $blendfileMoved file(s) to \\\\common, deleted $blendfileDuplicates duplicate(s)\\\" -ForegroundColor Green\\n $totalPass1Moved += $blendfileMoved\\n $totalPass1Duplicates += $blendfileDuplicates\\n }\\n \\n Write-Host \\\"\\\"\\n Write-Host \\\"Pass 1 complete: $totalPass1Moved file(s) moved, $totalPass1Duplicates duplicate(s) deleted\\\" -ForegroundColor Green\\n}\\n\\n# ============================================================================\\n# PASS 2: Inter-Blendfile Processing\\n# ============================================================================\\nWrite-Host \\\"\\\"\\nWrite-Host \\\"=== PASS 2: Inter-Blend" + }, + { + "lineNumber": 9992, + "content": " \"text\": \"# Collect FlatColors files separately (including those in \\\\common\\\\FlatColors folders, but not from root \\\\common\\\\FlatColors)\"," + }, + { + "lineNumber": 9996, + "content": " \"text\": \"Write-Host \\\"Collecting FlatColors files...\\\" -ForegroundColor Yellow\"," + }, + { + "lineNumber": 10000, + "content": " \"text\": \"$rootCommonFlatColorsPath = Join-Path -Path $textureFolderPath -ChildPath \\\"common\\\\FlatColors\\\"\"," + }, + { + "lineNumber": 10004, + "content": " \"text\": \"$allFlatColorsFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object { \"," + }, + { + "lineNumber": 10008, + "content": " \"text\": \" ($_.FullName -like \\\"*\\\\FlatColors\\\\*\\\" -or $_.Name -like \\\"*FlatColors*\\\") -and \"," + }, + { + "lineNumber": 10012, + "content": " \"text\": \" $_.FullName -notlike \\\"$([regex]::Escape($rootCommonFlatColorsPath))\\\\*\\\" \"," + }, + { + "lineNumber": 10023, + "content": " \"text\": \"# Get all remaining files (excluding all \\\\common folders, but we'll handle FlatColors separately)\"," + }, + { + "lineNumber": 16551, + "content": " \"plan\": \"# Texture Path Remapping in Blend Files\\n\\n## Overview\\nAfter organizing textures (moving duplicates to common folders, deleting duplicates, moving FlatColors), we need to update all texture path references in the corresponding &#96;.blend&#96; files to point to the new locations.\\n\\n## Implementation Steps\\n\\n### 1. Track File Moves in &#96;organize_textures.ps1&#96;\\n\\n**File:** &#96;organize_textures.ps1&#96;\\n\\n- **Modify &#96;Process-DuplicateGroup&#96; function:**\\n - Add a parameter &#96;$MoveLog&#96; (hashtable/array) to track moves\\n - When a file is moved (line 221), log: &#96;@{ OriginalPath = $firstFile.FullName; NewPath = $destinationPath; Type = \\\"moved\\\" }&#96;\\n - When duplicates are deleted (line 232), log: &#96;@{ OriginalPath = $fileObj.FullName; ReplacedBy = $destinationPath; Type = \\\"deleted\\\" }&#96;\\n - Return the move log entries along with counts\\n\\n- **Modify Pass 1 processing:**\\n - Create &#96;$pass1MoveLog = @()&#96; before the blendfile loop" + }, + { + "lineNumber": 16560, + "content": " \"content\": \"Modify Pass 2 processing to track moves for regular files and FlatColors files separately\"," + }, + { + "lineNumber": 16803, + "content": " # Process each checksum group (excluding FlatColors)" + }, + { + "lineNumber": 16832, + "content": "Updating FlatColors processing to track moves:" + }, + { + "lineNumber": 16842, + "content": " # Track filenames already in \\common\\FlatColors" + }, + { + "lineNumber": 16843, + "content": " $filesInFlatColors = @{}" + }, + { + "lineNumber": 16844, + "content": " $flatColorsMoved = 0" + }, + { + "lineNumber": 16845, + "content": " $flatColorsDuplicates = 0" + }, + { + "lineNumber": 16846, + "content": " $flatColorsMoveLog = [System.Collections.ArrayList]::new()" + }, + { + "lineNumber": 16848, + "content": " foreach ($group in $flatColorsGroupedByChecksum) {" + }, + { + "lineNumber": 16852, + "content": " # Single file - move to FlatColors folder" + }, + { + "lineNumber": 16862, + "content": " $destinationPath = Join-Path -Path $flatColorsPath -ChildPath $fileName" + }, + { + "lineNumber": 16865, + "content": " if ($filesInFlatColors.ContainsKey($fileName) -or (Test-Path -Path $destinationPath)) {" + }, + { + "lineNumber": 16871, + "content": " $destinationPath = Join-Path -Path $flatColorsPath -ChildPath $newFileName" + }, + { + "lineNumber": 16873, + "content": " } while ($filesInFlatColors.ContainsKey($newFileName) -or (Test-Path -Path $destinationPath))" + }, + { + "lineNumber": 16880, + "content": " $filesInFlatColors[$fileName] = $true" + }, + { + "lineNumber": 16881, + "content": " $flatColorsMoved++" + }, + { + "lineNumber": 16886, + "content": " $null = $flatColorsMoveLog.Add([PSCustomObject]@{" + }, + { + "lineNumber": 16892, + "content": " Write-Warning \"Failed to move FlatColors file: $($fileObj.FullName) - $($_.Exception.Message)\"" + }, + { + "lineNumber": 16897, + "content": " $result = Process-DuplicateGroup -Files $files -CommonPath $flatColorsPath -FilesInCommon $filesInFlatColors -StripPrefix -ValidPrefixes $validBlendfilePrefixes -MoveLog $flatColorsMoveLog" + }, + { + "lineNumber": 16898, + "content": " $flatColorsMoved += $result.MovedCount" + }, + { + "lineNumber": 16899, + "content": " $flatColorsDuplicates += $result.DuplicateCount" + }, + { + "lineNumber": 16935, + "content": "if ($null -ne $flatColorsMoveLog -and $flatColorsMoveLog.Count -gt 0) {" + }, + { + "lineNumber": 16936, + "content": " $allMoves += $flatColorsMoveLog" + }, + { + "lineNumber": 17331, + "content": "3. **Pass 2 tracking**: Added `$pass2MoveLog` and `$flatColorsMoveLog` to track inter-blendfile moves" + }, + { + "lineNumber": 18376, + "content": "Collecting FlatColors files..." + }, + { + "lineNumber": 18381, + "content": "Identifying FlatColors files..." + }, + { + "lineNumber": 18382, + "content": "Found 15 FlatColors file(s) (including from \\common\\FlatColors folders), 193 other file(s)" + }, + { + "lineNumber": 18387, + "content": "Processing FlatColors files (merging duplicates)..." + }, + { + "lineNumber": 18388, + "content": "Found 15 FlatColors file(s) to process" + }, + { + "lineNumber": 18389, + "content": "Calculating checksums for FlatColors files..." + }, + { + "lineNumber": 18390, + "content": "Found 6 unique FlatColors file(s)" + }, + { + "lineNumber": 18391, + "content": "Created directory: T:\\1 BlenderAssets\\Amazon\\Char\\Cartoon2\\AM\\common\\FlatColors" + }, + { + "lineNumber": 18392, + "content": "Moved 6 unique FlatColors file(s) to \\common\\FlatColors, deleted 9 duplicate(s)" + } + ] + }, + { + "file": ".specstory/history/2025-12-19_17-59Z-texture-folder-commonality-script.md", + "matches": [ + { + "lineNumber": 271, + "content": " \"absPath\": \"A:\\\\1 Amazon_Active_Projects\\\\1 BlenderAssets\\\\Amazon\\\\Char\\\\Cartoon1\\\\textures\\\\Chan\\\\common\\\\FlatColors\"," + }, + { + "lineNumber": 349, + "content": " \"absPath\": \"A:\\\\1 Amazon_Active_Projects\\\\1 BlenderAssets\\\\Amazon\\\\Char\\\\Cartoon1\\\\textures\\\\Demarco\\\\common\\\\FlatColors\"," + }, + { + "lineNumber": 514, + "content": " \"absPath\": \"A:\\\\1 Amazon_Active_Projects\\\\1 BlenderAssets\\\\Amazon\\\\Char\\\\Cartoon1\\\\textures\\\\Dennis\\\\common\\\\FlatColors\"," + }, + { + "lineNumber": 735, + "content": " \"absPath\": \"A:\\\\1 Amazon_Active_Projects\\\\1 BlenderAssets\\\\Amazon\\\\Char\\\\Cartoon1\\\\textures\\\\Hailey\\\\common\\\\FlatColors\"," + }, + { + "lineNumber": 900, + "content": " \"absPath\": \"A:\\\\1 Amazon_Active_Projects\\\\1 BlenderAssets\\\\Amazon\\\\Char\\\\Cartoon1\\\\textures\\\\Joe\\\\common\\\\FlatColors\"," + }, + { + "lineNumber": 1057, + "content": " \"absPath\": \"A:\\\\1 Amazon_Active_Projects\\\\1 BlenderAssets\\\\Amazon\\\\Char\\\\Cartoon1\\\\textures\\\\Kirk\\\\common\\\\FlatColors\"," + }, + { + "lineNumber": 1218, + "content": " \"absPath\": \"A:\\\\1 Amazon_Active_Projects\\\\1 BlenderAssets\\\\Amazon\\\\Char\\\\Cartoon1\\\\textures\\\\Manny\\\\common\\\\FlatColors\"," + }, + { + "lineNumber": 1470, + "content": " \"absPath\": \"A:\\\\1 Amazon_Active_Projects\\\\1 BlenderAssets\\\\Amazon\\\\Char\\\\Cartoon1\\\\textures\\\\Martha\\\\common\\\\FlatColors\"," + }, + { + "lineNumber": 1628, + "content": " \"absPath\": \"A:\\\\1 Amazon_Active_Projects\\\\1 BlenderAssets\\\\Amazon\\\\Char\\\\Cartoon1\\\\textures\\\\Regina\\\\common\\\\FlatColors\"," + }, + { + "lineNumber": 1850, + "content": " \"absPath\": \"A:\\\\1 Amazon_Active_Projects\\\\1 BlenderAssets\\\\Amazon\\\\Char\\\\Cartoon1\\\\textures\\\\Regina\\\\common\\\\FlatColors\"," + }, + { + "lineNumber": 3473, + "content": "let's make sure that universally, the FlatColors are all saved as 16x16 jpgs, unless they're .tga. also, duplicate flatcolors can and absolutely should be merged." + }, + { + "lineNumber": 3480, + "content": "Exploring the project structure to locate FlatColors and understand the current setup." + }, + { + "lineNumber": 3494, + "content": " \"query\": \"Where are FlatColors stored or referenced?\"," + }, + { + "lineNumber": 3516, + "content": " \"contents\": \" \\n if ($null -ne $flatColorsFiles -and $flatColorsFiles.Count -gt 0) {\\n Write-Host \\\"Found $($flatColorsFiles.Count) FlatColors file(s) to process\\\" -ForegroundColor Gray\\n \\n # Calculate checksums for FlatColors files\\n Write-Host \\\"Calculating checksums for FlatColors files...\\\" -ForegroundColor Yellow\\n $flatColorsWithChecksums = Get-FilesWithChecksums -Files $flatColorsFiles\\n \\n # Group by checksum to find duplicates\\n $flatColorsGroupedByChecksum = $flatColorsWithChecksums | Group-Object -Property Hash\\n \\n Write-Host \\\"Found $($flatColorsGroupedByChecksum.Count) unique FlatColors file(s)\\\" -ForegroundColor Gray\\n \\n # Create \\\\textures\\\\common\\\\FlatColors directory\\n $flatColorsPath = Join-Path -Path $rootCommonPath -ChildPath \\\"FlatColors\\\"\\n if (-not (Test-Path -Path $flatColorsPath -PathType Container)) {\\n New-Item -ItemType Directory -Pat" + }, + { + "lineNumber": 3524, + "content": " \"text\": \" if ($null -ne $flatColorsFiles -and $flatColorsFiles.Count -gt 0) {\"," + }, + { + "lineNumber": 3528, + "content": " \"text\": \" Write-Host \\\"Found $($flatColorsFiles.Count) FlatColors file(s) to process\\\" -ForegroundColor Gray\"," + }, + { + "lineNumber": 3536, + "content": " \"text\": \" # Calculate checksums for FlatColors files\"," + }, + { + "lineNumber": 3540, + "content": " \"text\": \" Write-Host \\\"Calculating checksums for FlatColors files...\\\" -ForegroundColor Yellow\"," + }, + { + "lineNumber": 3544, + "content": " \"text\": \" $flatColorsWithChecksums = Get-FilesWithChecksums -Files $flatColorsFiles\"," + }, + { + "lineNumber": 3556, + "content": " \"text\": \" $flatColorsGroupedByChecksum = $flatColorsWithChecksums | Group-Object -Property Hash\"," + }, + { + "lineNumber": 3564, + "content": " \"text\": \" Write-Host \\\"Found $($flatColorsGroupedByChecksum.Count) unique FlatColors file(s)\\\" -ForegroundColor Gray\"," + }, + { + "lineNumber": 3572, + "content": " \"text\": \" # Create \\\\textures\\\\common\\\\FlatColors directory\"," + }, + { + "lineNumber": 3576, + "content": " \"text\": \" $flatColorsPath = Join-Path -Path $rootCommonPath -ChildPath \\\"FlatColors\\\"\"," + }, + { + "lineNumber": 3580, + "content": " \"text\": \" if (-not (Test-Path -Path $flatColorsPath -PathType Container)) {\"," + }, + { + "lineNumber": 3584, + "content": " \"text\": \" New-Item -ItemType Directory -Path $flatColorsPath | Out-Null\"," + }, + { + "lineNumber": 3588, + "content": " \"text\": \" Write-Host \\\"Created directory: $flatColorsPath\\\" -ForegroundColor Green\"," + }, + { + "lineNumber": 3600, + "content": " \"text\": \" # Track filenames already in \\\\common\\\\FlatColors\"," + }, + { + "lineNumber": 3604, + "content": " \"text\": \" $filesInFlatColors = @{}\"," + }, + { + "lineNumber": 3608, + "content": " \"text\": \" $flatColorsMoved = 0\"," + }, + { + "lineNumber": 3612, + "content": " \"text\": \" $flatColorsDuplicates = 0\"," + }, + { + "lineNumber": 3616, + "content": " \"text\": \" $flatColorsMoveLog = [System.Collections.ArrayList]::new()\"," + }, + { + "lineNumber": 3624, + "content": " \"text\": \" foreach ($group in $flatColorsGroupedByChecksum) {\"," + }, + { + "lineNumber": 3658, + "content": " \"contents\": \"$allFlatColorsFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object { \\n ($_.FullName -like \\\"*\\\\FlatColors\\\\*\\\" -or $_.Name -like \\\"*FlatColors*\\\") -and \\n $_.FullName -notlike \\\"$([regex]::Escape($rootCommonFlatColorsPath))\\\\*\\\" \\n}\\n\\n# Get all remaining files (excluding all \\\\common folders, but we'll handle FlatColors separately)\\nWrite-Host \\\"Collecting remaining files...\\\" -ForegroundColor Yellow\\n$remainingFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object { $_.FullName -notlike \\\"*\\\\common\\\\*\\\" }\\n\\nif ($null -eq $remainingFiles -or $remainingFiles.Count -eq 0) {\\n Write-Host \\\"No remaining files found to process.\\\" -ForegroundColor Yellow\\n} else {\\n Write-Host \\\"Found $($remainingFiles.Count) remaining files to process.\\\" -ForegroundColor Green\\n \\n # Calculate checksums\\n Write-Host \\\"Calculating checksums using parallel processing (this may take a while)...\\\" -ForegroundColor Yellow\\" + }, + { + "lineNumber": 3662, + "content": " \"text\": \"$allFlatColorsFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object { \"," + }, + { + "lineNumber": 3666, + "content": " \"text\": \" ($_.FullName -like \\\"*\\\\FlatColors\\\\*\\\" -or $_.Name -like \\\"*FlatColors*\\\") -and \"," + }, + { + "lineNumber": 3670, + "content": " \"text\": \" $_.FullName -notlike \\\"$([regex]::Escape($rootCommonFlatColorsPath))\\\\*\\\" \"," + }, + { + "lineNumber": 3681, + "content": " \"text\": \"# Get all remaining files (excluding all \\\\common folders, but we'll handle FlatColors separately)\"," + }, + { + "lineNumber": 3740, + "content": " \"text\": \" # Separate FlatColors files from other files before processing\"," + }, + { + "lineNumber": 3744, + "content": " \"text\": \" Write-Host \\\"Identifying FlatColors files...\\\" -ForegroundColor Yellow\"," + }, + { + "lineNumber": 3748, + "content": " \"text\": \" $flatColorsFiles = $allFlatColorsFiles | Where-Object { (Test-Path -Path $_.FullName) }\"," + }, + { + "lineNumber": 3752, + "content": " \"text\": \" $nonFlatColorsFiles = $remainingFiles | Where-Object { $_.Name -notlike \\\"*FlatColors*\\\" }\"," + }, + { + "lineNumber": 3760, + "content": " \"text\": \" Write-Host \\\"Found $($flatColorsFiles.Count) FlatColors file(s) (including from \\\\common\\\\FlatColors folders), $($nonFlatColorsFiles.Count) other file(s)\\\" -ForegroundColor Gray\"," + }, + { + "lineNumber": 3768, + "content": " \"text\": \" # Group non-FlatColors files by checksum\"," + }, + { + "lineNumber": 3776, + "content": " \"text\": \" $nonFlatColorsWithChecksums = $filesWithChecksums | Where-Object { $_.File.Name -notlike \\\"*FlatColors*\\\" }\"," + }, + { + "lineNumber": 3780, + "content": " \"text\": \" $groupedByChecksum = $nonFlatColorsWithChecksums | Group-Object -Property Hash\"," + }, + { + "lineNumber": 3814, + "content": " \"contents\": \" \\n foreach ($group in $flatColorsGroupedByChecksum) {\\n $files = $group.Group\\n \\n if ($files.Count -eq 1) {\\n # Single file - move to FlatColors folder\\n $fileObj = $files[0].File\\n $fileName = $fileObj.Name\\n \\n # Strip blendfile prefix if present\\n $strippedName = Get-FileNameWithoutPrefix -FileName $fileName -ValidPrefixes $validBlendfilePrefixes\\n if ($strippedName -ne $fileName) {\\n $fileName = $strippedName\\n }\\n \\n $destinationPath = Join-Path -Path $flatColorsPath -ChildPath $fileName\\n \\n # Handle name conflicts (shouldn't happen for unique files, but just in case)\\n if ($filesInFlatColors.ContainsKey($fileName) -or (Test-Path -Path $destinationPath)) {\\n $baseName = [System.IO.P" + }, + { + "lineNumber": 3822, + "content": " \"text\": \" foreach ($group in $flatColorsGroupedByChecksum) {\"," + }, + { + "lineNumber": 3838, + "content": " \"text\": \" # Single file - move to FlatColors folder\"," + }, + { + "lineNumber": 3878, + "content": " \"text\": \" $destinationPath = Join-Path -Path $flatColorsPath -ChildPath $fileName\"," + }, + { + "lineNumber": 3890, + "content": " \"text\": \" if ($filesInFlatColors.ContainsKey($fileName) -or (Test-Path -Path $destinationPath)) {\"," + }, + { + "lineNumber": 3914, + "content": " \"text\": \" $destinationPath = Join-Path -Path $flatColorsPath -ChildPath $newFileName\"," + }, + { + "lineNumber": 3922, + "content": " \"text\": \" } while ($filesInFlatColors.ContainsKey($newFileName) -or (Test-Path -Path $destinationPath))\"," + }, + { + "lineNumber": 3964, + "content": " \"contents\": \" \\n try {\\n $originalPath = $fileObj.FullName\\n Move-Item -Path $originalPath -Destination $destinationPath -Force\\n $filesInFlatColors[$fileName] = $true\\n $flatColorsMoved++\\n \\n # Log the move\\n $normalizedOriginal = [System.IO.Path]::GetFullPath($originalPath)\\n $normalizedNew = [System.IO.Path]::GetFullPath($destinationPath)\\n $null = $flatColorsMoveLog.Add([PSCustomObject]@{\\n OriginalPath = $normalizedOriginal\\n NewPath = $normalizedNew\\n Type = \\\"moved\\\"\\n })\\n } catch {\\n Write-Warning \\\"Failed to move FlatColors file: $($fileObj.FullName) - $($_.Exception.Message)\\\"\\n }\\n } else {\\n # Multiple file" + }, + { + "lineNumber": 3984, + "content": " \"text\": \" $filesInFlatColors[$fileName] = $true\"," + }, + { + "lineNumber": 3988, + "content": " \"text\": \" $flatColorsMoved++\"," + }, + { + "lineNumber": 4008, + "content": " \"text\": \" $null = $flatColorsMoveLog.Add([PSCustomObject]@{\"," + }, + { + "lineNumber": 4032, + "content": " \"text\": \" Write-Warning \\\"Failed to move FlatColors file: $($fileObj.FullName) - $($_.Exception.Message)\\\"\"," + }, + { + "lineNumber": 4052, + "content": " \"text\": \" $result = Process-DuplicateGroup -Files $files -CommonPath $flatColorsPath -FilesInCommon $filesInFlatColors -StripPrefix -ValidPrefixes $validBlendfilePrefixes -MoveLog $flatColorsMoveLog\"," + }, + { + "lineNumber": 4056, + "content": " \"text\": \" $flatColorsMoved += $result.MovedCount\"," + }, + { + "lineNumber": 4060, + "content": " \"text\": \" $flatColorsDuplicates += $result.DuplicateCount\"," + }, + { + "lineNumber": 4076, + "content": " \"text\": \" Write-Host \\\"Moved $flatColorsMoved unique FlatColors file(s) to \\\\common\\\\FlatColors, deleted $flatColorsDuplicates duplicate(s)\\\" -ForegroundColor Green\"," + }, + { + "lineNumber": 4084, + "content": " \"text\": \" Write-Host \\\"No FlatColors files found to process.\\\" -ForegroundColor Gray\"," + }, + { + "lineNumber": 4145, + "content": " \"contents\": \" foreach ($group in $groupedByChecksum) {\\n $result = Process-DuplicateGroup -Files $group.Group -CommonPath $blendfileCommonPath -FilesInCommon $filesInBlendfileCommon -MoveLog $pass1MoveLog\\n $blendfileMoved += $result.MovedCount\\n $blendfileDuplicates += $result.DuplicateCount\\n }\\n \\n Write-Host \\\" Moved $blendfileMoved file(s) to \\\\common, deleted $blendfileDuplicates duplicate(s)\\\" -ForegroundColor Green\\n $totalPass1Moved += $blendfileMoved\\n $totalPass1Duplicates += $blendfileDuplicates\\n }\\n \\n Write-Host \\\"\\\"\\n Write-Host \\\"Pass 1 complete: $totalPass1Moved file(s) moved, $totalPass1Duplicates duplicate(s) deleted\\\" -ForegroundColor Green\\n}\\n\\n# ============================================================================\\n# PASS 2: Inter-Blendfile Processing\\n# ============================================================================\\nWrite-Host \\\"\\\"\\nWrite-Host \\\"" + }, + { + "lineNumber": 4262, + "content": " \"text\": \"# Collect FlatColors files separately (including those in \\\\common\\\\FlatColors folders, but not from root \\\\common\\\\FlatColors)\"," + }, + { + "lineNumber": 4266, + "content": " \"text\": \"Write-Host \\\"Collecting FlatColors files...\\\" -ForegroundColor Yellow\"," + }, + { + "lineNumber": 4270, + "content": " \"text\": \"$rootCommonFlatColorsPath = Join-Path -Path $textureFolderPath -ChildPath \\\"common\\\\FlatColors\\\"\"," + }, + { + "lineNumber": 4274, + "content": " \"text\": \"$allFlatColorsFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object { \"," + }, + { + "lineNumber": 4278, + "content": " \"text\": \" ($_.FullName -like \\\"*\\\\FlatColors\\\\*\\\" -or $_.Name -like \\\"*FlatColors*\\\") -and \"," + }, + { + "lineNumber": 4296, + "content": " \"contents\": \" \\n Write-Host \\\"Found $($groupedByChecksum.Count) unique checksums.\\\" -ForegroundColor Green\\n \\n # Create \\\\textures\\\\common directory\\n $rootCommonPath = Join-Path -Path $textureFolderPath -ChildPath \\\"common\\\"\\n \\n if (-not (Test-Path -Path $rootCommonPath -PathType Container)) {\\n New-Item -ItemType Directory -Path $rootCommonPath | Out-Null\\n Write-Host \\\"Created directory: $rootCommonPath\\\" -ForegroundColor Green\\n }\\n \\n # Track filenames already in \\\\textures\\\\common\\n $filesInRootCommon = @{}\\n \\n # Process each checksum group (excluding FlatColors)\\n Write-Host \\\"Moving files to \\\\common and deleting duplicates...\\\" -ForegroundColor Yellow\\n $pass2Moved = 0\\n $pass2Duplicates = 0\\n $pass2MoveLog = [System.Collections.ArrayList]::new()\\n \\n foreach ($group in $groupedByChecksum) {\\n $files = $group.Group\\n \\n if ($files.Count -eq 1) {\\n # Single file - l" + }, + { + "lineNumber": 4356, + "content": " \"text\": \" # Process each checksum group (excluding FlatColors)\"," + }, + { + "lineNumber": 4440, + "content": " \"text\": \" # Process FlatColors files: merge duplicates and move to \\\\common\\\\FlatColors\"," + }, + { + "lineNumber": 4444, + "content": " \"text\": \" Write-Host \\\"Processing FlatColors files (merging duplicates)...\\\" -ForegroundColor Yellow\"," + }, + { + "lineNumber": 4452, + "content": " \"text\": \" if ($null -ne $flatColorsFiles -and $flatColorsFiles.Count -gt 0) {\"," + }, + { + "lineNumber": 4456, + "content": " \"text\": \" Write-Host \\\"Found $($flatColorsFiles.Count) FlatColors file(s) to process\\\" -ForegroundColor Gray\"," + }, + { + "lineNumber": 5168, + "content": " \"contents\": \"# Save Move Log and Find Blend Files\\n# ============================================================================\\nWrite-Host \\\"\\\"\\nWrite-Host \\\"Saving move log and finding blend files...\\\" -ForegroundColor Yellow\\n\\n# Combine all move logs\\n$allMoves = @()\\nif ($null -ne $pass1MoveLog -and $pass1MoveLog.Count -gt 0) {\\n $allMoves += $pass1MoveLog\\n}\\nif ($null -ne $pass2MoveLog -and $pass2MoveLog.Count -gt 0) {\\n $allMoves += $pass2MoveLog\\n}\\nif ($null -ne $flatColorsMoveLog -and $flatColorsMoveLog.Count -gt 0) {\\n $allMoves += $flatColorsMoveLog\\n}\\n\\n# Get parent directory of texture folder\\n$blendFileParentDir = Split-Path -Path $textureFolderPath -Parent\\n\\n# Find matching blend files\\n# Match logic: blendfile folder name (e.g., \\\"Beth\\\") should appear in blend file name (e.g., \\\"AM_Beth_v3.2.blend\\\")\\n$blendFileMappings = @()\\nif ($null -ne $blendfileFolders -and $blendfileFolders.Count -gt 0) {\\n # Get blendfile folder names\\n $blendfileFo" + }, + { + "lineNumber": 5223, + "content": " \"text\": \"if ($null -ne $flatColorsMoveLog -and $flatColorsMoveLog.Count -gt 0) {\"," + }, + { + "lineNumber": 5227, + "content": " \"text\": \" $allMoves += $flatColorsMoveLog\"," + } + ] + } + ], + "totalLines": 337, + "totalMatchedLines": 337 + } + } + } + } +} +``` +Status: **completed** + + +
+
+ +--- + + +Reviewing the existing script to understand the structure, then creating a script to standardize FlatColors. + + +--- + + +
Tool use: **read_file_v2** • Read file: organize_textures.ps1 + +
+
+ +--- + + +
Tool use: **read_file_v2** • Read file: CONFIG.md + +
+
+ +--- + + +Creating a script to standardize FlatColors: convert PNGs to 16x16 JPGs (except TGA), merge duplicates by color, and ensure all are 16x16. + + +--- + + +
Tool use: **read_file_v2** • Read file: organize_textures.ps1 + +
+
+ +--- + + +
+Tool use: **semantic_search_full** + + +Parameters: + +```json +{ + "query": "How are image files processed or converted in PowerShell scripts?", + "topK": 10, + "explanation": "" +} +``` +Result: + +```json +{ + "codeResults": [ + { + "codeBlock": { + "relativeWorkspacePath": ".\\organize_textures.ps1", + "range": { + "startPosition": { + "line": 636 + }, + "endPosition": { + "line": 677 + } + }, + "contents": " \n try {\n # Run Blender and capture output while displaying it (like compress_blend_files.bat)\n # Build command with proper argument array\n $blenderArgsArray = @(\n \"--background\",\n \"--factory-startup\",\n \"--python\", $remapScriptPath,\n \"--\",\n $blendFilePath,\n $moveLogPath\n )\n \n # Execute and pipe output through Tee-Object to display and save\n & $blenderExe $blenderArgsArray 2>&1 | Tee-Object -FilePath \"blender_output.txt\" | ForEach-Object {\n Write-Host \" $_\"\n }\n \n # Check exit code\n $exitCode = $LASTEXITCODE\n \n if ($exitCode -eq 0) {\n Write-Host \" Successfully remapped texture paths\" -ForegroundColor Green\n $processedCount++\n } else {\n Write-Warning \" Failed to remap texture paths (exit code: $exitCode)\"\n $failedCount++\n }\n } catch {\n Write-Warning \" Exception while processing blend file: $($_.Exception.Message)\"\n $failedCount++\n }\n }\n \n # Clean up temporary output files\n Remove-Item -Path \"blender_output.txt\" -ErrorAction SilentlyContinue\n Remove-Item -Path \"blender_error.txt\" -ErrorAction SilentlyContinue\n \n Write-Host \"\"\n if ($processedCount -gt 0 -or $failedCount -gt 0) {\n Write-Host \"Blend file remapping complete: $processedCount succeeded, $failedCount failed\" -ForegroundColor $(if ($failedCount -eq 0) { \"Green\" } else { \"Yellow\" })", + "signatures": {}, + "detailedLines": [ + { + "text": " ", + "lineNumber": 637 + }, + { + "text": " try {", + "lineNumber": 638 + }, + { + "text": " # Run Blender and capture output while displaying it (like compress_blend_files.bat)", + "lineNumber": 639 + }, + { + "text": " # Build command with proper argument array", + "lineNumber": 640 + }, + { + "text": " $blenderArgsArray = @(", + "lineNumber": 641 + }, + { + "text": " \"--background\",", + "lineNumber": 642 + }, + { + "text": " \"--factory-startup\",", + "lineNumber": 643 + }, + { + "text": " \"--python\", $remapScriptPath,", + "lineNumber": 644 + }, + { + "text": " \"--\",", + "lineNumber": 645 + }, + { + "text": " $blendFilePath,", + "lineNumber": 646 + }, + { + "text": " $moveLogPath", + "lineNumber": 647 + }, + { + "text": " )", + "lineNumber": 648 + }, + { + "text": " ", + "lineNumber": 649 + }, + { + "text": " # Execute and pipe output through Tee-Object to display and save", + "lineNumber": 650 + }, + { + "text": " & $blenderExe $blenderArgsArray 2>&1 | Tee-Object -FilePath \"blender_output.txt\" | ForEach-Object {", + "lineNumber": 651 + }, + { + "text": " Write-Host \" $_\"", + "lineNumber": 652 + }, + { + "text": " }", + "lineNumber": 653 + }, + { + "text": " ", + "lineNumber": 654 + }, + { + "text": " # Check exit code", + "lineNumber": 655 + }, + { + "text": " $exitCode = $LASTEXITCODE", + "lineNumber": 656 + }, + { + "text": " ", + "lineNumber": 657 + }, + { + "text": " if ($exitCode -eq 0) {", + "lineNumber": 658 + }, + { + "text": " Write-Host \" Successfully remapped texture paths\" -ForegroundColor Green", + "lineNumber": 659 + }, + { + "text": " $processedCount++", + "lineNumber": 660 + }, + { + "text": " } else {", + "lineNumber": 661 + }, + { + "text": " Write-Warning \" Failed to remap texture paths (exit code: $exitCode)\"", + "lineNumber": 662 + }, + { + "text": " $failedCount++", + "lineNumber": 663 + }, + { + "text": " }", + "lineNumber": 664 + }, + { + "text": " } catch {", + "lineNumber": 665 + }, + { + "text": " Write-Warning \" Exception while processing blend file: $($_.Exception.Message)\"", + "lineNumber": 666 + }, + { + "text": " $failedCount++", + "lineNumber": 667 + }, + { + "text": " }", + "lineNumber": 668 + }, + { + "text": " }", + "lineNumber": 669 + }, + { + "text": " ", + "lineNumber": 670 + }, + { + "text": " # Clean up temporary output files", + "lineNumber": 671 + }, + { + "text": " Remove-Item -Path \"blender_output.txt\" -ErrorAction SilentlyContinue", + "lineNumber": 672 + }, + { + "text": " Remove-Item -Path \"blender_error.txt\" -ErrorAction SilentlyContinue", + "lineNumber": 673 + }, + { + "text": " ", + "lineNumber": 674 + }, + { + "text": " Write-Host \"\"", + "lineNumber": 675 + }, + { + "text": " if ($processedCount -gt 0 -or $failedCount -gt 0) {", + "lineNumber": 676 + }, + { + "text": " Write-Host \"Blend file remapping complete: $processedCount succeeded, $failedCount failed\" -ForegroundColor $(if ($failedCount -eq 0) { \"Green\" } else { \"Yellow\" })", + "lineNumber": 677 + } + ] + }, + "score": 0.39588218927383423 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\UpdateSequences.ps1", + "range": { + "startPosition": {}, + "endPosition": { + "line": 60 + } + }, + "contents": "[CmdletBinding()]\nparam(\n [switch]$DebugMode\n)\n\nSet-StrictMode -Version Latest\n$ErrorActionPreference = 'Stop'\n\nif (-not $PSScriptRoot) {\n $PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path\n}\n\n$configLoader = Join-Path -Path $PSScriptRoot -ChildPath 'ConfigLoader.ps1'\nif (-not (Test-Path -LiteralPath $configLoader)) {\n throw \"Missing ConfigLoader.ps1 in $PSScriptRoot\"\n}\n. $configLoader\n\n$useIsoDailyFormat = Use-IsoDailyFormat\n\nfunction Sync-SequenceFilenames {\n param(\n [Parameter(Mandatory)] [string]$SequenceFolderPath,\n [Parameter(Mandatory)] [string]$SequenceName,\n [string]$LogFile,\n [string[]]$Extensions = @('.png','.jpg','.jpeg','.exr','.tif','.tiff','.bmp','.tga')\n )\n $renamed = 0\n $collisions = 0\n $errors = 0\n $checked = 0\n $minFrame = [int]::MaxValue\n $maxFrame = -1\n $frameCount = 0\n\n if ($LogFile) { \"[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] RENAME CHECK in '$SequenceFolderPath' (seq='$SequenceName')\" | Add-Content -LiteralPath $LogFile }\n\n $files = Get-ChildItem -LiteralPath $SequenceFolderPath -File -Recurse -ErrorAction SilentlyContinue |\n Where-Object { $_.FullName -notlike '*\\_archive\\*' -and ($Extensions -contains $_.Extension.ToLower()) }\n foreach ($f in $files) {\n $checked++\n $base = [System.IO.Path]::GetFileNameWithoutExtension($f.Name)\n $ext = $f.Extension\n $digits = $null\n\n if ($base -match '_(\\d{6})$') {\n $digits = $Matches[1]\n }\n elseif ($base -match '(?<!_)\\b(\\d{6})$') {\n $digits = $Matches[1]\n }\n elseif ($base -match '(\\d{4})$') {\n $digits = ('00' + $Matches[1])\n }\n else {\n continue\n }\n\n try {\n $n = [int]$digits", + "signatures": {}, + "detailedLines": [ + { + "text": "[CmdletBinding()]", + "lineNumber": 1 + }, + { + "text": "param(", + "lineNumber": 2 + }, + { + "text": " [switch]$DebugMode", + "lineNumber": 3 + }, + { + "text": ")", + "lineNumber": 4 + }, + { + "lineNumber": 5 + }, + { + "text": "Set-StrictMode -Version Latest", + "lineNumber": 6 + }, + { + "text": "$ErrorActionPreference = 'Stop'", + "lineNumber": 7 + }, + { + "lineNumber": 8 + }, + { + "text": "if (-not $PSScriptRoot) {", + "lineNumber": 9 + }, + { + "text": " $PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path", + "lineNumber": 10 + }, + { + "text": "}", + "lineNumber": 11 + }, + { + "lineNumber": 12 + }, + { + "text": "$configLoader = Join-Path -Path $PSScriptRoot -ChildPath 'ConfigLoader.ps1'", + "lineNumber": 13 + }, + { + "text": "if (-not (Test-Path -LiteralPath $configLoader)) {", + "lineNumber": 14 + }, + { + "text": " throw \"Missing ConfigLoader.ps1 in $PSScriptRoot\"", + "lineNumber": 15 + }, + { + "text": "}", + "lineNumber": 16 + }, + { + "text": ". $configLoader", + "lineNumber": 17 + }, + { + "lineNumber": 18 + }, + { + "text": "$useIsoDailyFormat = Use-IsoDailyFormat", + "lineNumber": 19 + }, + { + "lineNumber": 20 + }, + { + "text": "function Sync-SequenceFilenames {", + "lineNumber": 21 + }, + { + "text": " param(", + "lineNumber": 22 + }, + { + "text": " [Parameter(Mandatory)] [string]$SequenceFolderPath,", + "lineNumber": 23 + }, + { + "text": " [Parameter(Mandatory)] [string]$SequenceName,", + "lineNumber": 24 + }, + { + "text": " [string]$LogFile,", + "lineNumber": 25 + }, + { + "text": " [string[]]$Extensions = @('.png','.jpg','.jpeg','.exr','.tif','.tiff','.bmp','.tga')", + "lineNumber": 26 + }, + { + "text": " )", + "lineNumber": 27 + }, + { + "text": " $renamed = 0", + "lineNumber": 28 + }, + { + "text": " $collisions = 0", + "lineNumber": 29 + }, + { + "text": " $errors = 0", + "lineNumber": 30 + }, + { + "text": " $checked = 0", + "lineNumber": 31 + }, + { + "text": " $minFrame = [int]::MaxValue", + "lineNumber": 32 + }, + { + "text": " $maxFrame = -1", + "lineNumber": 33 + }, + { + "text": " $frameCount = 0", + "lineNumber": 34 + }, + { + "lineNumber": 35 + }, + { + "text": " if ($LogFile) { \"[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] RENAME CHECK in '$SequenceFolderPath' (seq='$SequenceName')\" | Add-Content -LiteralPath $LogFile }", + "lineNumber": 36 + }, + { + "lineNumber": 37 + }, + { + "text": " $files = Get-ChildItem -LiteralPath $SequenceFolderPath -File -Recurse -ErrorAction SilentlyContinue |", + "lineNumber": 38 + }, + { + "text": " Where-Object { $_.FullName -notlike '*\\_archive\\*' -and ($Extensions -contains $_.Extension.ToLower()) }", + "lineNumber": 39 + }, + { + "text": " foreach ($f in $files) {", + "lineNumber": 40 + }, + { + "text": " $checked++", + "lineNumber": 41 + }, + { + "text": " $base = [System.IO.Path]::GetFileNameWithoutExtension($f.Name)", + "lineNumber": 42 + }, + { + "text": " $ext = $f.Extension", + "lineNumber": 43 + }, + { + "text": " $digits = $null", + "lineNumber": 44 + }, + { + "lineNumber": 45 + }, + { + "text": " if ($base -match '_(\\d{6})$') {", + "lineNumber": 46 + }, + { + "text": " $digits = $Matches[1]", + "lineNumber": 47 + }, + { + "text": " }", + "lineNumber": 48 + }, + { + "text": " elseif ($base -match '(?<!_)\\b(\\d{6})$') {", + "lineNumber": 49 + }, + { + "text": " $digits = $Matches[1]", + "lineNumber": 50 + }, + { + "text": " }", + "lineNumber": 51 + }, + { + "text": " elseif ($base -match '(\\d{4})$') {", + "lineNumber": 52 + }, + { + "text": " $digits = ('00' + $Matches[1])", + "lineNumber": 53 + }, + { + "text": " }", + "lineNumber": 54 + }, + { + "text": " else {", + "lineNumber": 55 + }, + { + "text": " continue", + "lineNumber": 56 + }, + { + "text": " }", + "lineNumber": 57 + }, + { + "lineNumber": 58 + }, + { + "text": " try {", + "lineNumber": 59 + }, + { + "text": " $n = [int]$digits", + "lineNumber": 60 + } + ] + }, + "score": 0.39077043533325195 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\organize_textures.ps1", + "range": { + "startPosition": { + "line": 604 + }, + "endPosition": { + "line": 639 + } + }, + "contents": " } else {\n Write-Host \"Found Blender: $blenderExe\" -ForegroundColor Gray\n \n # Get the remap script path (should be in the same directory as this script)\n $scriptDir = Split-Path -Path $MyInvocation.MyCommand.Path -Parent\n $remapScriptPath = Join-Path -Path $scriptDir -ChildPath \"remap_texture_paths.py\"\n \n if (-not (Test-Path -Path $remapScriptPath)) {\n Write-Warning \"Remap script not found: $remapScriptPath\"\n Write-Warning \"Skipping texture path remapping.\"\n } else {\n $processedCount = 0\n $failedCount = 0\n \n Write-Host \"Processing $($blendFileMappings.Count) blend file(s)...\" -ForegroundColor Gray\n \n foreach ($mapping in $blendFileMappings) {\n $blendFilePath = $mapping.BlendFile\n $blendFileName = Split-Path -Path $blendFilePath -Leaf\n \n Write-Host \" Processing: $blendFileName\" -ForegroundColor Cyan\n \n # Check if blend file exists\n if (-not (Test-Path -Path $blendFilePath)) {\n Write-Warning \" Blend file not found: $blendFilePath\"\n $failedCount++\n continue\n }\n \n # Run Blender with the remapping script (one file at a time)\n # Delete old output file\n Remove-Item -Path \"blender_output.txt\" -ErrorAction SilentlyContinue\n \n try {\n # Run Blender and capture output while displaying it (like compress_blend_files.bat)", + "signatures": {}, + "detailedLines": [ + { + "text": " } else {", + "lineNumber": 605 + }, + { + "text": " Write-Host \"Found Blender: $blenderExe\" -ForegroundColor Gray", + "lineNumber": 606 + }, + { + "text": " ", + "lineNumber": 607 + }, + { + "text": " # Get the remap script path (should be in the same directory as this script)", + "lineNumber": 608 + }, + { + "text": " $scriptDir = Split-Path -Path $MyInvocation.MyCommand.Path -Parent", + "lineNumber": 609 + }, + { + "text": " $remapScriptPath = Join-Path -Path $scriptDir -ChildPath \"remap_texture_paths.py\"", + "lineNumber": 610 + }, + { + "text": " ", + "lineNumber": 611 + }, + { + "text": " if (-not (Test-Path -Path $remapScriptPath)) {", + "lineNumber": 612 + }, + { + "text": " Write-Warning \"Remap script not found: $remapScriptPath\"", + "lineNumber": 613 + }, + { + "text": " Write-Warning \"Skipping texture path remapping.\"", + "lineNumber": 614 + }, + { + "text": " } else {", + "lineNumber": 615 + }, + { + "text": " $processedCount = 0", + "lineNumber": 616 + }, + { + "text": " $failedCount = 0", + "lineNumber": 617 + }, + { + "text": " ", + "lineNumber": 618 + }, + { + "text": " Write-Host \"Processing $($blendFileMappings.Count) blend file(s)...\" -ForegroundColor Gray", + "lineNumber": 619 + }, + { + "text": " ", + "lineNumber": 620 + }, + { + "text": " foreach ($mapping in $blendFileMappings) {", + "lineNumber": 621 + }, + { + "text": " $blendFilePath = $mapping.BlendFile", + "lineNumber": 622 + }, + { + "text": " $blendFileName = Split-Path -Path $blendFilePath -Leaf", + "lineNumber": 623 + }, + { + "text": " ", + "lineNumber": 624 + }, + { + "text": " Write-Host \" Processing: $blendFileName\" -ForegroundColor Cyan", + "lineNumber": 625 + }, + { + "text": " ", + "lineNumber": 626 + }, + { + "text": " # Check if blend file exists", + "lineNumber": 627 + }, + { + "text": " if (-not (Test-Path -Path $blendFilePath)) {", + "lineNumber": 628 + }, + { + "text": " Write-Warning \" Blend file not found: $blendFilePath\"", + "lineNumber": 629 + }, + { + "text": " $failedCount++", + "lineNumber": 630 + }, + { + "text": " continue", + "lineNumber": 631 + }, + { + "text": " }", + "lineNumber": 632 + }, + { + "text": " ", + "lineNumber": 633 + }, + { + "text": " # Run Blender with the remapping script (one file at a time)", + "lineNumber": 634 + }, + { + "text": " # Delete old output file", + "lineNumber": 635 + }, + { + "text": " Remove-Item -Path \"blender_output.txt\" -ErrorAction SilentlyContinue", + "lineNumber": 636 + }, + { + "text": " ", + "lineNumber": 637 + }, + { + "text": " try {", + "lineNumber": 638 + }, + { + "text": " # Run Blender and capture output while displaying it (like compress_blend_files.bat)", + "lineNumber": 639 + } + ] + }, + "score": 0.3801639676094055 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\compress_blend_files.bat", + "range": { + "startPosition": { + "line": 64 + }, + "endPosition": { + "line": 118 + } + }, + "contents": "echo output_file = os.path.join^(\"output\", filename^)\necho # Check if output file already exists\necho if os.path.exists^(output_file^):\necho print^(\"SKIP_EXISTING:\" + blend_file^)\necho continue\necho # Skip if source is already compressed\necho if is_compressed_file^(blend_file^):\necho print^(\"SKIP_ALREADY_COMPRESSED:\" + blend_file^)\necho continue\necho print^(\"PROCESSING:\" + blend_file^)\necho # Load the blend file\necho bpy.ops.wm.open_mainfile^(filepath=blend_file^)\necho # Save with compression to output folder\necho bpy.ops.wm.save_mainfile^(filepath=output_file, compress=True^)\necho print^(\"SUCCESS:\" + blend_file + \":\" + output_file^)\necho except Exception as e:\necho print^(\"CRASH:\" + blend_file + \":\" + str^(e^)^)\necho else:\necho print^(\"SKIP_NOT_BLEND:\" + blend_file^)\necho.\necho print^(\"COMPRESSION_COMPLETE\"^)\necho bpy.ops.wm.quit_blender^(^)\n) > \"!TEMP_SCRIPT!\"\n\nREM Check if script was created successfully\nif exist \"!TEMP_SCRIPT!\" (\n echo Script created successfully: !TEMP_SCRIPT!\n) else (\n echo ERROR: Failed to create script file!\n pause\n exit /b 1\n)\n\nREM Run Blender to process the dragged files\necho Processing dragged .blend files...\necho Using script: !TEMP_SCRIPT!\ndel /f /q \"blender_output.txt\" 2>nul\nblender --background --factory-startup --python \"!TEMP_SCRIPT!\" -- %* 2^>^&1 | powershell -NoProfile -Command \"$input | Tee-Object -FilePath 'blender_output.txt'\"\n\nREM Clean up temporary script\necho Cleaning up temporary script...\ndel \"!TEMP_SCRIPT!\" 2>nul\n\nREM Parse output and generate report\necho.\necho ========================================\necho COMPRESSION REPORT\necho ========================================\necho.\n\nREM Count processed files and get file info\nfor /f \"tokens=1,2,3 delims=:\" %%a in (blender_output.txt) do (\n if \"%%a\"==\"SUCCESS\" (\n set /a processed+=1", + "signatures": {}, + "detailedLines": [ + { + "text": "echo output_file = os.path.join^(\"output\", filename^)", + "lineNumber": 65 + }, + { + "text": "echo # Check if output file already exists", + "lineNumber": 66 + }, + { + "text": "echo if os.path.exists^(output_file^):", + "lineNumber": 67 + }, + { + "text": "echo print^(\"SKIP_EXISTING:\" + blend_file^)", + "lineNumber": 68 + }, + { + "text": "echo continue", + "lineNumber": 69 + }, + { + "text": "echo # Skip if source is already compressed", + "lineNumber": 70 + }, + { + "text": "echo if is_compressed_file^(blend_file^):", + "lineNumber": 71 + }, + { + "text": "echo print^(\"SKIP_ALREADY_COMPRESSED:\" + blend_file^)", + "lineNumber": 72 + }, + { + "text": "echo continue", + "lineNumber": 73 + }, + { + "text": "echo print^(\"PROCESSING:\" + blend_file^)", + "lineNumber": 74 + }, + { + "text": "echo # Load the blend file", + "lineNumber": 75 + }, + { + "text": "echo bpy.ops.wm.open_mainfile^(filepath=blend_file^)", + "lineNumber": 76 + }, + { + "text": "echo # Save with compression to output folder", + "lineNumber": 77 + }, + { + "text": "echo bpy.ops.wm.save_mainfile^(filepath=output_file, compress=True^)", + "lineNumber": 78 + }, + { + "text": "echo print^(\"SUCCESS:\" + blend_file + \":\" + output_file^)", + "lineNumber": 79 + }, + { + "text": "echo except Exception as e:", + "lineNumber": 80 + }, + { + "text": "echo print^(\"CRASH:\" + blend_file + \":\" + str^(e^)^)", + "lineNumber": 81 + }, + { + "text": "echo else:", + "lineNumber": 82 + }, + { + "text": "echo print^(\"SKIP_NOT_BLEND:\" + blend_file^)", + "lineNumber": 83 + }, + { + "text": "echo.", + "lineNumber": 84 + }, + { + "text": "echo print^(\"COMPRESSION_COMPLETE\"^)", + "lineNumber": 85 + }, + { + "text": "echo bpy.ops.wm.quit_blender^(^)", + "lineNumber": 86 + }, + { + "text": ") > \"!TEMP_SCRIPT!\"", + "lineNumber": 87 + }, + { + "lineNumber": 88 + }, + { + "text": "REM Check if script was created successfully", + "lineNumber": 89 + }, + { + "text": "if exist \"!TEMP_SCRIPT!\" (", + "lineNumber": 90 + }, + { + "text": " echo Script created successfully: !TEMP_SCRIPT!", + "lineNumber": 91 + }, + { + "text": ") else (", + "lineNumber": 92 + }, + { + "text": " echo ERROR: Failed to create script file!", + "lineNumber": 93 + }, + { + "text": " pause", + "lineNumber": 94 + }, + { + "text": " exit /b 1", + "lineNumber": 95 + }, + { + "text": ")", + "lineNumber": 96 + }, + { + "lineNumber": 97 + }, + { + "text": "REM Run Blender to process the dragged files", + "lineNumber": 98 + }, + { + "text": "echo Processing dragged .blend files...", + "lineNumber": 99 + }, + { + "text": "echo Using script: !TEMP_SCRIPT!", + "lineNumber": 100 + }, + { + "text": "del /f /q \"blender_output.txt\" 2>nul", + "lineNumber": 101 + }, + { + "text": "blender --background --factory-startup --python \"!TEMP_SCRIPT!\" -- %* 2^>^&1 | powershell -NoProfile -Command \"$input | Tee-Object -FilePath 'blender_output.txt'\"", + "lineNumber": 102 + }, + { + "lineNumber": 103 + }, + { + "text": "REM Clean up temporary script", + "lineNumber": 104 + }, + { + "text": "echo Cleaning up temporary script...", + "lineNumber": 105 + }, + { + "text": "del \"!TEMP_SCRIPT!\" 2>nul", + "lineNumber": 106 + }, + { + "lineNumber": 107 + }, + { + "text": "REM Parse output and generate report", + "lineNumber": 108 + }, + { + "text": "echo.", + "lineNumber": 109 + }, + { + "text": "echo ========================================", + "lineNumber": 110 + }, + { + "text": "echo COMPRESSION REPORT", + "lineNumber": 111 + }, + { + "text": "echo ========================================", + "lineNumber": 112 + }, + { + "text": "echo.", + "lineNumber": 113 + }, + { + "lineNumber": 114 + }, + { + "text": "REM Count processed files and get file info", + "lineNumber": 115 + }, + { + "text": "for /f \"tokens=1,2,3 delims=:\" %%a in (blender_output.txt) do (", + "lineNumber": 116 + }, + { + "text": " if \"%%a\"==\"SUCCESS\" (", + "lineNumber": 117 + }, + { + "text": " set /a processed+=1", + "lineNumber": 118 + } + ] + }, + "score": 0.3668818473815918 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\organize_textures.ps1", + "range": { + "startPosition": {}, + "endPosition": { + "line": 50 + } + }, + "contents": "# Script to organize texture files by checksum with two-level duplicate detection\n# Pass 1: Intra-blendfile duplicates → [blendfile]\\common\n# Pass 2: Inter-blendfile duplicates → \\textures\\common\n# Usage: .\\organize_textures.ps1\n\n# Prompt user for texture folder path\n$textureFolderPath = Read-Host \"Enter texture folder path\"\n\n# Validate the input path\nif ([string]::IsNullOrWhiteSpace($textureFolderPath)) {\n Write-Host \"Error: No path provided.\" -ForegroundColor Red\n exit\n}\n\nif (-not (Test-Path -Path $textureFolderPath -PathType Container)) {\n Write-Host \"Error: Path does not exist or is not a directory: $textureFolderPath\" -ForegroundColor Red\n exit\n}\n\n# Resolve the full path\n$textureFolderPath = (Resolve-Path $textureFolderPath).ProviderPath\nWrite-Host \"Processing texture folder: $textureFolderPath\" -ForegroundColor Cyan\n\n# Function to calculate checksums for files\nfunction Get-FilesWithChecksums {\n param(\n [array]$Files\n )\n \n $throttleLimit = [Math]::Max(1, [Environment]::ProcessorCount)\n $parallelScriptBlock = {\n try {\n $hash = Get-FileHash -Path $_.FullName -Algorithm SHA256\n [PSCustomObject]@{\n File = $_\n Hash = $hash.Hash\n }\n } catch {\n Write-Warning \"Failed to calculate checksum for: $($_.FullName) - $($_.Exception.Message)\"\n $null\n }\n }\n \n return $Files | ForEach-Object -Parallel $parallelScriptBlock -ThrottleLimit $throttleLimit | Where-Object { $null -ne $_ }\n}\n\n# Function to move files to common folder\nfunction Move-FilesToCommon {\n param(\n [array]$Files,", + "signatures": {}, + "detailedLines": [ + { + "text": "# Script to organize texture files by checksum with two-level duplicate detection", + "lineNumber": 1 + }, + { + "text": "# Pass 1: Intra-blendfile duplicates → [blendfile]\\common", + "lineNumber": 2 + }, + { + "text": "# Pass 2: Inter-blendfile duplicates → \\textures\\common", + "lineNumber": 3 + }, + { + "text": "# Usage: .\\organize_textures.ps1", + "lineNumber": 4 + }, + { + "lineNumber": 5 + }, + { + "text": "# Prompt user for texture folder path", + "lineNumber": 6 + }, + { + "text": "$textureFolderPath = Read-Host \"Enter texture folder path\"", + "lineNumber": 7 + }, + { + "lineNumber": 8 + }, + { + "text": "# Validate the input path", + "lineNumber": 9 + }, + { + "text": "if ([string]::IsNullOrWhiteSpace($textureFolderPath)) {", + "lineNumber": 10 + }, + { + "text": " Write-Host \"Error: No path provided.\" -ForegroundColor Red", + "lineNumber": 11 + }, + { + "text": " exit", + "lineNumber": 12 + }, + { + "text": "}", + "lineNumber": 13 + }, + { + "lineNumber": 14 + }, + { + "text": "if (-not (Test-Path -Path $textureFolderPath -PathType Container)) {", + "lineNumber": 15 + }, + { + "text": " Write-Host \"Error: Path does not exist or is not a directory: $textureFolderPath\" -ForegroundColor Red", + "lineNumber": 16 + }, + { + "text": " exit", + "lineNumber": 17 + }, + { + "text": "}", + "lineNumber": 18 + }, + { + "lineNumber": 19 + }, + { + "text": "# Resolve the full path", + "lineNumber": 20 + }, + { + "text": "$textureFolderPath = (Resolve-Path $textureFolderPath).ProviderPath", + "lineNumber": 21 + }, + { + "text": "Write-Host \"Processing texture folder: $textureFolderPath\" -ForegroundColor Cyan", + "lineNumber": 22 + }, + { + "lineNumber": 23 + }, + { + "text": "# Function to calculate checksums for files", + "lineNumber": 24 + }, + { + "text": "function Get-FilesWithChecksums {", + "lineNumber": 25 + }, + { + "text": " param(", + "lineNumber": 26 + }, + { + "text": " [array]$Files", + "lineNumber": 27 + }, + { + "text": " )", + "lineNumber": 28 + }, + { + "text": " ", + "lineNumber": 29 + }, + { + "text": " $throttleLimit = [Math]::Max(1, [Environment]::ProcessorCount)", + "lineNumber": 30 + }, + { + "text": " $parallelScriptBlock = {", + "lineNumber": 31 + }, + { + "text": " try {", + "lineNumber": 32 + }, + { + "text": " $hash = Get-FileHash -Path $_.FullName -Algorithm SHA256", + "lineNumber": 33 + }, + { + "text": " [PSCustomObject]@{", + "lineNumber": 34 + }, + { + "text": " File = $_", + "lineNumber": 35 + }, + { + "text": " Hash = $hash.Hash", + "lineNumber": 36 + }, + { + "text": " }", + "lineNumber": 37 + }, + { + "text": " } catch {", + "lineNumber": 38 + }, + { + "text": " Write-Warning \"Failed to calculate checksum for: $($_.FullName) - $($_.Exception.Message)\"", + "lineNumber": 39 + }, + { + "text": " $null", + "lineNumber": 40 + }, + { + "text": " }", + "lineNumber": 41 + }, + { + "text": " }", + "lineNumber": 42 + }, + { + "text": " ", + "lineNumber": 43 + }, + { + "text": " return $Files | ForEach-Object -Parallel $parallelScriptBlock -ThrottleLimit $throttleLimit | Where-Object { $null -ne $_ }", + "lineNumber": 44 + }, + { + "text": "}", + "lineNumber": 45 + }, + { + "lineNumber": 46 + }, + { + "text": "# Function to move files to common folder", + "lineNumber": 47 + }, + { + "text": "function Move-FilesToCommon {", + "lineNumber": 48 + }, + { + "text": " param(", + "lineNumber": 49 + }, + { + "text": " [array]$Files,", + "lineNumber": 50 + } + ] + }, + "score": 0.3616774082183838 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\UpdateSequences.ps1", + "range": { + "startPosition": { + "line": 183 + }, + "endPosition": { + "line": 223, + "column": 8 + } + }, + "contents": "function Add-SequenceFolder {\n param(\n [Parameter(Mandatory)] [System.IO.DirectoryInfo]$Directory,\n [Parameter(Mandatory)] [hashtable]$Map\n )\n if ($Directory.Name -like '_*') { return }\n $fullPath = $Directory.FullName\n if ($Map.ContainsKey($fullPath)) { return }\n \n # Check if directory contains sequence files directly (not just subdirectories)\n $extensions = @('.png','.jpg','.jpeg','.exr','.tif','.tiff','.bmp','.tga')\n $hasSequenceFiles = Get-ChildItem -LiteralPath $fullPath -File -ErrorAction SilentlyContinue |\n Where-Object { $extensions -contains $_.Extension.ToLower() } |\n Select-Object -First 1\n \n # If it only has subdirectories and no sequence files, skip it\n $hasSubdirs = Get-ChildItem -LiteralPath $fullPath -Directory -ErrorAction SilentlyContinue |\n Select-Object -First 1\n if ($null -eq $hasSequenceFiles -and $null -ne $hasSubdirs) {\n return\n }\n \n $Map[$fullPath] = Resolve-SequenceName -Directory $Directory\n}\n\ntry {\n $root = (Get-Location).ProviderPath\n $logFile = $null\n\n if ($DebugMode) {\n $logFile = Join-Path $root (\"UpdateSequences_{0}.log\" -f (Get-Date -Format 'yyyyMMdd_HHmmss'))\n \"[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] === UpdateSequences started in '$root' ===\" | Out-File -LiteralPath $logFile -Encoding UTF8\n }\n\n $sequenceMap = @{}\n\n $primaryPattern = if ($useIsoDailyFormat) { '????-??-??' } else { 'daily_*' }\n $secondaryPattern = if ($useIsoDailyFormat) { 'daily_*' } else { '????-??-??' }\n\n $primaryDirs = Get-ChildItem -LiteralPath $root -Directory -Filter $primaryPattern -ErrorAction SilentlyContinue |\n ", + "signatures": {}, + "detailedLines": [ + { + "text": "function Add-SequenceFolder {", + "lineNumber": 184 + }, + { + "text": " param(", + "lineNumber": 185 + }, + { + "text": " [Parameter(Mandatory)] [System.IO.DirectoryInfo]$Directory,", + "lineNumber": 186 + }, + { + "text": " [Parameter(Mandatory)] [hashtable]$Map", + "lineNumber": 187 + }, + { + "text": " )", + "lineNumber": 188 + }, + { + "text": " if ($Directory.Name -like '_*') { return }", + "lineNumber": 189 + }, + { + "text": " $fullPath = $Directory.FullName", + "lineNumber": 190 + }, + { + "text": " if ($Map.ContainsKey($fullPath)) { return }", + "lineNumber": 191 + }, + { + "text": " ", + "lineNumber": 192 + }, + { + "text": " # Check if directory contains sequence files directly (not just subdirectories)", + "lineNumber": 193 + }, + { + "text": " $extensions = @('.png','.jpg','.jpeg','.exr','.tif','.tiff','.bmp','.tga')", + "lineNumber": 194 + }, + { + "text": " $hasSequenceFiles = Get-ChildItem -LiteralPath $fullPath -File -ErrorAction SilentlyContinue |", + "lineNumber": 195 + }, + { + "text": " Where-Object { $extensions -contains $_.Extension.ToLower() } |", + "lineNumber": 196 + }, + { + "text": " Select-Object -First 1", + "lineNumber": 197 + }, + { + "text": " ", + "lineNumber": 198 + }, + { + "text": " # If it only has subdirectories and no sequence files, skip it", + "lineNumber": 199 + }, + { + "text": " $hasSubdirs = Get-ChildItem -LiteralPath $fullPath -Directory -ErrorAction SilentlyContinue |", + "lineNumber": 200 + }, + { + "text": " Select-Object -First 1", + "lineNumber": 201 + }, + { + "text": " if ($null -eq $hasSequenceFiles -and $null -ne $hasSubdirs) {", + "lineNumber": 202 + }, + { + "text": " return", + "lineNumber": 203 + }, + { + "text": " }", + "lineNumber": 204 + }, + { + "text": " ", + "lineNumber": 205 + }, + { + "text": " $Map[$fullPath] = Resolve-SequenceName -Directory $Directory", + "lineNumber": 206 + }, + { + "text": "}", + "lineNumber": 207 + }, + { + "lineNumber": 208 + }, + { + "text": "try {", + "lineNumber": 209 + }, + { + "text": " $root = (Get-Location).ProviderPath", + "lineNumber": 210 + }, + { + "text": " $logFile = $null", + "lineNumber": 211 + }, + { + "lineNumber": 212 + }, + { + "text": " if ($DebugMode) {", + "lineNumber": 213 + }, + { + "text": " $logFile = Join-Path $root (\"UpdateSequences_{0}.log\" -f (Get-Date -Format 'yyyyMMdd_HHmmss'))", + "lineNumber": 214 + }, + { + "text": " \"[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] === UpdateSequences started in '$root' ===\" | Out-File -LiteralPath $logFile -Encoding UTF8", + "lineNumber": 215 + }, + { + "text": " }", + "lineNumber": 216 + }, + { + "lineNumber": 217 + }, + { + "text": " $sequenceMap = @{}", + "lineNumber": 218 + }, + { + "lineNumber": 219 + }, + { + "text": " $primaryPattern = if ($useIsoDailyFormat) { '????-??-??' } else { 'daily_*' }", + "lineNumber": 220 + }, + { + "text": " $secondaryPattern = if ($useIsoDailyFormat) { 'daily_*' } else { '????-??-??' }", + "lineNumber": 221 + }, + { + "lineNumber": 222 + }, + { + "text": " $primaryDirs = Get-ChildItem -LiteralPath $root -Directory -Filter $primaryPattern -ErrorAction SilentlyContinue |", + "lineNumber": 223 + }, + { + "text": " ", + "lineNumber": 224 + } + ] + }, + "score": 0.3424009084701538 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\remap_texture_paths.py", + "range": { + "startPosition": { + "line": 73 + }, + "endPosition": { + "line": 229 + } + }, + "contents": "def remap_texture_paths(blend_file_path, move_log_path):\n\n for image in bpy.data.images:\n if not image.filepath:\n continue\n \n # Convert to absolute path for comparison\n abs_path = bpy.path.abspath(image.filepath)\n if not abs_path:\n continue\n \n abs_norm = normalize_path(abs_path)\n was_relative = not os.path.isabs(image.filepath)\n \n # Check if this path needs remapping\n new_path = None\n \n # First check moved files\n if abs_norm in original_to_new:\n new_path = original_to_new[abs_norm]\n \n # Then check deleted files (replaced by)\n elif abs_norm in original_to_replacement:\n new_path = original_to_replacement[abs_norm]\n \n if new_path:\n # Convert to relative path if original was relative\n if was_relative:\n try:\n rel_path = bpy.path.relpath(new_path, blend_file_dir)\n image.filepath = rel_path\n except:\n # Fallback to absolute if relative conversion fails\n image.filepath = new_path\n else:\n image.filepath = new_path\n \n print(f\" Remapped: {os.path.basename(abs_path)} -> {os.path.basename(new_path)}\")\n remapped_count += 1\n else:\n # Check if file exists - if not, it might be a broken reference\n if not os.path.exists(abs_path):\n not_found_count += 1\n \n # Also check material node trees for image texture nodes\n # Note: Most image texture nodes reference the image datablock (which we already remapped above),\n # but we check node.filepath for completeness in case any nodes have direct file paths\n print(\"\\nRemapping material node texture paths...\")\n node_remapped_count = 0\n for material in bpy.data.materials:\n if", + "signatures": { + "ranges": [ + { + "startPosition": { + "line": 74, + "column": 1 + }, + "endPosition": { + "line": 75, + "column": 5 + } + } + ] + }, + "detailedLines": [ + { + "text": "def remap_texture_paths(blend_file_path, move_log_path):", + "lineNumber": 74, + "isSignature": true + }, + { + "lineNumber": 97 + }, + { + "text": " for image in bpy.data.images:", + "lineNumber": 98 + }, + { + "text": " if not image.filepath:", + "lineNumber": 99 + }, + { + "text": " continue", + "lineNumber": 100 + }, + { + "text": " ", + "lineNumber": 101 + }, + { + "text": " # Convert to absolute path for comparison", + "lineNumber": 102 + }, + { + "text": " abs_path = bpy.path.abspath(image.filepath)", + "lineNumber": 103 + }, + { + "text": " if not abs_path:", + "lineNumber": 104 + }, + { + "text": " continue", + "lineNumber": 105 + }, + { + "text": " ", + "lineNumber": 106 + }, + { + "text": " abs_norm = normalize_path(abs_path)", + "lineNumber": 107 + }, + { + "text": " was_relative = not os.path.isabs(image.filepath)", + "lineNumber": 108 + }, + { + "text": " ", + "lineNumber": 109 + }, + { + "text": " # Check if this path needs remapping", + "lineNumber": 110 + }, + { + "text": " new_path = None", + "lineNumber": 111 + }, + { + "text": " ", + "lineNumber": 112 + }, + { + "text": " # First check moved files", + "lineNumber": 113 + }, + { + "text": " if abs_norm in original_to_new:", + "lineNumber": 114 + }, + { + "text": " new_path = original_to_new[abs_norm]", + "lineNumber": 115 + }, + { + "text": " ", + "lineNumber": 116 + }, + { + "text": " # Then check deleted files (replaced by)", + "lineNumber": 117 + }, + { + "text": " elif abs_norm in original_to_replacement:", + "lineNumber": 118 + }, + { + "text": " new_path = original_to_replacement[abs_norm]", + "lineNumber": 119 + }, + { + "text": " ", + "lineNumber": 120 + }, + { + "text": " if new_path:", + "lineNumber": 121 + }, + { + "text": " # Convert to relative path if original was relative", + "lineNumber": 122 + }, + { + "text": " if was_relative:", + "lineNumber": 123 + }, + { + "text": " try:", + "lineNumber": 124 + }, + { + "text": " rel_path = bpy.path.relpath(new_path, blend_file_dir)", + "lineNumber": 125 + }, + { + "text": " image.filepath = rel_path", + "lineNumber": 126 + }, + { + "text": " except:", + "lineNumber": 127 + }, + { + "text": " # Fallback to absolute if relative conversion fails", + "lineNumber": 128 + }, + { + "text": " image.filepath = new_path", + "lineNumber": 129 + }, + { + "text": " else:", + "lineNumber": 130 + }, + { + "text": " image.filepath = new_path", + "lineNumber": 131 + }, + { + "text": " ", + "lineNumber": 132 + }, + { + "text": " print(f\" Remapped: {os.path.basename(abs_path)} -> {os.path.basename(new_path)}\")", + "lineNumber": 133 + }, + { + "text": " remapped_count += 1", + "lineNumber": 134 + }, + { + "text": " else:", + "lineNumber": 135 + }, + { + "text": " # Check if file exists - if not, it might be a broken reference", + "lineNumber": 136 + }, + { + "text": " if not os.path.exists(abs_path):", + "lineNumber": 137 + }, + { + "text": " not_found_count += 1", + "lineNumber": 138 + }, + { + "text": " ", + "lineNumber": 139 + }, + { + "text": " # Also check material node trees for image texture nodes", + "lineNumber": 140 + }, + { + "text": " # Note: Most image texture nodes reference the image datablock (which we already remapped above),", + "lineNumber": 141 + }, + { + "text": " # but we check node.filepath for completeness in case any nodes have direct file paths", + "lineNumber": 142 + }, + { + "text": " print(\"\\nRemapping material node texture paths...\")", + "lineNumber": 143 + }, + { + "text": " node_remapped_count = 0", + "lineNumber": 144 + }, + { + "text": " for material in bpy.data.materials:", + "lineNumber": 145 + }, + { + "text": " if", + "lineNumber": 146 + } + ] + }, + "score": 0.3386910557746887 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\remap_texture_paths.py", + "range": { + "startPosition": { + "line": 73 + }, + "endPosition": { + "line": 229 + } + }, + "contents": "def remap_texture_paths(blend_file_path, move_log_path):\n\n abs_to_rel_count = 0\n for image in bpy.data.images:\n # Skip images from linked files (library datablocks)\n if image.library:\n continue\n \n if not image.filepath:\n continue\n \n # Check if path is absolute\n if os.path.isabs(image.filepath):\n try:\n # Convert to relative path\n rel_path = bpy.path.relpath(image.filepath, blend_file_dir)\n if rel_path != image.filepath:\n image.filepath = rel_path\n print(f\" Converted to relative: {os.path.basename(image.filepath)}\")\n abs_to_rel_count += 1\n except Exception as e:\n # If conversion fails, skip it (might be a network path or other issue)\n pass\n \n if abs_to_rel_count > 0:\n remapped_count += abs_to_rel_count\n \n print(f\"\\n=== REMAPPING SUMMARY ===\")\n print(f\"Paths remapped: {remapped_count}\")\n print(f\"Broken references (not found): {not_found_count}\")\n \n # Make all paths relative after remapping (this handles other datablock types)\n try:\n print(f\"\\nMaking paths relative...\")\n bpy.ops.file.make_paths_relative()\n print(f\" Converted absolute paths to relative paths\")\n except Exception as e:\n print(f\" Warning: Failed to make paths relative: {e}\")\n \n # Save the blend file\n try:\n print(f\"\\nSaving blend file...\")", + "signatures": { + "ranges": [ + { + "startPosition": { + "line": 74, + "column": 1 + }, + "endPosition": { + "line": 75, + "column": 5 + } + } + ] + }, + "detailedLines": [ + { + "text": "def remap_texture_paths(blend_file_path, move_log_path):", + "lineNumber": 74, + "isSignature": true + }, + { + "lineNumber": 171 + }, + { + "text": " abs_to_rel_count = 0", + "lineNumber": 172 + }, + { + "text": " for image in bpy.data.images:", + "lineNumber": 173 + }, + { + "text": " # Skip images from linked files (library datablocks)", + "lineNumber": 174 + }, + { + "text": " if image.library:", + "lineNumber": 175 + }, + { + "text": " continue", + "lineNumber": 176 + }, + { + "text": " ", + "lineNumber": 177 + }, + { + "text": " if not image.filepath:", + "lineNumber": 178 + }, + { + "text": " continue", + "lineNumber": 179 + }, + { + "text": " ", + "lineNumber": 180 + }, + { + "text": " # Check if path is absolute", + "lineNumber": 181 + }, + { + "text": " if os.path.isabs(image.filepath):", + "lineNumber": 182 + }, + { + "text": " try:", + "lineNumber": 183 + }, + { + "text": " # Convert to relative path", + "lineNumber": 184 + }, + { + "text": " rel_path = bpy.path.relpath(image.filepath, blend_file_dir)", + "lineNumber": 185 + }, + { + "text": " if rel_path != image.filepath:", + "lineNumber": 186 + }, + { + "text": " image.filepath = rel_path", + "lineNumber": 187 + }, + { + "text": " print(f\" Converted to relative: {os.path.basename(image.filepath)}\")", + "lineNumber": 188 + }, + { + "text": " abs_to_rel_count += 1", + "lineNumber": 189 + }, + { + "text": " except Exception as e:", + "lineNumber": 190 + }, + { + "text": " # If conversion fails, skip it (might be a network path or other issue)", + "lineNumber": 191 + }, + { + "text": " pass", + "lineNumber": 192 + }, + { + "text": " ", + "lineNumber": 193 + }, + { + "text": " if abs_to_rel_count > 0:", + "lineNumber": 194 + }, + { + "text": " remapped_count += abs_to_rel_count", + "lineNumber": 195 + }, + { + "text": " ", + "lineNumber": 196 + }, + { + "text": " print(f\"\\n=== REMAPPING SUMMARY ===\")", + "lineNumber": 197 + }, + { + "text": " print(f\"Paths remapped: {remapped_count}\")", + "lineNumber": 198 + }, + { + "text": " print(f\"Broken references (not found): {not_found_count}\")", + "lineNumber": 199 + }, + { + "text": " ", + "lineNumber": 200 + }, + { + "text": " # Make all paths relative after remapping (this handles other datablock types)", + "lineNumber": 201 + }, + { + "text": " try:", + "lineNumber": 202 + }, + { + "text": " print(f\"\\nMaking paths relative...\")", + "lineNumber": 203 + }, + { + "text": " bpy.ops.file.make_paths_relative()", + "lineNumber": 204 + }, + { + "text": " print(f\" Converted absolute paths to relative paths\")", + "lineNumber": 205 + }, + { + "text": " except Exception as e:", + "lineNumber": 206 + }, + { + "text": " print(f\" Warning: Failed to make paths relative: {e}\")", + "lineNumber": 207 + }, + { + "text": " ", + "lineNumber": 208 + }, + { + "text": " # Save the blend file", + "lineNumber": 209 + }, + { + "text": " try:", + "lineNumber": 210 + }, + { + "text": " print(f\"\\nSaving blend file...\")", + "lineNumber": 211 + } + ] + }, + "score": 0.33739519119262695 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\UpdateProjectBatches.ps1", + "range": { + "startPosition": { + "line": 55 + }, + "endPosition": { + "line": 115 + } + }, + "contents": ")\n\n# Config files to deploy to projectroot\\.config\\\n$configAssets = @(\n @{ Name = 'config.json'; Source = Join-Path -Path $structDir -ChildPath 'config.json' },\n @{ Name = 'GetStructDir.ps1'; Source = Join-Path -Path $structDir -ChildPath 'GetStructDir.ps1' }\n)\n\nforeach ($spec in $specs) {\n if (-not (Test-Path -LiteralPath $spec.Source -PathType Leaf)) {\n Write-Error \"Source file not found: $($spec.Source)\"\n exit 1\n }\n}\n\nforeach ($asset in $configAssets) {\n if (-not (Test-Path -LiteralPath $asset.Source -PathType Leaf)) {\n Write-Error \"Config asset not found: $($asset.Source)\"\n exit 1\n }\n}\n\n# Ensure .config directory exists in project root\n$projectConfigDir = Join-Path -Path $resolvedProject -ChildPath '.config'\nif (-not (Test-Path -LiteralPath $projectConfigDir -PathType Container)) {\n New-Item -Path $projectConfigDir -ItemType Directory -Force | Out-Null\n Write-Host \"Created .config directory: $projectConfigDir\" -ForegroundColor Cyan\n}\n\n$touchedDirs = @{}\n$summary = @()\n\nforeach ($spec in $specs) {\n Write-Host \"`n=== Updating $($spec.Name) ===\" -ForegroundColor Magenta\n\n $targets = Get-ChildItem -LiteralPath $resolvedProject -Recurse -Filter $spec.Name -File -ErrorAction SilentlyContinue\n $targets = $targets | Where-Object { $_.FullName -ne $spec.Source }\n\n if (-not $targets) {\n Write-Host \"No targets found.\" -ForegroundColor Yellow\n $summary += [pscustomobject]@{\n Name = $spec.Name\n Updated = 0\n Failed = 0\n Skipped = 0\n Total = 0\n }\n continue\n }\n\n $updated = 0\n $failed = 0\n\n foreach ($target in $targets) {\n try {\n Copy-Item -Path $spec.Source -Destination $target.FullName -Force\n Write-Host \"[OK] $($target.FullName)\" -ForegroundColor Green\n $updated++\n\n $targetDir = $target.Directory.FullName", + "signatures": {}, + "detailedLines": [ + { + "text": ")", + "lineNumber": 56 + }, + { + "lineNumber": 57 + }, + { + "text": "# Config files to deploy to projectroot\\.config\\", + "lineNumber": 58 + }, + { + "text": "$configAssets = @(", + "lineNumber": 59 + }, + { + "text": " @{ Name = 'config.json'; Source = Join-Path -Path $structDir -ChildPath 'config.json' },", + "lineNumber": 60 + }, + { + "text": " @{ Name = 'GetStructDir.ps1'; Source = Join-Path -Path $structDir -ChildPath 'GetStructDir.ps1' }", + "lineNumber": 61 + }, + { + "text": ")", + "lineNumber": 62 + }, + { + "lineNumber": 63 + }, + { + "text": "foreach ($spec in $specs) {", + "lineNumber": 64 + }, + { + "text": " if (-not (Test-Path -LiteralPath $spec.Source -PathType Leaf)) {", + "lineNumber": 65 + }, + { + "text": " Write-Error \"Source file not found: $($spec.Source)\"", + "lineNumber": 66 + }, + { + "text": " exit 1", + "lineNumber": 67 + }, + { + "text": " }", + "lineNumber": 68 + }, + { + "text": "}", + "lineNumber": 69 + }, + { + "lineNumber": 70 + }, + { + "text": "foreach ($asset in $configAssets) {", + "lineNumber": 71 + }, + { + "text": " if (-not (Test-Path -LiteralPath $asset.Source -PathType Leaf)) {", + "lineNumber": 72 + }, + { + "text": " Write-Error \"Config asset not found: $($asset.Source)\"", + "lineNumber": 73 + }, + { + "text": " exit 1", + "lineNumber": 74 + }, + { + "text": " }", + "lineNumber": 75 + }, + { + "text": "}", + "lineNumber": 76 + }, + { + "lineNumber": 77 + }, + { + "text": "# Ensure .config directory exists in project root", + "lineNumber": 78 + }, + { + "text": "$projectConfigDir = Join-Path -Path $resolvedProject -ChildPath '.config'", + "lineNumber": 79 + }, + { + "text": "if (-not (Test-Path -LiteralPath $projectConfigDir -PathType Container)) {", + "lineNumber": 80 + }, + { + "text": " New-Item -Path $projectConfigDir -ItemType Directory -Force | Out-Null", + "lineNumber": 81 + }, + { + "text": " Write-Host \"Created .config directory: $projectConfigDir\" -ForegroundColor Cyan", + "lineNumber": 82 + }, + { + "text": "}", + "lineNumber": 83 + }, + { + "lineNumber": 84 + }, + { + "text": "$touchedDirs = @{}", + "lineNumber": 85 + }, + { + "text": "$summary = @()", + "lineNumber": 86 + }, + { + "lineNumber": 87 + }, + { + "text": "foreach ($spec in $specs) {", + "lineNumber": 88 + }, + { + "text": " Write-Host \"`n=== Updating $($spec.Name) ===\" -ForegroundColor Magenta", + "lineNumber": 89 + }, + { + "lineNumber": 90 + }, + { + "text": " $targets = Get-ChildItem -LiteralPath $resolvedProject -Recurse -Filter $spec.Name -File -ErrorAction SilentlyContinue", + "lineNumber": 91 + }, + { + "text": " $targets = $targets | Where-Object { $_.FullName -ne $spec.Source }", + "lineNumber": 92 + }, + { + "lineNumber": 93 + }, + { + "text": " if (-not $targets) {", + "lineNumber": 94 + }, + { + "text": " Write-Host \"No targets found.\" -ForegroundColor Yellow", + "lineNumber": 95 + }, + { + "text": " $summary += [pscustomobject]@{", + "lineNumber": 96 + }, + { + "text": " Name = $spec.Name", + "lineNumber": 97 + }, + { + "text": " Updated = 0", + "lineNumber": 98 + }, + { + "text": " Failed = 0", + "lineNumber": 99 + }, + { + "text": " Skipped = 0", + "lineNumber": 100 + }, + { + "text": " Total = 0", + "lineNumber": 101 + }, + { + "text": " }", + "lineNumber": 102 + }, + { + "text": " continue", + "lineNumber": 103 + }, + { + "text": " }", + "lineNumber": 104 + }, + { + "lineNumber": 105 + }, + { + "text": " $updated = 0", + "lineNumber": 106 + }, + { + "text": " $failed = 0", + "lineNumber": 107 + }, + { + "lineNumber": 108 + }, + { + "text": " foreach ($target in $targets) {", + "lineNumber": 109 + }, + { + "text": " try {", + "lineNumber": 110 + }, + { + "text": " Copy-Item -Path $spec.Source -Destination $target.FullName -Force", + "lineNumber": 111 + }, + { + "text": " Write-Host \"[OK] $($target.FullName)\" -ForegroundColor Green", + "lineNumber": 112 + }, + { + "text": " $updated++", + "lineNumber": 113 + }, + { + "lineNumber": 114 + }, + { + "text": " $targetDir = $target.Directory.FullName", + "lineNumber": 115 + } + ] + }, + "score": 0.3361758887767792 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\organize_textures.ps1", + "range": { + "startPosition": { + "line": 355 + }, + "endPosition": { + "line": 390 + } + }, + "contents": "$allFlatColorsFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object { \n ($_.FullName -like \"*\\FlatColors\\*\" -or $_.Name -like \"*FlatColors*\") -and \n $_.FullName -notlike \"$([regex]::Escape($rootCommonFlatColorsPath))\\*\" \n}\n\n# Get all remaining files (excluding all \\common folders, but we'll handle FlatColors separately)\nWrite-Host \"Collecting remaining files...\" -ForegroundColor Yellow\n$remainingFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object { $_.FullName -notlike \"*\\common\\*\" }\n\nif ($null -eq $remainingFiles -or $remainingFiles.Count -eq 0) {\n Write-Host \"No remaining files found to process.\" -ForegroundColor Yellow\n} else {\n Write-Host \"Found $($remainingFiles.Count) remaining files to process.\" -ForegroundColor Green\n \n # Calculate checksums\n Write-Host \"Calculating checksums using parallel processing (this may take a while)...\" -ForegroundColor Yellow\n $filesWithChecksums = Get-FilesWithChecksums -Files $remainingFiles\n \n Write-Host \"Checksum calculation complete.\" -ForegroundColor Green\n \n # Separate FlatColors files from other files before processing\n Write-Host \"Identifying FlatColors files...\" -ForegroundColor Yellow\n $flatColorsFiles = $allFlatColorsFiles | Where-Object { (Test-Path -Path $_.FullName) }\n $nonFlatColorsFiles = $remainingFiles | Where-Object { $_.Name -notlike \"*FlatColors*\" }\n \n Write-Host \"Found $($flatColorsFiles.Count) FlatColors file(s) (including from \\common\\FlatColors folders), $($nonFlatColorsFiles.Count) other file(s)\" -ForegroundColor Gray\n \n # Group non-FlatColors files by checksum\n Write-Host \"Grouping files by checksum...\" -ForegroundColor Yellow\n $nonFlatColorsWithChecksums = $filesWithChecksums | Where-Object { $_.File.Name -notlike \"*FlatColors*\" }\n $groupedByChecksum = $nonFlatColorsWithChecksums | Group-Object -Property Hash\n \n Write-Host \"Found $($groupedByChecksum.Count) unique checksums.\" -ForegroundColor Green\n \n # Create \\textures\\common directory", + "signatures": {}, + "detailedLines": [ + { + "text": "$allFlatColorsFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object { ", + "lineNumber": 356 + }, + { + "text": " ($_.FullName -like \"*\\FlatColors\\*\" -or $_.Name -like \"*FlatColors*\") -and ", + "lineNumber": 357 + }, + { + "text": " $_.FullName -notlike \"$([regex]::Escape($rootCommonFlatColorsPath))\\*\" ", + "lineNumber": 358 + }, + { + "text": "}", + "lineNumber": 359 + }, + { + "lineNumber": 360 + }, + { + "text": "# Get all remaining files (excluding all \\common folders, but we'll handle FlatColors separately)", + "lineNumber": 361 + }, + { + "text": "Write-Host \"Collecting remaining files...\" -ForegroundColor Yellow", + "lineNumber": 362 + }, + { + "text": "$remainingFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object { $_.FullName -notlike \"*\\common\\*\" }", + "lineNumber": 363 + }, + { + "lineNumber": 364 + }, + { + "text": "if ($null -eq $remainingFiles -or $remainingFiles.Count -eq 0) {", + "lineNumber": 365 + }, + { + "text": " Write-Host \"No remaining files found to process.\" -ForegroundColor Yellow", + "lineNumber": 366 + }, + { + "text": "} else {", + "lineNumber": 367 + }, + { + "text": " Write-Host \"Found $($remainingFiles.Count) remaining files to process.\" -ForegroundColor Green", + "lineNumber": 368 + }, + { + "text": " ", + "lineNumber": 369 + }, + { + "text": " # Calculate checksums", + "lineNumber": 370 + }, + { + "text": " Write-Host \"Calculating checksums using parallel processing (this may take a while)...\" -ForegroundColor Yellow", + "lineNumber": 371 + }, + { + "text": " $filesWithChecksums = Get-FilesWithChecksums -Files $remainingFiles", + "lineNumber": 372 + }, + { + "text": " ", + "lineNumber": 373 + }, + { + "text": " Write-Host \"Checksum calculation complete.\" -ForegroundColor Green", + "lineNumber": 374 + }, + { + "text": " ", + "lineNumber": 375 + }, + { + "text": " # Separate FlatColors files from other files before processing", + "lineNumber": 376 + }, + { + "text": " Write-Host \"Identifying FlatColors files...\" -ForegroundColor Yellow", + "lineNumber": 377 + }, + { + "text": " $flatColorsFiles = $allFlatColorsFiles | Where-Object { (Test-Path -Path $_.FullName) }", + "lineNumber": 378 + }, + { + "text": " $nonFlatColorsFiles = $remainingFiles | Where-Object { $_.Name -notlike \"*FlatColors*\" }", + "lineNumber": 379 + }, + { + "text": " ", + "lineNumber": 380 + }, + { + "text": " Write-Host \"Found $($flatColorsFiles.Count) FlatColors file(s) (including from \\common\\FlatColors folders), $($nonFlatColorsFiles.Count) other file(s)\" -ForegroundColor Gray", + "lineNumber": 381 + }, + { + "text": " ", + "lineNumber": 382 + }, + { + "text": " # Group non-FlatColors files by checksum", + "lineNumber": 383 + }, + { + "text": " Write-Host \"Grouping files by checksum...\" -ForegroundColor Yellow", + "lineNumber": 384 + }, + { + "text": " $nonFlatColorsWithChecksums = $filesWithChecksums | Where-Object { $_.File.Name -notlike \"*FlatColors*\" }", + "lineNumber": 385 + }, + { + "text": " $groupedByChecksum = $nonFlatColorsWithChecksums | Group-Object -Property Hash", + "lineNumber": 386 + }, + { + "text": " ", + "lineNumber": 387 + }, + { + "text": " Write-Host \"Found $($groupedByChecksum.Count) unique checksums.\" -ForegroundColor Green", + "lineNumber": 388 + }, + { + "text": " ", + "lineNumber": 389 + }, + { + "text": " # Create \\textures\\common directory", + "lineNumber": 390 + } + ] + }, + "score": 0.33034563064575195 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\organize_textures.ps1", + "range": { + "startPosition": { + "line": 279 + }, + "endPosition": { + "line": 325 + } + }, + "contents": "} else {\n Write-Host \"Found $($blendfileFolders.Count) blendfile folder(s) to process.\" -ForegroundColor Green\n \n $totalPass1Moved = 0\n $totalPass1Duplicates = 0\n $pass1MoveLog = [System.Collections.ArrayList]::new()\n \n foreach ($blendfileFolder in $blendfileFolders) {\n Write-Host \"\"\n Write-Host \"Processing blendfile: $($blendfileFolder.Name)\" -ForegroundColor Yellow\n \n # Get all files in this blendfile folder, excluding \\common folders\n $blendfileFiles = Get-ChildItem -Path $blendfileFolder.FullName -Recurse -File | Where-Object { $_.FullName -notlike \"*\\common\\*\" }\n \n if ($null -eq $blendfileFiles -or $blendfileFiles.Count -eq 0) {\n Write-Host \" No files found in this blendfile folder.\" -ForegroundColor Gray\n continue\n }\n \n Write-Host \" Found $($blendfileFiles.Count) files.\" -ForegroundColor Gray\n \n # Calculate checksums\n Write-Host \" Calculating checksums...\" -ForegroundColor Gray\n $filesWithChecksums = Get-FilesWithChecksums -Files $blendfileFiles\n \n # Group by checksum\n $groupedByChecksum = $filesWithChecksums | Group-Object -Property Hash\n \n Write-Host \" Found $($groupedByChecksum.Count) unique checksums.\" -ForegroundColor Gray\n \n # Create [blendfile]\\common directory\n $blendfileCommonPath = Join-Path -Path $blendfileFolder.FullName -ChildPath \"common\"\n \n if (-not (Test-Path -Path $blendfileCommonPath -PathType Container)) {\n New-Item -ItemType Directory -Path $blendfileCommonPath | Out-Null\n }\n \n # Track filenames already in [blendfile]\\common\n $filesInBlendfileCommon = @{}\n \n # Process each checksum group\n $blendfileMoved = 0\n $blendfileDuplicates = 0\n \n foreach ($group in $groupedByChecksum) {\n $result = Process-DuplicateGroup -Files $group.Group -CommonPath $blendfileCommonPath -FilesInCommon $filesInBlendfileCommon -MoveLog $pass1MoveLog", + "signatures": {}, + "detailedLines": [ + { + "text": "} else {", + "lineNumber": 280 + }, + { + "text": " Write-Host \"Found $($blendfileFolders.Count) blendfile folder(s) to process.\" -ForegroundColor Green", + "lineNumber": 281 + }, + { + "text": " ", + "lineNumber": 282 + }, + { + "text": " $totalPass1Moved = 0", + "lineNumber": 283 + }, + { + "text": " $totalPass1Duplicates = 0", + "lineNumber": 284 + }, + { + "text": " $pass1MoveLog = [System.Collections.ArrayList]::new()", + "lineNumber": 285 + }, + { + "text": " ", + "lineNumber": 286 + }, + { + "text": " foreach ($blendfileFolder in $blendfileFolders) {", + "lineNumber": 287 + }, + { + "text": " Write-Host \"\"", + "lineNumber": 288 + }, + { + "text": " Write-Host \"Processing blendfile: $($blendfileFolder.Name)\" -ForegroundColor Yellow", + "lineNumber": 289 + }, + { + "text": " ", + "lineNumber": 290 + }, + { + "text": " # Get all files in this blendfile folder, excluding \\common folders", + "lineNumber": 291 + }, + { + "text": " $blendfileFiles = Get-ChildItem -Path $blendfileFolder.FullName -Recurse -File | Where-Object { $_.FullName -notlike \"*\\common\\*\" }", + "lineNumber": 292 + }, + { + "text": " ", + "lineNumber": 293 + }, + { + "text": " if ($null -eq $blendfileFiles -or $blendfileFiles.Count -eq 0) {", + "lineNumber": 294 + }, + { + "text": " Write-Host \" No files found in this blendfile folder.\" -ForegroundColor Gray", + "lineNumber": 295 + }, + { + "text": " continue", + "lineNumber": 296 + }, + { + "text": " }", + "lineNumber": 297 + }, + { + "text": " ", + "lineNumber": 298 + }, + { + "text": " Write-Host \" Found $($blendfileFiles.Count) files.\" -ForegroundColor Gray", + "lineNumber": 299 + }, + { + "text": " ", + "lineNumber": 300 + }, + { + "text": " # Calculate checksums", + "lineNumber": 301 + }, + { + "text": " Write-Host \" Calculating checksums...\" -ForegroundColor Gray", + "lineNumber": 302 + }, + { + "text": " $filesWithChecksums = Get-FilesWithChecksums -Files $blendfileFiles", + "lineNumber": 303 + }, + { + "text": " ", + "lineNumber": 304 + }, + { + "text": " # Group by checksum", + "lineNumber": 305 + }, + { + "text": " $groupedByChecksum = $filesWithChecksums | Group-Object -Property Hash", + "lineNumber": 306 + }, + { + "text": " ", + "lineNumber": 307 + }, + { + "text": " Write-Host \" Found $($groupedByChecksum.Count) unique checksums.\" -ForegroundColor Gray", + "lineNumber": 308 + }, + { + "text": " ", + "lineNumber": 309 + }, + { + "text": " # Create [blendfile]\\common directory", + "lineNumber": 310 + }, + { + "text": " $blendfileCommonPath = Join-Path -Path $blendfileFolder.FullName -ChildPath \"common\"", + "lineNumber": 311 + }, + { + "text": " ", + "lineNumber": 312 + }, + { + "text": " if (-not (Test-Path -Path $blendfileCommonPath -PathType Container)) {", + "lineNumber": 313 + }, + { + "text": " New-Item -ItemType Directory -Path $blendfileCommonPath | Out-Null", + "lineNumber": 314 + }, + { + "text": " }", + "lineNumber": 315 + }, + { + "text": " ", + "lineNumber": 316 + }, + { + "text": " # Track filenames already in [blendfile]\\common", + "lineNumber": 317 + }, + { + "text": " $filesInBlendfileCommon = @{}", + "lineNumber": 318 + }, + { + "text": " ", + "lineNumber": 319 + }, + { + "text": " # Process each checksum group", + "lineNumber": 320 + }, + { + "text": " $blendfileMoved = 0", + "lineNumber": 321 + }, + { + "text": " $blendfileDuplicates = 0", + "lineNumber": 322 + }, + { + "text": " ", + "lineNumber": 323 + }, + { + "text": " foreach ($group in $groupedByChecksum) {", + "lineNumber": 324 + }, + { + "text": " $result = Process-DuplicateGroup -Files $group.Group -CommonPath $blendfileCommonPath -FilesInCommon $filesInBlendfileCommon -MoveLog $pass1MoveLog", + "lineNumber": 325 + } + ] + }, + "score": 0.32454758882522583 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\remove_action_fake_users.bat", + "range": { + "startPosition": { + "line": 64 + }, + "endPosition": { + "line": 107 + } + }, + "contents": "echo ^\t\t\t# Save to output folder\necho ^\t\t\tbpy.ops.wm.save_mainfile^(filepath=output_file, compress=True^)\necho ^\t\t\tprint^(\"SUCCESS:\" + blend_file + \":\" + output_file^)\necho ^\t\texcept Exception as e:\necho ^\t\t\tprint^(\"CRASH:\" + blend_file + \":\" + str^(e^)^)\necho ^\telse:\necho ^\t\tprint^(\"SKIP_NOT_BLEND:\" + blend_file^)\necho.\necho print^(\"FAKE_USER_REMOVAL_COMPLETE\"^)\necho bpy.ops.wm.quit_blender^(^)\n) > \"!TEMP_SCRIPT!\"\n\nREM Check if script was created successfully\nif exist \"!TEMP_SCRIPT!\" (\n\techo Script created successfully: !TEMP_SCRIPT!\n) else (\n\techo ERROR: Failed to create script file!\n\tpause\n\texit /b 1\n)\n\nREM Run Blender to process the dragged files\necho Processing dragged .blend files...\necho Using script: !TEMP_SCRIPT!\ndel /f /q \"blender_output.txt\" 2>nul\nblender --background --factory-startup --python \"!TEMP_SCRIPT!\" -- %* 2^>^&1 | powershell -NoProfile -Command \"$input | Tee-Object -FilePath 'blender_output.txt'\"\n\nREM Clean up temporary script\necho Cleaning up temporary script...\ndel \"!TEMP_SCRIPT!\" 2>nul\n\nREM Parse output and generate report\necho.\necho ========================================\necho ACTION FAKE USER REMOVAL REPORT\necho ========================================\necho.\n\nREM Track updated counts per file during parse\nfor /f \"tokens=1,2,3 delims=:\" %%a in (blender_output.txt) do (\n\tif \"%%a\"==\"SUCCESS\" (\n\t\tset /a processed+=1\n\t\techo [!processed!] SUCCESS: %%b", + "signatures": {}, + "detailedLines": [ + { + "text": "echo ^\t\t\t# Save to output folder", + "lineNumber": 65 + }, + { + "text": "echo ^\t\t\tbpy.ops.wm.save_mainfile^(filepath=output_file, compress=True^)", + "lineNumber": 66 + }, + { + "text": "echo ^\t\t\tprint^(\"SUCCESS:\" + blend_file + \":\" + output_file^)", + "lineNumber": 67 + }, + { + "text": "echo ^\t\texcept Exception as e:", + "lineNumber": 68 + }, + { + "text": "echo ^\t\t\tprint^(\"CRASH:\" + blend_file + \":\" + str^(e^)^)", + "lineNumber": 69 + }, + { + "text": "echo ^\telse:", + "lineNumber": 70 + }, + { + "text": "echo ^\t\tprint^(\"SKIP_NOT_BLEND:\" + blend_file^)", + "lineNumber": 71 + }, + { + "text": "echo.", + "lineNumber": 72 + }, + { + "text": "echo print^(\"FAKE_USER_REMOVAL_COMPLETE\"^)", + "lineNumber": 73 + }, + { + "text": "echo bpy.ops.wm.quit_blender^(^)", + "lineNumber": 74 + }, + { + "text": ") > \"!TEMP_SCRIPT!\"", + "lineNumber": 75 + }, + { + "lineNumber": 76 + }, + { + "text": "REM Check if script was created successfully", + "lineNumber": 77 + }, + { + "text": "if exist \"!TEMP_SCRIPT!\" (", + "lineNumber": 78 + }, + { + "text": "\techo Script created successfully: !TEMP_SCRIPT!", + "lineNumber": 79 + }, + { + "text": ") else (", + "lineNumber": 80 + }, + { + "text": "\techo ERROR: Failed to create script file!", + "lineNumber": 81 + }, + { + "text": "\tpause", + "lineNumber": 82 + }, + { + "text": "\texit /b 1", + "lineNumber": 83 + }, + { + "text": ")", + "lineNumber": 84 + }, + { + "lineNumber": 85 + }, + { + "text": "REM Run Blender to process the dragged files", + "lineNumber": 86 + }, + { + "text": "echo Processing dragged .blend files...", + "lineNumber": 87 + }, + { + "text": "echo Using script: !TEMP_SCRIPT!", + "lineNumber": 88 + }, + { + "text": "del /f /q \"blender_output.txt\" 2>nul", + "lineNumber": 89 + }, + { + "text": "blender --background --factory-startup --python \"!TEMP_SCRIPT!\" -- %* 2^>^&1 | powershell -NoProfile -Command \"$input | Tee-Object -FilePath 'blender_output.txt'\"", + "lineNumber": 90 + }, + { + "lineNumber": 91 + }, + { + "text": "REM Clean up temporary script", + "lineNumber": 92 + }, + { + "text": "echo Cleaning up temporary script...", + "lineNumber": 93 + }, + { + "text": "del \"!TEMP_SCRIPT!\" 2>nul", + "lineNumber": 94 + }, + { + "lineNumber": 95 + }, + { + "text": "REM Parse output and generate report", + "lineNumber": 96 + }, + { + "text": "echo.", + "lineNumber": 97 + }, + { + "text": "echo ========================================", + "lineNumber": 98 + }, + { + "text": "echo ACTION FAKE USER REMOVAL REPORT", + "lineNumber": 99 + }, + { + "text": "echo ========================================", + "lineNumber": 100 + }, + { + "text": "echo.", + "lineNumber": 101 + }, + { + "lineNumber": 102 + }, + { + "text": "REM Track updated counts per file during parse", + "lineNumber": 103 + }, + { + "text": "for /f \"tokens=1,2,3 delims=:\" %%a in (blender_output.txt) do (", + "lineNumber": 104 + }, + { + "text": "\tif \"%%a\"==\"SUCCESS\" (", + "lineNumber": 105 + }, + { + "text": "\t\tset /a processed+=1", + "lineNumber": 106 + }, + { + "text": "\t\techo [!processed!] SUCCESS: %%b", + "lineNumber": 107 + } + ] + }, + "score": 0.3208807110786438 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\ConfigLoader.ps1", + "range": { + "startPosition": { + "line": 307 + }, + "endPosition": { + "line": 354 + } + }, + "contents": " foreach ($spec in $specs) {\n Write-Host \"`n=== Updating $($spec.Name) ===\" -ForegroundColor Magenta\n\n $targets = Get-ChildItem -LiteralPath $resolvedProject -Recurse -Filter $spec.Name -File -Force -ErrorAction SilentlyContinue\n $targets = $targets | Where-Object { $_.FullName -ne $spec.Source }\n\n if (-not $targets) {\n Write-Host \"No targets found.\" -ForegroundColor Yellow\n $summary += [pscustomobject]@{\n Name = $spec.Name\n Updated = 0\n Failed = 0\n Skipped = 0\n Total = 0\n }\n continue\n }\n\n $updated = 0\n $failed = 0\n\n foreach ($target in $targets) {\n try {\n Copy-Item -Path $spec.Source -Destination $target.FullName -Force\n # Set hidden attribute for .gitattributes and .gitignore files\n if ($spec.Name -eq '.gitattributes' -or $spec.Name -eq '.gitignore') {\n $file = Get-Item -LiteralPath $target.FullName -Force\n $file.Attributes = $file.Attributes -bor [System.IO.FileAttributes]::Hidden\n }\n Write-Host \"[OK] $($target.FullName)\" -ForegroundColor Green\n $updated++\n\n $targetDir = $target.Directory.FullName\n if (-not $touchedDirs.ContainsKey($targetDir)) {\n $touchedDirs[$targetDir] = $true\n }\n }\n catch {\n Write-Host \"[FAIL] $($target.FullName)\" -ForegroundColor Red\n Write-Host \" $($_.Exception.Message)\" -ForegroundColor DarkRed\n $failed++\n }\n }\n\n $summary += [pscustomobject]@{\n Name = $spec.Name\n Updated = $updated", + "signatures": {}, + "detailedLines": [ + { + "text": " foreach ($spec in $specs) {", + "lineNumber": 308 + }, + { + "text": " Write-Host \"`n=== Updating $($spec.Name) ===\" -ForegroundColor Magenta", + "lineNumber": 309 + }, + { + "lineNumber": 310 + }, + { + "text": " $targets = Get-ChildItem -LiteralPath $resolvedProject -Recurse -Filter $spec.Name -File -Force -ErrorAction SilentlyContinue", + "lineNumber": 311 + }, + { + "text": " $targets = $targets | Where-Object { $_.FullName -ne $spec.Source }", + "lineNumber": 312 + }, + { + "lineNumber": 313 + }, + { + "text": " if (-not $targets) {", + "lineNumber": 314 + }, + { + "text": " Write-Host \"No targets found.\" -ForegroundColor Yellow", + "lineNumber": 315 + }, + { + "text": " $summary += [pscustomobject]@{", + "lineNumber": 316 + }, + { + "text": " Name = $spec.Name", + "lineNumber": 317 + }, + { + "text": " Updated = 0", + "lineNumber": 318 + }, + { + "text": " Failed = 0", + "lineNumber": 319 + }, + { + "text": " Skipped = 0", + "lineNumber": 320 + }, + { + "text": " Total = 0", + "lineNumber": 321 + }, + { + "text": " }", + "lineNumber": 322 + }, + { + "text": " continue", + "lineNumber": 323 + }, + { + "text": " }", + "lineNumber": 324 + }, + { + "lineNumber": 325 + }, + { + "text": " $updated = 0", + "lineNumber": 326 + }, + { + "text": " $failed = 0", + "lineNumber": 327 + }, + { + "lineNumber": 328 + }, + { + "text": " foreach ($target in $targets) {", + "lineNumber": 329 + }, + { + "text": " try {", + "lineNumber": 330 + }, + { + "text": " Copy-Item -Path $spec.Source -Destination $target.FullName -Force", + "lineNumber": 331 + }, + { + "text": " # Set hidden attribute for .gitattributes and .gitignore files", + "lineNumber": 332 + }, + { + "text": " if ($spec.Name -eq '.gitattributes' -or $spec.Name -eq '.gitignore') {", + "lineNumber": 333 + }, + { + "text": " $file = Get-Item -LiteralPath $target.FullName -Force", + "lineNumber": 334 + }, + { + "text": " $file.Attributes = $file.Attributes -bor [System.IO.FileAttributes]::Hidden", + "lineNumber": 335 + }, + { + "text": " }", + "lineNumber": 336 + }, + { + "text": " Write-Host \"[OK] $($target.FullName)\" -ForegroundColor Green", + "lineNumber": 337 + }, + { + "text": " $updated++", + "lineNumber": 338 + }, + { + "lineNumber": 339 + }, + { + "text": " $targetDir = $target.Directory.FullName", + "lineNumber": 340 + }, + { + "text": " if (-not $touchedDirs.ContainsKey($targetDir)) {", + "lineNumber": 341 + }, + { + "text": " $touchedDirs[$targetDir] = $true", + "lineNumber": 342 + }, + { + "text": " }", + "lineNumber": 343 + }, + { + "text": " }", + "lineNumber": 344 + }, + { + "text": " catch {", + "lineNumber": 345 + }, + { + "text": " Write-Host \"[FAIL] $($target.FullName)\" -ForegroundColor Red", + "lineNumber": 346 + }, + { + "text": " Write-Host \" $($_.Exception.Message)\" -ForegroundColor DarkRed", + "lineNumber": 347 + }, + { + "text": " $failed++", + "lineNumber": 348 + }, + { + "text": " }", + "lineNumber": 349 + }, + { + "text": " }", + "lineNumber": 350 + }, + { + "lineNumber": 351 + }, + { + "text": " $summary += [pscustomobject]@{", + "lineNumber": 352 + }, + { + "text": " Name = $spec.Name", + "lineNumber": 353 + }, + { + "text": " Updated = $updated", + "lineNumber": 354 + } + ] + }, + "score": 0.3176653981208801 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\remap_texture_paths.py", + "range": { + "startPosition": { + "line": 73 + }, + "endPosition": { + "line": 229 + } + }, + "contents": "def remap_texture_paths(blend_file_path, move_log_path):\n\n for material in bpy.data.materials:\n if not material.use_nodes or not material.node_tree:\n continue\n \n for node in material.node_tree.nodes:\n if node.type == 'TEX_IMAGE' and hasattr(node, 'filepath') and node.filepath:\n abs_path = bpy.path.abspath(node.filepath)\n if abs_path:\n abs_norm = normalize_path(abs_path)\n \n new_path = None\n if abs_norm in original_to_new:\n new_path = original_to_new[abs_norm]\n elif abs_norm in original_to_replacement:\n new_path = original_to_replacement[abs_norm]\n \n if new_path:\n node.filepath = new_path\n print(f\" Remapped node texture: {os.path.basename(abs_path)} -> {os.path.basename(new_path)}\")\n node_remapped_count += 1\n \n if node_remapped_count > 0:\n remapped_count += node_remapped_count\n \n # Convert any remaining absolute paths in image datablocks to relative\n # (ignoring images from linked files)\n print(\"\\nConverting absolute image paths to relative...\")\n abs_to_rel_count = 0\n for image in bpy.data.images:\n # Skip images from linked files (library datablocks)", + "signatures": { + "ranges": [ + { + "startPosition": { + "line": 74, + "column": 1 + }, + "endPosition": { + "line": 75, + "column": 5 + } + } + ] + }, + "detailedLines": [ + { + "text": "def remap_texture_paths(blend_file_path, move_log_path):", + "lineNumber": 74, + "isSignature": true + }, + { + "lineNumber": 144 + }, + { + "text": " for material in bpy.data.materials:", + "lineNumber": 145 + }, + { + "text": " if not material.use_nodes or not material.node_tree:", + "lineNumber": 146 + }, + { + "text": " continue", + "lineNumber": 147 + }, + { + "text": " ", + "lineNumber": 148 + }, + { + "text": " for node in material.node_tree.nodes:", + "lineNumber": 149 + }, + { + "text": " if node.type == 'TEX_IMAGE' and hasattr(node, 'filepath') and node.filepath:", + "lineNumber": 150 + }, + { + "text": " abs_path = bpy.path.abspath(node.filepath)", + "lineNumber": 151 + }, + { + "text": " if abs_path:", + "lineNumber": 152 + }, + { + "text": " abs_norm = normalize_path(abs_path)", + "lineNumber": 153 + }, + { + "text": " ", + "lineNumber": 154 + }, + { + "text": " new_path = None", + "lineNumber": 155 + }, + { + "text": " if abs_norm in original_to_new:", + "lineNumber": 156 + }, + { + "text": " new_path = original_to_new[abs_norm]", + "lineNumber": 157 + }, + { + "text": " elif abs_norm in original_to_replacement:", + "lineNumber": 158 + }, + { + "text": " new_path = original_to_replacement[abs_norm]", + "lineNumber": 159 + }, + { + "text": " ", + "lineNumber": 160 + }, + { + "text": " if new_path:", + "lineNumber": 161 + }, + { + "text": " node.filepath = new_path", + "lineNumber": 162 + }, + { + "text": " print(f\" Remapped node texture: {os.path.basename(abs_path)} -> {os.path.basename(new_path)}\")", + "lineNumber": 163 + }, + { + "text": " node_remapped_count += 1", + "lineNumber": 164 + }, + { + "text": " ", + "lineNumber": 165 + }, + { + "text": " if node_remapped_count > 0:", + "lineNumber": 166 + }, + { + "text": " remapped_count += node_remapped_count", + "lineNumber": 167 + }, + { + "text": " ", + "lineNumber": 168 + }, + { + "text": " # Convert any remaining absolute paths in image datablocks to relative", + "lineNumber": 169 + }, + { + "text": " # (ignoring images from linked files)", + "lineNumber": 170 + }, + { + "text": " print(\"\\nConverting absolute image paths to relative...\")", + "lineNumber": 171 + }, + { + "text": " abs_to_rel_count = 0", + "lineNumber": 172 + }, + { + "text": " for image in bpy.data.images:", + "lineNumber": 173 + }, + { + "text": " # Skip images from linked files (library datablocks)", + "lineNumber": 174 + } + ] + }, + "score": 0.3171687126159668 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\organize_textures.ps1", + "range": { + "startPosition": { + "line": 93 + }, + "endPosition": { + "line": 131 + } + }, + "contents": "function Get-FileNameWithoutPrefix {\n param(\n [string]$FileName,\n [string[]]$ValidPrefixes\n )\n \n # Validate input\n if ([string]::IsNullOrWhiteSpace($FileName)) {\n return $FileName\n }\n \n # If no valid prefixes provided, return original filename\n if ($null -eq $ValidPrefixes -or $ValidPrefixes.Count -eq 0) {\n return $FileName\n }\n \n # Use Split instead of regex for robustness (avoids $matches variable issues in loops)\n # Split by the first underscore only (limit to 2 parts)\n $parts = $FileName.Split('_', 2)\n \n if ($parts.Length -eq 2) {\n $prefix = $parts[0]\n $suffix = $parts[1]\n \n # Only strip if the prefix is in the valid prefixes list\n if ($ValidPrefixes -contains $prefix -and -not [string]::IsNullOrWhiteSpace($suffix)) {\n return $suffix\n }\n }\n \n # No valid prefix found or suffix is empty, return original filename\n return $FileName\n}\n\n# Function to process duplicate group\nfunction Process-DuplicateGroup {\n param(\n [array]$Files,", + "signatures": {}, + "detailedLines": [ + { + "text": "function Get-FileNameWithoutPrefix {", + "lineNumber": 94 + }, + { + "text": " param(", + "lineNumber": 95 + }, + { + "text": " [string]$FileName,", + "lineNumber": 96 + }, + { + "text": " [string[]]$ValidPrefixes", + "lineNumber": 97 + }, + { + "text": " )", + "lineNumber": 98 + }, + { + "text": " ", + "lineNumber": 99 + }, + { + "text": " # Validate input", + "lineNumber": 100 + }, + { + "text": " if ([string]::IsNullOrWhiteSpace($FileName)) {", + "lineNumber": 101 + }, + { + "text": " return $FileName", + "lineNumber": 102 + }, + { + "text": " }", + "lineNumber": 103 + }, + { + "text": " ", + "lineNumber": 104 + }, + { + "text": " # If no valid prefixes provided, return original filename", + "lineNumber": 105 + }, + { + "text": " if ($null -eq $ValidPrefixes -or $ValidPrefixes.Count -eq 0) {", + "lineNumber": 106 + }, + { + "text": " return $FileName", + "lineNumber": 107 + }, + { + "text": " }", + "lineNumber": 108 + }, + { + "text": " ", + "lineNumber": 109 + }, + { + "text": " # Use Split instead of regex for robustness (avoids $matches variable issues in loops)", + "lineNumber": 110 + }, + { + "text": " # Split by the first underscore only (limit to 2 parts)", + "lineNumber": 111 + }, + { + "text": " $parts = $FileName.Split('_', 2)", + "lineNumber": 112 + }, + { + "text": " ", + "lineNumber": 113 + }, + { + "text": " if ($parts.Length -eq 2) {", + "lineNumber": 114 + }, + { + "text": " $prefix = $parts[0]", + "lineNumber": 115 + }, + { + "text": " $suffix = $parts[1]", + "lineNumber": 116 + }, + { + "text": " ", + "lineNumber": 117 + }, + { + "text": " # Only strip if the prefix is in the valid prefixes list", + "lineNumber": 118 + }, + { + "text": " if ($ValidPrefixes -contains $prefix -and -not [string]::IsNullOrWhiteSpace($suffix)) {", + "lineNumber": 119 + }, + { + "text": " return $suffix", + "lineNumber": 120 + }, + { + "text": " }", + "lineNumber": 121 + }, + { + "text": " }", + "lineNumber": 122 + }, + { + "text": " ", + "lineNumber": 123 + }, + { + "text": " # No valid prefix found or suffix is empty, return original filename", + "lineNumber": 124 + }, + { + "text": " return $FileName", + "lineNumber": 125 + }, + { + "text": "}", + "lineNumber": 126 + }, + { + "lineNumber": 127 + }, + { + "text": "# Function to process duplicate group", + "lineNumber": 128 + }, + { + "text": "function Process-DuplicateGroup {", + "lineNumber": 129 + }, + { + "text": " param(", + "lineNumber": 130 + }, + { + "text": " [array]$Files,", + "lineNumber": 131 + } + ] + }, + "score": 0.31633880734443665 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\organize_textures.ps1", + "range": { + "startPosition": { + "line": 543 + }, + "endPosition": { + "line": 585 + } + }, + "contents": " \n if ($null -ne $blendFiles -and $blendFiles.Count -gt 0) {\n foreach ($blendFile in $blendFiles) {\n $blendFileName = $blendFile.BaseName\n \n # Check if any blendfile folder name appears in the blend file name\n foreach ($folderName in $blendfileFolderNames) {\n # Match folder name when surrounded by underscores, dots, hyphens, or at start/end\n # This avoids partial matches (e.g., \"Beth\" in \"Bethany\") while allowing \"Beth\" in \"AM_Beth_v3.2\"\n $escapedFolderName = [regex]::Escape($folderName)\n if ($blendFileName -match \"(^|[._-])$escapedFolderName([._-]|$)\") {\n $blendFileMappings += [PSCustomObject]@{\n BlendFile = [System.IO.Path]::GetFullPath($blendFile.FullName)\n BlendfileFolder = $folderName\n }\n Write-Host \"Found matching blend file: $($blendFile.Name) -> $folderName\" -ForegroundColor Gray\n break # Only match once per blend file\n }\n }\n }\n }\n}\n\n# Create move log object\n$moveLogData = [PSCustomObject]@{\n TextureFolderPath = $textureFolderPath\n Timestamp = (Get-Date -Format \"yyyy-MM-ddTHH:mm:ssZ\")\n TotalMoves = ($allMoves | Where-Object { $_.Type -eq \"moved\" }).Count\n TotalDeletes = ($allMoves | Where-Object { $_.Type -eq \"deleted\" }).Count\n Moves = $allMoves\n BlendFileMappings = $blendFileMappings\n}\n\n# Save to JSON file\n$moveLogPath = Join-Path -Path $blendFileParentDir -ChildPath \"texture_moves.json\"\ntry {\n $moveLogData | ConvertTo-Json -Depth 10 | Set-Content -Path $moveLogPath -Encoding UTF8\n Write-Host \"Move log saved to: $moveLogPath\" -ForegroundColor Green\n Write-Host \" Total moves: $($moveLogData.TotalMoves), Total deletes: $($moveLogData.TotalDeletes)\" -ForegroundColor Gray\n Write-Host \" Blend files found: $($blendFileMappings.Count)\" -ForegroundColor Gray\n} catch {\n Write-Warning \"Failed to save move log: $($_.Exception.Message)\"", + "signatures": {}, + "detailedLines": [ + { + "text": " ", + "lineNumber": 544 + }, + { + "text": " if ($null -ne $blendFiles -and $blendFiles.Count -gt 0) {", + "lineNumber": 545 + }, + { + "text": " foreach ($blendFile in $blendFiles) {", + "lineNumber": 546 + }, + { + "text": " $blendFileName = $blendFile.BaseName", + "lineNumber": 547 + }, + { + "text": " ", + "lineNumber": 548 + }, + { + "text": " # Check if any blendfile folder name appears in the blend file name", + "lineNumber": 549 + }, + { + "text": " foreach ($folderName in $blendfileFolderNames) {", + "lineNumber": 550 + }, + { + "text": " # Match folder name when surrounded by underscores, dots, hyphens, or at start/end", + "lineNumber": 551 + }, + { + "text": " # This avoids partial matches (e.g., \"Beth\" in \"Bethany\") while allowing \"Beth\" in \"AM_Beth_v3.2\"", + "lineNumber": 552 + }, + { + "text": " $escapedFolderName = [regex]::Escape($folderName)", + "lineNumber": 553 + }, + { + "text": " if ($blendFileName -match \"(^|[._-])$escapedFolderName([._-]|$)\") {", + "lineNumber": 554 + }, + { + "text": " $blendFileMappings += [PSCustomObject]@{", + "lineNumber": 555 + }, + { + "text": " BlendFile = [System.IO.Path]::GetFullPath($blendFile.FullName)", + "lineNumber": 556 + }, + { + "text": " BlendfileFolder = $folderName", + "lineNumber": 557 + }, + { + "text": " }", + "lineNumber": 558 + }, + { + "text": " Write-Host \"Found matching blend file: $($blendFile.Name) -> $folderName\" -ForegroundColor Gray", + "lineNumber": 559 + }, + { + "text": " break # Only match once per blend file", + "lineNumber": 560 + }, + { + "text": " }", + "lineNumber": 561 + }, + { + "text": " }", + "lineNumber": 562 + }, + { + "text": " }", + "lineNumber": 563 + }, + { + "text": " }", + "lineNumber": 564 + }, + { + "text": "}", + "lineNumber": 565 + }, + { + "lineNumber": 566 + }, + { + "text": "# Create move log object", + "lineNumber": 567 + }, + { + "text": "$moveLogData = [PSCustomObject]@{", + "lineNumber": 568 + }, + { + "text": " TextureFolderPath = $textureFolderPath", + "lineNumber": 569 + }, + { + "text": " Timestamp = (Get-Date -Format \"yyyy-MM-ddTHH:mm:ssZ\")", + "lineNumber": 570 + }, + { + "text": " TotalMoves = ($allMoves | Where-Object { $_.Type -eq \"moved\" }).Count", + "lineNumber": 571 + }, + { + "text": " TotalDeletes = ($allMoves | Where-Object { $_.Type -eq \"deleted\" }).Count", + "lineNumber": 572 + }, + { + "text": " Moves = $allMoves", + "lineNumber": 573 + }, + { + "text": " BlendFileMappings = $blendFileMappings", + "lineNumber": 574 + }, + { + "text": "}", + "lineNumber": 575 + }, + { + "lineNumber": 576 + }, + { + "text": "# Save to JSON file", + "lineNumber": 577 + }, + { + "text": "$moveLogPath = Join-Path -Path $blendFileParentDir -ChildPath \"texture_moves.json\"", + "lineNumber": 578 + }, + { + "text": "try {", + "lineNumber": 579 + }, + { + "text": " $moveLogData | ConvertTo-Json -Depth 10 | Set-Content -Path $moveLogPath -Encoding UTF8", + "lineNumber": 580 + }, + { + "text": " Write-Host \"Move log saved to: $moveLogPath\" -ForegroundColor Green", + "lineNumber": 581 + }, + { + "text": " Write-Host \" Total moves: $($moveLogData.TotalMoves), Total deletes: $($moveLogData.TotalDeletes)\" -ForegroundColor Gray", + "lineNumber": 582 + }, + { + "text": " Write-Host \" Blend files found: $($blendFileMappings.Count)\" -ForegroundColor Gray", + "lineNumber": 583 + }, + { + "text": "} catch {", + "lineNumber": 584 + }, + { + "text": " Write-Warning \"Failed to save move log: $($_.Exception.Message)\"", + "lineNumber": 585 + } + ] + }, + "score": 0.3160834312438965 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\remap_texture_paths.py", + "range": { + "startPosition": { + "line": 71, + "column": 25 + }, + "endPosition": { + "line": 229 + } + }, + "contents": "def remap_texture_paths(blend_file_path, move_log_path):\n \"\"\"Remap all texture paths in the blend file\"\"\"\n \n print(f\"\\n=== REMAPPING TEXTURE PATHS ===\")\n print(f\"Blend file: {blend_file_path}\")\n print(f\"Move log: {move_log_path}\")\n \n # Load move log\n original_to_new, original_to_replacement, texture_folder_path = load_move_log(move_log_path)\n \n if not original_to_new and not original_to_replacement:\n print(\"WARNING: No moves found in move log. Nothing to remap.\")\n return 0\n \n print(f\"Loaded {len(original_to_new)} move mappings and {len(original_to_replacement)} replacement mappings\")\n \n # Get blend file directory for relative path conversion\n blend_file_dir = os.path.dirname(os.path.abspath(blend_file_path))\n \n remapped_count = 0\n not_found_count = 0\n \n # Remap paths in image datablocks\n print(\"\\nRemapping image datablock paths...\")\n for image in bpy.data.images:\n if not image.filepath:\n continue", + "signatures": {}, + "detailedLines": [ + { + "text": "def remap_texture_paths(blend_file_path, move_log_path):", + "lineNumber": 74, + "isSignature": true + }, + { + "text": " \"\"\"Remap all texture paths in the blend file\"\"\"", + "lineNumber": 75 + }, + { + "text": " ", + "lineNumber": 76 + }, + { + "text": " print(f\"\\n=== REMAPPING TEXTURE PATHS ===\")", + "lineNumber": 77 + }, + { + "text": " print(f\"Blend file: {blend_file_path}\")", + "lineNumber": 78 + }, + { + "text": " print(f\"Move log: {move_log_path}\")", + "lineNumber": 79 + }, + { + "text": " ", + "lineNumber": 80 + }, + { + "text": " # Load move log", + "lineNumber": 81 + }, + { + "text": " original_to_new, original_to_replacement, texture_folder_path = load_move_log(move_log_path)", + "lineNumber": 82 + }, + { + "text": " ", + "lineNumber": 83 + }, + { + "text": " if not original_to_new and not original_to_replacement:", + "lineNumber": 84 + }, + { + "text": " print(\"WARNING: No moves found in move log. Nothing to remap.\")", + "lineNumber": 85 + }, + { + "text": " return 0", + "lineNumber": 86 + }, + { + "text": " ", + "lineNumber": 87 + }, + { + "text": " print(f\"Loaded {len(original_to_new)} move mappings and {len(original_to_replacement)} replacement mappings\")", + "lineNumber": 88 + }, + { + "text": " ", + "lineNumber": 89 + }, + { + "text": " # Get blend file directory for relative path conversion", + "lineNumber": 90 + }, + { + "text": " blend_file_dir = os.path.dirname(os.path.abspath(blend_file_path))", + "lineNumber": 91 + }, + { + "text": " ", + "lineNumber": 92 + }, + { + "text": " remapped_count = 0", + "lineNumber": 93 + }, + { + "text": " not_found_count = 0", + "lineNumber": 94 + }, + { + "text": " ", + "lineNumber": 95 + }, + { + "text": " # Remap paths in image datablocks", + "lineNumber": 96 + }, + { + "text": " print(\"\\nRemapping image datablock paths...\")", + "lineNumber": 97 + }, + { + "text": " for image in bpy.data.images:", + "lineNumber": 98 + }, + { + "text": " if not image.filepath:", + "lineNumber": 99 + }, + { + "text": " continue", + "lineNumber": 100 + } + ] + }, + "score": 0.31581223011016846 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\organize_textures.ps1", + "range": { + "startPosition": { + "line": 47 + }, + "endPosition": { + "line": 99 + } + }, + "contents": "function Move-FilesToCommon {\n param(\n [array]$Files,\n [string]$CommonPath,\n [string]$DuplicatesPath,\n [hashtable]$FilesInCommon\n )\n \n $movedCount = 0\n $duplicateCount = 0\n \n foreach ($fileObj in $Files) {\n $fileName = $fileObj.Name\n $destinationPath = Join-Path -Path $CommonPath -ChildPath $fileName\n \n # Handle name conflicts\n if ($FilesInCommon.ContainsKey($fileName)) {\n $baseName = [System.IO.Path]::GetFileNameWithoutExtension($fileName)\n $extension = [System.IO.Path]::GetExtension($fileName)\n $counter = 1\n do {\n $newFileName = \"${baseName}_${counter}${extension}\"\n $destinationPath = Join-Path -Path $CommonPath -ChildPath $newFileName\n $counter++\n } while ($FilesInCommon.ContainsKey($newFileName) -or (Test-Path -Path $destinationPath))\n \n $fileName = $newFileName\n }\n \n try {\n Move-Item -Path $fileObj.FullName -Destination $destinationPath -Force\n $FilesInCommon[$fileName] = $true\n $movedCount++\n } catch {\n Write-Warning \"Failed to move file: $($fileObj.FullName) - $($_.Exception.Message)\"\n }\n }\n \n return @{\n MovedCount = $movedCount\n DuplicateCount = $duplicateCount\n }\n}\n\n# Function to extract suffix after blendfile prefix (e.g., \"Demarco_Std_Teeth_ao.jpg\" -> \"Std_Teeth_ao.jpg\")\n# Only strips prefixes that are in the $ValidPrefixes list\nfunction Get-FileNameWithoutPrefix {\n param(\n [string]$FileName,\n [string[]]$ValidPrefixes\n )\n ", + "signatures": {}, + "detailedLines": [ + { + "text": "function Move-FilesToCommon {", + "lineNumber": 48 + }, + { + "text": " param(", + "lineNumber": 49 + }, + { + "text": " [array]$Files,", + "lineNumber": 50 + }, + { + "text": " [string]$CommonPath,", + "lineNumber": 51 + }, + { + "text": " [string]$DuplicatesPath,", + "lineNumber": 52 + }, + { + "text": " [hashtable]$FilesInCommon", + "lineNumber": 53 + }, + { + "text": " )", + "lineNumber": 54 + }, + { + "text": " ", + "lineNumber": 55 + }, + { + "text": " $movedCount = 0", + "lineNumber": 56 + }, + { + "text": " $duplicateCount = 0", + "lineNumber": 57 + }, + { + "text": " ", + "lineNumber": 58 + }, + { + "text": " foreach ($fileObj in $Files) {", + "lineNumber": 59 + }, + { + "text": " $fileName = $fileObj.Name", + "lineNumber": 60 + }, + { + "text": " $destinationPath = Join-Path -Path $CommonPath -ChildPath $fileName", + "lineNumber": 61 + }, + { + "text": " ", + "lineNumber": 62 + }, + { + "text": " # Handle name conflicts", + "lineNumber": 63 + }, + { + "text": " if ($FilesInCommon.ContainsKey($fileName)) {", + "lineNumber": 64 + }, + { + "text": " $baseName = [System.IO.Path]::GetFileNameWithoutExtension($fileName)", + "lineNumber": 65 + }, + { + "text": " $extension = [System.IO.Path]::GetExtension($fileName)", + "lineNumber": 66 + }, + { + "text": " $counter = 1", + "lineNumber": 67 + }, + { + "text": " do {", + "lineNumber": 68 + }, + { + "text": " $newFileName = \"${baseName}_${counter}${extension}\"", + "lineNumber": 69 + }, + { + "text": " $destinationPath = Join-Path -Path $CommonPath -ChildPath $newFileName", + "lineNumber": 70 + }, + { + "text": " $counter++", + "lineNumber": 71 + }, + { + "text": " } while ($FilesInCommon.ContainsKey($newFileName) -or (Test-Path -Path $destinationPath))", + "lineNumber": 72 + }, + { + "text": " ", + "lineNumber": 73 + }, + { + "text": " $fileName = $newFileName", + "lineNumber": 74 + }, + { + "text": " }", + "lineNumber": 75 + }, + { + "text": " ", + "lineNumber": 76 + }, + { + "text": " try {", + "lineNumber": 77 + }, + { + "text": " Move-Item -Path $fileObj.FullName -Destination $destinationPath -Force", + "lineNumber": 78 + }, + { + "text": " $FilesInCommon[$fileName] = $true", + "lineNumber": 79 + }, + { + "text": " $movedCount++", + "lineNumber": 80 + }, + { + "text": " } catch {", + "lineNumber": 81 + }, + { + "text": " Write-Warning \"Failed to move file: $($fileObj.FullName) - $($_.Exception.Message)\"", + "lineNumber": 82 + }, + { + "text": " }", + "lineNumber": 83 + }, + { + "text": " }", + "lineNumber": 84 + }, + { + "text": " ", + "lineNumber": 85 + }, + { + "text": " return @{", + "lineNumber": 86 + }, + { + "text": " MovedCount = $movedCount", + "lineNumber": 87 + }, + { + "text": " DuplicateCount = $duplicateCount", + "lineNumber": 88 + }, + { + "text": " }", + "lineNumber": 89 + }, + { + "text": "}", + "lineNumber": 90 + }, + { + "lineNumber": 91 + }, + { + "text": "# Function to extract suffix after blendfile prefix (e.g., \"Demarco_Std_Teeth_ao.jpg\" -> \"Std_Teeth_ao.jpg\")", + "lineNumber": 92 + }, + { + "text": "# Only strips prefixes that are in the $ValidPrefixes list", + "lineNumber": 93 + }, + { + "text": "function Get-FileNameWithoutPrefix {", + "lineNumber": 94 + }, + { + "text": " param(", + "lineNumber": 95 + }, + { + "text": " [string]$FileName,", + "lineNumber": 96 + }, + { + "text": " [string[]]$ValidPrefixes", + "lineNumber": 97 + }, + { + "text": " )", + "lineNumber": 98 + }, + { + "text": " ", + "lineNumber": 99 + } + ] + }, + "score": 0.3142794370651245 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\organize_textures.ps1", + "range": { + "startPosition": { + "line": 583 + }, + "endPosition": { + "line": 606 + } + }, + "contents": "} catch {\n Write-Warning \"Failed to save move log: $($_.Exception.Message)\"\n}\n\n# ============================================================================\n# Remap Texture Paths in Blend Files\n# ============================================================================\nif ($blendFileMappings.Count -gt 0 -and (Test-Path -Path $moveLogPath)) {\n Write-Host \"\"\n Write-Host \"Remapping texture paths in blend files...\" -ForegroundColor Yellow\n \n # Find Blender executable from PATH\n $blenderExe = $null\n $blenderInPath = Get-Command blender -ErrorAction SilentlyContinue\n if ($null -ne $blenderInPath) {\n $blenderExe = $blenderInPath.Source\n }\n \n if ($null -eq $blenderExe) {\n Write-Warning \"Blender executable not found. Skipping texture path remapping.\"\n Write-Host \" Please install Blender or add it to your PATH.\" -ForegroundColor Yellow\n } else {\n Write-Host \"Found Blender: $blenderExe\" -ForegroundColor Gray", + "signatures": {}, + "detailedLines": [ + { + "text": "} catch {", + "lineNumber": 584 + }, + { + "text": " Write-Warning \"Failed to save move log: $($_.Exception.Message)\"", + "lineNumber": 585 + }, + { + "text": "}", + "lineNumber": 586 + }, + { + "lineNumber": 587 + }, + { + "text": "# ============================================================================", + "lineNumber": 588 + }, + { + "text": "# Remap Texture Paths in Blend Files", + "lineNumber": 589 + }, + { + "text": "# ============================================================================", + "lineNumber": 590 + }, + { + "text": "if ($blendFileMappings.Count -gt 0 -and (Test-Path -Path $moveLogPath)) {", + "lineNumber": 591 + }, + { + "text": " Write-Host \"\"", + "lineNumber": 592 + }, + { + "text": " Write-Host \"Remapping texture paths in blend files...\" -ForegroundColor Yellow", + "lineNumber": 593 + }, + { + "text": " ", + "lineNumber": 594 + }, + { + "text": " # Find Blender executable from PATH", + "lineNumber": 595 + }, + { + "text": " $blenderExe = $null", + "lineNumber": 596 + }, + { + "text": " $blenderInPath = Get-Command blender -ErrorAction SilentlyContinue", + "lineNumber": 597 + }, + { + "text": " if ($null -ne $blenderInPath) {", + "lineNumber": 598 + }, + { + "text": " $blenderExe = $blenderInPath.Source", + "lineNumber": 599 + }, + { + "text": " }", + "lineNumber": 600 + }, + { + "text": " ", + "lineNumber": 601 + }, + { + "text": " if ($null -eq $blenderExe) {", + "lineNumber": 602 + }, + { + "text": " Write-Warning \"Blender executable not found. Skipping texture path remapping.\"", + "lineNumber": 603 + }, + { + "text": " Write-Host \" Please install Blender or add it to your PATH.\" -ForegroundColor Yellow", + "lineNumber": 604 + }, + { + "text": " } else {", + "lineNumber": 605 + }, + { + "text": " Write-Host \"Found Blender: $blenderExe\" -ForegroundColor Gray", + "lineNumber": 606 + } + ] + }, + "score": 0.3072027862071991 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\organize_textures.ps1", + "range": { + "startPosition": { + "line": 240 + }, + "endPosition": { + "line": 281 + } + }, + "contents": " for ($i = 1; $i -lt $Files.Count; $i++) {\n $fileObj = $Files[$i].File\n try {\n $originalPath = $fileObj.FullName\n Remove-Item -Path $originalPath -Force\n $duplicateCount++\n \n # Log the deletion (replaced by the moved file)\n if ($null -ne $MoveLog) {\n $normalizedOriginal = [System.IO.Path]::GetFullPath($originalPath)\n $normalizedReplacement = [System.IO.Path]::GetFullPath($destinationPath)\n $null = $MoveLog.Add([PSCustomObject]@{\n OriginalPath = $normalizedOriginal\n ReplacedBy = $normalizedReplacement\n Type = \"deleted\"\n })\n }\n } catch {\n Write-Warning \"Failed to delete duplicate file: $($fileObj.FullName) - $($_.Exception.Message)\"\n }\n }\n \n return @{\n MovedCount = $movedCount\n DuplicateCount = $duplicateCount\n }\n}\n\n# ============================================================================\n# PASS 1: Intra-Blendfile Processing\n# ============================================================================\nWrite-Host \"\"\nWrite-Host \"=== PASS 1: Intra-Blendfile Processing ===\" -ForegroundColor Cyan\n\n# Get all direct subdirectories of texture folder (blendfile folders)\n$blendfileFolders = Get-ChildItem -Path $textureFolderPath -Directory | Where-Object { $_.Name -ne \"common\" }\n\nif ($null -eq $blendfileFolders -or $blendfileFolders.Count -eq 0) {\n Write-Host \"No blendfile folders found. Skipping Pass 1.\" -ForegroundColor Yellow\n} else {\n Write-Host \"Found $($blendfileFolders.Count) blendfile folder(s) to process.\" -ForegroundColor Green", + "signatures": {}, + "detailedLines": [ + { + "text": " for ($i = 1; $i -lt $Files.Count; $i++) {", + "lineNumber": 241 + }, + { + "text": " $fileObj = $Files[$i].File", + "lineNumber": 242 + }, + { + "text": " try {", + "lineNumber": 243 + }, + { + "text": " $originalPath = $fileObj.FullName", + "lineNumber": 244 + }, + { + "text": " Remove-Item -Path $originalPath -Force", + "lineNumber": 245 + }, + { + "text": " $duplicateCount++", + "lineNumber": 246 + }, + { + "text": " ", + "lineNumber": 247 + }, + { + "text": " # Log the deletion (replaced by the moved file)", + "lineNumber": 248 + }, + { + "text": " if ($null -ne $MoveLog) {", + "lineNumber": 249 + }, + { + "text": " $normalizedOriginal = [System.IO.Path]::GetFullPath($originalPath)", + "lineNumber": 250 + }, + { + "text": " $normalizedReplacement = [System.IO.Path]::GetFullPath($destinationPath)", + "lineNumber": 251 + }, + { + "text": " $null = $MoveLog.Add([PSCustomObject]@{", + "lineNumber": 252 + }, + { + "text": " OriginalPath = $normalizedOriginal", + "lineNumber": 253 + }, + { + "text": " ReplacedBy = $normalizedReplacement", + "lineNumber": 254 + }, + { + "text": " Type = \"deleted\"", + "lineNumber": 255 + }, + { + "text": " })", + "lineNumber": 256 + }, + { + "text": " }", + "lineNumber": 257 + }, + { + "text": " } catch {", + "lineNumber": 258 + }, + { + "text": " Write-Warning \"Failed to delete duplicate file: $($fileObj.FullName) - $($_.Exception.Message)\"", + "lineNumber": 259 + }, + { + "text": " }", + "lineNumber": 260 + }, + { + "text": " }", + "lineNumber": 261 + }, + { + "text": " ", + "lineNumber": 262 + }, + { + "text": " return @{", + "lineNumber": 263 + }, + { + "text": " MovedCount = $movedCount", + "lineNumber": 264 + }, + { + "text": " DuplicateCount = $duplicateCount", + "lineNumber": 265 + }, + { + "text": " }", + "lineNumber": 266 + }, + { + "text": "}", + "lineNumber": 267 + }, + { + "lineNumber": 268 + }, + { + "text": "# ============================================================================", + "lineNumber": 269 + }, + { + "text": "# PASS 1: Intra-Blendfile Processing", + "lineNumber": 270 + }, + { + "text": "# ============================================================================", + "lineNumber": 271 + }, + { + "text": "Write-Host \"\"", + "lineNumber": 272 + }, + { + "text": "Write-Host \"=== PASS 1: Intra-Blendfile Processing ===\" -ForegroundColor Cyan", + "lineNumber": 273 + }, + { + "lineNumber": 274 + }, + { + "text": "# Get all direct subdirectories of texture folder (blendfile folders)", + "lineNumber": 275 + }, + { + "text": "$blendfileFolders = Get-ChildItem -Path $textureFolderPath -Directory | Where-Object { $_.Name -ne \"common\" }", + "lineNumber": 276 + }, + { + "lineNumber": 277 + }, + { + "text": "if ($null -eq $blendfileFolders -or $blendfileFolders.Count -eq 0) {", + "lineNumber": 278 + }, + { + "text": " Write-Host \"No blendfile folders found. Skipping Pass 1.\" -ForegroundColor Yellow", + "lineNumber": 279 + }, + { + "text": "} else {", + "lineNumber": 280 + }, + { + "text": " Write-Host \"Found $($blendfileFolders.Count) blendfile folder(s) to process.\" -ForegroundColor Green", + "lineNumber": 281 + } + ] + }, + "score": 0.30335870385169983 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\organize_textures.ps1", + "range": { + "startPosition": { + "line": 128 + }, + "endPosition": { + "line": 173 + } + }, + "contents": "function Process-DuplicateGroup {\n param(\n [array]$Files,\n [string]$CommonPath,\n [hashtable]$FilesInCommon,\n [switch]$StripPrefix,\n [string[]]$ValidPrefixes = @(),\n [System.Collections.ArrayList]$MoveLog = $null\n )\n \n $movedCount = 0\n $duplicateCount = 0\n \n if ($Files.Count -eq 1) {\n # Single file - leave in place (will be processed in Pass 2)\n return @{\n MovedCount = 0\n DuplicateCount = 0\n }\n }\n \n # Validate files array\n if ($null -eq $Files -or $Files.Count -eq 0) {\n return @{\n MovedCount = 0\n DuplicateCount = 0\n }\n }\n \n # Multiple files with same checksum (duplicates)\n # Determine the filename to use\n $firstFile = $Files[0].File\n if ($null -eq $firstFile -or [string]::IsNullOrWhiteSpace($firstFile.Name)) {\n Write-Warning \"Invalid file object in duplicate group\"\n return @{\n MovedCount = 0\n DuplicateCount = 0\n }\n }\n \n $fileName = $firstFile.Name\n \n # If StripPrefix is enabled, always strip prefix from the filename\n if ($StripPrefix) {\n # Always try to strip prefix - if file has a prefix, it will be removed", + "signatures": {}, + "detailedLines": [ + { + "text": "function Process-DuplicateGroup {", + "lineNumber": 129 + }, + { + "text": " param(", + "lineNumber": 130 + }, + { + "text": " [array]$Files,", + "lineNumber": 131 + }, + { + "text": " [string]$CommonPath,", + "lineNumber": 132 + }, + { + "text": " [hashtable]$FilesInCommon,", + "lineNumber": 133 + }, + { + "text": " [switch]$StripPrefix,", + "lineNumber": 134 + }, + { + "text": " [string[]]$ValidPrefixes = @(),", + "lineNumber": 135 + }, + { + "text": " [System.Collections.ArrayList]$MoveLog = $null", + "lineNumber": 136 + }, + { + "text": " )", + "lineNumber": 137 + }, + { + "text": " ", + "lineNumber": 138 + }, + { + "text": " $movedCount = 0", + "lineNumber": 139 + }, + { + "text": " $duplicateCount = 0", + "lineNumber": 140 + }, + { + "text": " ", + "lineNumber": 141 + }, + { + "text": " if ($Files.Count -eq 1) {", + "lineNumber": 142 + }, + { + "text": " # Single file - leave in place (will be processed in Pass 2)", + "lineNumber": 143 + }, + { + "text": " return @{", + "lineNumber": 144 + }, + { + "text": " MovedCount = 0", + "lineNumber": 145 + }, + { + "text": " DuplicateCount = 0", + "lineNumber": 146 + }, + { + "text": " }", + "lineNumber": 147 + }, + { + "text": " }", + "lineNumber": 148 + }, + { + "text": " ", + "lineNumber": 149 + }, + { + "text": " # Validate files array", + "lineNumber": 150 + }, + { + "text": " if ($null -eq $Files -or $Files.Count -eq 0) {", + "lineNumber": 151 + }, + { + "text": " return @{", + "lineNumber": 152 + }, + { + "text": " MovedCount = 0", + "lineNumber": 153 + }, + { + "text": " DuplicateCount = 0", + "lineNumber": 154 + }, + { + "text": " }", + "lineNumber": 155 + }, + { + "text": " }", + "lineNumber": 156 + }, + { + "text": " ", + "lineNumber": 157 + }, + { + "text": " # Multiple files with same checksum (duplicates)", + "lineNumber": 158 + }, + { + "text": " # Determine the filename to use", + "lineNumber": 159 + }, + { + "text": " $firstFile = $Files[0].File", + "lineNumber": 160 + }, + { + "text": " if ($null -eq $firstFile -or [string]::IsNullOrWhiteSpace($firstFile.Name)) {", + "lineNumber": 161 + }, + { + "text": " Write-Warning \"Invalid file object in duplicate group\"", + "lineNumber": 162 + }, + { + "text": " return @{", + "lineNumber": 163 + }, + { + "text": " MovedCount = 0", + "lineNumber": 164 + }, + { + "text": " DuplicateCount = 0", + "lineNumber": 165 + }, + { + "text": " }", + "lineNumber": 166 + }, + { + "text": " }", + "lineNumber": 167 + }, + { + "text": " ", + "lineNumber": 168 + }, + { + "text": " $fileName = $firstFile.Name", + "lineNumber": 169 + }, + { + "text": " ", + "lineNumber": 170 + }, + { + "text": " # If StripPrefix is enabled, always strip prefix from the filename", + "lineNumber": 171 + }, + { + "text": " if ($StripPrefix) {", + "lineNumber": 172 + }, + { + "text": " # Always try to strip prefix - if file has a prefix, it will be removed", + "lineNumber": 173 + } + ] + }, + "score": 0.30188310146331787 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\organize_textures.ps1", + "range": { + "startPosition": { + "line": 514 + }, + "endPosition": { + "line": 546, + "column": 12 + } + }, + "contents": "# Save Move Log and Find Blend Files\n# ============================================================================\nWrite-Host \"\"\nWrite-Host \"Saving move log and finding blend files...\" -ForegroundColor Yellow\n\n# Combine all move logs\n$allMoves = @()\nif ($null -ne $pass1MoveLog -and $pass1MoveLog.Count -gt 0) {\n $allMoves += $pass1MoveLog\n}\nif ($null -ne $pass2MoveLog -and $pass2MoveLog.Count -gt 0) {\n $allMoves += $pass2MoveLog\n}\nif ($null -ne $flatColorsMoveLog -and $flatColorsMoveLog.Count -gt 0) {\n $allMoves += $flatColorsMoveLog\n}\n\n# Get parent directory of texture folder\n$blendFileParentDir = Split-Path -Path $textureFolderPath -Parent\n\n# Find matching blend files\n# Match logic: blendfile folder name (e.g., \"Beth\") should appear in blend file name (e.g., \"AM_Beth_v3.2.blend\")\n$blendFileMappings = @()\nif ($null -ne $blendfileFolders -and $blendfileFolders.Count -gt 0) {\n # Get blendfile folder names\n $blendfileFolderNames = $blendfileFolders | ForEach-Object { $_.Name }\n \n # Find all .blend files in parent directory\n $blendFiles = Get-ChildItem -Path $blendFileParentDir -Filter \"*.blend\" -File -ErrorAction SilentlyContinue\n \n if ($null -ne $blendFiles -and $blendFiles.Count -gt 0) {\n foreach ($blendFile in $blendFiles) {\n ", + "signatures": {}, + "detailedLines": [ + { + "text": "# Save Move Log and Find Blend Files", + "lineNumber": 515 + }, + { + "text": "# ============================================================================", + "lineNumber": 516 + }, + { + "text": "Write-Host \"\"", + "lineNumber": 517 + }, + { + "text": "Write-Host \"Saving move log and finding blend files...\" -ForegroundColor Yellow", + "lineNumber": 518 + }, + { + "lineNumber": 519 + }, + { + "text": "# Combine all move logs", + "lineNumber": 520 + }, + { + "text": "$allMoves = @()", + "lineNumber": 521 + }, + { + "text": "if ($null -ne $pass1MoveLog -and $pass1MoveLog.Count -gt 0) {", + "lineNumber": 522 + }, + { + "text": " $allMoves += $pass1MoveLog", + "lineNumber": 523 + }, + { + "text": "}", + "lineNumber": 524 + }, + { + "text": "if ($null -ne $pass2MoveLog -and $pass2MoveLog.Count -gt 0) {", + "lineNumber": 525 + }, + { + "text": " $allMoves += $pass2MoveLog", + "lineNumber": 526 + }, + { + "text": "}", + "lineNumber": 527 + }, + { + "text": "if ($null -ne $flatColorsMoveLog -and $flatColorsMoveLog.Count -gt 0) {", + "lineNumber": 528 + }, + { + "text": " $allMoves += $flatColorsMoveLog", + "lineNumber": 529 + }, + { + "text": "}", + "lineNumber": 530 + }, + { + "lineNumber": 531 + }, + { + "text": "# Get parent directory of texture folder", + "lineNumber": 532 + }, + { + "text": "$blendFileParentDir = Split-Path -Path $textureFolderPath -Parent", + "lineNumber": 533 + }, + { + "lineNumber": 534 + }, + { + "text": "# Find matching blend files", + "lineNumber": 535 + }, + { + "text": "# Match logic: blendfile folder name (e.g., \"Beth\") should appear in blend file name (e.g., \"AM_Beth_v3.2.blend\")", + "lineNumber": 536 + }, + { + "text": "$blendFileMappings = @()", + "lineNumber": 537 + }, + { + "text": "if ($null -ne $blendfileFolders -and $blendfileFolders.Count -gt 0) {", + "lineNumber": 538 + }, + { + "text": " # Get blendfile folder names", + "lineNumber": 539 + }, + { + "text": " $blendfileFolderNames = $blendfileFolders | ForEach-Object { $_.Name }", + "lineNumber": 540 + }, + { + "text": " ", + "lineNumber": 541 + }, + { + "text": " # Find all .blend files in parent directory", + "lineNumber": 542 + }, + { + "text": " $blendFiles = Get-ChildItem -Path $blendFileParentDir -Filter \"*.blend\" -File -ErrorAction SilentlyContinue", + "lineNumber": 543 + }, + { + "text": " ", + "lineNumber": 544 + }, + { + "text": " if ($null -ne $blendFiles -and $blendFiles.Count -gt 0) {", + "lineNumber": 545 + }, + { + "text": " foreach ($blendFile in $blendFiles) {", + "lineNumber": 546 + }, + { + "text": " ", + "lineNumber": 547 + } + ] + }, + "score": 0.2999364137649536 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\organize_textures.ps1", + "range": { + "startPosition": { + "line": 207 + }, + "endPosition": { + "line": 243, + "column": 12 + } + }, + "contents": " if ($FilesInCommon.ContainsKey($fileName)) {\n $baseName = [System.IO.Path]::GetFileNameWithoutExtension($fileName)\n $extension = [System.IO.Path]::GetExtension($fileName)\n $counter = 1\n do {\n $newFileName = \"${baseName}_${counter}${extension}\"\n $destinationPath = Join-Path -Path $CommonPath -ChildPath $newFileName\n $counter++\n } while ($FilesInCommon.ContainsKey($newFileName) -or (Test-Path -Path $destinationPath))\n \n $fileName = $newFileName\n }\n \n try {\n Move-Item -Path $firstFile.FullName -Destination $destinationPath -Force\n $FilesInCommon[$fileName] = $true\n $movedCount++\n \n # Log the move\n if ($null -ne $MoveLog) {\n $normalizedOriginal = [System.IO.Path]::GetFullPath($firstFile.FullName)\n $normalizedNew = [System.IO.Path]::GetFullPath($destinationPath)\n $null = $MoveLog.Add([PSCustomObject]@{\n OriginalPath = $normalizedOriginal\n NewPath = $normalizedNew\n Type = \"moved\"\n })\n }\n } catch {\n Write-Warning \"Failed to move first duplicate file: $($firstFile.FullName) - $($_.Exception.Message)\"\n }\n \n # Delete remaining duplicate files (they're replaced by the common file)\n for ($i = 1; $i -lt $Files.Count; $i++) {\n $fileObj = $Files[$i].File\n try {\n ", + "signatures": {}, + "detailedLines": [ + { + "text": " if ($FilesInCommon.ContainsKey($fileName)) {", + "lineNumber": 208 + }, + { + "text": " $baseName = [System.IO.Path]::GetFileNameWithoutExtension($fileName)", + "lineNumber": 209 + }, + { + "text": " $extension = [System.IO.Path]::GetExtension($fileName)", + "lineNumber": 210 + }, + { + "text": " $counter = 1", + "lineNumber": 211 + }, + { + "text": " do {", + "lineNumber": 212 + }, + { + "text": " $newFileName = \"${baseName}_${counter}${extension}\"", + "lineNumber": 213 + }, + { + "text": " $destinationPath = Join-Path -Path $CommonPath -ChildPath $newFileName", + "lineNumber": 214 + }, + { + "text": " $counter++", + "lineNumber": 215 + }, + { + "text": " } while ($FilesInCommon.ContainsKey($newFileName) -or (Test-Path -Path $destinationPath))", + "lineNumber": 216 + }, + { + "text": " ", + "lineNumber": 217 + }, + { + "text": " $fileName = $newFileName", + "lineNumber": 218 + }, + { + "text": " }", + "lineNumber": 219 + }, + { + "text": " ", + "lineNumber": 220 + }, + { + "text": " try {", + "lineNumber": 221 + }, + { + "text": " Move-Item -Path $firstFile.FullName -Destination $destinationPath -Force", + "lineNumber": 222 + }, + { + "text": " $FilesInCommon[$fileName] = $true", + "lineNumber": 223 + }, + { + "text": " $movedCount++", + "lineNumber": 224 + }, + { + "text": " ", + "lineNumber": 225 + }, + { + "text": " # Log the move", + "lineNumber": 226 + }, + { + "text": " if ($null -ne $MoveLog) {", + "lineNumber": 227 + }, + { + "text": " $normalizedOriginal = [System.IO.Path]::GetFullPath($firstFile.FullName)", + "lineNumber": 228 + }, + { + "text": " $normalizedNew = [System.IO.Path]::GetFullPath($destinationPath)", + "lineNumber": 229 + }, + { + "text": " $null = $MoveLog.Add([PSCustomObject]@{", + "lineNumber": 230 + }, + { + "text": " OriginalPath = $normalizedOriginal", + "lineNumber": 231 + }, + { + "text": " NewPath = $normalizedNew", + "lineNumber": 232 + }, + { + "text": " Type = \"moved\"", + "lineNumber": 233 + }, + { + "text": " })", + "lineNumber": 234 + }, + { + "text": " }", + "lineNumber": 235 + }, + { + "text": " } catch {", + "lineNumber": 236 + }, + { + "text": " Write-Warning \"Failed to move first duplicate file: $($firstFile.FullName) - $($_.Exception.Message)\"", + "lineNumber": 237 + }, + { + "text": " }", + "lineNumber": 238 + }, + { + "text": " ", + "lineNumber": 239 + }, + { + "text": " # Delete remaining duplicate files (they're replaced by the common file)", + "lineNumber": 240 + }, + { + "text": " for ($i = 1; $i -lt $Files.Count; $i++) {", + "lineNumber": 241 + }, + { + "text": " $fileObj = $Files[$i].File", + "lineNumber": 242 + }, + { + "text": " try {", + "lineNumber": 243 + }, + { + "text": " ", + "lineNumber": 244 + } + ] + }, + "score": 0.29972875118255615 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\UpdateProjectBatches.ps1", + "range": { + "startPosition": { + "line": 112 + }, + "endPosition": { + "line": 164 + } + }, + "contents": " $updated++\n\n $targetDir = $target.Directory.FullName\n if (-not $touchedDirs.ContainsKey($targetDir)) {\n $touchedDirs[$targetDir] = $true\n }\n }\n catch {\n Write-Host \"[FAIL] $($target.FullName)\" -ForegroundColor Red\n Write-Host \" $($_.Exception.Message)\" -ForegroundColor DarkRed\n $failed++\n }\n }\n\n $summary += [pscustomobject]@{\n Name = $spec.Name\n Updated = $updated\n Failed = $failed\n Skipped = 0\n Total = @($targets).Count\n }\n}\n\nWrite-Host \"`n=== Summary ===\" -ForegroundColor Cyan\nforeach ($item in $summary) {\n Write-Host (\"{0,-22} Updated: {1,3} Failed: {2,3} Total: {3,3}\" -f $item.Name, $item.Updated, $item.Failed, $item.Total)\n}\n\nif (($summary | Measure-Object -Property Failed -Sum).Sum -gt 0) {\n Write-Host \"Completed with errors.\" -ForegroundColor Yellow\n exit 1\n}\n\nWrite-Host \"All batch files refreshed successfully.\" -ForegroundColor Green\n\n# Deploy config files to projectroot\\.config\\\nWrite-Host \"`n=== Deploying config files to .config\\ ===\" -ForegroundColor Magenta\nforeach ($asset in $configAssets) {\n $targetPath = Join-Path -Path $projectConfigDir -ChildPath $asset.Name\n try {\n Copy-Item -Path $asset.Source -Destination $targetPath -Force\n Write-Host \"[OK] $targetPath\" -ForegroundColor Green\n }\n catch {\n Write-Host \"[FAIL] $targetPath\" -ForegroundColor Red\n Write-Host \" $($_.Exception.Message)\" -ForegroundColor DarkRed\n exit 1\n }\n}\n\nWrite-Host \"Config files deployed successfully.\" -ForegroundColor Green", + "signatures": {}, + "detailedLines": [ + { + "text": " $updated++", + "lineNumber": 113 + }, + { + "lineNumber": 114 + }, + { + "text": " $targetDir = $target.Directory.FullName", + "lineNumber": 115 + }, + { + "text": " if (-not $touchedDirs.ContainsKey($targetDir)) {", + "lineNumber": 116 + }, + { + "text": " $touchedDirs[$targetDir] = $true", + "lineNumber": 117 + }, + { + "text": " }", + "lineNumber": 118 + }, + { + "text": " }", + "lineNumber": 119 + }, + { + "text": " catch {", + "lineNumber": 120 + }, + { + "text": " Write-Host \"[FAIL] $($target.FullName)\" -ForegroundColor Red", + "lineNumber": 121 + }, + { + "text": " Write-Host \" $($_.Exception.Message)\" -ForegroundColor DarkRed", + "lineNumber": 122 + }, + { + "text": " $failed++", + "lineNumber": 123 + }, + { + "text": " }", + "lineNumber": 124 + }, + { + "text": " }", + "lineNumber": 125 + }, + { + "lineNumber": 126 + }, + { + "text": " $summary += [pscustomobject]@{", + "lineNumber": 127 + }, + { + "text": " Name = $spec.Name", + "lineNumber": 128 + }, + { + "text": " Updated = $updated", + "lineNumber": 129 + }, + { + "text": " Failed = $failed", + "lineNumber": 130 + }, + { + "text": " Skipped = 0", + "lineNumber": 131 + }, + { + "text": " Total = @($targets).Count", + "lineNumber": 132 + }, + { + "text": " }", + "lineNumber": 133 + }, + { + "text": "}", + "lineNumber": 134 + }, + { + "lineNumber": 135 + }, + { + "text": "Write-Host \"`n=== Summary ===\" -ForegroundColor Cyan", + "lineNumber": 136 + }, + { + "text": "foreach ($item in $summary) {", + "lineNumber": 137 + }, + { + "text": " Write-Host (\"{0,-22} Updated: {1,3} Failed: {2,3} Total: {3,3}\" -f $item.Name, $item.Updated, $item.Failed, $item.Total)", + "lineNumber": 138 + }, + { + "text": "}", + "lineNumber": 139 + }, + { + "lineNumber": 140 + }, + { + "text": "if (($summary | Measure-Object -Property Failed -Sum).Sum -gt 0) {", + "lineNumber": 141 + }, + { + "text": " Write-Host \"Completed with errors.\" -ForegroundColor Yellow", + "lineNumber": 142 + }, + { + "text": " exit 1", + "lineNumber": 143 + }, + { + "text": "}", + "lineNumber": 144 + }, + { + "lineNumber": 145 + }, + { + "text": "Write-Host \"All batch files refreshed successfully.\" -ForegroundColor Green", + "lineNumber": 146 + }, + { + "lineNumber": 147 + }, + { + "text": "# Deploy config files to projectroot\\.config\\", + "lineNumber": 148 + }, + { + "text": "Write-Host \"`n=== Deploying config files to .config\\ ===\" -ForegroundColor Magenta", + "lineNumber": 149 + }, + { + "text": "foreach ($asset in $configAssets) {", + "lineNumber": 150 + }, + { + "text": " $targetPath = Join-Path -Path $projectConfigDir -ChildPath $asset.Name", + "lineNumber": 151 + }, + { + "text": " try {", + "lineNumber": 152 + }, + { + "text": " Copy-Item -Path $asset.Source -Destination $targetPath -Force", + "lineNumber": 153 + }, + { + "text": " Write-Host \"[OK] $targetPath\" -ForegroundColor Green", + "lineNumber": 154 + }, + { + "text": " }", + "lineNumber": 155 + }, + { + "text": " catch {", + "lineNumber": 156 + }, + { + "text": " Write-Host \"[FAIL] $targetPath\" -ForegroundColor Red", + "lineNumber": 157 + }, + { + "text": " Write-Host \" $($_.Exception.Message)\" -ForegroundColor DarkRed", + "lineNumber": 158 + }, + { + "text": " exit 1", + "lineNumber": 159 + }, + { + "text": " }", + "lineNumber": 160 + }, + { + "text": "}", + "lineNumber": 161 + }, + { + "lineNumber": 162 + }, + { + "text": "Write-Host \"Config files deployed successfully.\" -ForegroundColor Green", + "lineNumber": 163 + } + ] + }, + "score": 0.29805418848991394 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\organize_textures.bat", + "range": { + "startPosition": {}, + "endPosition": { + "line": 22, + "column": 12 + } + }, + "contents": "@echo off\nsetlocal EnableExtensions\n\nset \"script_dir=%~dp0\"\nset \"ps1_path=%script_dir%organize_textures.ps1\"\n\nif not exist \"%ps1_path%\" (\n echo [ERROR] organize_textures.ps1 not found at %ps1_path%\n exit /b 1\n)\n\necho Running texture organizer...\npwsh -NoProfile -ExecutionPolicy Bypass -File \"%ps1_path%\"\nset \"rc=%errorlevel%\"\n\nif %rc% neq 0 (\n echo.\n echo Script exited with error code %rc%\n)\n\necho.\npause\nexit /b %rc%", + "signatures": {}, + "detailedLines": [ + { + "text": "@echo off", + "lineNumber": 1 + }, + { + "text": "setlocal EnableExtensions", + "lineNumber": 2 + }, + { + "lineNumber": 3 + }, + { + "text": "set \"script_dir=%~dp0\"", + "lineNumber": 4 + }, + { + "text": "set \"ps1_path=%script_dir%organize_textures.ps1\"", + "lineNumber": 5 + }, + { + "lineNumber": 6 + }, + { + "text": "if not exist \"%ps1_path%\" (", + "lineNumber": 7 + }, + { + "text": " echo [ERROR] organize_textures.ps1 not found at %ps1_path%", + "lineNumber": 8 + }, + { + "text": " exit /b 1", + "lineNumber": 9 + }, + { + "text": ")", + "lineNumber": 10 + }, + { + "lineNumber": 11 + }, + { + "text": "echo Running texture organizer...", + "lineNumber": 12 + }, + { + "text": "pwsh -NoProfile -ExecutionPolicy Bypass -File \"%ps1_path%\"", + "lineNumber": 13 + }, + { + "text": "set \"rc=%errorlevel%\"", + "lineNumber": 14 + }, + { + "lineNumber": 15 + }, + { + "text": "if %rc% neq 0 (", + "lineNumber": 16 + }, + { + "text": " echo.", + "lineNumber": 17 + }, + { + "text": " echo Script exited with error code %rc%", + "lineNumber": 18 + }, + { + "text": ")", + "lineNumber": 19 + }, + { + "lineNumber": 20 + }, + { + "text": "echo.", + "lineNumber": 21 + }, + { + "text": "pause", + "lineNumber": 22 + }, + { + "text": "exit /b %rc%", + "lineNumber": 23 + } + ] + }, + "score": 0.2977990508079529 + } + ] +} +``` +Status: **completed** + + +
+
+ +--- + + +Creating a script to standardize FlatColors: convert PNGs to 16x16 JPGs (except TGA), merge duplicates by color, and ensure all are 16x16. + + +--- + + + +
Tool use: **edit_file_v2** • Edit file: A:\1 Amazon_Active_Projects\3 ProjectStructure\standardize_flatcolors.ps1 + +
+ +
+ +--- + + +Refining the script to better handle edge cases and improve duplicate detection: + + +--- + + + +
Tool use: **edit_file_v2** • Edit file: standardize_flatcolors.ps1 + +
+ +
+ +--- + + + +
Tool use: **edit_file_v2** • Edit file: standardize_flatcolors.ps1 + +
+ +
+ +--- + + +Fixing the color code extraction to handle all filename variations: + + +--- + + + +
Tool use: **edit_file_v2** • Edit file: standardize_flatcolors.ps1 + +
+ +
+ +--- + + +Reviewing the script to verify the logic: + + +--- + + +
Tool use: **read_file_v2** • Read file: standardize_flatcolors.ps1 + +
+
+ +--- + + +Ensuring the target directory exists before processing: + + +--- + + + +
Tool use: **edit_file_v2** • Edit file: standardize_flatcolors.ps1 + +
+ +
+ +--- + + +Created a script `standardize_flatcolors.ps1` that: + +1. **Finds all FlatColors files** in any `FlatColors` folder within the texture directory +2. **Extracts color codes** from filenames (handles `#RRGGBB`, `#RRGGBB_1`, `#RRGGBB_2`, etc.) +3. **Groups by color code** to identify duplicates +4. **Converts PNG to 16x16 JPG** (unless the file is TGA) +5. **Resizes to 16x16** if needed +6. **Preserves TGA files** as-is (no conversion) +7. **Merges duplicates** by keeping one file per color and deleting the rest +8. **Organizes files** in the target directory (prefers `common\FlatColors` if it exists) + +The script: +- Prefers existing JPG files when multiple formats exist for the same color +- Preserves TGA files without conversion +- Handles files already in the correct format/size +- Provides a summary of actions taken + +Run it with: +```powershell +.\standardize_flatcolors.ps1 +``` + +It will prompt for the texture folder path and process all FlatColors files accordingly. + +--- + +_**User**_ + +merge this script into organize_textures.ps1 pls + +--- + +_**Agent (model default, mode Agent)**_ + + +Reading `organize_textures.ps1` to understand its structure, then integrating the FlatColors standardization logic. + + +--- + + +
Tool use: **read_file_v2** • Read file: organize_textures.ps1 + +
+
+ +--- + + +Integrating FlatColors standardization into `organize_textures.ps1`. Adding the required functions and updating the FlatColors processing section. + + +--- + + + +
Tool use: **edit_file_v2** • Edit file: organize_textures.ps1 + +
+ +
+ +--- + +The model provided an ambiguous search string to replace + +--- + + + +
Tool use: **edit_file_v2** • Edit file: organize_textures.ps1 + +Status: **loading** + +
+ +
--- diff --git a/config.json b/config.json index ff6cb79..d6572d9 100644 --- a/config.json +++ b/config.json @@ -1,6 +1,6 @@ { "dailyFormat": "YYYY-MM-DD", - "structDir": "D:\\0 ProjectStructure", + "structDir": "A:\\1 Amazon_Active_Projects\\3 ProjectStructure", "zipper": "7z", "compression": 0, "Max7zInst": 0 diff --git a/organize_textures.ps1 b/organize_textures.ps1 index e3af864..0842881 100644 --- a/organize_textures.ps1 +++ b/organize_textures.ps1 @@ -21,6 +21,9 @@ if (-not (Test-Path -Path $textureFolderPath -PathType Container)) { $textureFolderPath = (Resolve-Path $textureFolderPath).ProviderPath Write-Host "Processing texture folder: $textureFolderPath" -ForegroundColor Cyan +# Add required .NET assemblies for image processing (for FlatColors standardization) +Add-Type -AssemblyName System.Drawing + # Function to calculate checksums for files function Get-FilesWithChecksums { param( @@ -266,6 +269,81 @@ function Process-DuplicateGroup { } } +# Function to extract and normalize hex color code from filename (for FlatColors) +function Get-NormalizedColorCode { + param([string]$FileName) + + # Remove extension + $baseName = [System.IO.Path]::GetFileNameWithoutExtension($FileName) + + # Match hex color pattern: #RRGGBB or #RRGGBBAA (with optional suffix like _1, _2, etc.) + # Pattern matches: #RRGGBB, #RRGGBBAA, or just RRGGBB (without #) + # Also handles suffixes like _1, _2, etc. + if ($baseName -match '^(#?)([0-9A-Fa-f]{6})([0-9A-Fa-f]{2})?') { + $hasHash = $Matches[1] -eq "#" + $hexCode = $Matches[2].ToUpper() + # Return normalized format: #RRGGBB (always with #, always uppercase, no suffix) + return "#$hexCode" + } + + return $null +} + +# Function to convert and resize image to 16x16 JPG (for FlatColors) +function Convert-To16x16Jpg { + param( + [string]$SourcePath, + [string]$DestinationPath + ) + + try { + $image = [System.Drawing.Image]::FromFile($SourcePath) + + # Create 16x16 bitmap + $bitmap = New-Object System.Drawing.Bitmap(16, 16) + $graphics = [System.Drawing.Graphics]::FromImage($bitmap) + $graphics.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic + $graphics.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::HighQuality + $graphics.PixelOffsetMode = [System.Drawing.Drawing2D.PixelOffsetMode]::HighQuality + + # Draw resized image + $graphics.DrawImage($image, 0, 0, 16, 16) + + # Get JPEG codec + $jpegCodec = [System.Drawing.Imaging.ImageCodecInfo]::GetImageEncoders() | Where-Object { $_.MimeType -eq "image/jpeg" } + $encoderParams = New-Object System.Drawing.Imaging.EncoderParameters(1) + $encoderParams.Param[0] = New-Object System.Drawing.Imaging.EncoderParameter([System.Drawing.Imaging.Encoder]::Quality, 95) + + # Save as JPG + $bitmap.Save($DestinationPath, $jpegCodec, $encoderParams) + + # Cleanup + $graphics.Dispose() + $bitmap.Dispose() + $image.Dispose() + $encoderParams.Dispose() + + return $true + } catch { + Write-Warning "Failed to convert image: $SourcePath - $($_.Exception.Message)" + return $false + } +} + +# Function to check if image is 16x16 (for FlatColors) +function Test-ImageSize { + param([string]$ImagePath) + + try { + $image = [System.Drawing.Image]::FromFile($ImagePath) + $is16x16 = ($image.Width -eq 16 -and $image.Height -eq 16) + $image.Dispose() + return $is16x16 + } catch { + return $false + } +} + # ============================================================================ # PASS 1: Intra-Blendfile Processing # ============================================================================ @@ -419,20 +497,34 @@ if ($null -eq $remainingFiles -or $remainingFiles.Count -eq 0) { $pass2Duplicates += $result.DuplicateCount } - # Process FlatColors files: merge duplicates and move to \common\FlatColors - Write-Host "Processing FlatColors files (merging duplicates)..." -ForegroundColor Yellow + # Process FlatColors files: standardize to 16x16 JPG (except TGA), merge duplicates by color code + Write-Host "Processing FlatColors files (standardizing and 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 files by normalized color code (instead of checksum) + Write-Host "Grouping FlatColors files by color code..." -ForegroundColor Yellow + $filesByColor = @{} - # Group by checksum to find duplicates - $flatColorsGroupedByChecksum = $flatColorsWithChecksums | Group-Object -Property Hash + foreach ($file in $flatColorsFiles) { + if (-not (Test-Path -Path $file.FullName)) { + continue + } + + $colorCode = Get-NormalizedColorCode -FileName $file.Name + if ($null -eq $colorCode) { + Write-Warning "Could not extract color code from: $($file.Name)" + continue + } + + if (-not $filesByColor.ContainsKey($colorCode)) { + $filesByColor[$colorCode] = @() + } + $filesByColor[$colorCode] += $file + } - Write-Host "Found $($flatColorsGroupedByChecksum.Count) unique FlatColors file(s)" -ForegroundColor Gray + Write-Host "Found $($filesByColor.Count) unique color code(s)" -ForegroundColor Gray # Create \textures\common\FlatColors directory $flatColorsPath = Join-Path -Path $rootCommonPath -ChildPath "FlatColors" @@ -445,64 +537,185 @@ if ($null -eq $remainingFiles -or $remainingFiles.Count -eq 0) { $filesInFlatColors = @{} $flatColorsMoved = 0 $flatColorsDuplicates = 0 + $flatColorsConverted = 0 + $flatColorsResized = 0 $flatColorsMoveLog = [System.Collections.ArrayList]::new() - foreach ($group in $flatColorsGroupedByChecksum) { - $files = $group.Group + foreach ($colorCode in $filesByColor.Keys) { + $files = $filesByColor[$colorCode] - 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 + # Find the best file to keep (prefer existing JPG, then TGA, then others) + $fileToKeep = $null + $targetExtension = ".jpg" + $targetFileName = "$colorCode.jpg" + + # First, check if there's already a correct file in target location + $existingTarget = Join-Path -Path $flatColorsPath -ChildPath $targetFileName + if (Test-Path -Path $existingTarget) { + $existingFile = Get-Item -Path $existingTarget + # Check if it's already correct + if ($existingFile.Extension -eq ".jpg" -and (Test-ImageSize -ImagePath $existingFile.FullName)) { + $fileToKeep = $existingFile } + } + + # If no existing correct file, find best source file + if ($null -eq $fileToKeep) { + # Prefer existing JPG file + $jpgFile = $files | Where-Object { + ($_.Extension -eq ".jpg" -or $_.Extension -eq ".jpeg") -and + (Test-Path -Path $_.FullName) + } | Select-Object -First 1 - $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++ + if ($jpgFile) { + $fileToKeep = $jpgFile + } else { + # If no JPG, prefer TGA + $tgaFile = $files | Where-Object { + $_.Extension -eq ".tga" -and + (Test-Path -Path $_.FullName) + } | Select-Object -First 1 - # 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)" + if ($tgaFile) { + $fileToKeep = $tgaFile + $targetExtension = ".tga" + $targetFileName = "$colorCode.tga" + } else { + # Otherwise, use the first available file + $fileToKeep = $files | Where-Object { Test-Path -Path $_.FullName } | Select-Object -First 1 + } + } + } + + if ($null -eq $fileToKeep) { + Write-Warning " $colorCode: No valid file found to process" + continue + } + + $targetPath = Join-Path -Path $flatColorsPath -ChildPath $targetFileName + + # If target is TGA, preserve as-is (don't convert) + if ($targetExtension -eq ".tga") { + if ($fileToKeep.FullName -ne $targetPath) { + # Move TGA to target location + try { + if (Test-Path -Path $targetPath) { + Remove-Item -Path $targetPath -Force + } + $originalPath = $fileToKeep.FullName + Move-Item -Path $originalPath -Destination $targetPath -Force + $filesInFlatColors[$targetFileName] = $true + $flatColorsMoved++ + + # Log the move + $normalizedOriginal = [System.IO.Path]::GetFullPath($originalPath) + $normalizedNew = [System.IO.Path]::GetFullPath($targetPath) + $null = $flatColorsMoveLog.Add([PSCustomObject]@{ + OriginalPath = $normalizedOriginal + NewPath = $normalizedNew + Type = "moved" + }) + } catch { + Write-Warning " $colorCode: Failed to move TGA: $($_.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 + # Target is JPG - convert/resize if needed + $needsConversion = $false + $needsResize = $false + + if ($fileToKeep.Extension -ne ".jpg" -and $fileToKeep.Extension -ne ".jpeg") { + $needsConversion = $true + } + + if (-not (Test-ImageSize -ImagePath $fileToKeep.FullName)) { + $needsResize = $true + } + + # Check if target already exists and is correct + if ((Test-Path -Path $targetPath) -and + (Get-Item -Path $targetPath).Extension -eq ".jpg" -and + (Test-ImageSize -ImagePath $targetPath)) { + # Target already exists and is correct, skip + } elseif ($needsConversion -or $needsResize -or $fileToKeep.FullName -ne $targetPath) { + # Convert/resize to target + if (Convert-To16x16Jpg -SourcePath $fileToKeep.FullName -DestinationPath $targetPath) { + if ($needsConversion -and $needsResize) { + $flatColorsConverted++ + $flatColorsResized++ + } elseif ($needsConversion) { + $flatColorsConverted++ + } elseif ($needsResize) { + $flatColorsResized++ + } else { + $flatColorsMoved++ + } + + $filesInFlatColors[$targetFileName] = $true + + # Log the conversion/move + $normalizedOriginal = [System.IO.Path]::GetFullPath($fileToKeep.FullName) + $normalizedNew = [System.IO.Path]::GetFullPath($targetPath) + $null = $flatColorsMoveLog.Add([PSCustomObject]@{ + OriginalPath = $normalizedOriginal + NewPath = $normalizedNew + Type = "moved" + }) + } else { + Write-Warning " $colorCode: Failed to convert/resize" + continue + } + } else { + # File is already correct format and size + if ($fileToKeep.FullName -ne $targetPath) { + try { + if (Test-Path -Path $targetPath) { + Remove-Item -Path $targetPath -Force + } + $originalPath = $fileToKeep.FullName + Move-Item -Path $originalPath -Destination $targetPath -Force + $filesInFlatColors[$targetFileName] = $true + $flatColorsMoved++ + + # Log the move + $normalizedOriginal = [System.IO.Path]::GetFullPath($originalPath) + $normalizedNew = [System.IO.Path]::GetFullPath($targetPath) + $null = $flatColorsMoveLog.Add([PSCustomObject]@{ + OriginalPath = $normalizedOriginal + NewPath = $normalizedNew + Type = "moved" + }) + } catch { + Write-Warning " $colorCode: Failed to move: $($_.Exception.Message)" + } + } + } + } + + # Delete duplicate files (all files in the group except the target) + foreach ($file in $files) { + if ($file.FullName -ne $targetPath -and (Test-Path -Path $file.FullName)) { + try { + $originalPath = $file.FullName + Remove-Item -Path $originalPath -Force + $flatColorsDuplicates++ + + # Log the deletion + $normalizedOriginal = [System.IO.Path]::GetFullPath($originalPath) + $normalizedReplacement = [System.IO.Path]::GetFullPath($targetPath) + $null = $flatColorsMoveLog.Add([PSCustomObject]@{ + OriginalPath = $normalizedOriginal + ReplacedBy = $normalizedReplacement + Type = "deleted" + }) + } catch { + Write-Warning " Failed to delete duplicate: $($file.FullName) - $($_.Exception.Message)" + } + } } } - Write-Host "Moved $flatColorsMoved unique FlatColors file(s) to \common\FlatColors, deleted $flatColorsDuplicates duplicate(s)" -ForegroundColor Green + Write-Host "Processed FlatColors: $flatColorsMoved moved, $flatColorsConverted converted, $flatColorsResized resized, $flatColorsDuplicates duplicate(s) deleted" -ForegroundColor Green } else { Write-Host "No FlatColors files found to process." -ForegroundColor Gray }