Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

### Fixed
- DIM package ZIP names now use DIM-compatible product name segments so archives with spaces, underscores, hyphens, or dots in the product name are recognized correctly.
- Runtime/Support cover image names now normalize dots the same way DIM support metadata does, preventing missing Smart Content covers for products such as `G8.1`.

## v2.0.1

### Fixed
Expand Down
12 changes: 2 additions & 10 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import zipfile
import stat
import uuid
import re
import patoolib
import ctypes
import shiboken6
Expand Down Expand Up @@ -54,6 +53,7 @@
FileExplorer, BuildListWidget
)
from packaging_utils import PackagingWorker, PackageSpec, BatchPackagingWorker
from naming_utils import build_dim_zip_filename
from extraction_utils import (
ContentExtractionWorker, MultiBuildExtractionWorker,
classify_archives, detect_heuristic_ordering
Expand Down Expand Up @@ -781,15 +781,7 @@ def build_zip_filename(self) -> str:
part_val = self.product_part_input.value()
name_raw = self.product_name_input.text() or "Package"

prefix_clean = re.sub(r'[^A-Za-z0-9]+', '', str(prefix_raw)).upper() or "IM"
try:
sku_formatted = f"{int(str(sku_raw)):08d}"
except ValueError:
sku_formatted = (str(sku_raw) or "").zfill(8) if sku_raw else "00000000"
part_str = f"{int(part_val):02d}"
sanitized_name = re.sub(r'[^A-Za-z0-9._-]+', '_', str(name_raw)).strip('_') or "Package"

return f"{prefix_clean}{sku_formatted}-{part_str}_{sanitized_name}.zip"
return build_dim_zip_filename(prefix_raw, sku_raw, part_val, name_raw)

def updateZipPreview(self):
try:
Expand Down
39 changes: 39 additions & 0 deletions naming_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import re


def sanitize_dim_zip_product_name(product_name: str, fallback: str = "Package") -> str:
sanitized = re.sub(r'[^A-Za-z0-9]+', '', str(product_name))
return sanitized or fallback


def sanitize_support_filename_segment(value: str, fallback: str = "") -> str:
sanitized = re.sub(r'[^A-Za-z0-9_-]+', '_', str(value)).strip('_')
return sanitized or fallback


def format_dim_sku(sku: str) -> str:
try:
return f"{int(str(sku)):08d}"
except ValueError:
return str(sku).zfill(8)


def build_dim_zip_filename(
prefix: str,
sku: str,
product_part: int,
product_name: str,
fallback_prefix: str = "IM",
) -> str:
prefix_clean = re.sub(r'[^A-Za-z0-9]+', '', str(prefix)).upper() or fallback_prefix
sku_formatted = format_dim_sku(sku)
part_str = f"{int(product_part):02d}"
name_segment = sanitize_dim_zip_product_name(product_name)
return f"{prefix_clean}{sku_formatted}-{part_str}_{name_segment}.zip"


def build_support_cover_filename(store: str, sku: str, product_name: str) -> str:
store_segment = sanitize_support_filename_segment(store)
product_segment = sanitize_support_filename_segment(product_name, "Package")
sku_segment = str(sku).strip()
return f"{store_segment}_{sku_segment}_{product_segment}.jpg"
24 changes: 12 additions & 12 deletions packaging_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from typing import Callable, Dict, Optional, Any

from logger_utils import get_logger
from naming_utils import build_dim_zip_filename, build_support_cover_filename
from utils import calculate_total_size, find_7z_executable, suppress_cmd_window

log = get_logger(__name__)
Expand Down Expand Up @@ -133,9 +134,11 @@ def _process_and_paste_image(self) -> bool:

self.log.info("Attempting to generate Product cover from: %s", self.spec.image_path)
try:
sanitized_product_name = re.sub(r'[^A-Za-z0-9._-]+', '_', self.spec.product_name).strip('_')
store_formatted = re.sub(r'[^A-Za-z0-9._-]+', '_', self.spec.store).strip('_')
new_image_name = f"{store_formatted}_{self.spec.sku}_{sanitized_product_name}.jpg"
new_image_name = build_support_cover_filename(
self.spec.store,
self.spec.sku,
self.spec.product_name,
)

target_dir = os.path.join(self.spec.content_dir, "Runtime", "Support")
os.makedirs(target_dir, exist_ok=True)
Expand Down Expand Up @@ -196,15 +199,12 @@ def _create_supplement(self) -> bool:
return False

def _build_zip_name(self) -> str:
prefix_clean = re.sub(r'[^A-Za-z0-9]+', '', str(self.spec.prefix)).upper()
try:
sku_formatted = f"{int(str(self.spec.sku)):08d}"
except ValueError:
sku_formatted = str(self.spec.sku).zfill(8)

part_str = f"{int(self.spec.product_part):02d}"
sanitized_name = re.sub(r'[^A-Za-z0-9._-]+', '_', str(self.spec.product_name)).strip('_')
return f"{prefix_clean}{sku_formatted}-{part_str}_{sanitized_name}.zip"
return build_dim_zip_filename(
self.spec.prefix,
self.spec.sku,
self.spec.product_part,
self.spec.product_name,
)

def _zip_package(self, progress_callback: Callable[[int], None]) -> bool:
zip_name = self._build_zip_name()
Expand Down
52 changes: 52 additions & 0 deletions tests/test_naming_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import unittest

from naming_utils import (
build_dim_zip_filename,
build_support_cover_filename,
sanitize_dim_zip_product_name,
sanitize_support_filename_segment,
)


class NamingUtilsTests(unittest.TestCase):
def test_dim_zip_product_segment_allows_only_letters_and_digits(self):
self.assertEqual(
sanitize_dim_zip_product_name("X Fashion - Series_3 for G8-8.1 Females"),
"XFashionSeries3forG881Females",
)

def test_dim_zip_filename_pads_sku_and_part(self):
self.assertEqual(
build_dim_zip_filename("RE", "70127", 1, "Bull Boxers G8M G8.1M G9"),
"RE00070127-01_BullBoxersG8MG81MG9.zip",
)

def test_support_segment_replaces_dot_and_preserves_hyphen_and_underscore(self):
self.assertEqual(
sanitize_support_filename_segment("Bull_Boxers G8-8.1"),
"Bull_Boxers_G8-8_1",
)

def test_renderotica_support_cover_filename_matches_dim_support_basename(self):
self.assertEqual(
build_support_cover_filename(
"Renderotica",
"70127",
"Bull Boxers G8M G8.1M G9",
),
"Renderotica_70127_Bull_Boxers_G8M_G8_1M_G9.jpg",
)

def test_daz_support_cover_filename_matches_observed_dim_support_basename(self):
self.assertEqual(
build_support_cover_filename(
"DAZ 3D",
"163838",
"X Fashion - Series 3 for G8-8.1 Females",
),
"DAZ_3D_163838_X_Fashion_-_Series_3_for_G8-8_1_Females.jpg",
)


if __name__ == "__main__":
unittest.main()
Loading