begin develop configloader

This commit is contained in:
2025-11-08 02:36:20 -07:00
parent 78598f68db
commit e541aa1a12
12 changed files with 2485 additions and 59 deletions

File diff suppressed because one or more lines are too long

24
CONFIG.md Normal file
View File

@@ -0,0 +1,24 @@
# ProjectStructure Configuration
The repository reads user preferences from `config.json` in the ProjectStructure
root (copied alongside helper batches when they are deployed to projects).
## Keys
| Key | Type | Meaning |
| --- | --- | --- |
| `dailyFormat` | bool | `true` → daily folders named `YYYY-MM-DD`; `false``daily_*` style. |
| `structDir` | string | Absolute or relative path to the canonical ProjectStructure directory. Blank values default to the folder containing `config.json`. |
| `projectsRoot` | string (optional) | Override for the root directory scanned by `UpgradeSeqBatches.ps1`. Defaults to the parent of `structDir`. |
| `zipper` | bool | `true` → use 7Zip (if available); `false` → use Pythons built-in zipfile module. |
| `compression` | int | Compression level `0-9` (0 = store only, 9 = max). Applies to both zipfile and 7Zip. |
## Notes
- `UpgradeSeqBatches.ps1` copies `config.json` and `ConfigLoader.ps1` to every
target folder so the helper `.bat` launchers can resolve script locations.
- When `zipper` is `true`, the tool searches for `7z`/`7za` on `PATH`. If neither
is found it logs a warning and falls back to `zipfile`.
- Leaving `structDir` empty is safe—the scripts fall back to the directory that
contains `config.json`.

113
ConfigLoader.ps1 Normal file
View File

@@ -0,0 +1,113 @@
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
$script:LoaderRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
$script:ConfigPath = Join-Path -Path $script:LoaderRoot -ChildPath 'config.json'
$script:ConfigCache = $null
function Get-ProjectStructureConfig {
if ($null -ne $script:ConfigCache) {
return $script:ConfigCache
}
if (Test-Path -LiteralPath $script:ConfigPath) {
try {
$raw = Get-Content -LiteralPath $script:ConfigPath -Raw -ErrorAction Stop
if ($raw.Trim().Length -gt 0) {
$script:ConfigCache = $raw | ConvertFrom-Json
return $script:ConfigCache
}
}
catch {
Write-Warning "Failed to parse config.json: $($_.Exception.Message)"
}
}
$script:ConfigCache = [pscustomobject]@{}
return $script:ConfigCache
}
function Get-ConfigValue {
param(
[Parameter(Mandatory)] [string]$Name,
$Default = $null
)
$config = Get-ProjectStructureConfig
if ($config.PSObject.Properties.Name -contains $Name) {
$value = $config.$Name
if ($null -ne $value -and ($value -isnot [string] -or $value.Trim().Length -gt 0)) {
return $value
}
}
return $Default
}
function Get-StructDirectory {
$value = Get-ConfigValue -Name 'structDir'
if ($null -eq $value -or [string]::IsNullOrWhiteSpace($value)) {
return $script:LoaderRoot
}
if ([System.IO.Path]::IsPathRooted($value)) {
$resolved = Resolve-Path -LiteralPath $value -ErrorAction SilentlyContinue
if ($null -ne $resolved) { return $resolved.Path }
return $value
}
$candidate = Join-Path -Path $script:LoaderRoot -ChildPath $value
$resolvedCandidate = Resolve-Path -LiteralPath $candidate -ErrorAction SilentlyContinue
if ($null -ne $resolvedCandidate) { return $resolvedCandidate.Path }
return $candidate
}
function Get-ProjectsRoot {
$value = Get-ConfigValue -Name 'projectsRoot'
if ($null -eq $value -or [string]::IsNullOrWhiteSpace($value)) {
$structDir = Get-StructDirectory
$parent = Split-Path -Parent $structDir
if ($null -eq $parent -or $parent.Length -eq 0 -or $parent -eq $structDir) {
return $structDir
}
return $parent
}
if ([System.IO.Path]::IsPathRooted($value)) {
$resolved = Resolve-Path -LiteralPath $value -ErrorAction SilentlyContinue
if ($null -ne $resolved) { return $resolved.Path }
return $value
}
$candidate = Join-Path -Path $script:LoaderRoot -ChildPath $value
$resolvedCandidate = Resolve-Path -LiteralPath $candidate -ErrorAction SilentlyContinue
if ($null -ne $resolvedCandidate) { return $resolvedCandidate.Path }
return $candidate
}
function Use-IsoDailyFormat {
$dailyFormat = Get-ConfigValue -Name 'dailyFormat' -Default $true
return [bool]$dailyFormat
}
function Use-7Zip {
$zipper = Get-ConfigValue -Name 'zipper' -Default $true
return [bool]$zipper
}
function Get-ZipCompressionLevel {
$value = Get-ConfigValue -Name 'compression' -Default 9
if ($value -is [string]) {
$parsed = 0
if ([int]::TryParse($value, [ref]$parsed)) {
$value = $parsed
}
}
if ($value -isnot [int]) {
return 9
}
return [Math]::Min(9, [Math]::Max(0, $value))
}

View File

@@ -1,5 +1,27 @@
@echo off @echo off
setlocal setlocal EnableExtensions
set "SCRIPT_DIR=%~dp0"
set "CONFIG_LOADER=%SCRIPT_DIR%ConfigLoader.ps1"
set "CONFIG_PATH=%SCRIPT_DIR%config.json"
if not exist "%CONFIG_LOADER%" (
echo [ERROR] ConfigLoader.ps1 not found next to NewProject.bat.
exit /b 1
)
if not exist "%CONFIG_PATH%" (
echo [ERROR] config.json not found next to NewProject.bat.
exit /b 1
)
for /f "usebackq delims=" %%I in (`powershell -NoProfile -ExecutionPolicy Bypass -Command ^
"Set-StrictMode -Version Latest; $loader = Resolve-Path -LiteralPath '%CONFIG_LOADER%' -ErrorAction Stop; . $loader.Path; Write-Output (Get-StructDirectory)"`) do set "STRUCT_DIR=%%I"
if not defined STRUCT_DIR (
echo [ERROR] Unable to resolve ProjectStructure directory from config.
exit /b 1
)
:: Get current date in YYYY-MM-DD format :: Get current date in YYYY-MM-DD format
for /f "tokens=2-4 delims=/ " %%a in ('date /t') do ( for /f "tokens=2-4 delims=/ " %%a in ('date /t') do (
@@ -20,7 +42,7 @@ mkdir "%projectRoot%"
:: Create Assets structure :: Create Assets structure
mkdir "%projectRoot%\Assets\ElevenLabs" mkdir "%projectRoot%\Assets\ElevenLabs"
if exist "A:\1 Amazon_Active_Projects\3 ProjectStructure\NewDaily.bat" copy /Y "A:\1 Amazon_Active_Projects\3 ProjectStructure\NewDaily.bat" "%projectRoot%\Assets\ElevenLabs\NewDaily.bat" >nul if exist "%STRUCT_DIR%\NewDaily.bat" copy /Y "%STRUCT_DIR%\NewDaily.bat" "%projectRoot%\Assets\ElevenLabs\NewDaily.bat" >nul
mkdir "%projectRoot%\Assets\Blends" mkdir "%projectRoot%\Assets\Blends"
mkdir "%projectRoot%\Assets\Mocap" mkdir "%projectRoot%\Assets\Mocap"
mkdir "%projectRoot%\Assets\VO" mkdir "%projectRoot%\Assets\VO"
@@ -40,11 +62,10 @@ mkdir "%projectRoot%\Pr\RnR\RIFE"
if not exist "%projectRoot%\Renders" mkdir "%projectRoot%\Renders" if not exist "%projectRoot%\Renders" mkdir "%projectRoot%\Renders"
:: Place helper scripts into Renders :: Place helper scripts into Renders
set "templateRoot=%~dp0" set "templateRoot=%STRUCT_DIR%"
if not exist "%templateRoot%ZipSeqArchv.bat" set "templateRoot=A:\1 Amazon_Active_Projects\3 ProjectStructure\" for %%F in (UpdateSequences.bat ZipSeqArchv.bat UnzipSeqArchv.bat ConfigLoader.ps1 config.json) do (
if exist "%templateRoot%UpdateSequences.bat" copy /Y "%templateRoot%UpdateSequences.bat" "%projectRoot%\Renders\UpdateSequences.bat" >nul if exist "%templateRoot%\%%F" copy /Y "%templateRoot%\%%F" "%projectRoot%\Renders\%%F" >nul
if exist "%templateRoot%ZipSeqArchv.bat" copy /Y "%templateRoot%ZipSeqArchv.bat" "%projectRoot%\Renders\ZipSeqArchv.bat" >nul )
if exist "%templateRoot%UnzipSeqArchv.bat" copy /Y "%templateRoot%UnzipSeqArchv.bat" "%projectRoot%\Renders\UnzipSeqArchv.bat" >nul
:: Use repo-provided templates for git config files :: Use repo-provided templates for git config files
if exist "%~dp0components\gitignore" copy /Y "%~dp0components\gitignore" "%projectRoot%\.gitignore" >nul if exist "%~dp0components\gitignore" copy /Y "%~dp0components\gitignore" "%projectRoot%\.gitignore" >nul

View File

@@ -1,12 +1,29 @@
@echo off @echo off
setlocal setlocal EnableExtensions
set "REN_DIR=%~dp0" set "REN_DIR=%~dp0"
for %%I in ("%REN_DIR%..") do set "PROJ_ROOT=%%~fI" for %%I in ("%REN_DIR%..") do set "PROJ_ROOT=%%~fI"
set "PY_SCRIPT=A:\1 Amazon_Active_Projects\3 ProjectStructure\zip_sequences.py"
if not exist "%PY_SCRIPT%" ( set "CONFIG_LOADER=%REN_DIR%ConfigLoader.ps1"
echo Missing %PY_SCRIPT% set "CONFIG_PATH=%REN_DIR%config.json"
if not exist "%CONFIG_LOADER%" (
echo [ERROR] ConfigLoader.ps1 not found next to UnzipSeqArchv.bat.
echo Please run UpgradeSeqBatches.ps1 to refresh helper files.
exit /b 1
)
if not exist "%CONFIG_PATH%" (
echo [ERROR] config.json not found next to UnzipSeqArchv.bat.
echo Please run UpgradeSeqBatches.ps1 to refresh helper files.
exit /b 1
)
for /f "usebackq delims=" %%I in (`powershell -NoProfile -ExecutionPolicy Bypass -Command ^
"Set-StrictMode -Version Latest; $loader = Resolve-Path -LiteralPath '%CONFIG_LOADER%' -ErrorAction Stop; . $loader.Path; $pyPath = Join-Path (Get-StructDirectory) '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 exit /b 1
) )

View File

@@ -1,7 +1,30 @@
@echo off @echo off
setlocal EnableExtensions setlocal EnableExtensions
set "ps1=A:\1 Amazon_Active_Projects\3 ProjectStructure\UpdateSequences.ps1" set "script_dir=%~dp0"
set "config_loader=%script_dir%ConfigLoader.ps1"
set "config_path=%script_dir%config.json"
if not exist "%config_loader%" (
echo [ERROR] ConfigLoader.ps1 not found next to UpdateSequences.bat.
echo Please run UpgradeSeqBatches.ps1 to refresh helper files.
exit /b 1
)
if not exist "%config_path%" (
echo [ERROR] config.json not found next to UpdateSequences.bat.
echo Please run UpgradeSeqBatches.ps1 to refresh helper files.
exit /b 1
)
for /f "usebackq delims=" %%I in (`powershell -NoProfile -ExecutionPolicy Bypass -Command ^
"Set-StrictMode -Version Latest; $loader = Resolve-Path -LiteralPath '%config_loader%' -ErrorAction Stop; . $loader.Path; $ps1Path = Join-Path (Get-StructDirectory) '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
)
echo Running PowerShell update script... echo Running PowerShell update script...
powershell -NoProfile -ExecutionPolicy Bypass -File "%ps1%" powershell -NoProfile -ExecutionPolicy Bypass -File "%ps1%"
set "rc=%errorlevel%" set "rc=%errorlevel%"

View File

@@ -6,6 +6,18 @@ param(
Set-StrictMode -Version Latest Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop' $ErrorActionPreference = 'Stop'
if (-not $PSScriptRoot) {
$PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
}
$configLoader = Join-Path -Path $PSScriptRoot -ChildPath 'ConfigLoader.ps1'
if (-not (Test-Path -LiteralPath $configLoader)) {
throw "Missing ConfigLoader.ps1 in $PSScriptRoot"
}
. $configLoader
$useIsoDailyFormat = Use-IsoDailyFormat
function Sync-SequenceFilenames { function Sync-SequenceFilenames {
param( param(
[Parameter(Mandatory)] [string]$SequenceFolderPath, [Parameter(Mandatory)] [string]$SequenceFolderPath,
@@ -191,9 +203,12 @@ try {
$sequenceMap = @{} $sequenceMap = @{}
$dailyDirs = Get-ChildItem -LiteralPath $root -Directory -Filter 'daily_*' -ErrorAction SilentlyContinue | $primaryPattern = if ($useIsoDailyFormat) { '????-??-??' } else { 'daily_*' }
$secondaryPattern = if ($useIsoDailyFormat) { 'daily_*' } else { '????-??-??' }
$primaryDirs = Get-ChildItem -LiteralPath $root -Directory -Filter $primaryPattern -ErrorAction SilentlyContinue |
Where-Object { $_.Name -ne '_archive' } Where-Object { $_.Name -ne '_archive' }
foreach ($d in $dailyDirs) { foreach ($d in $primaryDirs) {
$seqDirs = @(Get-ChildItem -LiteralPath $d.FullName -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -ne '_archive' }) $seqDirs = @(Get-ChildItem -LiteralPath $d.FullName -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -ne '_archive' })
if ($seqDirs.Count -eq 0) { if ($seqDirs.Count -eq 0) {
Add-SequenceFolder -Directory $d -Map $sequenceMap Add-SequenceFolder -Directory $d -Map $sequenceMap
@@ -204,10 +219,9 @@ try {
} }
} }
# Scan for YYYY-MM-DD format folders (home convention) $secondaryDirs = Get-ChildItem -LiteralPath $root -Directory -Filter $secondaryPattern -ErrorAction SilentlyContinue |
$dailyDirsHome = Get-ChildItem -LiteralPath $root -Directory -Filter '????-??-??' -ErrorAction SilentlyContinue |
Where-Object { $_.Name -ne '_archive' } Where-Object { $_.Name -ne '_archive' }
foreach ($d in $dailyDirsHome) { foreach ($d in $secondaryDirs) {
$seqDirs = @(Get-ChildItem -LiteralPath $d.FullName -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -ne '_archive' }) $seqDirs = @(Get-ChildItem -LiteralPath $d.FullName -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -ne '_archive' })
if ($seqDirs.Count -eq 0) { if ($seqDirs.Count -eq 0) {
Add-SequenceFolder -Directory $d -Map $sequenceMap Add-SequenceFolder -Directory $d -Map $sequenceMap
@@ -218,9 +232,12 @@ try {
} }
} }
# Scan for direct sequence folders (not in daily_* or YYYY-MM-DD folders)
$directSeqs = Get-ChildItem -LiteralPath $root -Directory -ErrorAction SilentlyContinue | $directSeqs = Get-ChildItem -LiteralPath $root -Directory -ErrorAction SilentlyContinue |
Where-Object { $_.Name -ne '_archive' -and $_.Name -notlike 'daily_*' -and $_.Name -notmatch '^\d{4}-\d{2}-\d{2}$' } Where-Object {
$_.Name -ne '_archive' -and
$_.Name -notlike 'daily_*' -and
$_.Name -notmatch '^\d{4}-\d{2}-\d{2}$'
}
foreach ($seq in $directSeqs) { foreach ($seq in $directSeqs) {
Add-SequenceFolder -Directory $seq -Map $sequenceMap Add-SequenceFolder -Directory $seq -Map $sequenceMap
} }

View File

@@ -1,28 +1,59 @@
# Update subfolders with the latest UpdateSequences and UpdateAllSequences scripts # Update subfolders with the latest UpdateSequences and UpdateAllSequences scripts
$sourceBat = "R:\Creative\artsy\maya\0 ProjectStructure\UpdateSequences.bat" Set-StrictMode -Version Latest
$sourceAllBat = "R:\Creative\artsy\maya\0 ProjectStructure\UpdateAllSequences.bat" $ErrorActionPreference = 'Stop'
if (-not (Test-Path $sourceBat)) { Write-Error "Source file not found: $sourceBat"; exit 1 } if (-not $PSScriptRoot) {
if (-not (Test-Path $sourceAllBat)) { Write-Error "Source file not found: $sourceAllBat"; exit 1 } $PSScriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
}
$root = "R:\Creative\artsy\maya" $configLoader = Join-Path -Path $PSScriptRoot -ChildPath 'ConfigLoader.ps1'
if (-not (Test-Path -LiteralPath $configLoader)) {
throw "Missing ConfigLoader.ps1 in $PSScriptRoot"
}
. $configLoader
$structDir = Get-StructDirectory
$projectsRoot = Get-ProjectsRoot
$sourceBat = Join-Path -Path $structDir -ChildPath 'UpdateSequences.bat'
$sourceAllBat = Join-Path -Path $structDir -ChildPath 'UpdateAllSequences.bat'
$sourceZipBat = Join-Path -Path $structDir -ChildPath 'ZipSeqArchv.bat'
$sourceUnzipBat = Join-Path -Path $structDir -ChildPath 'UnzipSeqArchv.bat'
$configLoaderSource = Join-Path -Path $structDir -ChildPath 'ConfigLoader.ps1'
$configJsonSource = Join-Path -Path $structDir -ChildPath 'config.json'
if (-not (Test-Path -LiteralPath $sourceBat)) { Write-Error "Source file not found: $sourceBat"; exit 1 }
if (-not (Test-Path -LiteralPath $sourceAllBat)) { Write-Error "Source file not found: $sourceAllBat"; exit 1 }
if (-not (Test-Path -LiteralPath $sourceZipBat)) { Write-Error "Source file not found: $sourceZipBat"; exit 1 }
if (-not (Test-Path -LiteralPath $sourceUnzipBat)) { Write-Error "Source file not found: $sourceUnzipBat"; exit 1 }
if (-not (Test-Path -LiteralPath $configLoaderSource)) { Write-Error "Config loader not found: $configLoaderSource"; exit 1 }
if (-not (Test-Path -LiteralPath $configJsonSource)) { Write-Error "Config file not found: $configJsonSource"; exit 1 }
$specs = @( $specs = @(
@{ Name = "UpdateSequences.bat"; Source = $sourceBat }, @{ Name = "UpdateSequences.bat"; Source = $sourceBat },
@{ Name = "UpdateAllSequences.bat"; Source = $sourceAllBat } @{ Name = "UpdateAllSequences.bat"; Source = $sourceAllBat },
@{ Name = "ZipSeqArchv.bat"; Source = $sourceZipBat },
@{ Name = "UnzipSeqArchv.bat"; Source = $sourceUnzipBat }
)
$sharedAssets = @(
@{ Name = 'ConfigLoader.ps1'; Source = $configLoaderSource },
@{ Name = 'config.json'; Source = $configJsonSource }
) )
$grandTotal = 0 $grandTotal = 0
$grandUpdated = 0 $grandUpdated = 0
$grandFailed = 0 $grandFailed = 0
$touchedDirs = @{}
foreach ($spec in $specs) { foreach ($spec in $specs) {
Write-Host "=== Updating $($spec.Name) files ===" -ForegroundColor Cyan Write-Host "=== Updating $($spec.Name) files ===" -ForegroundColor Cyan
Write-Host "Source: $($spec.Source)" -ForegroundColor White Write-Host "Source: $($spec.Source)" -ForegroundColor White
Write-Host "" Write-Host ""
$targets = Get-ChildItem -Path $root -Recurse -Filter $spec.Name | Where-Object { $_.FullName -ne $spec.Source } $targets = Get-ChildItem -LiteralPath $projectsRoot -Recurse -Filter $spec.Name -File -ErrorAction SilentlyContinue |
Where-Object { $_.FullName -ne $spec.Source }
Write-Host "Found $($targets.Count) target files to update:" -ForegroundColor Yellow Write-Host "Found $($targets.Count) target files to update:" -ForegroundColor Yellow
foreach ($t in $targets) { Write-Host " - $($t.FullName)" -ForegroundColor Gray } foreach ($t in $targets) { Write-Host " - $($t.FullName)" -ForegroundColor Gray }
Write-Host "" Write-Host ""
@@ -30,10 +61,24 @@ foreach ($spec in $specs) {
$updated = 0 $updated = 0
$failed = 0 $failed = 0
foreach ($t in $targets) { foreach ($t in $targets) {
$targetDir = $t.Directory.FullName
try { try {
Copy-Item -Path $spec.Source -Destination $t.FullName -Force Copy-Item -Path $spec.Source -Destination $t.FullName -Force
Write-Host "✓ Updated: $($t.FullName)" -ForegroundColor Green Write-Host "✓ Updated: $($t.FullName)" -ForegroundColor Green
$updated++ $updated++
if (-not $touchedDirs.ContainsKey($targetDir)) {
foreach ($asset in $sharedAssets) {
try {
Copy-Item -Path $asset.Source -Destination (Join-Path -Path $targetDir -ChildPath $asset.Name) -Force
}
catch {
Write-Host "✗ Failed to copy $($asset.Name) to $targetDir" -ForegroundColor Red
Write-Host " Error: $($_.Exception.Message)" -ForegroundColor Red
}
}
$touchedDirs[$targetDir] = $true
}
} }
catch { catch {
Write-Host "✗ Failed to update: $($t.FullName)" -ForegroundColor Red Write-Host "✗ Failed to update: $($t.FullName)" -ForegroundColor Red

View File

@@ -56,6 +56,18 @@ for %%F in (UpdateSequences.bat ZipSeqArchv.bat UnzipSeqArchv.bat) do (
) )
) )
for %%F in (ConfigLoader.ps1 config.json) do (
if exist "%scriptDir%%%F" (
if "%DRY%"=="1" (
echo [DRY] copy "%scriptDir%%%F" "%rendersDir%\%%F"
) else (
copy /Y "%scriptDir%%%F" "%rendersDir%\%%F" >nul
)
) else (
echo [WARN] Missing template: "%scriptDir%%%F"
)
)
:: ----------------------------- :: -----------------------------
:: Merge .gitignore and .gitattributes from templates :: Merge .gitignore and .gitattributes from templates
:: ----------------------------- :: -----------------------------

View File

@@ -1,12 +1,29 @@
@echo off @echo off
setlocal setlocal EnableExtensions
set "REN_DIR=%~dp0" set "REN_DIR=%~dp0"
for %%I in ("%REN_DIR%..") do set "PROJ_ROOT=%%~fI" for %%I in ("%REN_DIR%..") do set "PROJ_ROOT=%%~fI"
set "PY_SCRIPT=A:\1 Amazon_Active_Projects\3 ProjectStructure\zip_sequences.py"
if not exist "%PY_SCRIPT%" ( set "CONFIG_LOADER=%REN_DIR%ConfigLoader.ps1"
echo Missing %PY_SCRIPT% set "CONFIG_PATH=%REN_DIR%config.json"
if not exist "%CONFIG_LOADER%" (
echo [ERROR] ConfigLoader.ps1 not found next to ZipSeqArchv.bat.
echo Please run UpgradeSeqBatches.ps1 to refresh helper files.
exit /b 1
)
if not exist "%CONFIG_PATH%" (
echo [ERROR] config.json not found next to ZipSeqArchv.bat.
echo Please run UpgradeSeqBatches.ps1 to refresh helper files.
exit /b 1
)
for /f "usebackq delims=" %%I in (`powershell -NoProfile -ExecutionPolicy Bypass -Command ^
"Set-StrictMode -Version Latest; $loader = Resolve-Path -LiteralPath '%CONFIG_LOADER%' -ErrorAction Stop; . $loader.Path; $pyPath = Join-Path (Get-StructDirectory) '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 exit /b 1
) )

7
config.json Normal file
View File

@@ -0,0 +1,7 @@
{
"dailyFormat": true,
"structDir": "D:\\ProjectStructure",
"zipper": true,
"compression": 9
}

View File

@@ -11,6 +11,7 @@ from __future__ import annotations
import argparse import argparse
import json import json
import subprocess
import os import os
import shutil import shutil
import sys import sys
@@ -30,6 +31,52 @@ SEQUENCE_EXTENSIONS = {
".exr", ".exr",
} }
STATE_SUFFIX = ".meta.json" STATE_SUFFIX = ".meta.json"
CONFIG_PATH = Path(__file__).resolve().with_name("config.json")
DEFAULT_CONFIG = {
"zipper": True,
"compression": 9,
}
def load_config() -> dict:
try:
text = CONFIG_PATH.read_text(encoding="utf-8")
except FileNotFoundError:
return DEFAULT_CONFIG.copy()
except OSError:
return DEFAULT_CONFIG.copy()
try:
data = json.loads(text)
except json.JSONDecodeError:
return DEFAULT_CONFIG.copy()
if not isinstance(data, dict):
return DEFAULT_CONFIG.copy()
merged = DEFAULT_CONFIG.copy()
merged.update(data)
return merged
CONFIG = load_config()
USE_7Z = bool(CONFIG.get("zipper", True))
COMPRESSION_LEVEL = CONFIG.get("compression", 9)
if isinstance(COMPRESSION_LEVEL, str):
try:
COMPRESSION_LEVEL = int(COMPRESSION_LEVEL)
except ValueError:
COMPRESSION_LEVEL = 9
if not isinstance(COMPRESSION_LEVEL, int):
COMPRESSION_LEVEL = 9
COMPRESSION_LEVEL = max(0, min(9, COMPRESSION_LEVEL))
SEVEN_Z_EXE: str | None = None
if USE_7Z:
SEVEN_Z_EXE = shutil.which("7z") or shutil.which("7za")
if SEVEN_Z_EXE is None:
print("[zip] Requested 7z compression but no 7z executable was found; falling back to zipfile.", file=sys.stderr)
USE_7Z = False
def parse_args() -> argparse.Namespace: def parse_args() -> argparse.Namespace:
@@ -138,24 +185,55 @@ def state_path_for(zip_path: Path) -> Path:
def zip_sequence(seq_dir: Path, zip_path: Path) -> None: def zip_sequence(seq_dir: Path, zip_path: Path) -> None:
from zipfile import ZIP_STORED, ZipFile if USE_7Z and SEVEN_Z_EXE:
zip_path.parent.mkdir(parents=True, exist_ok=True)
cmd = [
SEVEN_Z_EXE,
"a",
"-y",
f"-mx={COMPRESSION_LEVEL}",
"-tzip",
str(zip_path),
".\\*",
]
subprocess.run(cmd, cwd=seq_dir, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
return
from zipfile import ZIP_DEFLATED, ZIP_STORED, ZipFile
zip_path.parent.mkdir(parents=True, exist_ok=True) zip_path.parent.mkdir(parents=True, exist_ok=True)
with ZipFile(zip_path, "w", compression=ZIP_STORED) as archive: if COMPRESSION_LEVEL <= 0:
compression = ZIP_STORED
zip_kwargs = {}
else:
compression = ZIP_DEFLATED
zip_kwargs = {"compresslevel": COMPRESSION_LEVEL}
with ZipFile(zip_path, "w", compression=compression, **zip_kwargs) as archive:
for file_path in iter_sequence_files(seq_dir): for file_path in iter_sequence_files(seq_dir):
archive.write(file_path, arcname=file_path.relative_to(seq_dir).as_posix()) archive.write(file_path, arcname=file_path.relative_to(seq_dir).as_posix())
def expand_sequence(zip_path: Path, seq_state: dict) -> None: def expand_sequence(zip_path: Path, seq_state: dict) -> None:
from zipfile import ZipFile
target_dir = sequence_dir_for(zip_path) target_dir = sequence_dir_for(zip_path)
if target_dir.exists(): if target_dir.exists():
shutil.rmtree(target_dir) shutil.rmtree(target_dir)
target_dir.mkdir(parents=True, exist_ok=True) target_dir.mkdir(parents=True, exist_ok=True)
with ZipFile(zip_path, "r") as archive: if USE_7Z and SEVEN_Z_EXE:
archive.extractall(target_dir) cmd = [
SEVEN_Z_EXE,
"x",
"-y",
str(zip_path),
f"-o{target_dir}",
]
subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
else:
from zipfile import ZipFile
with ZipFile(zip_path, "r") as archive:
archive.extractall(target_dir)
for entry in seq_state.get("files", []): for entry in seq_state.get("files", []):
file_path = target_dir / entry["path"] file_path = target_dir / entry["path"]