Files
FabledCurator/backend/app/utils/paths.py
T
bvandeusen 4cb319b393 feat(fc2a): add slug and paths utilities
slugify() produces ASCII-only lowercase slugs from arbitrary text (used for
artist slugs and tag slugs). paths.derive_subdir/derive_top_level_artist
extract the destination layout and folder→artist convention from an import
source path. hash_suffixed_name builds IR-style 'stem__hash10.ext' filenames.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 12:04:05 -04:00

42 lines
1.3 KiB
Python

"""Filesystem path helpers — destination derivation, hash-suffixed names."""
from pathlib import Path
def derive_subdir(source_path: Path, import_root: Path) -> str:
"""Returns the relative subdirectory of source_path under import_root.
The top-level folder name is treated as the 'artist' bucket. Nested
paths preserve hierarchy.
import_root=/import
source_path=/import/Alice/sub/x.png -> "Alice/sub"
source_path=/import/Alice/x.png -> "Alice"
source_path=/import/x.png -> ""
"""
try:
rel = source_path.parent.relative_to(import_root)
except ValueError:
return ""
return str(rel) if str(rel) != "." else ""
def hash_suffixed_name(stem: str, sha256_hex: str, ext: str) -> str:
"""Builds 'stem__<first10ofhash><ext>'.
Examples:
hash_suffixed_name("photo", "abcdef1234567890...", ".png")
-> "photo__abcdef1234.png"
"""
return f"{stem}__{sha256_hex[:10]}{ext}"
def derive_top_level_artist(source_path: Path, import_root: Path) -> str | None:
"""Returns the top-level folder name under import_root, or None if the
file is directly in import_root.
"""
subdir = derive_subdir(source_path, import_root)
if not subdir:
return None
return subdir.split("/", 1)[0]