Skip to content

Commit aa97d16

Browse files
don't use All Photos album for the whole collection #1077 (#1089)
1 parent b10561f commit aa97d16

File tree

12 files changed

+102
-160
lines changed

12 files changed

+102
-160
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## Unreleased
44

5+
- fix: disambiguate whole photo collection from the album with `All Photos` name [#1077](https://github.com/icloud-photos-downloader/icloud_photos_downloader/issues/1077)
6+
57
## 1.27.0 (2025-02-22)
68

79
- feature: list and download from shared libraries for invitee [#947](https://github.com/icloud-photos-downloader/icloud_photos_downloader/issues/947)

docs/reference.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ This is a list of all options available for command line interface (CLI) of the
3131

3232
: Specifies what Album to download.
3333

34-
Default: "All Photos" - Special album where all assets are automatically added.
34+
When not specified, the whole asset collection is considered.
3535

3636
```{note}
3737
Only one album can be downloaded by `icloudpd`

src/icloudpd/base.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -346,9 +346,8 @@ def report_version(ctx: click.Context, _param: click.Parameter, value: bool) ->
346346
@click.option(
347347
"-a",
348348
"--album",
349-
help="Album to download (default: All Photos)",
349+
help="Album to download or whole collection if not specified",
350350
metavar="<album>",
351-
default="All Photos",
352351
)
353352
@click.option(
354353
"-l",
@@ -589,7 +588,7 @@ def main(
589588
live_photo_size: LivePhotoVersionSize,
590589
recent: Optional[int],
591590
until_found: Optional[int],
592-
album: str,
591+
album: Optional[str],
593592
list_albums: bool,
594593
library: str,
595594
list_libraries: bool,
@@ -1168,7 +1167,7 @@ def core(
11681167
primary_sizes: Sequence[AssetVersionSize],
11691168
recent: Optional[int],
11701169
until_found: Optional[int],
1171-
album: str,
1170+
album: Optional[str],
11721171
list_albums: bool,
11731172
library: str,
11741173
list_libraries: bool,
@@ -1258,8 +1257,6 @@ def core(
12581257

12591258
else:
12601259
while True:
1261-
# Default album is "All Photos", so this is the same as
1262-
# calling `icloud.photos.all`.
12631260
# After 6 or 7 runs within 1h Apple blocks the API for some time. In that
12641261
# case exit.
12651262
try:
@@ -1271,7 +1268,7 @@ def core(
12711268
else:
12721269
logger.error("Unknown library: %s", library)
12731270
return 1
1274-
photos = library_object.albums[album]
1271+
photos = library_object.albums[album] if album else library_object.all
12751272
except PyiCloudAPIResponseException as err:
12761273
# For later: come up with a nicer message to the user. For now take the
12771274
# exception text
@@ -1290,7 +1287,8 @@ def core(
12901287
directory = os.path.normpath(cast(str, directory))
12911288

12921289
videos_phrase = "" if skip_videos else " and videos"
1293-
logger.debug("Looking up all photos%s from album %s...", videos_phrase, album)
1290+
album_phrase = f" from album {album}" if album else ""
1291+
logger.debug(f"Looking up all photos{videos_phrase}{album_phrase}...")
12941292

12951293
session_exception_handler = session_error_handle_builder(logger, icloud)
12961294
internal_error_handler = internal_error_handle_builder(logger)

src/icloudpd/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def __init__(
1717
live_photo_size: LivePhotoVersionSize,
1818
recent: Optional[int],
1919
until_found: Optional[int],
20-
album: str,
20+
album: Optional[str],
2121
list_albums: bool,
2222
library: str,
2323
list_libraries: bool,

src/pyicloud_ipd/services/photos.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,13 @@ class PhotoLibrary(object):
3636
3737
This provides access to all the albums as well as the photos.
3838
"""
39-
SMART_FOLDERS = {
40-
"All Photos": {
39+
WHOLE_COLLECTION = {
4140
"obj_type": "CPLAssetByAssetDateWithoutHiddenOrDeleted",
4241
"list_type": "CPLAssetAndMasterByAssetDateWithoutHiddenOrDeleted",
4342
"direction": "ASCENDING",
4443
"query_filter": None
45-
},
44+
}
45+
SMART_FOLDERS = {
4646
"Time-lapse": {
4747
"obj_type": "CPLAssetInSmartAlbumByAssetDate:Timelapse",
4848
"list_type": "CPLAssetAndMasterInSmartAlbumByAssetDate",
@@ -161,6 +161,7 @@ def __init__(self, service: "PhotosService", zone_id: Dict[str, Any], library_ty
161161
self.service_endpoint = self.service.get_service_endpoint(library_type)
162162

163163
self._albums: Optional[Dict[str, PhotoAlbum]] = None
164+
self._all: Optional[PhotoAlbum] = None
164165

165166
url = ('%s/records/query?%s' %
166167
(self.service_endpoint, urlencode(self.service.params)))
@@ -240,7 +241,11 @@ def _fetch_folders(self) -> Sequence[Dict[str, Any]]:
240241

241242
@property
242243
def all(self) -> "PhotoAlbum":
243-
return self.albums['All Photos']
244+
if not self._all:
245+
self._all = PhotoAlbum(self.service, self.service_endpoint, "", zone_id=self.zone_id, **self.WHOLE_COLLECTION) # type: ignore[arg-type] # dynamically builing params
246+
# need to pull all albums because existing recorded tests expect all albums to be pulled...
247+
self.albums
248+
return self._all
244249

245250

246251
class PhotosService(PhotoLibrary):

tests/test_autodelete_photos.py

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def astimezone(self, _tz: (Optional[Any]) = None) -> NoReturn:
7575
print_result_exception(result)
7676

7777
self.assertIn(
78-
"DEBUG Looking up all photos and videos from album All Photos...",
78+
"DEBUG Looking up all photos and videos...",
7979
self._caplog.text,
8080
)
8181
self.assertIn(
@@ -122,7 +122,7 @@ def astimezone(self, _tz: (Optional[Any]) = None) -> NoReturn:
122122
print_result_exception(result)
123123

124124
self.assertIn(
125-
"DEBUG Looking up all photos and videos from album All Photos...",
125+
"DEBUG Looking up all photos and videos...",
126126
self._caplog.text,
127127
)
128128
self.assertIn(
@@ -182,7 +182,7 @@ def test_download_autodelete_photos(self) -> None:
182182
print_result_exception(result)
183183

184184
self.assertIn(
185-
"DEBUG Looking up all photos and videos from album All Photos...",
185+
"DEBUG Looking up all photos and videos...",
186186
self._caplog.text,
187187
)
188188
self.assertIn(
@@ -225,7 +225,7 @@ def test_download_autodelete_photos(self) -> None:
225225
print_result_exception(result)
226226

227227
self.assertIn(
228-
"DEBUG Looking up all photos and videos from album All Photos...",
228+
"DEBUG Looking up all photos and videos...",
229229
self._caplog.text,
230230
)
231231
self.assertIn(
@@ -311,9 +311,7 @@ def test_autodelete_photos(self) -> None:
311311
cookie_dir,
312312
],
313313
)
314-
self.assertIn(
315-
"DEBUG Looking up all photos from album All Photos...", self._caplog.text
316-
)
314+
self.assertIn("DEBUG Looking up all photos...", self._caplog.text)
317315
self.assertIn(
318316
f"INFO Downloading 0 original photos to {data_dir} ...",
319317
self._caplog.text,
@@ -424,7 +422,7 @@ def mocked_authenticate(self: PyiCloudService) -> None:
424422
print_result_exception(result)
425423

426424
self.assertIn(
427-
"DEBUG Looking up all photos and videos from album All Photos...",
425+
"DEBUG Looking up all photos and videos...",
428426
self._caplog.text,
429427
)
430428
self.assertIn(
@@ -519,7 +517,7 @@ def mocked_authenticate(self: PyiCloudService) -> None:
519517
print_result_exception(result)
520518

521519
self.assertIn(
522-
"DEBUG Looking up all photos and videos from album All Photos...",
520+
"DEBUG Looking up all photos and videos...",
523521
self._caplog.text,
524522
)
525523
self.assertIn(
@@ -606,7 +604,7 @@ def mock_raise_response_error(
606604
print_result_exception(result)
607605

608606
self.assertIn(
609-
"DEBUG Looking up all photos and videos from album All Photos...",
607+
"DEBUG Looking up all photos and videos...",
610608
self._caplog.text,
611609
)
612610
self.assertIn(
@@ -687,7 +685,7 @@ def mock_raise_response_error(
687685
print_result_exception(result)
688686

689687
self.assertIn(
690-
"DEBUG Looking up all photos and videos from album All Photos...",
688+
"DEBUG Looking up all photos and videos...",
691689
self._caplog.text,
692690
)
693691
self.assertIn(
@@ -791,9 +789,7 @@ def test_autodelete_photos_dry_run(self) -> None:
791789
)
792790
print_result_exception(result)
793791

794-
self.assertIn(
795-
"DEBUG Looking up all photos from album All Photos...", self._caplog.text
796-
)
792+
self.assertIn("DEBUG Looking up all photos...", self._caplog.text)
797793
self.assertIn(
798794
f"INFO Downloading 0 original photos to {data_dir} ...",
799795
self._caplog.text,
@@ -891,9 +887,7 @@ def test_autodelete_photos_folder_none(self) -> None:
891887
cookie_dir,
892888
],
893889
)
894-
self.assertIn(
895-
"DEBUG Looking up all photos from album All Photos...", self._caplog.text
896-
)
890+
self.assertIn("DEBUG Looking up all photos...", self._caplog.text)
897891
self.assertIn(
898892
f"INFO Downloading 0 original photos to {data_dir} ...",
899893
self._caplog.text,
@@ -988,9 +982,7 @@ def test_autodelete_photos_lp(self) -> None:
988982
cookie_dir,
989983
],
990984
)
991-
self.assertIn(
992-
"DEBUG Looking up all photos from album All Photos...", self._caplog.text
993-
)
985+
self.assertIn("DEBUG Looking up all photos...", self._caplog.text)
994986
self.assertIn(
995987
f"INFO Downloading 0 original photos to {data_dir} ...",
996988
self._caplog.text,
@@ -1085,9 +1077,7 @@ def test_autodelete_photos_lp_heic(self) -> None:
10851077
cookie_dir,
10861078
],
10871079
)
1088-
self.assertIn(
1089-
"DEBUG Looking up all photos from album All Photos...", self._caplog.text
1090-
)
1080+
self.assertIn("DEBUG Looking up all photos...", self._caplog.text)
10911081
self.assertIn(
10921082
f"INFO Downloading 0 original photos to {data_dir} ...",
10931083
self._caplog.text,

tests/test_download_live_photos.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,7 @@ def test_skip_existing_live_photodownloads(self) -> None:
100100
],
101101
)
102102

103-
self.assertIn(
104-
"DEBUG Looking up all photos and videos from album All Photos...", self._caplog.text
105-
)
103+
self.assertIn("DEBUG Looking up all photos and videos...", self._caplog.text)
106104
self.assertIn(
107105
f"INFO Downloading 3 original photos and videos to {data_dir} ...",
108106
self._caplog.text,

tests/test_download_live_photos_id.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,7 @@ def test_skip_existing_live_photodownloads_name_id7(self) -> None:
8888
],
8989
)
9090

91-
self.assertIn(
92-
"DEBUG Looking up all photos and videos from album All Photos...", self._caplog.text
93-
)
91+
self.assertIn("DEBUG Looking up all photos and videos...", self._caplog.text)
9492
self.assertIn(
9593
f"INFO Downloading 3 original photos and videos to {data_dir} ...",
9694
self._caplog.text,

0 commit comments

Comments
 (0)