from __future__ import annotations import re import shutil import zipfile from pathlib import Path from src.config import FAVORITES_DIR def ensure_dir(path: Path) -> None: Path(path).mkdir(parents=True, exist_ok=True) def safe_filename(name: str) -> str: cleaned = re.sub(r"[^A-Za-z0-9._-]+", "_", name.strip()) cleaned = cleaned.strip("._") return cleaned or "file" def _unique_destination(directory: Path, filename: str) -> Path: stem = Path(filename).stem suffix = Path(filename).suffix candidate = directory / filename index = 2 while candidate.exists(): candidate = directory / f"{stem}_{index}{suffix}" index += 1 return candidate def copy_to_favorites(image_path: str | Path) -> Path: source = Path(image_path) if not source.exists(): raise FileNotFoundError(f"Image file does not exist: {source}") ensure_dir(FAVORITES_DIR) filename = safe_filename(source.name) destination = _unique_destination(FAVORITES_DIR, filename) shutil.copy2(source, destination) return destination def export_favorites_to_zip(favorite_paths: list[str | Path], zip_path: Path) -> Path: zip_path = Path(zip_path) ensure_dir(zip_path.parent) valid_paths = [ Path(path) for path in favorite_paths if path and Path(path).exists() and Path(path).resolve() != zip_path.resolve() ] if not valid_paths: raise ValueError("No favorite image files are available to export.") used_names: dict[str, int] = {} with zipfile.ZipFile(zip_path, "w", compression=zipfile.ZIP_DEFLATED) as archive: for path in valid_paths: archive_name = safe_filename(path.name) count = used_names.get(archive_name, 0) used_names[archive_name] = count + 1 if count: stem = Path(archive_name).stem suffix = Path(archive_name).suffix archive_name = f"{stem}_{count + 1}{suffix}" archive.write(path, arcname=archive_name) return zip_path