Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
115 commits
Select commit Hold shift + click to select a range
694133a
limit `icloud` to keyring management
AndreyNikiforov Sep 3, 2025
e71fa12
remove unused parameter
AndreyNikiforov Sep 3, 2025
fc09c46
move re-auth due to global session error into bigger auth loop
AndreyNikiforov Sep 3, 2025
462d9a8
fix tests for invalid global session during photo iteration
AndreyNikiforov Sep 3, 2025
132f058
fix tests for invalid global session during deletion
AndreyNikiforov Sep 4, 2025
c433a6b
fix tests to support retry on internal error
AndreyNikiforov Sep 4, 2025
1a61826
remove local retries during downloads
AndreyNikiforov Sep 4, 2025
596c04c
always start auth with validation request
AndreyNikiforov Sep 5, 2025
56e78d9
ignore hars
AndreyNikiforov Sep 5, 2025
d48c255
better testing on 404 during downloading
AndreyNikiforov Sep 6, 2025
c82491d
move response processing out of session
AndreyNikiforov Sep 7, 2025
7b6871b
make cli test run with cassette to avoid accidental request
AndreyNikiforov Sep 7, 2025
c8575cd
fix test for missing dir
AndreyNikiforov Sep 7, 2025
b90889a
fix tests to use cassette
AndreyNikiforov Sep 7, 2025
7e7e117
Revert "move response processing out of session"
AndreyNikiforov Sep 12, 2025
b05a4d8
Replace session error test mocks with cassette-based approach
AndreyNikiforov Sep 11, 2025
c2cca05
refactor: replace mock-based session error tests with cassette-based …
AndreyNikiforov Sep 11, 2025
8f85605
refactor: remove unnecessary time.sleep mocks from session error tests
AndreyNikiforov Sep 11, 2025
8c3ec05
refactor: replace mock with VCR cassette for send_verification_code test
AndreyNikiforov Sep 11, 2025
6d083be
fix: update cassette to match Apple's actual API response format
AndreyNikiforov Sep 11, 2025
b18d1e1
refactor: convert test_handle_albums_error to use cassette instead of…
AndreyNikiforov Sep 12, 2025
e6aa964
fix: correct albums error cassette to use 200 status with error payload
AndreyNikiforov Sep 12, 2025
54e8b8d
refactor: convert more error tests to use cassettes instead of mocks
AndreyNikiforov Sep 12, 2025
bdbb122
fix: clarify download error handling with cassettes
AndreyNikiforov Sep 12, 2025
882a975
fix: remove is_streaming_response check for proper error handling
AndreyNikiforov Sep 12, 2025
5d34a86
refactor: convert error simulation tests from mocks to cassettes
AndreyNikiforov Sep 12, 2025
87e4f00
fix: update session error tests to expect successful retry
AndreyNikiforov Sep 12, 2025
fa20431
style: clean up test formatting for session error tests
AndreyNikiforov Sep 12, 2025
3e38874
skip 2sa failed auth test
AndreyNikiforov Sep 12, 2025
ef7b0db
fix: remove incorrect delete operations from session error iteration …
AndreyNikiforov Sep 12, 2025
4883633
refactor: simplify test paths by replacing datetime calculations with…
AndreyNikiforov Sep 12, 2025
203a2f3
refactor: remove mocks from test_delete_after_download_session_error
AndreyNikiforov Sep 12, 2025
b362f87
refactor: remove mocks from test_retry_delete_after_download_internal…
AndreyNikiforov Sep 12, 2025
ba95913
remove unused use case test
AndreyNikiforov Sep 12, 2025
99db5c6
test: simplify EXIF tests to download only one photo
AndreyNikiforov Sep 12, 2025
d217f79
refactor: update test_until_found* to use actual cassette downloads
AndreyNikiforov Sep 13, 2025
acb8b22
refactor: update size fallback tests to use cassette downloads
AndreyNikiforov Sep 13, 2025
630fc6b
refactor: update dedup test for name-id7 to match standard pattern
AndreyNikiforov Sep 13, 2025
729fd63
refactor: update adjusted size fallback test
AndreyNikiforov Sep 13, 2025
67d0a57
fix asset size in cassettes
AndreyNikiforov Sep 13, 2025
92dc2d2
refactor: remove mocks from test_download_two_sizes_with_force_size
AndreyNikiforov Sep 13, 2025
236a38e
refactor: remove mocks from live photo tests
AndreyNikiforov Sep 14, 2025
90bb641
refactor: remove mocks from Chinese live photo tests
AndreyNikiforov Sep 14, 2025
502ac49
refactor: remove mocks from delete-after-download dry-run tests
AndreyNikiforov Sep 14, 2025
94c275e
refactor: replace mocks with cassette in internal error test
AndreyNikiforov Sep 14, 2025
f575e67
refactor: share internal error download cassette between tests
AndreyNikiforov Sep 15, 2025
4be7ef4
refactor: share error handling cassettes between standard and name-id…
AndreyNikiforov Sep 15, 2025
3ba2eba
feat: add strict VCR cassette playback configuration
AndreyNikiforov Sep 15, 2025
096713a
remove error code overriding in tests
AndreyNikiforov Sep 15, 2025
4a9c29d
fix: disable request reuse in cassettes
AndreyNikiforov Sep 15, 2025
43da84b
refactor: remove mocks from test_force_size
AndreyNikiforov Sep 15, 2025
8e22a74
refactor: remove mocks from test_force_size_name_id7
AndreyNikiforov Sep 15, 2025
fa8d29c
remove unused imports
AndreyNikiforov Sep 15, 2025
64d2313
chore: update cassette files with modified content
AndreyNikiforov Sep 15, 2025
13c45e9
refactor: extract response evaluation logic from session.py::request()
AndreyNikiforov Sep 16, 2025
d7839a1
refactor: call evaluate_response() explicitly at request sites
AndreyNikiforov Sep 16, 2025
1757d9d
refactor: replace exceptions with ADTs in session.py evaluate_response
AndreyNikiforov Sep 16, 2025
115bc04
refactor: extract throw_on_503() from session.request() into evaluate…
AndreyNikiforov Sep 16, 2025
a4adbcc
refactor: replace exception handling with ADT pattern in authenticati…
AndreyNikiforov Sep 16, 2025
ab18a0f
refactor: replace PyiCloudService creation with ADT-returning factory…
AndreyNikiforov Sep 16, 2025
b542a95
refactor: use ADTs for 2FA/2SA methods in authenticator
AndreyNikiforov Sep 16, 2025
aaa9149
refactor: move exception re-throwing from authenticator to callers
AndreyNikiforov Sep 16, 2025
49b636a
refactor: Replace PhotoLibrary constructor checking with factory method
AndreyNikiforov Sep 17, 2025
e988e85
chore: Remove unused logging from pyicloud_ipd photos module
AndreyNikiforov Sep 17, 2025
630d49e
refactor: change _fetch_libraries() to return ADTs
AndreyNikiforov Sep 17, 2025
2537186
refactor: change _fetch_folders() to return ADTs
AndreyNikiforov Sep 17, 2025
4cf6bb9
refactor: replace PhotoAlbum.__len__() with ADT-returning method
AndreyNikiforov Sep 17, 2025
ebb5b5f
refactor: change download_asset() to return ADTs
AndreyNikiforov Sep 18, 2025
d119d7f
refactor: remove PhotoAlbum.__len__() magic method and use explicit A…
AndreyNikiforov Sep 18, 2025
5a22b4a
refactor: migrate PhotoAlbum iteration to return ADTs
AndreyNikiforov Sep 18, 2025
0b68bb6
refactor: propagate ADT returns into core_single_run()
AndreyNikiforov Sep 18, 2025
ea99fe8
refactor: eliminate AuthWithTokenFailed wrapper in favor of direct AD…
AndreyNikiforov Sep 18, 2025
1f248f4
refactor: replace exception-wrapping ADTs with unions of response ADTs
AndreyNikiforov Sep 18, 2025
08078c2
refactor: replace property calls with ADT methods in core_single_run()
AndreyNikiforov Sep 18, 2025
0542b82
refactor: update download.py to use get_photos_service() ADT method
AndreyNikiforov Sep 18, 2025
3d8e131
fix: correct import path for TrustedDevice type
AndreyNikiforov Sep 18, 2025
24a2c0a
refactor: replace trusted_devices property with get_trusted_devices()…
AndreyNikiforov Sep 19, 2025
cac635a
refactor: replace AuthenticationFailed exception wrapping with specif…
AndreyNikiforov Sep 19, 2025
b0f95b9
refactor: add ADT return type to core_single_run (Phase 1)
AndreyNikiforov Sep 19, 2025
5acda14
refactor: convert AuthenticatorTwoSAExit to ADT return (Phase 2 - Ste…
AndreyNikiforov Sep 19, 2025
623ec3b
refactor: convert AuthPasswordNotProvided to ADT return
AndreyNikiforov Sep 19, 2025
a5c9d12
refactor: convert AuthInvalidCredentials to ADT return
AndreyNikiforov Sep 19, 2025
48a23ea
refactor: convert AuthServiceNotActivated to ADT return
AndreyNikiforov Sep 20, 2025
9b3d1c7
refactor: convert AuthAPIError to ADT return
AndreyNikiforov Sep 20, 2025
dac14dd
refactor: convert PhotoLibraryNotFinishedIndexing to ADT return
AndreyNikiforov Sep 20, 2025
a57d1b8
docs: update refactoring plan with final results
AndreyNikiforov Sep 20, 2025
5cff247
refactor: simplify exception handling by removing catch-all
AndreyNikiforov Sep 20, 2025
f4952b9
refactor: move authentication outside try-catch in core_single_run
AndreyNikiforov Sep 20, 2025
dc20b1c
remove accidental context
AndreyNikiforov Sep 20, 2025
a35a57f
refactor: replace first two exceptions with ADT returns in core_singl…
AndreyNikiforov Sep 21, 2025
ff08ad4
refactor: replace more exceptions with ADT returns in private librari…
AndreyNikiforov Sep 21, 2025
09d1a09
refactor: replace exceptions with ADT returns in shared libraries check
AndreyNikiforov Sep 21, 2025
21b0afe
refactor: replace photo iteration 2SA exception with ADT return at li…
AndreyNikiforov Sep 21, 2025
fd99c9d
refactor: replace photo iteration service not activated exception wit…
AndreyNikiforov Sep 21, 2025
c713610
refactor: replace get_album_count exceptions with ADT error handling
AndreyNikiforov Sep 21, 2025
6d8a2bb
refactor: handle photo iteration errors directly without exceptions
AndreyNikiforov Sep 21, 2025
3906695
refactor: handle download result errors directly without exceptions
AndreyNikiforov Sep 21, 2025
4ef1463
refactor: handle delete photo errors directly without exceptions
AndreyNikiforov Sep 22, 2025
af8a995
refactor: handle autodelete errors directly without exceptions
AndreyNikiforov Sep 22, 2025
f09784b
refactor: remove exception handling try-catch block from core_single_run
AndreyNikiforov Sep 22, 2025
f6f4edd
Initial metadata_management: add favorite to ratings, processing exis…
spmp Dec 31, 2025
fc1b65c
More complete metadata management implementation. Remove separate exi…
spmp Jan 1, 2026
e3ce489
Clean up some functions and fix tests for metadata management
spmp Jan 1, 2026
f46d2fd
Format and lint metadata management
spmp Jan 1, 2026
f99611c
Metadata management code reduction and test cleanup
spmp Jan 1, 2026
485b443
src/icloudpd/base.py
spmp Jan 1, 2026
faf77b5
Revert change to where metadata management is called, fix failing exi…
spmp Jan 1, 2026
0439a84
Plugins infrastructure and Immich plugin
spmp Jan 2, 2026
67df444
Update download_size to requested_size to correctly get the size name…
spmp Jan 2, 2026
33bbe5e
Correct download_size to request_size in live photo hooks
spmp Jan 8, 2026
bd01a21
Fixed plugin configuration issue and add new hook for post config mes…
spmp Jan 8, 2026
3d774f4
Fix plugin finding so works with Docker image. Create build_docker_lo…
spmp Jan 8, 2026
accf5b0
Add --rm to docker run command for testing
spmp Jan 8, 2026
9a598cc
Change plugin list cli option name
spmp Jan 8, 2026
63be825
Fix demo plugin detection in docker container
spmp Jan 9, 2026
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,5 @@ node_modules/
.cookies/

.claude/

*.har
27 changes: 25 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,33 @@ For `musl` binaries, use `Dockerfile.build-musl`

### Building the Docker

For local development, use the helper script that handles the complete build process:

``` sh
scripts/build_docker_local [platform]
```

This script:
1. Builds musl binaries using Docker buildx
2. Renames them to the versioned format expected by the Dockerfile
3. Builds the Docker image tagged as `icloudpd_dev`

Default platform is `linux/amd64`. Other options: `linux/arm64`, `linux/arm/v7`

Example:
``` sh
scripts/build_docker_local linux/amd64
docker run --rm icloudpd_dev icloudpd --version
docker run --rm icloudpd_dev icloudpd --plugins-list
```

Alternatively, you can build manually (requires renaming binaries to versioned format):

``` sh
docker build -t icloudpd_dev_ .
docker build -t icloudpd_dev .
```
Note: command packs existing musl binaries from dist folder
Note: command packs existing musl binaries from dist folder with versioned names
(e.g., `icloud-1.32.2-linux-musl-amd64`, `icloudpd-1.32.2-linux-musl-amd64`)

### Developing Documentation

Expand Down
1 change: 1 addition & 0 deletions Dockerfile.build-musl
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ COPY scripts scripts/
COPY binary_dist binary_dist/
COPY pyproject.toml .
COPY src src/
COPY plugins plugins/
# staticx must be installed after scons
# staticx gives error: Error relocating /tmp/staticx-pyi-9b5nvfi_/_cffi_backend.cpython-312-x86_64-linux-musl.so: PyNumber_Long: symbol not found, so not using for musl
RUN \
Expand Down
39 changes: 38 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,44 @@ To independently create and authorize a session (and complete 2SA/2FA validation
icloudpd --username my@email.address --password my_password --auth-only
```
> [!TIP]
> This feature can also be used to check and verify that the session is still authenticated.
> This feature can also be used to check and verify that the session is still authenticated.

## Plugins

icloudpd includes a plugin system that allows you to extend functionality by hooking into the download process. Plugins can respond to events like file downloads, process photos after they're downloaded, and integrate with external services.

### Using Plugins

Enable a plugin with the `--plugin` flag:

```bash
icloudpd --directory /photos --username me@example.com --plugin immich
```

Each plugin adds its own CLI arguments. Use `--help` to see available options:

```bash
icloudpd --plugin immich --help
```

### Built-in Plugins

- **[Immich](plugins/immich/README.md)** - Integrates with [Immich](https://immich.app) photo management. Automatically registers downloaded photos, creates stacks for size variants, syncs favorites, and organizes photos into albums.

- **[Demo](src/icloudpd/plugins/demo.py)** - Demonstrates the plugin system's capabilities. Use as a reference when building your own plugins:
```bash
icloudpd --plugin demo --demo-verbose --recent 5
```

### Building Your Own Plugins

For developers interested in creating custom plugins, see the [Plugin Development Guide](docs/plugins.md) which covers:

- Available hooks and when they're called
- How to accumulate and process photo data
- Best practices and common gotchas
- Testing your plugin
- Complete code examples

## Contributing

Expand Down
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ size
raw
webui
nas
plugins
reference
```
Loading