feat: update character assets and registry for multiple packs

- Added new character images in .webp format for Dragon Ball FighterZ, Rivals of Aether II, and Skullgirls: 2nd Encore.
- Removed outdated .png images for characters in Dragon Ball FighterZ and Rivals of Aether II.
- Updated registry.json to reflect changes in character counts and total sizes for packs.
- Introduced new packs for BlazBlue Centralfiction and Rivals of Aether II with their respective assets and manifest files.
- Added scripts for updating image sizes and renaming images to match character slugs.
This commit is contained in:
2026-05-25 23:55:58 +02:00
parent c4e8506d60
commit dcff68153f
179 changed files with 576 additions and 29 deletions
+263
View File
@@ -0,0 +1,263 @@
# rename_images_to_slug.py
#
# Renames character images inside a selected pack's /characters folder
# to their manifest slug.
#
# Example:
# "Ryu Render.png" -> "ryu.png"
#
# Matching rules:
# - compares normalized filenames against character names
# - ignores spaces, punctuation, apostrophes and case
# - preserves original extension
#
# Safe behavior:
# - skips already-correct files
# - warns about unmatched files
# - warns about duplicate matches
# - never overwrites existing files
from __future__ import annotations
import json
import re
from pathlib import Path
from typing import Optional
REGISTRY_FILENAME = "registry.json"
IMAGE_EXTENSIONS = (
".png",
".jpg",
".jpeg",
".webp",
".avif",
)
def load_json(path: Path) -> dict:
return json.loads(path.read_text(encoding="utf-8"))
def normalize(text: str) -> str:
"""
Normalize text for fuzzy filename matching.
Example:
"Chun-Li" -> "chunli"
"Ryu Render" -> "ryurender"
"""
text = text.lower()
# Remove extension if present
text = Path(text).stem
# Remove non-alphanumeric chars
text = re.sub(r"[^a-z0-9]", "", text)
return text
def select_pack(packs: list[dict]) -> Optional[dict]:
print("\nAvailable packs:\n")
for index, pack in enumerate(packs, start=1):
print(f"{index}. {pack['name']} ({pack['id']})")
raw = input("\nSelect pack number: ").strip()
try:
selected_index = int(raw) - 1
except ValueError:
print("\n❌ Invalid number")
return None
if selected_index < 0 or selected_index >= len(packs):
print("\n❌ Invalid selection")
return None
return packs[selected_index]
def build_character_lookup(characters: list[dict]) -> dict[str, str]:
"""
Build normalized name -> slug mapping.
Example:
"chunli" -> "chun-li"
"""
lookup = {}
for character in characters:
name = character["name"]
slug = character["slug"]
lookup[normalize(name)] = slug
return lookup
def rename_images(pack_dir: Path) -> None:
manifest_path = pack_dir / "manifest.json"
characters_dir = pack_dir / "characters"
if not manifest_path.exists():
print("\n❌ manifest.json not found")
return
if not characters_dir.exists():
print("\n❌ characters folder not found")
return
manifest = load_json(manifest_path)
lookup = build_character_lookup(
manifest.get("characters", [])
)
image_files = [
file
for file in characters_dir.iterdir()
if file.is_file()
and file.suffix.lower() in IMAGE_EXTENSIONS
]
if not image_files:
print("\n❌ No images found")
return
print(f'\nScanning "{manifest["name"]}"...\n')
renamed_count = 0
for image_file in image_files:
normalized_filename = normalize(
image_file.name
)
matched_slug = None
# Exact normalized match
if normalized_filename in lookup:
matched_slug = lookup[
normalized_filename
]
else:
# Partial fuzzy fallback
matches = [
slug
for normalized_name, slug in lookup.items()
if normalized_name in normalized_filename
or normalized_filename in normalized_name
]
if len(matches) == 1:
matched_slug = matches[0]
elif len(matches) > 1:
print(
f"⚠ Multiple matches for "
f"{image_file.name}"
)
continue
if matched_slug is None:
print(
f"⚠ No character match for "
f"{image_file.name}"
)
continue
new_filename = (
matched_slug
+ image_file.suffix.lower()
)
new_path = (
characters_dir
/ new_filename
)
# Already correct
if image_file.name.lower() == new_filename.lower():
if image_file.name != new_filename:
image_file.rename(new_path)
print(
f"{image_file.name} "
f"-> {new_filename}"
)
renamed_count += 1
else:
print(f"{image_file.name}")
continue
# Prevent overwrite
if new_path.exists():
print(
f"⚠ Target already exists: "
f"{new_filename}"
)
continue
image_file.rename(new_path)
renamed_count += 1
print(
f"{image_file.name} "
f"-> {new_filename}"
)
print("\n✅ Done!\n")
print(f"Renamed: {renamed_count}")
def main() -> None:
root = Path(__file__).parent.resolve()
registry_path = (
root / REGISTRY_FILENAME
)
if not registry_path.exists():
print(
"❌ registry.json not found"
)
return
registry = load_json(
registry_path
)
packs = registry.get(
"packs",
[],
)
if not packs:
print(
"❌ No packs found"
)
return
selected_pack = select_pack(
packs
)
if selected_pack is None:
return
pack_dir = (
root
/ selected_pack["id"]
)
rename_images(pack_dir)
if __name__ == "__main__":
main()