From c0d625da13de9b70d6d6a7d9d23353f3cd17da99 Mon Sep 17 00:00:00 2001 From: Nathan Date: Fri, 19 Dec 2025 11:57:12 -0700 Subject: [PATCH] separate behavior for inter- and intra-blendfile commonalities --- ...7-59Z-texture-folder-commonality-script.md | 9 + ...2Z-texture-commonality-folder-structure.md | 5596 +++++++++++++++++ organize_textures.ps1 | 381 +- 3 files changed, 5866 insertions(+), 120 deletions(-) create mode 100644 .specstory/history/2025-12-19_18-52Z-texture-commonality-folder-structure.md 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 4c33b15..730c249 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 @@ -3441,3 +3441,12 @@ Got it, no more problems detected. --- +next issue: let's make sure it scans each folder separately. it goes \\textures\[Blendfile]\[Material] + +Intra-blendfile commonalities should go to `\\textures\[blendfile]\common` +Inter-blendfile commonalities should go to `\\textures\common` + +sound good? + +--- + diff --git a/.specstory/history/2025-12-19_18-52Z-texture-commonality-folder-structure.md b/.specstory/history/2025-12-19_18-52Z-texture-commonality-folder-structure.md new file mode 100644 index 0000000..b29c383 --- /dev/null +++ b/.specstory/history/2025-12-19_18-52Z-texture-commonality-folder-structure.md @@ -0,0 +1,5596 @@ + + + + +# Texture commonality folder structure (2025-12-19 18:52Z) + +_**User**_ + +context:@.specstory/history/2025-12-19_17-59Z-texture-folder-commonality-script.md + +next issue: let's make sure it scans each folder separately. it goes \\textures\[Blendfile]\[Material] + +Intra-blendfile commonalities should go to `\\textures\[blendfile]\common` +Inter-blendfile commonalities should go to `\\textures\common` + +sound good? + +--- + +_**Agent (model default, mode Plan)**_ + + +Reviewing the specstory and current implementation to understand the context. + + +--- + + +
Tool use: **read_file_v2** • Read file: a:\1 Amazon_Active_Projects\3 ProjectStructure\.specstory\history\2025-12-19_17-59Z-texture-folder-commonality-script.md + +
+
+ +--- + + +
Tool use: **read_file_v2** • Read file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.bat + +
+
+ +--- + + +
Tool use: **read_file_v2** • Read file: a:\1 Amazon_Active_Projects\3 ProjectStructure\organize_textures.ps1 + +
+
+ +--- + + +Reading the specstory file in sections to understand the context: + + +--- + + +
Tool use: **read_file_v2** • Read file: a:\1 Amazon_Active_Projects\3 ProjectStructure\.specstory\history\2025-12-19_17-59Z-texture-folder-commonality-script.md + +
+
+ +--- + + +Checking the folder structure to understand the layout: + + +--- + + +
+Tool use: **semantic_search_full** + + +Parameters: + +```json +{ + "query": "What is the folder structure for textures with blendfile and material subdirectories?", + "topK": 10, + "explanation": "" +} +``` +Result: + +```json +{ + "codeResults": [ + { + "codeBlock": { + "relativeWorkspacePath": ".\\components\\gitignore", + "range": { + "startPosition": {}, + "endPosition": { + "line": 125, + "column": 7 + } + }, + "contents": "# Blender Studio Git Management - .gitignore\n\n# Blender auto-save files\n*.blend1\n*.blend2\n*.blend3\n*.blend4\n*.blend5\n*.blend6\n*.blend7\n*.blend8\n*.blend9\n*.blend10\n*.blend11\n*.blend12\n*.blend13\n*.blend14\n*.blend15\n*.blend16\n*.blend17\n*.blend18\n*.blend19\n*.blend20\n*.blend21\n*.blend22\n*.blend23\n*.blend24\n*.blend25\n*.blend26\n*.blend27\n*.blend28\n*.blend29\n*.blend30\n*.blend31\n*.blend32\n\n# Blender cache and temporary files\n*.swp\n*.swo\n*~\n*.tmp\n*.temp\n\n# OS generated files\n.DS_Store\n.DS_Store?\n._*\n.Spotlight-V100\n.Trashes\nehthumbs.db\nThumbs.db\ndesktop.ini\n\n# Editor files\n.vscode/\n.idea/\n*.swp\n*.swo\n*~\n\n# Large media files (uncomment if you want to exclude rendered outputs)\n# *.mp4\n# *.avi\n# *.mov\n# *.png\n# *.jpg\n# *.jpeg\n# *.exr\n# *.hdr\n# *.tiff\n# *.tga\n\n# Audio files (uncomment if excluding)\n# *.wav\n# *.mp3\n# *.aac\n# *.ogg\n\n# Log files\n*.log\n\n# Python cache\n__pycache__/\n*.pyc\n*.pyo\n*.pyd\n.Python\n\n# Node modules (if using any web tools)\nnode_modules/\n\n# Environment files\n.env\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\n# Backup files\n*.bak\n*.backup\n*.old\n\n# Temporary files\ntemp/\ntmp/\ncache/ \n\nRenders/**\n!Renders/_zipped/\n!Renders/_zipped/**\n!Renders/**/\n!Renders/**/*.bat\n!Renders/**/*.log\nseq/\n\n# Premiere\n*.prlock\nAdobe Premiere Pro Video Previews/\nAdobe Premiere Pro Audio Previews/\nAdobe Premiere Pro (Beta) Video Previews/\nAdobe Premiere Pro (Beta) Audio Previews/\nfootage/\nplates/\n\nPr/RnR/", + "signatures": {}, + "detailedLines": [ + { + "text": "# Blender Studio Git Management - .gitignore", + "lineNumber": 1 + }, + { + "lineNumber": 2 + }, + { + "text": "# Blender auto-save files", + "lineNumber": 3 + }, + { + "text": "*.blend1", + "lineNumber": 4 + }, + { + "text": "*.blend2", + "lineNumber": 5 + }, + { + "text": "*.blend3", + "lineNumber": 6 + }, + { + "text": "*.blend4", + "lineNumber": 7 + }, + { + "text": "*.blend5", + "lineNumber": 8 + }, + { + "text": "*.blend6", + "lineNumber": 9 + }, + { + "text": "*.blend7", + "lineNumber": 10 + }, + { + "text": "*.blend8", + "lineNumber": 11 + }, + { + "text": "*.blend9", + "lineNumber": 12 + }, + { + "text": "*.blend10", + "lineNumber": 13 + }, + { + "text": "*.blend11", + "lineNumber": 14 + }, + { + "text": "*.blend12", + "lineNumber": 15 + }, + { + "text": "*.blend13", + "lineNumber": 16 + }, + { + "text": "*.blend14", + "lineNumber": 17 + }, + { + "text": "*.blend15", + "lineNumber": 18 + }, + { + "text": "*.blend16", + "lineNumber": 19 + }, + { + "text": "*.blend17", + "lineNumber": 20 + }, + { + "text": "*.blend18", + "lineNumber": 21 + }, + { + "text": "*.blend19", + "lineNumber": 22 + }, + { + "text": "*.blend20", + "lineNumber": 23 + }, + { + "text": "*.blend21", + "lineNumber": 24 + }, + { + "text": "*.blend22", + "lineNumber": 25 + }, + { + "text": "*.blend23", + "lineNumber": 26 + }, + { + "text": "*.blend24", + "lineNumber": 27 + }, + { + "text": "*.blend25", + "lineNumber": 28 + }, + { + "text": "*.blend26", + "lineNumber": 29 + }, + { + "text": "*.blend27", + "lineNumber": 30 + }, + { + "text": "*.blend28", + "lineNumber": 31 + }, + { + "text": "*.blend29", + "lineNumber": 32 + }, + { + "text": "*.blend30", + "lineNumber": 33 + }, + { + "text": "*.blend31", + "lineNumber": 34 + }, + { + "text": "*.blend32", + "lineNumber": 35 + }, + { + "lineNumber": 36 + }, + { + "text": "# Blender cache and temporary files", + "lineNumber": 37 + }, + { + "text": "*.swp", + "lineNumber": 38 + }, + { + "text": "*.swo", + "lineNumber": 39 + }, + { + "text": "*~", + "lineNumber": 40 + }, + { + "text": "*.tmp", + "lineNumber": 41 + }, + { + "text": "*.temp", + "lineNumber": 42 + }, + { + "lineNumber": 43 + }, + { + "text": "# OS generated files", + "lineNumber": 44 + }, + { + "text": ".DS_Store", + "lineNumber": 45 + }, + { + "text": ".DS_Store?", + "lineNumber": 46 + }, + { + "text": "._*", + "lineNumber": 47 + }, + { + "text": ".Spotlight-V100", + "lineNumber": 48 + }, + { + "text": ".Trashes", + "lineNumber": 49 + }, + { + "text": "ehthumbs.db", + "lineNumber": 50 + }, + { + "text": "Thumbs.db", + "lineNumber": 51 + }, + { + "text": "desktop.ini", + "lineNumber": 52 + }, + { + "lineNumber": 53 + }, + { + "text": "# Editor files", + "lineNumber": 54 + }, + { + "text": ".vscode/", + "lineNumber": 55 + }, + { + "text": ".idea/", + "lineNumber": 56 + }, + { + "text": "*.swp", + "lineNumber": 57 + }, + { + "text": "*.swo", + "lineNumber": 58 + }, + { + "text": "*~", + "lineNumber": 59 + }, + { + "lineNumber": 60 + }, + { + "text": "# Large media files (uncomment if you want to exclude rendered outputs)", + "lineNumber": 61 + }, + { + "text": "# *.mp4", + "lineNumber": 62 + }, + { + "text": "# *.avi", + "lineNumber": 63 + }, + { + "text": "# *.mov", + "lineNumber": 64 + }, + { + "text": "# *.png", + "lineNumber": 65 + }, + { + "text": "# *.jpg", + "lineNumber": 66 + }, + { + "text": "# *.jpeg", + "lineNumber": 67 + }, + { + "text": "# *.exr", + "lineNumber": 68 + }, + { + "text": "# *.hdr", + "lineNumber": 69 + }, + { + "text": "# *.tiff", + "lineNumber": 70 + }, + { + "text": "# *.tga", + "lineNumber": 71 + }, + { + "lineNumber": 72 + }, + { + "text": "# Audio files (uncomment if excluding)", + "lineNumber": 73 + }, + { + "text": "# *.wav", + "lineNumber": 74 + }, + { + "text": "# *.mp3", + "lineNumber": 75 + }, + { + "text": "# *.aac", + "lineNumber": 76 + }, + { + "text": "# *.ogg", + "lineNumber": 77 + }, + { + "lineNumber": 78 + }, + { + "text": "# Log files", + "lineNumber": 79 + }, + { + "text": "*.log", + "lineNumber": 80 + }, + { + "lineNumber": 81 + }, + { + "text": "# Python cache", + "lineNumber": 82 + }, + { + "text": "__pycache__/", + "lineNumber": 83 + }, + { + "text": "*.pyc", + "lineNumber": 84 + }, + { + "text": "*.pyo", + "lineNumber": 85 + }, + { + "text": "*.pyd", + "lineNumber": 86 + }, + { + "text": ".Python", + "lineNumber": 87 + }, + { + "lineNumber": 88 + }, + { + "text": "# Node modules (if using any web tools)", + "lineNumber": 89 + }, + { + "text": "node_modules/", + "lineNumber": 90 + }, + { + "lineNumber": 91 + }, + { + "text": "# Environment files", + "lineNumber": 92 + }, + { + "text": ".env", + "lineNumber": 93 + }, + { + "text": ".env.local", + "lineNumber": 94 + }, + { + "text": ".env.development.local", + "lineNumber": 95 + }, + { + "text": ".env.test.local", + "lineNumber": 96 + }, + { + "text": ".env.production.local", + "lineNumber": 97 + }, + { + "lineNumber": 98 + }, + { + "text": "# Backup files", + "lineNumber": 99 + }, + { + "text": "*.bak", + "lineNumber": 100 + }, + { + "text": "*.backup", + "lineNumber": 101 + }, + { + "text": "*.old", + "lineNumber": 102 + }, + { + "lineNumber": 103 + }, + { + "text": "# Temporary files", + "lineNumber": 104 + }, + { + "text": "temp/", + "lineNumber": 105 + }, + { + "text": "tmp/", + "lineNumber": 106 + }, + { + "text": "cache/ ", + "lineNumber": 107 + }, + { + "lineNumber": 108 + }, + { + "text": "Renders/**", + "lineNumber": 109 + }, + { + "text": "!Renders/_zipped/", + "lineNumber": 110 + }, + { + "text": "!Renders/_zipped/**", + "lineNumber": 111 + }, + { + "text": "!Renders/**/", + "lineNumber": 112 + }, + { + "text": "!Renders/**/*.bat", + "lineNumber": 113 + }, + { + "text": "!Renders/**/*.log", + "lineNumber": 114 + }, + { + "text": "seq/", + "lineNumber": 115 + }, + { + "lineNumber": 116 + }, + { + "text": "# Premiere", + "lineNumber": 117 + }, + { + "text": "*.prlock", + "lineNumber": 118 + }, + { + "text": "Adobe Premiere Pro Video Previews/", + "lineNumber": 119 + }, + { + "text": "Adobe Premiere Pro Audio Previews/", + "lineNumber": 120 + }, + { + "text": "Adobe Premiere Pro (Beta) Video Previews/", + "lineNumber": 121 + }, + { + "text": "Adobe Premiere Pro (Beta) Audio Previews/", + "lineNumber": 122 + }, + { + "text": "footage/", + "lineNumber": 123 + }, + { + "text": "plates/", + "lineNumber": 124 + }, + { + "lineNumber": 125 + }, + { + "text": "Pr/RnR/", + "lineNumber": 126 + } + ] + }, + "score": 0.354219913482666 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\NewProject.bat", + "range": { + "startPosition": {}, + "endPosition": { + "line": 63 + } + }, + "contents": "@echo off\nsetlocal EnableExtensions\n\nset \"SCRIPT_DIR=%~dp0\"\nset \"CONFIG_LOADER=%SCRIPT_DIR%ConfigLoader.ps1\"\nset \"CONFIG_PATH=%SCRIPT_DIR%config.json\"\n\nif not exist \"%CONFIG_LOADER%\" (\n echo [ERROR] ConfigLoader.ps1 not found next to NewProject.bat.\n exit /b 1\n)\n\nif not exist \"%CONFIG_PATH%\" (\n echo [ERROR] config.json not found next to NewProject.bat.\n exit /b 1\n)\n\nfor /f \"usebackq delims=\" %%I in (`powershell -NoProfile -ExecutionPolicy Bypass -Command ^\n \"Set-StrictMode -Version Latest; $loader = Resolve-Path -LiteralPath '%CONFIG_LOADER%' -ErrorAction Stop; . $loader.Path; Write-Output (Get-StructDirectory)\"`) do set \"STRUCT_DIR=%%I\"\n\nif not defined STRUCT_DIR (\n echo [ERROR] Unable to resolve ProjectStructure directory from config.\n exit /b 1\n)\n\n:: Get current date in YYYY-MM-DD format\nfor /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\"", + "signatures": {}, + "detailedLines": [ + { + "text": "@echo off", + "lineNumber": 1 + }, + { + "text": "setlocal EnableExtensions", + "lineNumber": 2 + }, + { + "lineNumber": 3 + }, + { + "text": "set \"SCRIPT_DIR=%~dp0\"", + "lineNumber": 4 + }, + { + "text": "set \"CONFIG_LOADER=%SCRIPT_DIR%ConfigLoader.ps1\"", + "lineNumber": 5 + }, + { + "text": "set \"CONFIG_PATH=%SCRIPT_DIR%config.json\"", + "lineNumber": 6 + }, + { + "lineNumber": 7 + }, + { + "text": "if not exist \"%CONFIG_LOADER%\" (", + "lineNumber": 8 + }, + { + "text": " echo [ERROR] ConfigLoader.ps1 not found next to NewProject.bat.", + "lineNumber": 9 + }, + { + "text": " exit /b 1", + "lineNumber": 10 + }, + { + "text": ")", + "lineNumber": 11 + }, + { + "lineNumber": 12 + }, + { + "text": "if not exist \"%CONFIG_PATH%\" (", + "lineNumber": 13 + }, + { + "text": " echo [ERROR] config.json not found next to NewProject.bat.", + "lineNumber": 14 + }, + { + "text": " exit /b 1", + "lineNumber": 15 + }, + { + "text": ")", + "lineNumber": 16 + }, + { + "lineNumber": 17 + }, + { + "text": "for /f \"usebackq delims=\" %%I in (`powershell -NoProfile -ExecutionPolicy Bypass -Command ^", + "lineNumber": 18 + }, + { + "text": " \"Set-StrictMode -Version Latest; $loader = Resolve-Path -LiteralPath '%CONFIG_LOADER%' -ErrorAction Stop; . $loader.Path; Write-Output (Get-StructDirectory)\"`) do set \"STRUCT_DIR=%%I\"", + "lineNumber": 19 + }, + { + "lineNumber": 20 + }, + { + "text": "if not defined STRUCT_DIR (", + "lineNumber": 21 + }, + { + "text": " echo [ERROR] Unable to resolve ProjectStructure directory from config.", + "lineNumber": 22 + }, + { + "text": " exit /b 1", + "lineNumber": 23 + }, + { + "text": ")", + "lineNumber": 24 + }, + { + "lineNumber": 25 + }, + { + "text": ":: Get current date in YYYY-MM-DD format", + "lineNumber": 26 + }, + { + "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 + } + ] + }, + "score": 0.3472631871700287 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\components\\gitattributes", + "range": { + "startPosition": {}, + "endPosition": { + "line": 53 + } + }, + "contents": "# Git LFS attributes configuration\n# All listed file types will be tracked by Git LFS\n\n# Video files\n*.avi filter=lfs diff=lfs merge=lfs -text\n*.mkv filter=lfs diff=lfs merge=lfs -text\n*.mov filter=lfs diff=lfs merge=lfs -text\n*.MOV filter=lfs diff=lfs merge=lfs -text\n*.mp4 filter=lfs diff=lfs merge=lfs -text\n*.webm filter=lfs diff=lfs merge=lfs -text\n\n# Image files\n*.bmp filter=lfs diff=lfs merge=lfs -text\n*.exr filter=lfs diff=lfs merge=lfs -text\n*.gif filter=lfs diff=lfs merge=lfs -text\n*.hdr filter=lfs diff=lfs merge=lfs -text\n*.jpg filter=lfs diff=lfs merge=lfs -text\n*.jpeg filter=lfs diff=lfs merge=lfs -text\n*.png filter=lfs diff=lfs merge=lfs -text\n*.tga filter=lfs diff=lfs merge=lfs -text\n*.tif filter=lfs diff=lfs merge=lfs -text\n*.tiff filter=lfs diff=lfs merge=lfs -text\n*.webp filter=lfs diff=lfs merge=lfs -text\n\n# 3D/CG files\n*.3ds filter=lfs diff=lfs merge=lfs -text\n*.abc filter=lfs diff=lfs merge=lfs -text\n*.blend filter=lfs diff=lfs merge=lfs -text\n*.blend1 filter=lfs diff=lfs merge=lfs -text\n*.blend2 filter=lfs diff=lfs merge=lfs -text\n*.bvh filter=lfs diff=lfs merge=lfs -text\n*.bvh.gz filter=lfs diff=lfs merge=lfs -text\n*.c4d filter=lfs diff=lfs merge=lfs -text\n*.dae filter=lfs diff=lfs merge=lfs -text\n*.fbx filter=lfs diff=lfs merge=lfs -text\n*.fbxkey filter=lfs diff=lfs merge=lfs -text\n*.ma filter=lfs diff=lfs merge=lfs -text\n*.max filter=lfs diff=lfs merge=lfs -text\n*.mb filter=lfs diff=lfs merge=lfs -text\n*.obj filter=lfs diff=lfs merge=lfs -text\n*.usd filter=lfs diff=lfs merge=lfs -text\n*.usdz filter=lfs diff=lfs merge=lfs -text\n*.vdb filter=lfs diff=lfs merge=lfs -text\n*.bphys filter=lfs diff=lfs merge=lfs -text\n*.bobj filter=lfs diff=lfs merge=lfs -text\n*.bvel filter=lfs diff=lfs merge=lfs -text\n*.bpointcache filter=lfs diff=lfs merge=lfs -text\n*.blob filter=lfs diff=lfs merge=lfs -text\n*.unitypackage filter=lfs diff=lfs merge=lfs -text\n\n# Houdini files\n*.hiplc filter=lfs diff=lfs merge=lfs -text\n*.bgeo filter=lfs diff=lfs merge=lfs -text", + "signatures": {}, + "detailedLines": [ + { + "text": "# Git LFS attributes configuration", + "lineNumber": 1 + }, + { + "text": "# All listed file types will be tracked by Git LFS", + "lineNumber": 2 + }, + { + "lineNumber": 3 + }, + { + "text": "# Video files", + "lineNumber": 4 + }, + { + "text": "*.avi filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 5 + }, + { + "text": "*.mkv filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 6 + }, + { + "text": "*.mov filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 7 + }, + { + "text": "*.MOV filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 8 + }, + { + "text": "*.mp4 filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 9 + }, + { + "text": "*.webm filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 10 + }, + { + "lineNumber": 11 + }, + { + "text": "# Image files", + "lineNumber": 12 + }, + { + "text": "*.bmp filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 13 + }, + { + "text": "*.exr filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 14 + }, + { + "text": "*.gif filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 15 + }, + { + "text": "*.hdr filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 16 + }, + { + "text": "*.jpg filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 17 + }, + { + "text": "*.jpeg filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 18 + }, + { + "text": "*.png filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 19 + }, + { + "text": "*.tga filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 20 + }, + { + "text": "*.tif filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 21 + }, + { + "text": "*.tiff filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 22 + }, + { + "text": "*.webp filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 23 + }, + { + "lineNumber": 24 + }, + { + "text": "# 3D/CG files", + "lineNumber": 25 + }, + { + "text": "*.3ds filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 26 + }, + { + "text": "*.abc filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 27 + }, + { + "text": "*.blend filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 28 + }, + { + "text": "*.blend1 filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 29 + }, + { + "text": "*.blend2 filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 30 + }, + { + "text": "*.bvh filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 31 + }, + { + "text": "*.bvh.gz filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 32 + }, + { + "text": "*.c4d filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 33 + }, + { + "text": "*.dae filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 34 + }, + { + "text": "*.fbx filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 35 + }, + { + "text": "*.fbxkey filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 36 + }, + { + "text": "*.ma filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 37 + }, + { + "text": "*.max filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 38 + }, + { + "text": "*.mb filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 39 + }, + { + "text": "*.obj filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 40 + }, + { + "text": "*.usd filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 41 + }, + { + "text": "*.usdz filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 42 + }, + { + "text": "*.vdb filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 43 + }, + { + "text": "*.bphys filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 44 + }, + { + "text": "*.bobj filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 45 + }, + { + "text": "*.bvel filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 46 + }, + { + "text": "*.bpointcache filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 47 + }, + { + "text": "*.blob filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 48 + }, + { + "text": "*.unitypackage filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 49 + }, + { + "lineNumber": 50 + }, + { + "text": "# Houdini files", + "lineNumber": 51 + }, + { + "text": "*.hiplc filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 52 + }, + { + "text": "*.bgeo filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 53 + } + ] + }, + "score": 0.3170698881149292 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\organize_textures.ps1", + "range": { + "startPosition": {}, + "endPosition": { + "line": 51 + } + }, + "contents": "# Script to organize texture files by checksum, moving all files to \\common and duplicates to \\common\\duplicates\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# Get all files recursively, excluding the \\common folder to avoid processing already-moved files\nWrite-Host \"Collecting files...\" -ForegroundColor Yellow\n$allFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object { $_.FullName -notlike \"*\\common\\*\" }\n\nif ($null -eq $allFiles -or $allFiles.Count -eq 0) {\n Write-Host \"No files found to process (excluding \\common folder).\" -ForegroundColor Yellow\n exit\n}\n\nWrite-Host \"Found $($allFiles.Count) files to process.\" -ForegroundColor Green\n\n# Calculate checksums for all files using parallel processing\nWrite-Host \"Calculating checksums using parallel processing (this may take a while)...\" -ForegroundColor Yellow\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$filesWithChecksums = $allFiles | ForEach-Object -Parallel $parallelScriptBlock -ThrottleLimit $throttleLimit | Where-Object { $null -ne $_ }\n\nWrite-Host \"Checksum calculation complete.\" -ForegroundColor Green", + "signatures": {}, + "detailedLines": [ + { + "text": "# Script to organize texture files by checksum, moving all files to \\common and duplicates to \\common\\duplicates", + "lineNumber": 1 + }, + { + "text": "# Usage: .\\organize_textures.ps1", + "lineNumber": 2 + }, + { + "lineNumber": 3 + }, + { + "text": "# Prompt user for texture folder path", + "lineNumber": 4 + }, + { + "text": "$textureFolderPath = Read-Host \"Enter texture folder path\"", + "lineNumber": 5 + }, + { + "lineNumber": 6 + }, + { + "text": "# Validate the input path", + "lineNumber": 7 + }, + { + "text": "if ([string]::IsNullOrWhiteSpace($textureFolderPath)) {", + "lineNumber": 8 + }, + { + "text": " Write-Host \"Error: No path provided.\" -ForegroundColor Red", + "lineNumber": 9 + }, + { + "text": " exit", + "lineNumber": 10 + }, + { + "text": "}", + "lineNumber": 11 + }, + { + "lineNumber": 12 + }, + { + "text": "if (-not (Test-Path -Path $textureFolderPath -PathType Container)) {", + "lineNumber": 13 + }, + { + "text": " Write-Host \"Error: Path does not exist or is not a directory: $textureFolderPath\" -ForegroundColor Red", + "lineNumber": 14 + }, + { + "text": " exit", + "lineNumber": 15 + }, + { + "text": "}", + "lineNumber": 16 + }, + { + "lineNumber": 17 + }, + { + "text": "# Resolve the full path", + "lineNumber": 18 + }, + { + "text": "$textureFolderPath = (Resolve-Path $textureFolderPath).ProviderPath", + "lineNumber": 19 + }, + { + "text": "Write-Host \"Processing texture folder: $textureFolderPath\" -ForegroundColor Cyan", + "lineNumber": 20 + }, + { + "lineNumber": 21 + }, + { + "text": "# Get all files recursively, excluding the \\common folder to avoid processing already-moved files", + "lineNumber": 22 + }, + { + "text": "Write-Host \"Collecting files...\" -ForegroundColor Yellow", + "lineNumber": 23 + }, + { + "text": "$allFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object { $_.FullName -notlike \"*\\common\\*\" }", + "lineNumber": 24 + }, + { + "lineNumber": 25 + }, + { + "text": "if ($null -eq $allFiles -or $allFiles.Count -eq 0) {", + "lineNumber": 26 + }, + { + "text": " Write-Host \"No files found to process (excluding \\common folder).\" -ForegroundColor Yellow", + "lineNumber": 27 + }, + { + "text": " exit", + "lineNumber": 28 + }, + { + "text": "}", + "lineNumber": 29 + }, + { + "lineNumber": 30 + }, + { + "text": "Write-Host \"Found $($allFiles.Count) files to process.\" -ForegroundColor Green", + "lineNumber": 31 + }, + { + "lineNumber": 32 + }, + { + "text": "# Calculate checksums for all files using parallel processing", + "lineNumber": 33 + }, + { + "text": "Write-Host \"Calculating checksums using parallel processing (this may take a while)...\" -ForegroundColor Yellow", + "lineNumber": 34 + }, + { + "text": "$throttleLimit = [Math]::Max(1, [Environment]::ProcessorCount)", + "lineNumber": 35 + }, + { + "text": "$parallelScriptBlock = {", + "lineNumber": 36 + }, + { + "text": " try {", + "lineNumber": 37 + }, + { + "text": " $hash = Get-FileHash -Path $_.FullName -Algorithm SHA256", + "lineNumber": 38 + }, + { + "text": " [PSCustomObject]@{", + "lineNumber": 39 + }, + { + "text": " File = $_", + "lineNumber": 40 + }, + { + "text": " Hash = $hash.Hash", + "lineNumber": 41 + }, + { + "text": " }", + "lineNumber": 42 + }, + { + "text": " } catch {", + "lineNumber": 43 + }, + { + "text": " Write-Warning \"Failed to calculate checksum for: $($_.FullName) - $($_.Exception.Message)\"", + "lineNumber": 44 + }, + { + "text": " $null", + "lineNumber": 45 + }, + { + "text": " }", + "lineNumber": 46 + }, + { + "text": "}", + "lineNumber": 47 + }, + { + "text": "$filesWithChecksums = $allFiles | ForEach-Object -Parallel $parallelScriptBlock -ThrottleLimit $throttleLimit | Where-Object { $null -ne $_ }", + "lineNumber": 48 + }, + { + "lineNumber": 49 + }, + { + "text": "Write-Host \"Checksum calculation complete.\" -ForegroundColor Green", + "lineNumber": 50 + } + ] + }, + "score": 0.3156466484069824 + }, + { + "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.30952730774879456 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\UpgradeToGitProj.bat", + "range": { + "startPosition": { + "line": 121 + }, + "endPosition": { + "line": 166 + } + }, + "contents": " )\n )\n )\n\n if \"!foundSubmodules!\"==\"1\" (\n if \"%DRY%\"==\"1\" echo [DRY] Using submodules under Blends\\animations\n for /d %%S in (\"%animDir%\\*\") do (\n set \"name=%%~nS\"\n set \"prefix=!name:~0,6!\"\n if /I not \"!prefix!\"==\"daily_\" (\n set \"submodName=%%~nS\"\n set \"_subdir=%rendersDir%\\!submodName!\"\n rem Ensure submodule dir exists and place helper scripts there\n if \"%DRY%\"==\"1\" (\n if not exist \"!_subdir!\" echo [DRY] mkdir \"!_subdir!\"\n if exist \"%scriptDir%UpdateSequences.bat\" echo [DRY] copy \"%scriptDir%UpdateSequences.bat\" \"!_subdir!\\UpdateSequences.bat\"\n if exist \"%scriptDir%ZipSeqArchv.bat\" echo [DRY] copy \"%scriptDir%ZipSeqArchv.bat\" \"!_subdir!\\ZipSeqArchv.bat\"\n if exist \"%scriptDir%UnzipSeqArchv.bat\" echo [DRY] copy \"%scriptDir%UnzipSeqArchv.bat\" \"!_subdir!\\UnzipSeqArchv.bat\"\n ) else (\n if not exist \"!_subdir!\" mkdir \"!_subdir!\" >nul 2>&1\n if exist \"%scriptDir%UpdateSequences.bat\" copy /Y \"%scriptDir%UpdateSequences.bat\" \"!_subdir!\\UpdateSequences.bat\" >nul\n if exist \"%scriptDir%ZipSeqArchv.bat\" copy /Y \"%scriptDir%ZipSeqArchv.bat\" \"!_subdir!\\ZipSeqArchv.bat\" >nul\n if exist \"%scriptDir%UnzipSeqArchv.bat\" copy /Y \"%scriptDir%UnzipSeqArchv.bat\" \"!_subdir!\\UnzipSeqArchv.bat\" >nul\n )\n for /d %%D in (\"%%S\\daily_*\") do (\n set \"dailyName=%%~nD\"\n set \"_src=%%D\\seq\"\n set \"_dst=%rendersDir%\\!submodName!\\!dailyName!\"\n set /a debugTotal+=1\n if \"%DRY%\"==\"1\" (\n if exist \"!_src!\" (\n echo [DRY] WOULD copy \"!_src!\" -^> \"!_dst!\"\n set /a debugPlanned+=1\n ) else (\n echo [DRY] Skip: missing \"!_src!\"\n set /a debugMissing+=1\n )\n )\n call :CopySeqToRenders \"!_src!\" \"!_dst!\"\n )\n )\n )\n set \"foundAny=1\"\n ) else (\n if \"%DRY%\"==\"1\" echo [DRY] No submodules found; using direct daily_* under animations", + "signatures": {}, + "detailedLines": [ + { + "text": " )", + "lineNumber": 122 + }, + { + "text": " )", + "lineNumber": 123 + }, + { + "text": " )", + "lineNumber": 124 + }, + { + "lineNumber": 125 + }, + { + "text": " if \"!foundSubmodules!\"==\"1\" (", + "lineNumber": 126 + }, + { + "text": " if \"%DRY%\"==\"1\" echo [DRY] Using submodules under Blends\\animations", + "lineNumber": 127 + }, + { + "text": " for /d %%S in (\"%animDir%\\*\") do (", + "lineNumber": 128 + }, + { + "text": " set \"name=%%~nS\"", + "lineNumber": 129 + }, + { + "text": " set \"prefix=!name:~0,6!\"", + "lineNumber": 130 + }, + { + "text": " if /I not \"!prefix!\"==\"daily_\" (", + "lineNumber": 131 + }, + { + "text": " set \"submodName=%%~nS\"", + "lineNumber": 132 + }, + { + "text": " set \"_subdir=%rendersDir%\\!submodName!\"", + "lineNumber": 133 + }, + { + "text": " rem Ensure submodule dir exists and place helper scripts there", + "lineNumber": 134 + }, + { + "text": " if \"%DRY%\"==\"1\" (", + "lineNumber": 135 + }, + { + "text": " if not exist \"!_subdir!\" echo [DRY] mkdir \"!_subdir!\"", + "lineNumber": 136 + }, + { + "text": " if exist \"%scriptDir%UpdateSequences.bat\" echo [DRY] copy \"%scriptDir%UpdateSequences.bat\" \"!_subdir!\\UpdateSequences.bat\"", + "lineNumber": 137 + }, + { + "text": " if exist \"%scriptDir%ZipSeqArchv.bat\" echo [DRY] copy \"%scriptDir%ZipSeqArchv.bat\" \"!_subdir!\\ZipSeqArchv.bat\"", + "lineNumber": 138 + }, + { + "text": " if exist \"%scriptDir%UnzipSeqArchv.bat\" echo [DRY] copy \"%scriptDir%UnzipSeqArchv.bat\" \"!_subdir!\\UnzipSeqArchv.bat\"", + "lineNumber": 139 + }, + { + "text": " ) else (", + "lineNumber": 140 + }, + { + "text": " if not exist \"!_subdir!\" mkdir \"!_subdir!\" >nul 2>&1", + "lineNumber": 141 + }, + { + "text": " if exist \"%scriptDir%UpdateSequences.bat\" copy /Y \"%scriptDir%UpdateSequences.bat\" \"!_subdir!\\UpdateSequences.bat\" >nul", + "lineNumber": 142 + }, + { + "text": " if exist \"%scriptDir%ZipSeqArchv.bat\" copy /Y \"%scriptDir%ZipSeqArchv.bat\" \"!_subdir!\\ZipSeqArchv.bat\" >nul", + "lineNumber": 143 + }, + { + "text": " if exist \"%scriptDir%UnzipSeqArchv.bat\" copy /Y \"%scriptDir%UnzipSeqArchv.bat\" \"!_subdir!\\UnzipSeqArchv.bat\" >nul", + "lineNumber": 144 + }, + { + "text": " )", + "lineNumber": 145 + }, + { + "text": " for /d %%D in (\"%%S\\daily_*\") do (", + "lineNumber": 146 + }, + { + "text": " set \"dailyName=%%~nD\"", + "lineNumber": 147 + }, + { + "text": " set \"_src=%%D\\seq\"", + "lineNumber": 148 + }, + { + "text": " set \"_dst=%rendersDir%\\!submodName!\\!dailyName!\"", + "lineNumber": 149 + }, + { + "text": " set /a debugTotal+=1", + "lineNumber": 150 + }, + { + "text": " if \"%DRY%\"==\"1\" (", + "lineNumber": 151 + }, + { + "text": " if exist \"!_src!\" (", + "lineNumber": 152 + }, + { + "text": " echo [DRY] WOULD copy \"!_src!\" -^> \"!_dst!\"", + "lineNumber": 153 + }, + { + "text": " set /a debugPlanned+=1", + "lineNumber": 154 + }, + { + "text": " ) else (", + "lineNumber": 155 + }, + { + "text": " echo [DRY] Skip: missing \"!_src!\"", + "lineNumber": 156 + }, + { + "text": " set /a debugMissing+=1", + "lineNumber": 157 + }, + { + "text": " )", + "lineNumber": 158 + }, + { + "text": " )", + "lineNumber": 159 + }, + { + "text": " call :CopySeqToRenders \"!_src!\" \"!_dst!\"", + "lineNumber": 160 + }, + { + "text": " )", + "lineNumber": 161 + }, + { + "text": " )", + "lineNumber": 162 + }, + { + "text": " )", + "lineNumber": 163 + }, + { + "text": " set \"foundAny=1\"", + "lineNumber": 164 + }, + { + "text": " ) else (", + "lineNumber": 165 + }, + { + "text": " if \"%DRY%\"==\"1\" echo [DRY] No submodules found; using direct daily_* under animations", + "lineNumber": 166 + } + ] + }, + "score": 0.2996269464492798 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\UpgradeToGitProj.bat", + "range": { + "startPosition": { + "line": 58 + }, + "endPosition": { + "line": 126, + "column": 4 + } + }, + "contents": "for %%F in (ConfigLoader.ps1 config.json) do (\n if exist \"%scriptDir%%%F\" (\n if \"%DRY%\"==\"1\" (\n echo [DRY] copy \"%scriptDir%%%F\" \"%rendersDir%\\%%F\"\n ) else (\n copy /Y \"%scriptDir%%%F\" \"%rendersDir%\\%%F\" >nul\n )\n ) else (\n echo [WARN] Missing template: \"%scriptDir%%%F\"\n )\n)\n\n:: -----------------------------\n:: Merge .gitignore and .gitattributes from templates\n:: -----------------------------\nset \"tplGitIgnore=%scriptDir%components\\gitignore\"\nset \"dstGitIgnore=%projectDir%\\.gitignore\"\nset \"tplGitAttr=%scriptDir%components\\gitattributes\"\nset \"dstGitAttr=%projectDir%\\.gitattributes\"\n\ncall :MergeTemplate \"%tplGitIgnore%\" \"%dstGitIgnore%\"\ncall :MergeTemplate \"%tplGitAttr%\" \"%dstGitAttr%\"\n\n:: -----------------------------\n:: Initialize git and Git LFS\n:: -----------------------------\nif not exist \"%projectDir%\\.git\" (\n if \"%DRY%\"==\"1\" (\n echo [DRY] git init\n ) else (\n pushd \"%projectDir%\" >nul\n git init\n popd >nul\n )\n)\n\nif \"%DRY%\"==\"1\" (\n echo [DRY] git lfs install\n) else (\n pushd \"%projectDir%\" >nul\n git lfs install\n popd >nul\n)\n\n:: -----------------------------\n:: Collect seq outputs from daily_* into Renders\n:: -----------------------------\nset \"animDir=%projectDir%\\Blends\\animations\"\nset \"foundAny=0\"\nset \"foundSubmodules=0\"\n\nif exist \"%animDir%\" (\n if \"%DRY%\"==\"1\" echo [DRY] Scanning animations dir: \"%animDir%\"\n :: Detect submodules: first-level folders under animations that contain daily_*\n for /d %%S in (\"%animDir%\\*\") do (\n set \"name=%%~nS\"\n set \"prefix=!name:~0,6!\"\n if /I not \"!prefix!\"==\"daily_\" (\n for /d %%D in (\"%%S\\daily_*\") do (\n set \"foundSubmodules=1\"\n )\n if \"%DRY%\"==\"1\" (\n if exist \"%%S\\daily_*\" echo [DRY] Detected submodule: \"%%~nS\"\n )\n )\n )\n\n if \"!foundSubmodules!\"==\"1\" (\n ", + "signatures": {}, + "detailedLines": [ + { + "text": "for %%F in (ConfigLoader.ps1 config.json) do (", + "lineNumber": 59 + }, + { + "text": " if exist \"%scriptDir%%%F\" (", + "lineNumber": 60 + }, + { + "text": " if \"%DRY%\"==\"1\" (", + "lineNumber": 61 + }, + { + "text": " echo [DRY] copy \"%scriptDir%%%F\" \"%rendersDir%\\%%F\"", + "lineNumber": 62 + }, + { + "text": " ) else (", + "lineNumber": 63 + }, + { + "text": " copy /Y \"%scriptDir%%%F\" \"%rendersDir%\\%%F\" >nul", + "lineNumber": 64 + }, + { + "text": " )", + "lineNumber": 65 + }, + { + "text": " ) else (", + "lineNumber": 66 + }, + { + "text": " echo [WARN] Missing template: \"%scriptDir%%%F\"", + "lineNumber": 67 + }, + { + "text": " )", + "lineNumber": 68 + }, + { + "text": ")", + "lineNumber": 69 + }, + { + "lineNumber": 70 + }, + { + "text": ":: -----------------------------", + "lineNumber": 71 + }, + { + "text": ":: Merge .gitignore and .gitattributes from templates", + "lineNumber": 72 + }, + { + "text": ":: -----------------------------", + "lineNumber": 73 + }, + { + "text": "set \"tplGitIgnore=%scriptDir%components\\gitignore\"", + "lineNumber": 74 + }, + { + "text": "set \"dstGitIgnore=%projectDir%\\.gitignore\"", + "lineNumber": 75 + }, + { + "text": "set \"tplGitAttr=%scriptDir%components\\gitattributes\"", + "lineNumber": 76 + }, + { + "text": "set \"dstGitAttr=%projectDir%\\.gitattributes\"", + "lineNumber": 77 + }, + { + "lineNumber": 78 + }, + { + "text": "call :MergeTemplate \"%tplGitIgnore%\" \"%dstGitIgnore%\"", + "lineNumber": 79 + }, + { + "text": "call :MergeTemplate \"%tplGitAttr%\" \"%dstGitAttr%\"", + "lineNumber": 80 + }, + { + "lineNumber": 81 + }, + { + "text": ":: -----------------------------", + "lineNumber": 82 + }, + { + "text": ":: Initialize git and Git LFS", + "lineNumber": 83 + }, + { + "text": ":: -----------------------------", + "lineNumber": 84 + }, + { + "text": "if not exist \"%projectDir%\\.git\" (", + "lineNumber": 85 + }, + { + "text": " if \"%DRY%\"==\"1\" (", + "lineNumber": 86 + }, + { + "text": " echo [DRY] git init", + "lineNumber": 87 + }, + { + "text": " ) else (", + "lineNumber": 88 + }, + { + "text": " pushd \"%projectDir%\" >nul", + "lineNumber": 89 + }, + { + "text": " git init", + "lineNumber": 90 + }, + { + "text": " popd >nul", + "lineNumber": 91 + }, + { + "text": " )", + "lineNumber": 92 + }, + { + "text": ")", + "lineNumber": 93 + }, + { + "lineNumber": 94 + }, + { + "text": "if \"%DRY%\"==\"1\" (", + "lineNumber": 95 + }, + { + "text": " echo [DRY] git lfs install", + "lineNumber": 96 + }, + { + "text": ") else (", + "lineNumber": 97 + }, + { + "text": " pushd \"%projectDir%\" >nul", + "lineNumber": 98 + }, + { + "text": " git lfs install", + "lineNumber": 99 + }, + { + "text": " popd >nul", + "lineNumber": 100 + }, + { + "text": ")", + "lineNumber": 101 + }, + { + "lineNumber": 102 + }, + { + "text": ":: -----------------------------", + "lineNumber": 103 + }, + { + "text": ":: Collect seq outputs from daily_* into Renders", + "lineNumber": 104 + }, + { + "text": ":: -----------------------------", + "lineNumber": 105 + }, + { + "text": "set \"animDir=%projectDir%\\Blends\\animations\"", + "lineNumber": 106 + }, + { + "text": "set \"foundAny=0\"", + "lineNumber": 107 + }, + { + "text": "set \"foundSubmodules=0\"", + "lineNumber": 108 + }, + { + "lineNumber": 109 + }, + { + "text": "if exist \"%animDir%\" (", + "lineNumber": 110 + }, + { + "text": " if \"%DRY%\"==\"1\" echo [DRY] Scanning animations dir: \"%animDir%\"", + "lineNumber": 111 + }, + { + "text": " :: Detect submodules: first-level folders under animations that contain daily_*", + "lineNumber": 112 + }, + { + "text": " for /d %%S in (\"%animDir%\\*\") do (", + "lineNumber": 113 + }, + { + "text": " set \"name=%%~nS\"", + "lineNumber": 114 + }, + { + "text": " set \"prefix=!name:~0,6!\"", + "lineNumber": 115 + }, + { + "text": " if /I not \"!prefix!\"==\"daily_\" (", + "lineNumber": 116 + }, + { + "text": " for /d %%D in (\"%%S\\daily_*\") do (", + "lineNumber": 117 + }, + { + "text": " set \"foundSubmodules=1\"", + "lineNumber": 118 + }, + { + "text": " )", + "lineNumber": 119 + }, + { + "text": " if \"%DRY%\"==\"1\" (", + "lineNumber": 120 + }, + { + "text": " if exist \"%%S\\daily_*\" echo [DRY] Detected submodule: \"%%~nS\"", + "lineNumber": 121 + }, + { + "text": " )", + "lineNumber": 122 + }, + { + "text": " )", + "lineNumber": 123 + }, + { + "text": " )", + "lineNumber": 124 + }, + { + "lineNumber": 125 + }, + { + "text": " if \"!foundSubmodules!\"==\"1\" (", + "lineNumber": 126 + }, + { + "text": " ", + "lineNumber": 127 + } + ] + }, + "score": 0.29278281331062317 + }, + { + "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.2842274010181427 + }, + { + "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.2787865400314331 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\components\\gitattributes", + "range": { + "startPosition": { + "line": 51 + }, + "endPosition": { + "line": 111, + "column": 40 + } + }, + "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\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\n# Python files\n*.npz filter=lfs diff=lfs merge=lfs -text\n\n# Adobe Alternatives\n*.xcf filter=lfs diff=lfs merge=lfs -text\n*.af filter=lfs diff=lfs merge=lfs -text", + "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 + }, + { + "lineNumber": 69 + }, + { + "text": "# Archive/Compression files", + "lineNumber": 70 + }, + { + "text": "*.7z filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 71 + }, + { + "text": "*.bz2 filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 72 + }, + { + "text": "*.gz filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 73 + }, + { + "text": "*.rar filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 74 + }, + { + "text": "*.tar filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 75 + }, + { + "text": "*.zip filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 76 + }, + { + "lineNumber": 77 + }, + { + "text": "# Documents", + "lineNumber": 78 + }, + { + "text": "*.docx filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 79 + }, + { + "text": "*.xlsx filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 80 + }, + { + "text": "*.eps filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 81 + }, + { + "text": "*.pdf filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 82 + }, + { + "lineNumber": 83 + }, + { + "text": "# Adobe files", + "lineNumber": 84 + }, + { + "text": "*.aegraphic filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 85 + }, + { + "text": "*.aep filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 86 + }, + { + "text": "*.prel filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 87 + }, + { + "text": "*.prin filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 88 + }, + { + "text": "*.prmf filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 89 + }, + { + "text": "*.prproj filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 90 + }, + { + "text": "*.ai filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 91 + }, + { + "text": "*.psd filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 92 + }, + { + "lineNumber": 93 + }, + { + "text": "# Davinci Resolve files", + "lineNumber": 94 + }, + { + "text": "*.dpx filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 95 + }, + { + "text": "*.drp filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 96 + }, + { + "lineNumber": 97 + }, + { + "text": "# Data files", + "lineNumber": 98 + }, + { + "text": "*.h5 filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 99 + }, + { + "text": "*.hdf5 filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 100 + }, + { + "lineNumber": 101 + }, + { + "text": "# Other", + "lineNumber": 102 + }, + { + "text": "*.uni filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 103 + }, + { + "text": "*.pdn filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 104 + }, + { + "text": "*.pur filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 105 + }, + { + "lineNumber": 106 + }, + { + "text": "# Python files", + "lineNumber": 107 + }, + { + "text": "*.npz filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 108 + }, + { + "lineNumber": 109 + }, + { + "text": "# Adobe Alternatives", + "lineNumber": 110 + }, + { + "text": "*.xcf filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 111 + }, + { + "text": "*.af filter=lfs diff=lfs merge=lfs -text", + "lineNumber": 112 + } + ] + }, + "score": 0.27743393182754517 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\compress_blend_files.bat", + "range": { + "startPosition": {}, + "endPosition": { + "line": 66 + } + }, + "contents": "@echo off\nsetlocal enabledelayedexpansion\n\necho Starting Blender file compression...\n\nREM Check if files were dragged onto the batch file\nif \"%~1\"==\"\" (\n echo.\n echo Usage: Drag .blend files onto this batch file to compress them.\n echo Output will be saved to the \\output folder.\n echo.\n pause\n exit /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\"\n\nREM Create a temporary Python script for compression\nset \"TEMP_SCRIPT=compress_blend_temp.py\"\necho Creating Python script: !TEMP_SCRIPT!\n\n(\necho import bpy\necho import os\necho import sys\necho.\necho # Enable compression globally\necho bpy.context.preferences.filepaths.save_version = 0\necho bpy.context.preferences.filepaths.use_file_compression = True\necho.\necho # Create output directory if it doesn't exist\necho if not os.path.exists^(\"output\"^):\necho os.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 compress\"^)\necho.\necho def is_compressed_file^(path^):\necho try:\necho with open^(path, 'rb'^) as f:\necho header = f.read^(4^)\necho if header[:2] == b'\\x1f\\x8b': # gzip\necho return True\necho if header == b'\\x28\\xb5\\x2f\\xfd': # zstd\necho return True\necho return False\necho except Exception:\necho return False\necho.\necho for blend_file in blend_files:\necho if blend_file.lower^(^).endswith^(\".blend\"^):\necho try:\necho # Create output path in output folder\necho filename = os.path.basename^(blend_file^)\necho output_file = os.path.join^(\"output\", filename^)\necho # Check if output file already exists", + "signatures": {}, + "detailedLines": [ + { + "text": "@echo off", + "lineNumber": 1 + }, + { + "text": "setlocal enabledelayedexpansion", + "lineNumber": 2 + }, + { + "lineNumber": 3 + }, + { + "text": "echo Starting Blender file compression...", + "lineNumber": 4 + }, + { + "lineNumber": 5 + }, + { + "text": "REM Check if files were dragged onto the batch file", + "lineNumber": 6 + }, + { + "text": "if \"%~1\"==\"\" (", + "lineNumber": 7 + }, + { + "text": " echo.", + "lineNumber": 8 + }, + { + "text": " echo Usage: Drag .blend files onto this batch file to compress them.", + "lineNumber": 9 + }, + { + "text": " echo Output will be saved to the \\output folder.", + "lineNumber": 10 + }, + { + "text": " echo.", + "lineNumber": 11 + }, + { + "text": " pause", + "lineNumber": 12 + }, + { + "text": " exit /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 + }, + { + "lineNumber": 25 + }, + { + "text": "REM Create a temporary Python script for compression", + "lineNumber": 26 + }, + { + "text": "set \"TEMP_SCRIPT=compress_blend_temp.py\"", + "lineNumber": 27 + }, + { + "text": "echo Creating Python script: !TEMP_SCRIPT!", + "lineNumber": 28 + }, + { + "lineNumber": 29 + }, + { + "text": "(", + "lineNumber": 30 + }, + { + "text": "echo import bpy", + "lineNumber": 31 + }, + { + "text": "echo import os", + "lineNumber": 32 + }, + { + "text": "echo import sys", + "lineNumber": 33 + }, + { + "text": "echo.", + "lineNumber": 34 + }, + { + "text": "echo # Enable compression globally", + "lineNumber": 35 + }, + { + "text": "echo bpy.context.preferences.filepaths.save_version = 0", + "lineNumber": 36 + }, + { + "text": "echo bpy.context.preferences.filepaths.use_file_compression = True", + "lineNumber": 37 + }, + { + "text": "echo.", + "lineNumber": 38 + }, + { + "text": "echo # Create output directory if it doesn't exist", + "lineNumber": 39 + }, + { + "text": "echo if not os.path.exists^(\"output\"^):", + "lineNumber": 40 + }, + { + "text": "echo os.makedirs^(\"output\"^)", + "lineNumber": 41 + }, + { + "text": "echo.", + "lineNumber": 42 + }, + { + "text": "echo # Get command line arguments ^(the dragged files^)", + "lineNumber": 43 + }, + { + "text": "echo blend_files = sys.argv[sys.argv.index^(\"--\"^) + 1:] if \"--\" in sys.argv else []", + "lineNumber": 44 + }, + { + "text": "echo.", + "lineNumber": 45 + }, + { + "text": "echo print^(\"Found \" + str^(len^(blend_files^)^) + \" .blend files to compress\"^)", + "lineNumber": 46 + }, + { + "text": "echo.", + "lineNumber": 47 + }, + { + "text": "echo def is_compressed_file^(path^):", + "lineNumber": 48 + }, + { + "text": "echo try:", + "lineNumber": 49 + }, + { + "text": "echo with open^(path, 'rb'^) as f:", + "lineNumber": 50 + }, + { + "text": "echo header = f.read^(4^)", + "lineNumber": 51 + }, + { + "text": "echo if header[:2] == b'\\x1f\\x8b': # gzip", + "lineNumber": 52 + }, + { + "text": "echo return True", + "lineNumber": 53 + }, + { + "text": "echo if header == b'\\x28\\xb5\\x2f\\xfd': # zstd", + "lineNumber": 54 + }, + { + "text": "echo return True", + "lineNumber": 55 + }, + { + "text": "echo return False", + "lineNumber": 56 + }, + { + "text": "echo except Exception:", + "lineNumber": 57 + }, + { + "text": "echo return False", + "lineNumber": 58 + }, + { + "text": "echo.", + "lineNumber": 59 + }, + { + "text": "echo for blend_file in blend_files:", + "lineNumber": 60 + }, + { + "text": "echo if blend_file.lower^(^).endswith^(\".blend\"^):", + "lineNumber": 61 + }, + { + "text": "echo try:", + "lineNumber": 62 + }, + { + "text": "echo # Create output path in output folder", + "lineNumber": 63 + }, + { + "text": "echo filename = os.path.basename^(blend_file^)", + "lineNumber": 64 + }, + { + "text": "echo output_file = os.path.join^(\"output\", filename^)", + "lineNumber": 65 + }, + { + "text": "echo # Check if output file already exists", + "lineNumber": 66 + } + ] + }, + "score": 0.27458083629608154 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\organize_textures.ps1", + "range": { + "startPosition": { + "line": 44 + }, + "endPosition": { + "line": 83, + "column": 8 + } + }, + "contents": " $null\n }\n}\n$filesWithChecksums = $allFiles | ForEach-Object -Parallel $parallelScriptBlock -ThrottleLimit $throttleLimit | Where-Object { $null -ne $_ }\n\nWrite-Host \"Checksum calculation complete.\" -ForegroundColor Green\n\n# Group files by checksum\nWrite-Host \"Grouping files by checksum...\" -ForegroundColor Yellow\n$groupedByChecksum = $filesWithChecksums | Group-Object -Property Hash\n\nWrite-Host \"Found $($groupedByChecksum.Count) unique checksums.\" -ForegroundColor Green\n\n# Create \\common and \\common\\duplicates directories\n$commonPath = Join-Path -Path $textureFolderPath -ChildPath \"common\"\n$duplicatesPath = Join-Path -Path $commonPath -ChildPath \"duplicates\"\n\nif (-not (Test-Path -Path $commonPath -PathType Container)) {\n New-Item -ItemType Directory -Path $commonPath | Out-Null\n Write-Host \"Created directory: $commonPath\" -ForegroundColor Green\n}\n\nif (-not (Test-Path -Path $duplicatesPath -PathType Container)) {\n New-Item -ItemType Directory -Path $duplicatesPath | Out-Null\n Write-Host \"Created directory: $duplicatesPath\" -ForegroundColor Green\n}\n\n# Track filenames already in \\common to handle name conflicts\n$filesInCommon = @{}\n\n# Process each checksum group\nWrite-Host \"Moving files to \\common and \\common\\duplicates...\" -ForegroundColor Yellow\n$movedCount = 0\n$duplicateCount = 0\n\nforeach ($group in $groupedByChecksum) {\n $files = $group.Group\n \n if ($files.Count -eq 1) {\n ", + "signatures": {}, + "detailedLines": [ + { + "text": " $null", + "lineNumber": 45 + }, + { + "text": " }", + "lineNumber": 46 + }, + { + "text": "}", + "lineNumber": 47 + }, + { + "text": "$filesWithChecksums = $allFiles | ForEach-Object -Parallel $parallelScriptBlock -ThrottleLimit $throttleLimit | Where-Object { $null -ne $_ }", + "lineNumber": 48 + }, + { + "lineNumber": 49 + }, + { + "text": "Write-Host \"Checksum calculation complete.\" -ForegroundColor Green", + "lineNumber": 50 + }, + { + "lineNumber": 51 + }, + { + "text": "# Group files by checksum", + "lineNumber": 52 + }, + { + "text": "Write-Host \"Grouping files by checksum...\" -ForegroundColor Yellow", + "lineNumber": 53 + }, + { + "text": "$groupedByChecksum = $filesWithChecksums | Group-Object -Property Hash", + "lineNumber": 54 + }, + { + "lineNumber": 55 + }, + { + "text": "Write-Host \"Found $($groupedByChecksum.Count) unique checksums.\" -ForegroundColor Green", + "lineNumber": 56 + }, + { + "lineNumber": 57 + }, + { + "text": "# Create \\common and \\common\\duplicates directories", + "lineNumber": 58 + }, + { + "text": "$commonPath = Join-Path -Path $textureFolderPath -ChildPath \"common\"", + "lineNumber": 59 + }, + { + "text": "$duplicatesPath = Join-Path -Path $commonPath -ChildPath \"duplicates\"", + "lineNumber": 60 + }, + { + "lineNumber": 61 + }, + { + "text": "if (-not (Test-Path -Path $commonPath -PathType Container)) {", + "lineNumber": 62 + }, + { + "text": " New-Item -ItemType Directory -Path $commonPath | Out-Null", + "lineNumber": 63 + }, + { + "text": " Write-Host \"Created directory: $commonPath\" -ForegroundColor Green", + "lineNumber": 64 + }, + { + "text": "}", + "lineNumber": 65 + }, + { + "lineNumber": 66 + }, + { + "text": "if (-not (Test-Path -Path $duplicatesPath -PathType Container)) {", + "lineNumber": 67 + }, + { + "text": " New-Item -ItemType Directory -Path $duplicatesPath | Out-Null", + "lineNumber": 68 + }, + { + "text": " Write-Host \"Created directory: $duplicatesPath\" -ForegroundColor Green", + "lineNumber": 69 + }, + { + "text": "}", + "lineNumber": 70 + }, + { + "lineNumber": 71 + }, + { + "text": "# Track filenames already in \\common to handle name conflicts", + "lineNumber": 72 + }, + { + "text": "$filesInCommon = @{}", + "lineNumber": 73 + }, + { + "lineNumber": 74 + }, + { + "text": "# Process each checksum group", + "lineNumber": 75 + }, + { + "text": "Write-Host \"Moving files to \\common and \\common\\duplicates...\" -ForegroundColor Yellow", + "lineNumber": 76 + }, + { + "text": "$movedCount = 0", + "lineNumber": 77 + }, + { + "text": "$duplicateCount = 0", + "lineNumber": 78 + }, + { + "lineNumber": 79 + }, + { + "text": "foreach ($group in $groupedByChecksum) {", + "lineNumber": 80 + }, + { + "text": " $files = $group.Group", + "lineNumber": 81 + }, + { + "text": " ", + "lineNumber": 82 + }, + { + "text": " if ($files.Count -eq 1) {", + "lineNumber": 83 + }, + { + "text": " ", + "lineNumber": 84 + } + ] + }, + "score": 0.2703059911727905 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\NewProject.bat", + "range": { + "startPosition": { + "line": 61 + }, + "endPosition": { + "line": 83 + } + }, + "contents": "if 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\necho Project structure created successfully in folder: %projectRoot%\npause ", + "signatures": {}, + "detailedLines": [ + { + "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": "echo Project structure created successfully in folder: %projectRoot%", + "lineNumber": 82 + }, + { + "text": "pause ", + "lineNumber": 83 + } + ] + }, + "score": 0.2641300559043884 + }, + { + "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.263225793838501 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\replace_cel_with_bsdf.py", + "range": { + "startPosition": { + "line": 188 + }, + "endPosition": { + "line": 355 + } + }, + "contents": "def replace_cel_materials():\n\n \n # Build a mapping from base BSDF name to BSDF material (without suffix)\n bsdf_base_map = {bsdf_pattern.match(mat.name).group(1): mat for mat in materials if bsdf_pattern.match(mat.name)}\n \n # Build a mapping from exact material names to materials\n exact_material_map = {mat.name: mat for mat in materials}\n\n # Helpers to normalize names (case-insensitive, ignore numeric suffixes and library suffix)\n def normalize_base(name):\n base_name = name.split(\".blend\")[0] if \".blend\" in name else name\n match = re.match(r\"^(.*?)(\\.\\d{3})?$\", base_name)\n base_name = match.group(1) if match else base_name\n return base_name.strip().casefold()\n\n # Map normalized base name -> list of materials\n materials_by_base = {}\n for mat in materials:\n base = normalize_base(mat.name)\n materials_by_base.setdefault(base, []).append(mat)\n\n # Normalize BSDF base name map for robust target lookups\n bsdf_base_map_normalized = {normalize_base(base): mat for base, mat in bsdf_base_map.items()}\n \n replacements_made = 0\n missing_targets = []\n \n # Process custom mappings first (case/suffix-insensitive)", + "signatures": { + "ranges": [ + { + "startPosition": { + "line": 189, + "column": 1 + }, + "endPosition": { + "line": 190, + "column": 5 + } + } + ] + }, + "detailedLines": [ + { + "text": "def replace_cel_materials():", + "lineNumber": 189, + "isSignature": true + }, + { + "lineNumber": 235 + }, + { + "text": " ", + "lineNumber": 236 + }, + { + "text": " # Build a mapping from base BSDF name to BSDF material (without suffix)", + "lineNumber": 237 + }, + { + "text": " bsdf_base_map = {bsdf_pattern.match(mat.name).group(1): mat for mat in materials if bsdf_pattern.match(mat.name)}", + "lineNumber": 238 + }, + { + "text": " ", + "lineNumber": 239 + }, + { + "text": " # Build a mapping from exact material names to materials", + "lineNumber": 240 + }, + { + "text": " exact_material_map = {mat.name: mat for mat in materials}", + "lineNumber": 241 + }, + { + "lineNumber": 242 + }, + { + "text": " # Helpers to normalize names (case-insensitive, ignore numeric suffixes and library suffix)", + "lineNumber": 243 + }, + { + "text": " def normalize_base(name):", + "lineNumber": 244 + }, + { + "text": " base_name = name.split(\".blend\")[0] if \".blend\" in name else name", + "lineNumber": 245 + }, + { + "text": " match = re.match(r\"^(.*?)(\\.\\d{3})?$\", base_name)", + "lineNumber": 246 + }, + { + "text": " base_name = match.group(1) if match else base_name", + "lineNumber": 247 + }, + { + "text": " return base_name.strip().casefold()", + "lineNumber": 248 + }, + { + "lineNumber": 249 + }, + { + "text": " # Map normalized base name -> list of materials", + "lineNumber": 250 + }, + { + "text": " materials_by_base = {}", + "lineNumber": 251 + }, + { + "text": " for mat in materials:", + "lineNumber": 252 + }, + { + "text": " base = normalize_base(mat.name)", + "lineNumber": 253 + }, + { + "text": " materials_by_base.setdefault(base, []).append(mat)", + "lineNumber": 254 + }, + { + "lineNumber": 255 + }, + { + "text": " # Normalize BSDF base name map for robust target lookups", + "lineNumber": 256 + }, + { + "text": " bsdf_base_map_normalized = {normalize_base(base): mat for base, mat in bsdf_base_map.items()}", + "lineNumber": 257 + }, + { + "text": " ", + "lineNumber": 258 + }, + { + "text": " replacements_made = 0", + "lineNumber": 259 + }, + { + "text": " missing_targets = []", + "lineNumber": 260 + }, + { + "text": " ", + "lineNumber": 261 + }, + { + "text": " # Process custom mappings first (case/suffix-insensitive)", + "lineNumber": 262 + } + ] + }, + "score": 0.2553691864013672 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\UpgradeToGitProj.bat", + "range": { + "startPosition": {}, + "endPosition": { + "line": 61, + "column": 6 + } + }, + "contents": "@echo off\nsetlocal EnableExtensions EnableDelayedExpansion\n\n:: UpgradeToGitProj.bat\n:: Run this inside an existing (pre-git) project root.\n:: - Merges .gitignore and .gitattributes from components/ templates\n:: - Initializes git and installs Git LFS\n:: - Creates Renders, copies helper scripts\n:: - Collects seq/ outputs from daily_* folders under Blends\\animations (with submodule support)\n\n:: -----------------------------\n:: Arguments\n:: -----------------------------\nset \"DRY=0\"\nif /I \"%~1\"==\"/dry-run\" set \"DRY=1\"\nif /I \"%~1\"==\"--dry-run\" set \"DRY=1\"\nif /I \"%~1\"==\"-n\" set \"DRY=1\"\nif /I \"%~1\"==\"/n\" set \"DRY=1\"\n\nset \"projectDir=%CD%\"\nset \"scriptDir=%~dp0\"\nset \"RUN_ID=%RANDOM%_%RANDOM%\"\nset \"DELETE_LIST=%TEMP%\\upg_delete_%RUN_ID%.lst\"\n\nsetlocal EnableDelayedExpansion\nset /a debugTotal=0\nset /a debugPlanned=0\nset /a debugMissing=0\n\necho ==============================================\necho UpgradeToGitProj in \"%projectDir%\"\nif \"%DRY%\"==\"1\" (echo Mode: DRY-RUN) else (echo Mode: APPLY)\necho ==============================================\n\n:: -----------------------------\n:: Ensure Renders exists and copy helper scripts\n:: -----------------------------\nset \"rendersDir=%projectDir%\\Renders\"\nif not exist \"%rendersDir%\" (\n if \"%DRY%\"==\"1\" (\n echo [DRY] mkdir \"%rendersDir%\"\n ) else (\n mkdir \"%rendersDir%\" >nul 2>&1\n )\n)\n\nfor %%F in (UpdateSequences.bat ZipSeqArchv.bat UnzipSeqArchv.bat) do (\n if exist \"%scriptDir%%%F\" (\n if \"%DRY%\"==\"1\" (\n echo [DRY] copy \"%scriptDir%%%F\" \"%rendersDir%\\%%F\"\n ) else (\n copy /Y \"%scriptDir%%%F\" \"%rendersDir%\\%%F\" >nul\n )\n ) else (\n echo [WARN] Missing template: \"%scriptDir%%%F\"\n )\n)\n\nfor %%F in (ConfigLoader.ps1 config.json) do (\n if exist \"%scriptDir%%%F\" (\n if \"%DRY%\"==\"1\" (\n ", + "signatures": {}, + "detailedLines": [ + { + "text": "@echo off", + "lineNumber": 1 + }, + { + "text": "setlocal EnableExtensions EnableDelayedExpansion", + "lineNumber": 2 + }, + { + "lineNumber": 3 + }, + { + "text": ":: UpgradeToGitProj.bat", + "lineNumber": 4 + }, + { + "text": ":: Run this inside an existing (pre-git) project root.", + "lineNumber": 5 + }, + { + "text": ":: - Merges .gitignore and .gitattributes from components/ templates", + "lineNumber": 6 + }, + { + "text": ":: - Initializes git and installs Git LFS", + "lineNumber": 7 + }, + { + "text": ":: - Creates Renders, copies helper scripts", + "lineNumber": 8 + }, + { + "text": ":: - Collects seq/ outputs from daily_* folders under Blends\\animations (with submodule support)", + "lineNumber": 9 + }, + { + "lineNumber": 10 + }, + { + "text": ":: -----------------------------", + "lineNumber": 11 + }, + { + "text": ":: Arguments", + "lineNumber": 12 + }, + { + "text": ":: -----------------------------", + "lineNumber": 13 + }, + { + "text": "set \"DRY=0\"", + "lineNumber": 14 + }, + { + "text": "if /I \"%~1\"==\"/dry-run\" set \"DRY=1\"", + "lineNumber": 15 + }, + { + "text": "if /I \"%~1\"==\"--dry-run\" set \"DRY=1\"", + "lineNumber": 16 + }, + { + "text": "if /I \"%~1\"==\"-n\" set \"DRY=1\"", + "lineNumber": 17 + }, + { + "text": "if /I \"%~1\"==\"/n\" set \"DRY=1\"", + "lineNumber": 18 + }, + { + "lineNumber": 19 + }, + { + "text": "set \"projectDir=%CD%\"", + "lineNumber": 20 + }, + { + "text": "set \"scriptDir=%~dp0\"", + "lineNumber": 21 + }, + { + "text": "set \"RUN_ID=%RANDOM%_%RANDOM%\"", + "lineNumber": 22 + }, + { + "text": "set \"DELETE_LIST=%TEMP%\\upg_delete_%RUN_ID%.lst\"", + "lineNumber": 23 + }, + { + "lineNumber": 24 + }, + { + "text": "setlocal EnableDelayedExpansion", + "lineNumber": 25 + }, + { + "text": "set /a debugTotal=0", + "lineNumber": 26 + }, + { + "text": "set /a debugPlanned=0", + "lineNumber": 27 + }, + { + "text": "set /a debugMissing=0", + "lineNumber": 28 + }, + { + "lineNumber": 29 + }, + { + "text": "echo ==============================================", + "lineNumber": 30 + }, + { + "text": "echo UpgradeToGitProj in \"%projectDir%\"", + "lineNumber": 31 + }, + { + "text": "if \"%DRY%\"==\"1\" (echo Mode: DRY-RUN) else (echo Mode: APPLY)", + "lineNumber": 32 + }, + { + "text": "echo ==============================================", + "lineNumber": 33 + }, + { + "lineNumber": 34 + }, + { + "text": ":: -----------------------------", + "lineNumber": 35 + }, + { + "text": ":: Ensure Renders exists and copy helper scripts", + "lineNumber": 36 + }, + { + "text": ":: -----------------------------", + "lineNumber": 37 + }, + { + "text": "set \"rendersDir=%projectDir%\\Renders\"", + "lineNumber": 38 + }, + { + "text": "if not exist \"%rendersDir%\" (", + "lineNumber": 39 + }, + { + "text": " if \"%DRY%\"==\"1\" (", + "lineNumber": 40 + }, + { + "text": " echo [DRY] mkdir \"%rendersDir%\"", + "lineNumber": 41 + }, + { + "text": " ) else (", + "lineNumber": 42 + }, + { + "text": " mkdir \"%rendersDir%\" >nul 2>&1", + "lineNumber": 43 + }, + { + "text": " )", + "lineNumber": 44 + }, + { + "text": ")", + "lineNumber": 45 + }, + { + "lineNumber": 46 + }, + { + "text": "for %%F in (UpdateSequences.bat ZipSeqArchv.bat UnzipSeqArchv.bat) do (", + "lineNumber": 47 + }, + { + "text": " if exist \"%scriptDir%%%F\" (", + "lineNumber": 48 + }, + { + "text": " if \"%DRY%\"==\"1\" (", + "lineNumber": 49 + }, + { + "text": " echo [DRY] copy \"%scriptDir%%%F\" \"%rendersDir%\\%%F\"", + "lineNumber": 50 + }, + { + "text": " ) else (", + "lineNumber": 51 + }, + { + "text": " copy /Y \"%scriptDir%%%F\" \"%rendersDir%\\%%F\" >nul", + "lineNumber": 52 + }, + { + "text": " )", + "lineNumber": 53 + }, + { + "text": " ) else (", + "lineNumber": 54 + }, + { + "text": " echo [WARN] Missing template: \"%scriptDir%%%F\"", + "lineNumber": 55 + }, + { + "text": " )", + "lineNumber": 56 + }, + { + "text": ")", + "lineNumber": 57 + }, + { + "lineNumber": 58 + }, + { + "text": "for %%F in (ConfigLoader.ps1 config.json) do (", + "lineNumber": 59 + }, + { + "text": " if exist \"%scriptDir%%%F\" (", + "lineNumber": 60 + }, + { + "text": " if \"%DRY%\"==\"1\" (", + "lineNumber": 61 + }, + { + "text": " ", + "lineNumber": 62 + } + ] + }, + "score": 0.25357121229171753 + }, + { + "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.251534104347229 + }, + { + "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.24592049419879913 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\ConfigLoader.ps1", + "range": { + "startPosition": { + "line": 226 + }, + "endPosition": { + "line": 268 + } + }, + "contents": " exit 1\n }\n\n if (-not (Test-Path -LiteralPath $resolvedProject -PathType Container)) {\n Write-Error \"Project path is not a directory: $resolvedProject\"\n exit 1\n }\n\n Write-Host \"`nDeploying to: $resolvedProject\" -ForegroundColor Cyan\n Write-Host \"Struct directory: $structDir\" -ForegroundColor Cyan\n\n $specs = @(\n @{ Name = 'UpdateSequences.bat'; Source = Join-Path -Path $structDir -ChildPath 'UpdateSequences.bat' },\n @{ Name = 'UpdateAllSequences.bat'; Source = Join-Path -Path $structDir -ChildPath 'UpdateAllSequences.bat' },\n @{ Name = 'ZipSeqArchv.bat'; Source = Join-Path -Path $structDir -ChildPath 'ZipSeqArchv.bat' },\n @{ Name = 'UnzipSeqArchv.bat'; Source = Join-Path -Path $structDir -ChildPath 'UnzipSeqArchv.bat' },\n @{ Name = 'NewDaily.bat'; Source = Join-Path -Path $structDir -ChildPath 'NewDaily.bat' },\n @{ Name = '.gitattributes'; Source = Join-Path -Path $structDir -ChildPath 'components\\gitattributes' },\n @{ Name = '.gitignore'; Source = Join-Path -Path $structDir -ChildPath 'components\\gitignore' }\n )\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\n foreach ($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\n foreach ($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 and is hidden", + "signatures": {}, + "detailedLines": [ + { + "text": " exit 1", + "lineNumber": 227 + }, + { + "text": " }", + "lineNumber": 228 + }, + { + "lineNumber": 229 + }, + { + "text": " if (-not (Test-Path -LiteralPath $resolvedProject -PathType Container)) {", + "lineNumber": 230 + }, + { + "text": " Write-Error \"Project path is not a directory: $resolvedProject\"", + "lineNumber": 231 + }, + { + "text": " exit 1", + "lineNumber": 232 + }, + { + "text": " }", + "lineNumber": 233 + }, + { + "lineNumber": 234 + }, + { + "text": " Write-Host \"`nDeploying to: $resolvedProject\" -ForegroundColor Cyan", + "lineNumber": 235 + }, + { + "text": " Write-Host \"Struct directory: $structDir\" -ForegroundColor Cyan", + "lineNumber": 236 + }, + { + "lineNumber": 237 + }, + { + "text": " $specs = @(", + "lineNumber": 238 + }, + { + "text": " @{ Name = 'UpdateSequences.bat'; Source = Join-Path -Path $structDir -ChildPath 'UpdateSequences.bat' },", + "lineNumber": 239 + }, + { + "text": " @{ Name = 'UpdateAllSequences.bat'; Source = Join-Path -Path $structDir -ChildPath 'UpdateAllSequences.bat' },", + "lineNumber": 240 + }, + { + "text": " @{ Name = 'ZipSeqArchv.bat'; Source = Join-Path -Path $structDir -ChildPath 'ZipSeqArchv.bat' },", + "lineNumber": 241 + }, + { + "text": " @{ Name = 'UnzipSeqArchv.bat'; Source = Join-Path -Path $structDir -ChildPath 'UnzipSeqArchv.bat' },", + "lineNumber": 242 + }, + { + "text": " @{ Name = 'NewDaily.bat'; Source = Join-Path -Path $structDir -ChildPath 'NewDaily.bat' },", + "lineNumber": 243 + }, + { + "text": " @{ Name = '.gitattributes'; Source = Join-Path -Path $structDir -ChildPath 'components\\gitattributes' },", + "lineNumber": 244 + }, + { + "text": " @{ Name = '.gitignore'; Source = Join-Path -Path $structDir -ChildPath 'components\\gitignore' }", + "lineNumber": 245 + }, + { + "text": " )", + "lineNumber": 246 + }, + { + "lineNumber": 247 + }, + { + "text": " # Config files to deploy to projectroot\\.config\\", + "lineNumber": 248 + }, + { + "text": " $configAssets = @(", + "lineNumber": 249 + }, + { + "text": " @{ Name = 'config.json'; Source = Join-Path -Path $structDir -ChildPath 'config.json' },", + "lineNumber": 250 + }, + { + "text": " @{ Name = 'GetStructDir.ps1'; Source = Join-Path -Path $structDir -ChildPath 'GetStructDir.ps1' }", + "lineNumber": 251 + }, + { + "text": " )", + "lineNumber": 252 + }, + { + "lineNumber": 253 + }, + { + "text": " foreach ($spec in $specs) {", + "lineNumber": 254 + }, + { + "text": " if (-not (Test-Path -LiteralPath $spec.Source -PathType Leaf)) {", + "lineNumber": 255 + }, + { + "text": " Write-Error \"Source file not found: $($spec.Source)\"", + "lineNumber": 256 + }, + { + "text": " exit 1", + "lineNumber": 257 + }, + { + "text": " }", + "lineNumber": 258 + }, + { + "text": " }", + "lineNumber": 259 + }, + { + "lineNumber": 260 + }, + { + "text": " foreach ($asset in $configAssets) {", + "lineNumber": 261 + }, + { + "text": " if (-not (Test-Path -LiteralPath $asset.Source -PathType Leaf)) {", + "lineNumber": 262 + }, + { + "text": " Write-Error \"Config asset not found: $($asset.Source)\"", + "lineNumber": 263 + }, + { + "text": " exit 1", + "lineNumber": 264 + }, + { + "text": " }", + "lineNumber": 265 + }, + { + "text": " }", + "lineNumber": 266 + }, + { + "lineNumber": 267 + }, + { + "text": " # Ensure .config directory exists in project root and is hidden", + "lineNumber": 268 + } + ] + }, + "score": 0.24059920012950897 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\UpdateSequences.ps1", + "range": { + "startPosition": { + "line": 221 + }, + "endPosition": { + "line": 266, + "column": 8 + } + }, + "contents": " $primaryDirs = Get-ChildItem -LiteralPath $root -Directory -Filter $primaryPattern -ErrorAction SilentlyContinue |\n Where-Object { $_.Name -notlike '_*' }\n foreach ($d in $primaryDirs) {\n $seqDirs = @(Get-ChildItem -LiteralPath $d.FullName -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -notlike '_*' })\n if ($seqDirs.Count -eq 0) {\n Add-SequenceFolder -Directory $d -Map $sequenceMap\n } else {\n foreach ($s in $seqDirs) {\n Add-SequenceFolder -Directory $s -Map $sequenceMap\n }\n }\n }\n\n $secondaryDirs = Get-ChildItem -LiteralPath $root -Directory -Filter $secondaryPattern -ErrorAction SilentlyContinue |\n Where-Object { $_.Name -notlike '_*' }\n foreach ($d in $secondaryDirs) {\n $seqDirs = @(Get-ChildItem -LiteralPath $d.FullName -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -notlike '_*' })\n if ($seqDirs.Count -eq 0) {\n Add-SequenceFolder -Directory $d -Map $sequenceMap\n } else {\n foreach ($s in $seqDirs) {\n Add-SequenceFolder -Directory $s -Map $sequenceMap\n }\n }\n }\n\n $directSeqs = Get-ChildItem -LiteralPath $root -Directory -ErrorAction SilentlyContinue |\n Where-Object {\n $_.Name -notlike '_*' -and\n $_.Name -notlike 'daily_*' -and\n $_.Name -notmatch '^\\d{4}-\\d{2}-\\d{2}$'\n }\n foreach ($seq in $directSeqs) {\n Add-SequenceFolder -Directory $seq -Map $sequenceMap\n }\n\n $sequenceFolders = $sequenceMap.GetEnumerator() | ForEach-Object {\n [pscustomobject]@{\n Path = $_.Key\n Name = $_.Value\n }\n } | Sort-Object -Property Path\n\n if (-not $sequenceFolders) {\n ", + "signatures": {}, + "detailedLines": [ + { + "text": " $primaryDirs = Get-ChildItem -LiteralPath $root -Directory -Filter $primaryPattern -ErrorAction SilentlyContinue |", + "lineNumber": 223 + }, + { + "text": " Where-Object { $_.Name -notlike '_*' }", + "lineNumber": 224 + }, + { + "text": " foreach ($d in $primaryDirs) {", + "lineNumber": 225 + }, + { + "text": " $seqDirs = @(Get-ChildItem -LiteralPath $d.FullName -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -notlike '_*' })", + "lineNumber": 226 + }, + { + "text": " if ($seqDirs.Count -eq 0) {", + "lineNumber": 227 + }, + { + "text": " Add-SequenceFolder -Directory $d -Map $sequenceMap", + "lineNumber": 228 + }, + { + "text": " } else {", + "lineNumber": 229 + }, + { + "text": " foreach ($s in $seqDirs) {", + "lineNumber": 230 + }, + { + "text": " Add-SequenceFolder -Directory $s -Map $sequenceMap", + "lineNumber": 231 + }, + { + "text": " }", + "lineNumber": 232 + }, + { + "text": " }", + "lineNumber": 233 + }, + { + "text": " }", + "lineNumber": 234 + }, + { + "lineNumber": 235 + }, + { + "text": " $secondaryDirs = Get-ChildItem -LiteralPath $root -Directory -Filter $secondaryPattern -ErrorAction SilentlyContinue |", + "lineNumber": 236 + }, + { + "text": " Where-Object { $_.Name -notlike '_*' }", + "lineNumber": 237 + }, + { + "text": " foreach ($d in $secondaryDirs) {", + "lineNumber": 238 + }, + { + "text": " $seqDirs = @(Get-ChildItem -LiteralPath $d.FullName -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -notlike '_*' })", + "lineNumber": 239 + }, + { + "text": " if ($seqDirs.Count -eq 0) {", + "lineNumber": 240 + }, + { + "text": " Add-SequenceFolder -Directory $d -Map $sequenceMap", + "lineNumber": 241 + }, + { + "text": " } else {", + "lineNumber": 242 + }, + { + "text": " foreach ($s in $seqDirs) {", + "lineNumber": 243 + }, + { + "text": " Add-SequenceFolder -Directory $s -Map $sequenceMap", + "lineNumber": 244 + }, + { + "text": " }", + "lineNumber": 245 + }, + { + "text": " }", + "lineNumber": 246 + }, + { + "text": " }", + "lineNumber": 247 + }, + { + "lineNumber": 248 + }, + { + "text": " $directSeqs = Get-ChildItem -LiteralPath $root -Directory -ErrorAction SilentlyContinue |", + "lineNumber": 249 + }, + { + "text": " Where-Object {", + "lineNumber": 250 + }, + { + "text": " $_.Name -notlike '_*' -and", + "lineNumber": 251 + }, + { + "text": " $_.Name -notlike 'daily_*' -and", + "lineNumber": 252 + }, + { + "text": " $_.Name -notmatch '^\\d{4}-\\d{2}-\\d{2}$'", + "lineNumber": 253 + }, + { + "text": " }", + "lineNumber": 254 + }, + { + "text": " foreach ($seq in $directSeqs) {", + "lineNumber": 255 + }, + { + "text": " Add-SequenceFolder -Directory $seq -Map $sequenceMap", + "lineNumber": 256 + }, + { + "text": " }", + "lineNumber": 257 + }, + { + "lineNumber": 258 + }, + { + "text": " $sequenceFolders = $sequenceMap.GetEnumerator() | ForEach-Object {", + "lineNumber": 259 + }, + { + "text": " [pscustomobject]@{", + "lineNumber": 260 + }, + { + "text": " Path = $_.Key", + "lineNumber": 261 + }, + { + "text": " Name = $_.Value", + "lineNumber": 262 + }, + { + "text": " }", + "lineNumber": 263 + }, + { + "text": " } | Sort-Object -Property Path", + "lineNumber": 264 + }, + { + "lineNumber": 265 + }, + { + "text": " if (-not $sequenceFolders) {", + "lineNumber": 266 + }, + { + "text": " ", + "lineNumber": 267 + } + ] + }, + "score": 0.2402079999446869 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\zip_sequences.py", + "range": { + "startPosition": { + "line": 645, + "column": 42 + }, + "endPosition": { + "line": 661, + "column": 63 + } + }, + "contents": "def sequence_dir_for(zip_path: Path) -> Path:\n rel = zip_path.relative_to(ARCHIVE_ROOT)\n # Remove the archive suffix (.7z or .zip) from the end\n # Handle both .7z and .zip extensions\n rel_str = str(rel)\n if rel_str.endswith(\".7z\"):\n rel_str = rel_str[:-3]\n elif rel_str.endswith(\".zip\"):\n rel_str = rel_str[:-4]\n return RENDER_ROOT / rel_str\n\n\ndef state_path_for(zip_path: Path) -> Path:\n return zip_path.with_suffix(zip_path.suffix + STATE_SUFFIX)", + "signatures": {}, + "detailedLines": [ + { + "text": "def sequence_dir_for(zip_path: Path) -> Path:", + "lineNumber": 649, + "isSignature": true + }, + { + "text": " rel = zip_path.relative_to(ARCHIVE_ROOT)", + "lineNumber": 650 + }, + { + "text": " # Remove the archive suffix (.7z or .zip) from the end", + "lineNumber": 651 + }, + { + "text": " # Handle both .7z and .zip extensions", + "lineNumber": 652 + }, + { + "text": " rel_str = str(rel)", + "lineNumber": 653 + }, + { + "text": " if rel_str.endswith(\".7z\"):", + "lineNumber": 654 + }, + { + "text": " rel_str = rel_str[:-3]", + "lineNumber": 655 + }, + { + "text": " elif rel_str.endswith(\".zip\"):", + "lineNumber": 656 + }, + { + "text": " rel_str = rel_str[:-4]", + "lineNumber": 657 + }, + { + "text": " return RENDER_ROOT / rel_str", + "lineNumber": 658, + "isSignature": true + }, + { + "lineNumber": 659 + }, + { + "lineNumber": 660 + }, + { + "text": "def state_path_for(zip_path: Path) -> Path:", + "lineNumber": 661, + "isSignature": true + }, + { + "text": " return zip_path.with_suffix(zip_path.suffix + STATE_SUFFIX)", + "lineNumber": 662, + "isSignature": true + } + ] + }, + "score": 0.23667949438095093 + }, + { + "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.23035340011119843 + }, + { + "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.22555430233478546 + }, + { + "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.2200496941804886 + }, + { + "codeBlock": { + "relativeWorkspacePath": ".\\ConfigLoader.ps1", + "range": { + "startPosition": {}, + "endPosition": { + "line": 64 + } + }, + "contents": "Set-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\n if ($MyInvocation.InvocationName -ne '.') {\n return $script:LoaderRoot\n }\n\n $value = Get-ConfigValue -Name 'structDir'\n if ($null -eq $value -or [string]::IsNullOrWhiteSpace($value)) {\n return $script:LoaderRoot\n }\n\n if ([System.IO.Path]::IsPathRooted($value)) {\n $resolved = Resolve-Path -LiteralPath $value -ErrorAction SilentlyContinue\n if ($null -ne $resolved) { return $resolved.Path }\n return $value\n }\n\n $candidate = Join-Path -Path $script:LoaderRoot -ChildPath $value", + "signatures": {}, + "detailedLines": [ + { + "text": "Set-StrictMode -Version Latest", + "lineNumber": 1 + }, + { + "text": "$ErrorActionPreference = 'Stop'", + "lineNumber": 2 + }, + { + "lineNumber": 3 + }, + { + "text": "$script:LoaderRoot = Split-Path -Parent $MyInvocation.MyCommand.Path", + "lineNumber": 4 + }, + { + "text": "$script:ConfigPath = Join-Path -Path $script:LoaderRoot -ChildPath 'config.json'", + "lineNumber": 5 + }, + { + "text": "$script:ConfigCache = $null", + "lineNumber": 6 + }, + { + "lineNumber": 7 + }, + { + "text": "function Get-ProjectStructureConfig {", + "lineNumber": 8 + }, + { + "text": " if ($null -ne $script:ConfigCache) {", + "lineNumber": 9 + }, + { + "text": " return $script:ConfigCache", + "lineNumber": 10 + }, + { + "text": " }", + "lineNumber": 11 + }, + { + "lineNumber": 12 + }, + { + "text": " if (Test-Path -LiteralPath $script:ConfigPath) {", + "lineNumber": 13 + }, + { + "text": " try {", + "lineNumber": 14 + }, + { + "text": " $raw = Get-Content -LiteralPath $script:ConfigPath -Raw -ErrorAction Stop", + "lineNumber": 15 + }, + { + "text": " if ($raw.Trim().Length -gt 0) {", + "lineNumber": 16 + }, + { + "text": " $script:ConfigCache = $raw | ConvertFrom-Json", + "lineNumber": 17 + }, + { + "text": " return $script:ConfigCache", + "lineNumber": 18 + }, + { + "text": " }", + "lineNumber": 19 + }, + { + "text": " }", + "lineNumber": 20 + }, + { + "text": " catch {", + "lineNumber": 21 + }, + { + "text": " Write-Warning \"Failed to parse config.json: $($_.Exception.Message)\"", + "lineNumber": 22 + }, + { + "text": " }", + "lineNumber": 23 + }, + { + "text": " }", + "lineNumber": 24 + }, + { + "lineNumber": 25 + }, + { + "text": " $script:ConfigCache = [pscustomobject]@{}", + "lineNumber": 26 + }, + { + "text": " return $script:ConfigCache", + "lineNumber": 27 + }, + { + "text": "}", + "lineNumber": 28 + }, + { + "lineNumber": 29 + }, + { + "text": "function Get-ConfigValue {", + "lineNumber": 30 + }, + { + "text": " param(", + "lineNumber": 31 + }, + { + "text": " [Parameter(Mandatory)] [string]$Name,", + "lineNumber": 32 + }, + { + "text": " $Default = $null", + "lineNumber": 33 + }, + { + "text": " )", + "lineNumber": 34 + }, + { + "lineNumber": 35 + }, + { + "text": " $config = Get-ProjectStructureConfig", + "lineNumber": 36 + }, + { + "text": " if ($config.PSObject.Properties.Name -contains $Name) {", + "lineNumber": 37 + }, + { + "text": " $value = $config.$Name", + "lineNumber": 38 + }, + { + "text": " if ($null -ne $value -and ($value -isnot [string] -or $value.Trim().Length -gt 0)) {", + "lineNumber": 39 + }, + { + "text": " return $value", + "lineNumber": 40 + }, + { + "text": " }", + "lineNumber": 41 + }, + { + "text": " }", + "lineNumber": 42 + }, + { + "lineNumber": 43 + }, + { + "text": " return $Default", + "lineNumber": 44 + }, + { + "text": "}", + "lineNumber": 45 + }, + { + "lineNumber": 46 + }, + { + "text": "function Get-StructDirectory {", + "lineNumber": 47 + }, + { + "text": " # When script is run directly (not dot-sourced), always use script's directory for portability", + "lineNumber": 48 + }, + { + "text": " if ($MyInvocation.InvocationName -ne '.') {", + "lineNumber": 49 + }, + { + "text": " return $script:LoaderRoot", + "lineNumber": 50 + }, + { + "text": " }", + "lineNumber": 51 + }, + { + "lineNumber": 52 + }, + { + "text": " $value = Get-ConfigValue -Name 'structDir'", + "lineNumber": 53 + }, + { + "text": " if ($null -eq $value -or [string]::IsNullOrWhiteSpace($value)) {", + "lineNumber": 54 + }, + { + "text": " return $script:LoaderRoot", + "lineNumber": 55 + }, + { + "text": " }", + "lineNumber": 56 + }, + { + "lineNumber": 57 + }, + { + "text": " if ([System.IO.Path]::IsPathRooted($value)) {", + "lineNumber": 58 + }, + { + "text": " $resolved = Resolve-Path -LiteralPath $value -ErrorAction SilentlyContinue", + "lineNumber": 59 + }, + { + "text": " if ($null -ne $resolved) { return $resolved.Path }", + "lineNumber": 60 + }, + { + "text": " return $value", + "lineNumber": 61 + }, + { + "text": " }", + "lineNumber": 62 + }, + { + "lineNumber": 63 + }, + { + "text": " $candidate = Join-Path -Path $script:LoaderRoot -ChildPath $value", + "lineNumber": 64 + } + ] + }, + "score": 0.21668344736099243 + } + ] +} +``` +Status: **completed** + + +
+
+ +--- + + +Creating a plan to update the script for two-level duplicate detection: + + +--- + + +
+Tool use: **create_plan** + + +Parameters: + +```json +{ + "plan": "# Two-Level Texture Organization Script\n\n## Current Behavior\nThe script currently processes all files recursively and moves everything to a single `\\common` folder at the texture root level.\n\n## New Requirements\nThe texture folder structure is: `\\\\textures\\[Blendfile]\\[Material]`\n\nThe script needs to:\n1. **Intra-blendfile commonalities**: Files that appear in multiple materials within the same blendfile → `\\\\textures\\[blendfile]\\common`\n2. **Inter-blendfile commonalities**: Files that appear across multiple blendfiles → `\\\\textures\\common`\n\n## Implementation Plan\n\n### File: `organize_textures.ps1`\n\n**Two-Pass Approach:**\n\n#### Pass 1: Intra-Blendfile Processing\n1. Get all direct subdirectories of the texture folder (these are blendfile folders)\n2. For each blendfile folder:\n - Get all files recursively within that blendfile folder (excluding `\\common` folders)\n - Calculate checksums for all files in that blendfile\n - Group files by checksum\n - For each checksum group:\n - If multiple files (duplicates within blendfile):\n - Move first file to `[blendfile]\\common`\n - Move remaining files to `[blendfile]\\common\\duplicates` with numbered suffixes\n - If single file: leave it in place (will be processed in Pass 2)\n\n#### Pass 2: Inter-Blendfile Processing\n1. After Pass 1 completes, get all remaining files (excluding all `\\common` folders)\n2. Calculate checksums for all remaining files\n3. Group files by checksum\n4. For each checksum group:\n - If multiple files (duplicates across blendfiles):\n - Move first file to `\\textures\\common`\n - Move remaining files to `\\textures\\common\\duplicates` with numbered suffixes\n - If single file: leave it in place (unique file)\n\n**Key Changes:**\n- Identify blendfile folders as direct subdirectories of the texture root\n- Process each blendfile folder independently in Pass 1\n- Exclude `\\common` folders from file collection in both passes\n- Create `[blendfile]\\common` and `[blendfile]\\common\\duplicates` directories as needed\n- Create `\\textures\\common` and `\\textures\\common\\duplicates` directories for Pass 2\n- Handle filename conflicts when moving files\n- Provide progress feedback for each blendfile and overall progress\n\n**Structure Detection:**\n- Assume texture folder structure: `[textureRoot]\\[Blendfile]\\[Material]\\...`\n- Blendfile folders are direct children of the texture root\n- Material folders are children of blendfile folders\n\n**Edge Cases:**\n- Handle blendfile folders that already have `\\common` subdirectories\n- Skip processing if a blendfile folder has no files\n- Handle files directly in blendfile folder (not in material subfolders)", + "name": "Two-level texture organization", + "todos": [ + { + "content": "Add logic to identify blendfile folders as direct subdirectories of texture root", + "status": "pending", + "id": "identify_blendfile_folders" + }, + { + "content": "Implement Pass 1: Process each blendfile folder separately, finding duplicates within each blendfile and moving to [blendfile]\\common", + "status": "pending", + "id": "pass1_intra_blendfile" + }, + { + "content": "Implement Pass 2: Process remaining files across all blendfiles, finding duplicates across blendfiles and moving to \\textures\\common", + "status": "pending", + "id": "pass2_inter_blendfile" + }, + { + "content": "Update file collection to exclude all \\common folders (both blendfile-level and root-level)", + "status": "pending", + "id": "update_exclusions" + }, + { + "content": "Ensure proper directory creation for both [blendfile]\\common and \\textures\\common paths", + "status": "pending", + "id": "handle_directory_creation" + } + ], + "overview": "Update organize_textures.ps1 to scan each blendfile folder separately, moving intra-blendfile duplicates to [blendfile]\\common and inter-blendfile duplicates to \\textures\\common" +} +``` +Additional data: + +```json +{ + "reviewData": { + "status": "Requested", + "selectedOption": "none", + "isShowingInput": false + }, + "planUri": "c:\\Users\\Nathan\\.cursor\\plans\\two-level_texture_organization_df41b675.plan.md", + "hasOpenedEditor": true +} +``` +Result: + +```json +{ + "rejected": {} +} +``` +Status: **completed** + + +
+
+ +--- + +_**User**_ + +Implement the plan as specified, it is attached for your reference. Do NOT edit the plan file itself. + +To-do's from the plan have already been created. Do not create them again. Mark them as in_progress as you work, starting with the first one. Don't stop until you have completed all the to-dos. + +--- + +_**Agent (model default, mode Agent)**_ + + +Implementing the plan. Reviewing the current script, then updating it for two-level duplicate detection. + + +--- + + +
+Tool use: **read_file_v2** + +Status: **loading** + + +
+
+ +--- + diff --git a/organize_textures.ps1 b/organize_textures.ps1 index 60be93e..cd707c6 100644 --- a/organize_textures.ps1 +++ b/organize_textures.ps1 @@ -1,4 +1,6 @@ -# Script to organize texture files by checksum, moving all files to \common and duplicates to \common\duplicates +# Script to organize texture files by checksum with two-level duplicate detection +# Pass 1: Intra-blendfile duplicates → [blendfile]\common +# Pass 2: Inter-blendfile duplicates → \textures\common # Usage: .\organize_textures.ps1 # Prompt user for texture folder path @@ -19,153 +21,292 @@ if (-not (Test-Path -Path $textureFolderPath -PathType Container)) { $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 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 $_ } - -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 +# Function to calculate checksums for files +function Get-FilesWithChecksums { + param( + [array]$Files + ) - if ($files.Count -eq 1) { - # Single file - move to \common - $fileObj = $files[0].File + $throttleLimit = [Math]::Max(1, [Environment]::ProcessorCount) + $parallelScriptBlock = { + try { + $hash = Get-FileHash -Path $_.FullName -Algorithm SHA256 + [PSCustomObject]@{ + File = $_ + Hash = $hash.Hash + } + } catch { + Write-Warning "Failed to calculate checksum for: $($_.FullName) - $($_.Exception.Message)" + $null + } + } + + return $Files | ForEach-Object -Parallel $parallelScriptBlock -ThrottleLimit $throttleLimit | Where-Object { $null -ne $_ } +} + +# Function to move files to common folder +function Move-FilesToCommon { + param( + [array]$Files, + [string]$CommonPath, + [string]$DuplicatesPath, + [hashtable]$FilesInCommon + ) + + $movedCount = 0 + $duplicateCount = 0 + + foreach ($fileObj in $Files) { $fileName = $fileObj.Name - $destinationPath = Join-Path -Path $commonPath -ChildPath $fileName + $destinationPath = Join-Path -Path $CommonPath -ChildPath $fileName # Handle name conflicts - if ($filesInCommon.ContainsKey($fileName)) { - # File with same name but different checksum already exists + 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 + $destinationPath = Join-Path -Path $CommonPath -ChildPath $newFileName $counter++ - } while ($filesInCommon.ContainsKey($newFileName) -or (Test-Path -Path $destinationPath)) + } 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 + $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 + } + + return @{ + MovedCount = $movedCount + DuplicateCount = $duplicateCount + } +} + +# Function to process duplicate group +function Process-DuplicateGroup { + param( + [array]$Files, + [string]$CommonPath, + [string]$DuplicatesPath, + [hashtable]$FilesInCommon + ) + + $movedCount = 0 + $duplicateCount = 0 + + if ($Files.Count -eq 1) { + # Single file - leave in place (will be processed in Pass 2) + return @{ + MovedCount = 0 + DuplicateCount = 0 + } + } + + # Multiple files with same checksum (duplicates) + # Move first file to \common + $firstFile = $Files[0].File + $fileName = $firstFile.Name + $destinationPath = Join-Path -Path $CommonPath -ChildPath $fileName + + # Handle name conflicts for the first file + if ($FilesInCommon.ContainsKey($fileName)) { + $baseName = [System.IO.Path]::GetFileNameWithoutExtension($fileName) + $extension = [System.IO.Path]::GetExtension($fileName) + $counter = 1 + do { + $newFileName = "${baseName}_${counter}${extension}" + $destinationPath = Join-Path -Path $CommonPath -ChildPath $newFileName + $counter++ + } while ($FilesInCommon.ContainsKey($newFileName) -or (Test-Path -Path $destinationPath)) - # 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 + $fileName = $newFileName + } + + try { + Move-Item -Path $firstFile.FullName -Destination $destinationPath -Force + $FilesInCommon[$fileName] = $true + $movedCount++ + } catch { + Write-Warning "Failed to move first duplicate file: $($firstFile.FullName) - $($_.Exception.Message)" + } + + # Move remaining files to \common\duplicates with numbered suffixes + for ($i = 1; $i -lt $Files.Count; $i++) { + $fileObj = $Files[$i].File + $baseName = [System.IO.Path]::GetFileNameWithoutExtension($fileObj.Name) + $extension = [System.IO.Path]::GetExtension($fileObj.Name) + $numberedFileName = "${baseName}.$($i.ToString('000'))${extension}" + $duplicateDestinationPath = Join-Path -Path $DuplicatesPath -ChildPath $numberedFileName + + # Handle name conflicts in duplicates folder + $conflictCounter = 1 + while (Test-Path -Path $duplicateDestinationPath) { + $numberedFileName = "${baseName}.$($i.ToString('000'))_${conflictCounter}${extension}" + $duplicateDestinationPath = Join-Path -Path $DuplicatesPath -ChildPath $numberedFileName + $conflictCounter++ } try { - Move-Item -Path $firstFile.FullName -Destination $destinationPath -Force - $filesInCommon[$fileName] = $true - $movedCount++ + Move-Item -Path $fileObj.FullName -Destination $duplicateDestinationPath -Force + $duplicateCount++ } 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-Warning "Failed to move duplicate file: $($fileObj.FullName) - $($_.Exception.Message)" } } + + return @{ + MovedCount = $movedCount + DuplicateCount = $duplicateCount + } +} + +# ============================================================================ +# PASS 1: Intra-Blendfile Processing +# ============================================================================ +Write-Host "" +Write-Host "=== PASS 1: Intra-Blendfile Processing ===" -ForegroundColor Cyan + +# Get all direct subdirectories of texture folder (blendfile folders) +$blendfileFolders = Get-ChildItem -Path $textureFolderPath -Directory | Where-Object { $_.Name -ne "common" } + +if ($null -eq $blendfileFolders -or $blendfileFolders.Count -eq 0) { + Write-Host "No blendfile folders found. Skipping Pass 1." -ForegroundColor Yellow +} else { + Write-Host "Found $($blendfileFolders.Count) blendfile folder(s) to process." -ForegroundColor Green + + $totalPass1Moved = 0 + $totalPass1Duplicates = 0 + + foreach ($blendfileFolder in $blendfileFolders) { + Write-Host "" + Write-Host "Processing blendfile: $($blendfileFolder.Name)" -ForegroundColor Yellow + + # Get all files in this blendfile folder, excluding \common folders + $blendfileFiles = Get-ChildItem -Path $blendfileFolder.FullName -Recurse -File | Where-Object { $_.FullName -notlike "*\common\*" } + + if ($null -eq $blendfileFiles -or $blendfileFiles.Count -eq 0) { + Write-Host " No files found in this blendfile folder." -ForegroundColor Gray + continue + } + + Write-Host " Found $($blendfileFiles.Count) files." -ForegroundColor Gray + + # Calculate checksums + Write-Host " Calculating checksums..." -ForegroundColor Gray + $filesWithChecksums = Get-FilesWithChecksums -Files $blendfileFiles + + # Group by checksum + $groupedByChecksum = $filesWithChecksums | Group-Object -Property Hash + + Write-Host " Found $($groupedByChecksum.Count) unique checksums." -ForegroundColor Gray + + # Create [blendfile]\common and [blendfile]\common\duplicates directories + $blendfileCommonPath = Join-Path -Path $blendfileFolder.FullName -ChildPath "common" + $blendfileDuplicatesPath = Join-Path -Path $blendfileCommonPath -ChildPath "duplicates" + + if (-not (Test-Path -Path $blendfileCommonPath -PathType Container)) { + New-Item -ItemType Directory -Path $blendfileCommonPath | Out-Null + } + + if (-not (Test-Path -Path $blendfileDuplicatesPath -PathType Container)) { + New-Item -ItemType Directory -Path $blendfileDuplicatesPath | Out-Null + } + + # Track filenames already in [blendfile]\common + $filesInBlendfileCommon = @{} + + # Process each checksum group + $blendfileMoved = 0 + $blendfileDuplicates = 0 + + foreach ($group in $groupedByChecksum) { + $result = Process-DuplicateGroup -Files $group.Group -CommonPath $blendfileCommonPath -DuplicatesPath $blendfileDuplicatesPath -FilesInCommon $filesInBlendfileCommon + $blendfileMoved += $result.MovedCount + $blendfileDuplicates += $result.DuplicateCount + } + + Write-Host " Moved $blendfileMoved file(s) to \common, $blendfileDuplicates duplicate(s) to \common\duplicates" -ForegroundColor Green + $totalPass1Moved += $blendfileMoved + $totalPass1Duplicates += $blendfileDuplicates + } + + Write-Host "" + Write-Host "Pass 1 complete: $totalPass1Moved file(s) moved, $totalPass1Duplicates duplicate(s) moved" -ForegroundColor Green +} + +# ============================================================================ +# PASS 2: Inter-Blendfile Processing +# ============================================================================ +Write-Host "" +Write-Host "=== PASS 2: Inter-Blendfile Processing ===" -ForegroundColor Cyan + +# Get all remaining files (excluding all \common folders) +Write-Host "Collecting remaining files..." -ForegroundColor Yellow +$remainingFiles = Get-ChildItem -Path $textureFolderPath -Recurse -File | Where-Object { $_.FullName -notlike "*\common\*" } + +if ($null -eq $remainingFiles -or $remainingFiles.Count -eq 0) { + Write-Host "No remaining files found to process." -ForegroundColor Yellow +} else { + Write-Host "Found $($remainingFiles.Count) remaining files to process." -ForegroundColor Green + + # Calculate checksums + Write-Host "Calculating checksums using parallel processing (this may take a while)..." -ForegroundColor Yellow + $filesWithChecksums = Get-FilesWithChecksums -Files $remainingFiles + + Write-Host "Checksum calculation complete." -ForegroundColor Green + + # Group files by checksum + Write-Host "Grouping files by checksum..." -ForegroundColor Yellow + $groupedByChecksum = $filesWithChecksums | Group-Object -Property Hash + + Write-Host "Found $($groupedByChecksum.Count) unique checksums." -ForegroundColor Green + + # Create \textures\common and \textures\common\duplicates directories + $rootCommonPath = Join-Path -Path $textureFolderPath -ChildPath "common" + $rootDuplicatesPath = Join-Path -Path $rootCommonPath -ChildPath "duplicates" + + if (-not (Test-Path -Path $rootCommonPath -PathType Container)) { + New-Item -ItemType Directory -Path $rootCommonPath | Out-Null + Write-Host "Created directory: $rootCommonPath" -ForegroundColor Green + } + + if (-not (Test-Path -Path $rootDuplicatesPath -PathType Container)) { + New-Item -ItemType Directory -Path $rootDuplicatesPath | Out-Null + Write-Host "Created directory: $rootDuplicatesPath" -ForegroundColor Green + } + + # Track filenames already in \textures\common + $filesInRootCommon = @{} + + # Process each checksum group + Write-Host "Moving files to \common and \common\duplicates..." -ForegroundColor Yellow + $pass2Moved = 0 + $pass2Duplicates = 0 + + foreach ($group in $groupedByChecksum) { + $files = $group.Group + + if ($files.Count -eq 1) { + # Single file - leave in place (unique file) + continue + } + + # Multiple files with same checksum (duplicates across blendfiles) + $result = Process-DuplicateGroup -Files $files -CommonPath $rootCommonPath -DuplicatesPath $rootDuplicatesPath -FilesInCommon $filesInRootCommon + $pass2Moved += $result.MovedCount + $pass2Duplicates += $result.DuplicateCount + } + + Write-Host "" + Write-Host "Pass 2 complete: $pass2Moved file(s) moved to \common, $pass2Duplicates duplicate(s) moved to \common\duplicates" -ForegroundColor Green } Write-Host "" Write-Host "File organization complete!" -ForegroundColor Green -Write-Host " Files moved to \common: $movedCount" -ForegroundColor Cyan -Write-Host " Duplicate files moved to \common\duplicates: $duplicateCount" -ForegroundColor Cyan