diff --git a/icloudpy/base.py b/icloudpy/base.py index 5df471aa..df8e93ab 100644 --- a/icloudpy/base.py +++ b/icloudpy/base.py @@ -29,6 +29,7 @@ FindMyiPhoneServiceManager, PhotosService, RemindersService, + SharedPhotosService, ) from icloudpy.utils import get_password_from_keyring @@ -642,6 +643,14 @@ def photos(self): self._photos = PhotosService(service_root, self.session, self.params) return self._photos + @property + def shared_photos(self): + """Gets the Shared 'Photo' service.""" + if not self._photos: + service_root = self._get_webservice_url("ckdatabasews") + self._shared_photos = SharedPhotosService(service_root, self.session, self.params) + return self._shared_photos + @property def calendar(self): """Gets the 'Calendar' service.""" diff --git a/icloudpy/services/__init__.py b/icloudpy/services/__init__.py index 6415e4d7..ecc569b5 100644 --- a/icloudpy/services/__init__.py +++ b/icloudpy/services/__init__.py @@ -8,7 +8,7 @@ from icloudpy.services.findmyiphone import ( FindMyiPhoneServiceManager, ) -from icloudpy.services.photos import PhotosService +from icloudpy.services.photos import PhotosService, SharedPhotosService from icloudpy.services.reminders import ( RemindersService, ) diff --git a/icloudpy/services/photos.py b/icloudpy/services/photos.py index 8afb41dc..6660c4b8 100644 --- a/icloudpy/services/photos.py +++ b/icloudpy/services/photos.py @@ -274,6 +274,71 @@ def libraries(self): return self._libraries +class SharedPhotosService(PhotoLibrary): + """The 'Photos' iCloud service. + + This also acts as the shared library if I am not the owner of the library. + """ + + def __init__(self, service_root, session, params): + self.session = session + self.params = dict(params) + self._service_root = service_root + + self._libraries = None + + self.params.update({"remapEnums": True, "getCurrentSyncToken": True}) + + self._service_endpoint = f"{self._service_root}/database/1/com.apple.photos.cloud/production/shared" + + self._libraries = None + + self._photo_assets = {} + + try: + # url = f"{self._service_endpoint}/zones/list" + url = f"{self._service_root}/database/1/com.apple.photos.cloud/production/shared/zones/list" + request = self.session.post( + url, + data="{}", + headers={"Content-type": "text/plain"}, + ) + response = request.json() + zones = response["zones"] + except Exception as e: + LOGGER.error(f"library exception: {str(e)}") + + # The call to `/records/query` requires the `ownerRecordName` to be provided, which is known only after obtaining it from the API. + + if not zones: + return + super().__init__(service=self, zone_id=zones[0]["zoneID"]) + + @property + def libraries(self): + if not self._libraries: + try: + url = f"{self._service_endpoint}/zones/list" + request = self.session.post( + url, + data="{}", + headers={"Content-type": "text/plain"}, + ) + response = request.json() + zones = response["zones"] + except Exception as e: + LOGGER.error(f"library exception: {str(e)}") + + libraries = {} + for zone in zones: + if not zone.get("deleted"): + zone_name = zone["zoneID"]["zoneName"] + libraries[zone_name] = PhotoLibrary(self, zone_id=zone["zoneID"]) + # obj_type='CPLAssetByAssetDateWithoutHiddenOrDeleted', + # list_type="CPLAssetAndMasterByAssetDateWithoutHiddenOrDeleted", + # direction="ASCENDING", query_filter=None, + # zone_id=zone['zoneID']) + return libraries class PhotoAlbum: """A photo album."""