diff --git a/CHANGELOG.md b/CHANGELOG.md index fc8ab8f..79a270a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), ## [Unreleased] +## [1.0.5] — 2026-05-17 + +Source-folder validation fix: the "Choose source folder" pre-flight check no longer rejects collections whose media lives in subfolders, and now accepts the same set of extensions (including RAW) as the importer itself. + +### Fixed +- **Recursive source-folder validation**: the UI pre-flight check (`_has_media_files`) walked only the top level of the chosen folder via `Path.iterdir()`, which rejected sources whose photos lived in nested subfolders (e.g. year/month layouts). Validation now walks the tree with `os.walk`, early-exits on first match, and skips hidden directories, `@eaDir` (Synology) and dotfiles — mirroring the scanner's traversal exactly. Nested subfolder layouts up to arbitrary depth are now accepted. +- **RAW format parity between validator and scanner**: the validator used a local `MEDIA_EXTENSIONS` constant that had drifted from `scanner.SUPPORTED_FORMATS`. RAW folders (`.cr2`, `.nef`, `.arw`, `.dng`, `.raw`) were silently rejected by the UI even though the scanner would happily import them. The validator now imports `SUPPORTED_FORMATS` directly from `icloudphotonator.scanner`, so photo + video extensions stay in lockstep with the importer. + +### Internal +- Single source of truth for media-extension definitions (`scanner.SUPPORTED_FORMATS`); local `MEDIA_EXTENSIONS` constant removed from `icloudphotonator/ui/app.py`. +- +10 unit tests covering empty/top-level/nested (1–5 levels) folders, hidden-dir/`@eaDir`/dotfile skipping, sidecar/text-only rejection, Canon RAW detection and mixed-case extensions. Full suite: 266 → 276 passing, 0 regressions. + ## [1.0.4] — 2026-05-16 FDA registration UX fix: app now appears reliably in System Settings → Privacy & Security → Full Disk Access on fresh macOS Tahoe installs, without requiring users to manually drag the bundle into the FDA pane via the "+" button. diff --git a/CLAUDE.md b/CLAUDE.md index 4639297..fff4b7a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,7 @@ This file documents non-obvious facts and conventions for AI assistants (and hum ## Landing Page (GitHub Pages) -- Public URL: https://hanselstner.github.io/icloudphotonator/ +- Public URL: [https://hanselstner.github.io/icloudphotonator/](https://hanselstner.github.io/icloudphotonator/) - Source: `main` branch, `/docs` folder (legacy Pages build, no Actions workflow) - Single file: `docs/index.html` (no Jekyll, no build step) - Download button URL is hardcoded — must be updated on every release to point at the new DMG asset @@ -41,6 +41,6 @@ Additionally, `icloudphotonator/__main__.py` runs an early FDA-attribution probe - Coordinator-agent workflow: spec note + delegated implementor agents; no direct edits by Coordinator - Auto-commit is enabled in the workspace -- README.md has a hardcoded version badge (currently shows v1.0.2 — non-blocking, update opportunistically) -- Tests: `pytest` from repo root, 266+ passing as of v1.0.4 +- README.md version badge is auto-updated by `scripts/build_release.sh` Step 8 on every release +- Tests: `pytest` from repo root, 276+ passing as of v1.0.5 - Python: 3.13+ diff --git a/README.md b/README.md index 3ea2af7..cd2f995 100644 --- a/README.md +++ b/README.md @@ -267,6 +267,11 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for development guidelines. ## Changelog +### v1.0.5 — May 17, 2026 + +- "Choose source folder" now accepts collections organised into subfolders (year/month, event-named, multi-level — up to arbitrary depth). Previously the picker rejected sources whose media lived only one level down. +- RAW formats (`.cr2`, `.nef`, `.arw`, `.dng`, `.raw`) are now recognised by the source-folder check, matching what the importer already supported. + ### v1.0.4 — May 16, 2026 - Full Disk Access UI visibility fix on macOS Tahoe: bundle now declares the full standard set of `NS*UsageDescription` keys, so the app reliably appears in System Settings → Privacy & Security → Full Disk Access diff --git a/iCloudPhotonator.spec b/iCloudPhotonator.spec index e114dcc..563e89d 100644 --- a/iCloudPhotonator.spec +++ b/iCloudPhotonator.spec @@ -6,7 +6,7 @@ import customtkinter from PyInstaller.utils.hooks import collect_all APP_NAME = "iCloudPhotonator" -APP_VERSION = "1.0.4" +APP_VERSION = "1.0.5" BUNDLE_IDENTIFIER = "com.hanselstner.icloudphotonator" PROJECT_ROOT = Path(SPECPATH) ENTRYPOINT = PROJECT_ROOT / "icloudphotonator" / "__main__.py" diff --git a/icloudphotonator/__init__.py b/icloudphotonator/__init__.py index e3595c0..a538d7b 100644 --- a/icloudphotonator/__init__.py +++ b/icloudphotonator/__init__.py @@ -4,7 +4,7 @@ from .job import Job from .state import FileStatus, InvalidTransitionError, JobState, transition -__version__ = "1.0.3" +__version__ = "1.0.5" __all__ = [ "Database", diff --git a/pyproject.toml b/pyproject.toml index 85aff04..e88c573 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "icloudphotonator" -version = "1.0.4" +version = "1.0.5" description = "Intelligent photo migration helper for Apple Photos on macOS" requires-python = ">=3.13" dependencies = [ diff --git a/tests/test_basic.py b/tests/test_basic.py index 583fd64..e2985b7 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -2,4 +2,4 @@ def test_package_version() -> None: - assert __version__ == "1.0.3" \ No newline at end of file + assert __version__ == "1.0.5" \ No newline at end of file diff --git a/tests/test_cli.py b/tests/test_cli.py index f275254..c7ef770 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -16,7 +16,7 @@ def test_version_works() -> None: result = CliRunner().invoke(main, ["--version"]) assert result.exit_code == 0 - assert "1.0.3" in result.output + assert "1.0.5" in result.output def test_import_photos_help_shows_expected_options() -> None: diff --git a/uv.lock b/uv.lock index 26e68ee..3e45436 100644 --- a/uv.lock +++ b/uv.lock @@ -482,7 +482,7 @@ wheels = [ [[package]] name = "icloudphotonator" -version = "1.0.4" +version = "1.0.5" source = { editable = "." } dependencies = [ { name = "aiohttp" },