Expanded generation options. Multiple outfits support.
This commit is contained in:
153
migrate_wardrobe.py
Normal file
153
migrate_wardrobe.py
Normal file
@@ -0,0 +1,153 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Migration script to convert wardrobe structure from flat to nested format.
|
||||
|
||||
Before:
|
||||
"wardrobe": {
|
||||
"headwear": "...",
|
||||
"top": "...",
|
||||
...
|
||||
}
|
||||
|
||||
After:
|
||||
"wardrobe": {
|
||||
"default": {
|
||||
"headwear": "...",
|
||||
"top": "...",
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
This enables multiple outfits per character.
|
||||
"""
|
||||
|
||||
import os
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def migrate_wardrobe(characters_dir: str = "characters", dry_run: bool = False):
|
||||
"""
|
||||
Migrate all character JSON files to the new wardrobe structure.
|
||||
|
||||
Args:
|
||||
characters_dir: Path to the directory containing character JSON files
|
||||
dry_run: If True, only print what would be changed without modifying files
|
||||
"""
|
||||
characters_path = Path(characters_dir)
|
||||
|
||||
if not characters_path.exists():
|
||||
print(f"Error: Directory '{characters_dir}' does not exist")
|
||||
return
|
||||
|
||||
json_files = list(characters_path.glob("*.json"))
|
||||
|
||||
if not json_files:
|
||||
print(f"No JSON files found in '{characters_dir}'")
|
||||
return
|
||||
|
||||
migrated_count = 0
|
||||
skipped_count = 0
|
||||
error_count = 0
|
||||
|
||||
for json_file in json_files:
|
||||
try:
|
||||
with open(json_file, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
# Check if character has a wardrobe
|
||||
if 'wardrobe' not in data:
|
||||
print(f" [SKIP] {json_file.name}: No wardrobe field")
|
||||
skipped_count += 1
|
||||
continue
|
||||
|
||||
wardrobe = data['wardrobe']
|
||||
|
||||
# Check if already migrated (wardrobe contains 'default' key with nested dict)
|
||||
if 'default' in wardrobe and isinstance(wardrobe['default'], dict):
|
||||
# Verify it's actually the new format (has wardrobe keys inside)
|
||||
expected_keys = {'headwear', 'top', 'legwear', 'footwear', 'hands', 'accessories',
|
||||
'inner_layer', 'outer_layer', 'lower_body', 'gloves'}
|
||||
if any(key in wardrobe['default'] for key in expected_keys):
|
||||
print(f" [SKIP] {json_file.name}: Already migrated")
|
||||
skipped_count += 1
|
||||
continue
|
||||
|
||||
# Check if wardrobe is a flat structure (not already nested)
|
||||
# A flat wardrobe has string values, a nested one has dict values
|
||||
if not isinstance(wardrobe, dict):
|
||||
print(f" [ERROR] {json_file.name}: Wardrobe is not a dictionary")
|
||||
error_count += 1
|
||||
continue
|
||||
|
||||
# Check if any value is a dict (indicating partial migration or different structure)
|
||||
has_nested_values = any(isinstance(v, dict) for v in wardrobe.values())
|
||||
if has_nested_values:
|
||||
print(f" [SKIP] {json_file.name}: Wardrobe has nested values, may already be migrated")
|
||||
skipped_count += 1
|
||||
continue
|
||||
|
||||
# Perform migration
|
||||
new_wardrobe = {
|
||||
"default": wardrobe
|
||||
}
|
||||
data['wardrobe'] = new_wardrobe
|
||||
|
||||
if dry_run:
|
||||
print(f" [DRY-RUN] {json_file.name}: Would migrate wardrobe")
|
||||
print(f" Old: {json.dumps(wardrobe, indent=2)[:100]}...")
|
||||
print(f" New: {json.dumps(new_wardrobe, indent=2)[:100]}...")
|
||||
else:
|
||||
with open(json_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(data, f, indent=2, ensure_ascii=False)
|
||||
print(f" [MIGRATED] {json_file.name}")
|
||||
|
||||
migrated_count += 1
|
||||
|
||||
except json.JSONDecodeError as e:
|
||||
print(f" [ERROR] {json_file.name}: Invalid JSON - {e}")
|
||||
error_count += 1
|
||||
except Exception as e:
|
||||
print(f" [ERROR] {json_file.name}: {e}")
|
||||
error_count += 1
|
||||
|
||||
print()
|
||||
print("=" * 50)
|
||||
print(f"Migration complete:")
|
||||
print(f" - Migrated: {migrated_count}")
|
||||
print(f" - Skipped: {skipped_count}")
|
||||
print(f" - Errors: {error_count}")
|
||||
if dry_run:
|
||||
print()
|
||||
print("This was a dry run. No files were modified.")
|
||||
print("Run with --execute to apply changes.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Migrate character wardrobe structure to support multiple outfits"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--execute",
|
||||
action="store_true",
|
||||
help="Actually modify files (default is dry-run)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--dir",
|
||||
default="characters",
|
||||
help="Directory containing character JSON files (default: characters)"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
print("=" * 50)
|
||||
print("Wardrobe Migration Script")
|
||||
print("=" * 50)
|
||||
print(f"Directory: {args.dir}")
|
||||
print(f"Mode: {'EXECUTE' if args.execute else 'DRY-RUN'}")
|
||||
print("=" * 50)
|
||||
print()
|
||||
|
||||
migrate_wardrobe(characters_dir=args.dir, dry_run=not args.execute)
|
||||
Reference in New Issue
Block a user