Compare commits

...

4 Commits

Author SHA1 Message Date
Raincloud eaa078540e cfgdeploy
finally, modernization in this year old project
2026-05-24 16:02:47 -06:00
Raincloud 0eb9b4d494 ignore specst 2026-05-24 15:59:48 -06:00
Raincloud 60075b7466 prproj gzip to LFS
originally 10/29/2025 @ 7:29 PM, commit SHA 1ed427d0b2ad74f550ab2ade0fdaee143a06e137. Committing from the synology NAS adds all the @eaDir folders, which should never be in upstream. I should have checked these changes. It also added a ton of changes to binaries that technically weren't made due to the fact that this repo began without LFS, which was fixed via `git lfs migrate import`.
2026-05-24 15:59:48 -06:00
Raincloud dc461a36c0 append autosaves 2025-08-17 23:13:27 -06:00
21 changed files with 559 additions and 6666 deletions
+68
View File
@@ -0,0 +1,68 @@
# Simple helper script to get structDir from project config.json
# Reads config.json from .config folder in project root
param(
[string]$ProjectRoot
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
if ([string]::IsNullOrWhiteSpace($ProjectRoot)) {
# Try to determine project root from script location
if ($PSScriptRoot) {
$ProjectRoot = Split-Path -Parent $PSScriptRoot
}
elseif ($MyInvocation.MyCommand.Path) {
$ProjectRoot = Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path)
}
else {
Write-Error "Unable to determine project root. Please provide -ProjectRoot parameter."
exit 1
}
}
$configPath = Join-Path -Path $ProjectRoot -ChildPath '.config\config.json'
if (-not (Test-Path -LiteralPath $configPath -PathType Leaf)) {
Write-Error "config.json not found at: $configPath"
exit 1
}
try {
$config = Get-Content -LiteralPath $configPath -Raw -ErrorAction Stop | ConvertFrom-Json
if ($config.PSObject.Properties.Name -contains 'structDir') {
$structDir = $config.structDir
if ($null -ne $structDir -and ($structDir -isnot [string] -or $structDir.Trim().Length -gt 0)) {
# If it's an absolute path, resolve it
if ([System.IO.Path]::IsPathRooted($structDir)) {
$resolved = Resolve-Path -LiteralPath $structDir -ErrorAction SilentlyContinue
if ($null -ne $resolved) {
Write-Output $resolved.Path
exit 0
}
Write-Output $structDir
exit 0
}
# Relative path - resolve relative to config location
$candidate = Join-Path -Path (Split-Path -Parent $configPath) -ChildPath $structDir
$resolvedCandidate = Resolve-Path -LiteralPath $candidate -ErrorAction SilentlyContinue
if ($null -ne $resolvedCandidate) {
Write-Output $resolvedCandidate.Path
exit 0
}
Write-Output $candidate
exit 0
}
}
# Default: return the directory containing config.json (project root)
Write-Output $ProjectRoot
exit 0
}
catch {
Write-Error "Failed to read or parse config.json: $($_.Exception.Message)"
exit 1
}
+8
View File
@@ -0,0 +1,8 @@
{
"dailyFormat": "YYYY-MM-DD",
"structDir": "C:\\Users\\Nathan\\SynologyDrive\\Creative\\artsy\\maya\\0 ProjectStructure",
"zipper": "7z",
"compression": 0,
"Max7zInst": 0,
"zipsegLimit": "2G"
}
+3 -3
View File
@@ -1,3 +1,3 @@
# Don't index SpecStory auto-save files, but allow explicit context inclusion via @ references
.specstory/**
# Don't index SpecStory auto-save files, but allow explicit context inclusion via @ references
.specstory/**
+126 -2
View File
@@ -1,7 +1,131 @@
# Git LFS attributes configuration
# All listed file types will be tracked by Git LFS
# Video files
*.avi filter=lfs diff=lfs merge=lfs -text
*.mkv filter=lfs diff=lfs merge=lfs -text
*.mov filter=lfs diff=lfs merge=lfs -text
*.MOV filter=lfs diff=lfs merge=lfs -text
*.mp4 filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text
*.webm filter=lfs diff=lfs merge=lfs -text
# Image files
*.bmp filter=lfs diff=lfs merge=lfs -text
*.exr filter=lfs diff=lfs merge=lfs -text
*.gif filter=lfs diff=lfs merge=lfs -text
*.hdr filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text
*.jpeg filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.tga filter=lfs diff=lfs merge=lfs -text
*.tif filter=lfs diff=lfs merge=lfs -text
*.tiff filter=lfs diff=lfs merge=lfs -text
*.webp filter=lfs diff=lfs merge=lfs -text
*.heic filter=lfs diff=lfs merge=lfs -text
*.HEIC filter=lfs diff=lfs merge=lfs -text
# 3D/CG files
*.3ds filter=lfs diff=lfs merge=lfs -text
*.abc filter=lfs diff=lfs merge=lfs -text
*.blend filter=lfs diff=lfs merge=lfs -text
*.blend1 filter=lfs diff=lfs merge=lfs -text
*.blend2 filter=lfs diff=lfs merge=lfs -text
*.bvh filter=lfs diff=lfs merge=lfs -text
*.bvh.gz filter=lfs diff=lfs merge=lfs -text
*.c4d filter=lfs diff=lfs merge=lfs -text
*.dae filter=lfs diff=lfs merge=lfs -text
*.fbx filter=lfs diff=lfs merge=lfs -text
*.fbxkey filter=lfs diff=lfs merge=lfs -text
*.ma filter=lfs diff=lfs merge=lfs -text
*.max filter=lfs diff=lfs merge=lfs -text
*.mb filter=lfs diff=lfs merge=lfs -text
*.obj filter=lfs diff=lfs merge=lfs -text
*.usd filter=lfs diff=lfs merge=lfs -text
*.usdz filter=lfs diff=lfs merge=lfs -text
*.vdb filter=lfs diff=lfs merge=lfs -text
*.bphys filter=lfs diff=lfs merge=lfs -text
*.bobj filter=lfs diff=lfs merge=lfs -text
*.bvel filter=lfs diff=lfs merge=lfs -text
*.bpointcache filter=lfs diff=lfs merge=lfs -text
*.blob filter=lfs diff=lfs merge=lfs -text
*.unitypackage filter=lfs diff=lfs merge=lfs -text
# Character Creator files (Reallusion)
*.ccAvatar filter=lfs diff=lfs merge=lfs -text
*.ccProject filter=lfs diff=lfs merge=lfs -text
*.ccCloth filter=lfs diff=lfs merge=lfs -text
*.ccProp filter=lfs diff=lfs merge=lfs -text
*.ccScene filter=lfs diff=lfs merge=lfs -text
*.ccHair filter=lfs diff=lfs merge=lfs -text
*.rlMotion filter=lfs diff=lfs merge=lfs -text
*.rlPose filter=lfs diff=lfs merge=lfs -text
*.iAvatar filter=lfs diff=lfs merge=lfs -text
*.iMotion filter=lfs diff=lfs merge=lfs -text
*.iProp filter=lfs diff=lfs merge=lfs -text
*.iMaterial filter=lfs diff=lfs merge=lfs -text
*.rlHead filter=lfs diff=lfs merge=lfs -text
*.rlHair filter=lfs diff=lfs merge=lfs -text
*.rlScene filter=lfs diff=lfs merge=lfs -text
*.rlSkintex filter=lfs diff=lfs merge=lfs -text
# Houdini files
*.hiplc filter=lfs diff=lfs merge=lfs -text
*.bgeo filter=lfs diff=lfs merge=lfs -text
*.bgeo.sc filter=lfs diff=lfs merge=lfs -text
# Flip Fluids cache files
*.data filter=lfs diff=lfs merge=lfs -text
*.sqlite3 filter=lfs diff=lfs merge=lfs -text
*.ffp3 filter=lfs diff=lfs merge=lfs -text
# Substance files
*.sbs filter=lfs diff=lfs merge=lfs -text
*.sbsar filter=lfs diff=lfs merge=lfs -text
*.spp filter=lfs diff=lfs merge=lfs -text
# Audio files
*.mp3 filter=lfs diff=lfs merge=lfs -text
*.wav filter=lfs diff=lfs merge=lfs -text
*.m4a filter=lfs diff=lfs merge=lfs -text
*.aac filter=lfs diff=lfs merge=lfs -text
*.ogg filter=lfs diff=lfs merge=lfs -text
*.flac filter=lfs diff=lfs merge=lfs -text
# Archive/Compression files
*.7z filter=lfs diff=lfs merge=lfs -text
*.7z.[0-9][0-9][0-9] filter=lfs diff=lfs merge=lfs -text
*.bz2 filter=lfs diff=lfs merge=lfs -text
*.gz filter=lfs diff=lfs merge=lfs -text
*.rar filter=lfs diff=lfs merge=lfs -text
*.tar filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text
# Documents
*.docx filter=lfs diff=lfs merge=lfs -text
*.xlsx filter=lfs diff=lfs merge=lfs -text
*.eps filter=lfs diff=lfs merge=lfs -text
*.pdf filter=lfs diff=lfs merge=lfs -text
# Adobe files
*.aegraphic filter=lfs diff=lfs merge=lfs -text
*.aep filter=lfs diff=lfs merge=lfs -text
*.prel filter=lfs diff=lfs merge=lfs -text
*.prin filter=lfs diff=lfs merge=lfs -text
*.prmf filter=lfs diff=lfs merge=lfs -text
*.prproj filter=lfs diff=lfs merge=lfs -text
*.ai filter=lfs diff=lfs merge=lfs -text
*.psd filter=lfs diff=lfs merge=lfs -text
*.pk filter=lfs diff=lfs merge=lfs -text
*.pkf filter=lfs diff=lfs merge=lfs -text
# Davinci Resolve files
*.dpx filter=lfs diff=lfs merge=lfs -text
*.drp filter=lfs diff=lfs merge=lfs -text
# Data files
*.h5 filter=lfs diff=lfs merge=lfs -text
*.hdf5 filter=lfs diff=lfs merge=lfs -text
# Other
*.uni filter=lfs diff=lfs merge=lfs -text
*.pdn filter=lfs diff=lfs merge=lfs -text
*.pur filter=lfs diff=lfs merge=lfs -text
*.db filter=lfs diff=lfs merge=lfs -text
*.raw filter=lfs diff=lfs merge=lfs -text
*.lnk filter=lfs diff=lfs merge=lfs -text
# Python files
*.npz filter=lfs diff=lfs merge=lfs -text
# Adobe Alternatives
*.xcf filter=lfs diff=lfs merge=lfs -text
*.af filter=lfs diff=lfs merge=lfs -text
*.gitignore !text !filter !merge !diff
*.cursorindexingignore !text !filter !merge !diff
*.md !text !filter !merge !diff
*.py !text !filter !merge !diff
+51 -15
View File
@@ -10,6 +10,29 @@
*.blend7
*.blend8
*.blend9
*.blend10
*.blend11
*.blend12
*.blend13
*.blend14
*.blend15
*.blend16
*.blend17
*.blend18
*.blend19
*.blend20
*.blend21
*.blend22
*.blend23
*.blend24
*.blend25
*.blend26
*.blend27
*.blend28
*.blend29
*.blend30
*.blend31
*.blend32
# Blender cache and temporary files
*.swp
@@ -17,13 +40,7 @@
*~
*.tmp
*.temp
# Blender internal cache files
*.bpy
*.bmesh
*.bvh
*.bobj
*.bphys
BL_proxy/
# OS generated files
.DS_Store
@@ -41,6 +58,8 @@ desktop.ini
*.swp
*.swo
*~
.specstory/
.cursorindexingignore
# Large media files (uncomment if you want to exclude rendered outputs)
# *.mp4
@@ -60,15 +79,8 @@ desktop.ini
# *.aac
# *.ogg
# Archive files
*.zip
*.rar
*.7z
*.tar.gz
# Log files
*.log
*.txt
# Python cache
__pycache__/
@@ -95,4 +107,28 @@ node_modules/
# Temporary files
temp/
tmp/
cache/
cache/
Renders/**
!Renders/_zipped/
!Renders/_zipped/**
!Renders/**/
!Renders/**/*.bat
!Renders/**/*.log
seq/
# Premiere
*.prlock
Adobe Premiere Pro Video Previews/
Adobe Premiere Pro Audio Previews/
Adobe Premiere Pro (Beta) Video Previews/
Adobe Premiere Pro (Beta) Audio Previews/
footage/
plates/
RnR/
# Microsoft Office temporary files
~$*
_archive/
-2
View File
@@ -1,2 +0,0 @@
# SpecStory explanation file
/.what-is-this.md
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.
+43
View File
@@ -0,0 +1,43 @@
@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "REN_DIR=%~dp0"
for %%I in ("%REN_DIR%..") do set "PROJ_ROOT=%%~fI"
set "CONFIG_DIR=%PROJ_ROOT%\.config"
set "CONFIG_PATH=%CONFIG_DIR%\config.json"
set "GET_STRUCT_DIR=%CONFIG_DIR%\GetStructDir.ps1"
if not exist "%CONFIG_PATH%" (
echo [ERROR] config.json not found at %CONFIG_PATH%
echo Please run CfgDeploy.ps1 to deploy helper files.
exit /b 1
)
if not exist "%GET_STRUCT_DIR%" (
echo [ERROR] GetStructDir.ps1 not found at %GET_STRUCT_DIR%
echo Please run CfgDeploy.ps1 to deploy helper files.
exit /b 1
)
for /f "usebackq delims=" %%I in (`powershell -NoProfile -ExecutionPolicy Bypass -Command ^
"Set-StrictMode -Version Latest; $structDir = & '%GET_STRUCT_DIR%' -ProjectRoot '%PROJ_ROOT%'; if (-not $structDir) { throw \"Failed to get structDir from GetStructDir.ps1\" }; $pyPath = Join-Path $structDir 'compress_sequence_pngs.py'; if (-not (Test-Path -LiteralPath $pyPath)) { throw \"compress_sequence_pngs.py not found at $pyPath\" }; Write-Output $pyPath"`) do set "PY_SCRIPT=%%~I"
if not defined PY_SCRIPT (
echo [ERROR] Unable to resolve compress_sequence_pngs.py path from config.
exit /b 1
)
pushd "%PROJ_ROOT%" >nul 2>&1
python "%PY_SCRIPT%" %*
set "ERR=!ERRORLEVEL!"
popd >nul 2>&1
if !ERR! NEQ 0 (
echo PNG compression failed ^(exit code !ERR!^).
exit /b !ERR!
)
exit /b 0
+42
View File
@@ -0,0 +1,42 @@
@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "REN_DIR=%~dp0"
for %%I in ("%REN_DIR%..") do set "PROJ_ROOT=%%~fI"
set "CONFIG_DIR=%PROJ_ROOT%\.config"
set "CONFIG_PATH=%CONFIG_DIR%\config.json"
set "GET_STRUCT_DIR=%CONFIG_DIR%\GetStructDir.ps1"
if not exist "%CONFIG_PATH%" (
echo [ERROR] config.json not found at %CONFIG_PATH%
echo Please run CfgDeploy.ps1 to deploy helper files.
exit /b 1
)
if not exist "%GET_STRUCT_DIR%" (
echo [ERROR] GetStructDir.ps1 not found at %GET_STRUCT_DIR%
echo Please run CfgDeploy.ps1 to deploy helper files.
exit /b 1
)
for /f "usebackq delims=" %%I in (`powershell -NoProfile -ExecutionPolicy Bypass -Command ^
"Set-StrictMode -Version Latest; $structDir = & '%GET_STRUCT_DIR%' -ProjectRoot '%PROJ_ROOT%'; if (-not $structDir) { throw \"Failed to get structDir from GetStructDir.ps1\" }; $pyPath = Join-Path $structDir 'zip_sequences.py'; if (-not (Test-Path -LiteralPath $pyPath)) { throw \"zip_sequences.py not found at $pyPath\" }; Write-Output $pyPath"`) do set "PY_SCRIPT=%%I"
if not defined PY_SCRIPT (
echo [ERROR] Unable to resolve zip_sequences.py path from config.
exit /b 1
)
pushd "%PROJ_ROOT%" >nul 2>&1
python "%PY_SCRIPT%" --mode expand --verbose %*
set "ERR=!ERRORLEVEL!"
if not "!ERR!"=="0" (
echo Failed to expand render sequence archives (exit code !ERR!).
)
popd >nul 2>&1
exit /b !ERR!
+71
View File
@@ -0,0 +1,71 @@
@echo off
setlocal EnableExtensions
set "script_dir=%~dp0"
set "current_dir=%CD%"
set "PROJ_ROOT="
REM First, check project level (one directory up from current) - most common case
for %%I in ("%current_dir%..") do set "project_level=%%~fI"
set "project_config=%project_level%\.config\config.json"
if exist "%project_config%" (
set "PROJ_ROOT=%project_level%"
)
REM If not found at project level, search up from current working directory
if not defined PROJ_ROOT (
for /f "usebackq delims=" %%I in (`powershell -NoProfile -ExecutionPolicy Bypass -Command "Set-StrictMode -Version Latest; $dir = '%current_dir%'; $found = $null; while ($dir -and -not $found) { $configPath = Join-Path $dir '.config\config.json'; if (Test-Path -LiteralPath $configPath) { $found = $dir; break }; $parent = Split-Path -Parent $dir; if ($parent -eq $dir) { break }; $dir = $parent }; if ($found) { Write-Output $found } else { Write-Output '' }"`) do set "PROJ_ROOT=%%I"
)
REM If still not found, try searching from script location
if not defined PROJ_ROOT (
for /f "usebackq delims=" %%I in (`powershell -NoProfile -ExecutionPolicy Bypass -Command "Set-StrictMode -Version Latest; $dir = '%script_dir%'; $found = $null; while ($dir -and -not $found) { $configPath = Join-Path $dir '.config\config.json'; if (Test-Path -LiteralPath $configPath) { $found = $dir; break }; $parent = Split-Path -Parent $dir; if ($parent -eq $dir) { break }; $dir = $parent }; if ($found) { Write-Output $found } else { Write-Output '' }"`) do set "PROJ_ROOT=%%I"
)
REM Fallback: try original logic (script in 3 ProjectStructure)
if not defined PROJ_ROOT (
for %%I in ("%script_dir%..\..") do set "PROJ_ROOT=%%~fI"
)
set "CONFIG_DIR=%PROJ_ROOT%\.config"
set "CONFIG_PATH=%CONFIG_DIR%\config.json"
if not exist "%CONFIG_PATH%" (
echo [ERROR] config.json not found at %CONFIG_PATH%
if defined project_config (
echo Also checked: %project_config%
)
echo Please run CfgDeploy.ps1 to deploy helper files.
exit /b 1
)
set "GET_STRUCT_DIR=%CONFIG_DIR%\GetStructDir.ps1"
if not exist "%GET_STRUCT_DIR%" (
echo [ERROR] GetStructDir.ps1 not found at %GET_STRUCT_DIR%
echo Please run CfgDeploy.ps1 to deploy helper files.
exit /b 1
)
for /f "usebackq delims=" %%I in (`powershell -NoProfile -ExecutionPolicy Bypass -Command ^
"Set-StrictMode -Version Latest; $structDir = & '%GET_STRUCT_DIR%' -ProjectRoot '%PROJ_ROOT%'; if (-not $structDir) { throw \"Failed to get structDir from GetStructDir.ps1\" }; $ps1Path = Join-Path $structDir 'UpdateSequences.ps1'; if (-not (Test-Path -LiteralPath $ps1Path)) { throw \"UpdateSequences.ps1 not found at $ps1Path\" }; Write-Output $ps1Path"`) do set "ps1=%%I"
if not defined ps1 (
echo [ERROR] Unable to resolve UpdateSequences.ps1 path from config.
exit /b 1
)
REM Run from batch directory (sequences next to batch, or submodule root)
set "WORK_DIR=%script_dir%"
if "%WORK_DIR:~-1%"=="\" set "WORK_DIR=%WORK_DIR:~0,-1%"
pushd "%WORK_DIR%" >nul 2>&1
echo Running PowerShell update script in %WORK_DIR%...
powershell -NoProfile -ExecutionPolicy Bypass -File "%ps1%"
set "rc=%errorlevel%"
popd >nul 2>&1
echo PowerShell exited with RC=%rc%
echo Done.
pause >nul
exit /b %rc%
+44
View File
@@ -0,0 +1,44 @@
@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "REN_DIR=%~dp0"
for %%I in ("%REN_DIR%..") do set "PROJ_ROOT=%%~fI"
set "CONFIG_DIR=%PROJ_ROOT%\.config"
set "CONFIG_PATH=%CONFIG_DIR%\config.json"
set "GET_STRUCT_DIR=%CONFIG_DIR%\GetStructDir.ps1"
if not exist "%CONFIG_PATH%" (
echo [ERROR] config.json not found at %CONFIG_PATH%
echo Please run CfgDeploy.ps1 to deploy helper files.
exit /b 1
)
if not exist "%GET_STRUCT_DIR%" (
echo [ERROR] GetStructDir.ps1 not found at %GET_STRUCT_DIR%
echo Please run CfgDeploy.ps1 to deploy helper files.
exit /b 1
)
for /f "usebackq delims=" %%I in (`powershell -NoProfile -ExecutionPolicy Bypass -Command ^
"Set-StrictMode -Version Latest; $structDir = & '%GET_STRUCT_DIR%' -ProjectRoot '%PROJ_ROOT%'; if (-not $structDir) { throw \"Failed to get structDir from GetStructDir.ps1\" }; $pyPath = Join-Path $structDir 'zip_sequences.py'; if (-not (Test-Path -LiteralPath $pyPath)) { throw \"zip_sequences.py not found at $pyPath\" }; Write-Output $pyPath"`) do set "PY_SCRIPT=%%~I"
if not defined PY_SCRIPT (
echo [ERROR] Unable to resolve zip_sequences.py path from config.
exit /b 1
)
pushd "%PROJ_ROOT%" >nul 2>&1
python "%PY_SCRIPT%" --verbose %*
set "ERR=!ERRORLEVEL!"
popd >nul 2>&1
if !ERR! NEQ 0 (
echo Failed to update render sequence archives ^(exit code !ERR!^).
exit /b !ERR!
)
exit /b 0
+82 -82
View File
@@ -1,83 +1,83 @@
import bpy
import os
import re
def relocate_libraries():
"""
Relocate linked library files from Synology Drive to NAS storage.
Changes paths from C:\\Users\\Nathan\\SynologyDrive\\ to R:\\
"""
# Define the path mappings
old_base = r"C:\Users\Nathan\SynologyDrive"
new_base = r"R:"
# Track changes
changed_files = []
failed_files = []
print("=== Library Relocation Script ===")
print(f"Mapping: {old_base}{new_base}")
print()
# Process all library files
for lib in bpy.data.libraries:
if lib.filepath:
old_path = lib.filepath
# Check if this is a Synology Drive path
if old_base in old_path:
# Create new path
new_path = old_path.replace(old_base, new_base)
# Verify the new file exists
if os.path.exists(new_path):
try:
# Update the library path
lib.filepath = new_path
changed_files.append((old_path, new_path))
print(f"✓ Relocated: {os.path.basename(old_path)}")
print(f" {old_path}")
print(f"{new_path}")
print()
except Exception as e:
failed_files.append((old_path, str(e)))
print(f"✗ Failed to relocate: {os.path.basename(old_path)}")
print(f" Error: {e}")
print()
else:
failed_files.append((old_path, "Target file not found"))
print(f"✗ Target not found: {new_path}")
print()
else:
print(f" Skipped (not Synology Drive): {old_path}")
print()
# Summary
print("=== Summary ===")
print(f"Successfully relocated: {len(changed_files)} files")
print(f"Failed to relocate: {len(failed_files)} files")
if changed_files:
print("\nRelocated files:")
for old, new in changed_files:
print(f" {os.path.basename(old)}")
if failed_files:
print("\nFailed files:")
for old, reason in failed_files:
print(f" {os.path.basename(old)}: {reason}")
return len(changed_files), len(failed_files)
# Run the script
if __name__ == "__main__":
success_count, fail_count = relocate_libraries()
if success_count > 0:
print(f"\n✅ Successfully relocated {success_count} library files!")
print("You may need to save your .blend file to preserve these changes.")
if fail_count > 0:
print(f"\n⚠️ {fail_count} files failed to relocate.")
import bpy
import os
import re
def relocate_libraries():
"""
Relocate linked library files from Synology Drive to NAS storage.
Changes paths from C:\\Users\\Nathan\\SynologyDrive\\ to R:\\
"""
# Define the path mappings
old_base = r"C:\Users\Nathan\SynologyDrive"
new_base = r"R:"
# Track changes
changed_files = []
failed_files = []
print("=== Library Relocation Script ===")
print(f"Mapping: {old_base}{new_base}")
print()
# Process all library files
for lib in bpy.data.libraries:
if lib.filepath:
old_path = lib.filepath
# Check if this is a Synology Drive path
if old_base in old_path:
# Create new path
new_path = old_path.replace(old_base, new_base)
# Verify the new file exists
if os.path.exists(new_path):
try:
# Update the library path
lib.filepath = new_path
changed_files.append((old_path, new_path))
print(f"✓ Relocated: {os.path.basename(old_path)}")
print(f" {old_path}")
print(f"{new_path}")
print()
except Exception as e:
failed_files.append((old_path, str(e)))
print(f"✗ Failed to relocate: {os.path.basename(old_path)}")
print(f" Error: {e}")
print()
else:
failed_files.append((old_path, "Target file not found"))
print(f"✗ Target not found: {new_path}")
print()
else:
print(f" Skipped (not Synology Drive): {old_path}")
print()
# Summary
print("=== Summary ===")
print(f"Successfully relocated: {len(changed_files)} files")
print(f"Failed to relocate: {len(failed_files)} files")
if changed_files:
print("\nRelocated files:")
for old, new in changed_files:
print(f" {os.path.basename(old)}")
if failed_files:
print("\nFailed files:")
for old, reason in failed_files:
print(f" {os.path.basename(old)}: {reason}")
return len(changed_files), len(failed_files)
# Run the script
if __name__ == "__main__":
success_count, fail_count = relocate_libraries()
if success_count > 0:
print(f"\n✅ Successfully relocated {success_count} library files!")
print("You may need to save your .blend file to preserve these changes.")
if fail_count > 0:
print(f"\n⚠️ {fail_count} files failed to relocate.")
print("Check that the NAS paths exist and are accessible.")