picklepete / pyicloud

A Python + iCloud wrapper to access iPhone and Calendar data.
MIT License
2.46k stars 438 forks source link

Only the first 209 albums listed using api.photos.albums #388

Open aengeringh opened 1 year ago

aengeringh commented 1 year ago

Only the first 209 albums listed using api.photos.albums

When using: for album in api.photos.albums

Only the first 209 albums are listed. When I delte 4 albums from iCloud, 4 additional albums I was missing earlier appear. The total of albums remains 209, while I do have more albums in my iCloud account.

from pyicloud import PyiCloudService
api = PyiCloudService(icloud_id)
for album in api.photos.albums:
    print(album)

Environment

pip show pyicloud:
Name: pyicloud
Version: 1.0.0
Summary: PyiCloud is a module which allows pythonistas to interact with iCloud webservices.
Home-page: https://github.com/picklepete/pyicloud
Author: 
Author-email: 
License: MIT
Location: /home/andre/src/icloud-photobackup/venv/lib/python3.10/site-packages
Requires: certifi, click, keyring, keyrings.alt, requests, tzlocal
Required-by:

python -V:
Python 3.10.5

Operating environment: Fedora 36

Traceback/Error logs

n/a

Additional information

n/a

gordonaspin commented 1 year ago

I have the same issue. Only 209 albums returned. There must be some pagination functionality in the API. I'm happy to help implement but cannot find documentation of the Photos API anywhere. Where is it ?

gordonaspin commented 1 year ago

I fixed locally by changing the implementation of _fetch_folders to;

def _fetch_folders(self):
    url = f"{self.service_endpoint}/records/query?{urlencode(self.params)}"
    json_data = (
        '{"query":{"recordType":"CPLAlbumByPositionLive"},'
        '"zoneID":{"zoneName":"PrimarySync"}}'
    )

    request = self.session.post(
        url, data=json_data, headers={"Content-type": "text/plain"}
    )

    response = request.json()

    records = response["records"]
    while 'continuationMarker' in response:
        json_data = (
        '{"query":{"recordType":"CPLAlbumByPositionLive"},'
        '"zoneID":{"zoneName":"PrimarySync"},'
        '"continuationMarker":"' + response['continuationMarker'] + '"}'
        )
        request = self.session.post(
            url, data=json_data, headers={"Content-type": "text/plain"}
        )
        response = request.json()
        records.extend(response["records"])

    return records
aengeringh commented 1 year ago

@gordonaspin thanks! tested your code using PIP develop mode and it fixed the issue for me locally.

gordonaspin commented 1 year ago

Great! Checkout my fork of icloud-photos-downloader. I added features to download photos by album name, include or exclude reserved album names (store to local filesystem organized by album name) and updated to use my fork of pyicloud vs pyicloud_ipd and update to python 3.10.6

I use it on Linux mint to download my entire photos library for backup purposes.