Skip to content

Commit b4be921

Browse files
improve 503 reporting #1188 (#1189)
1 parent 0878373 commit b4be921

File tree

4 files changed

+57
-46
lines changed

4 files changed

+57
-46
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: 503 response reported as an error [#1188](https://github.com/icloud-photos-downloader/icloud_photos_downloader/issues/1188)
6+
57
## 1.28.2 (2025-07-06)
68

79
- chore: bump min python version 3.9->3.10

src/icloudpd/base.py

Lines changed: 53 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1264,34 +1264,11 @@ def core(
12641264
raise_error_on_2sa,
12651265
os.environ.get("CLIENT_ID"),
12661266
)
1267-
except PyiCloudAPIResponseException as error:
1268-
# for 503 with watching, we just continue waiting
1269-
if error.code == "503" and watch_interval:
1270-
icloud = None
1271-
else:
1272-
raise
1273-
except TwoStepAuthRequiredError:
1274-
if notification_script is not None:
1275-
subprocess.call([notification_script])
1276-
if smtp_username is not None or notification_email is not None:
1277-
send_2sa_notification(
1278-
logger,
1279-
username,
1280-
smtp_username,
1281-
smtp_password,
1282-
smtp_host,
1283-
smtp_port,
1284-
smtp_no_tls,
1285-
notification_email,
1286-
notification_email_from,
1287-
)
1288-
return 1
12891267

1290-
if auth_only:
1291-
logger.info("Authentication completed successfully")
1292-
return 0
1268+
if auth_only:
1269+
logger.info("Authentication completed successfully")
1270+
return 0
12931271

1294-
if icloud: # it can be None for 503 errors
12951272
if list_libraries:
12961273
library_names = (
12971274
icloud.photos.private_libraries.keys() | icloud.photos.shared_libraries.keys()
@@ -1302,22 +1279,16 @@ def core(
13021279
else:
13031280
# After 6 or 7 runs within 1h Apple blocks the API for some time. In that
13041281
# case exit.
1305-
try:
1306-
# Access to the selected library. Defaults to the primary photos object.
1307-
library_object: PhotoLibrary = icloud.photos
1308-
if library:
1309-
if library in icloud.photos.private_libraries:
1310-
library_object = icloud.photos.private_libraries[library]
1311-
elif library in icloud.photos.shared_libraries:
1312-
library_object = icloud.photos.shared_libraries[library]
1313-
else:
1314-
logger.error("Unknown library: %s", library)
1315-
return 1
1316-
except PyiCloudAPIResponseException as err:
1317-
# For later: come up with a nicer message to the user. For now take the
1318-
# exception text
1319-
logger.error("error?? %s", err)
1320-
return 1
1282+
# Access to the selected library. Defaults to the primary photos object.
1283+
library_object: PhotoLibrary = icloud.photos
1284+
if library:
1285+
if library in icloud.photos.private_libraries:
1286+
library_object = icloud.photos.private_libraries[library]
1287+
elif library in icloud.photos.shared_libraries:
1288+
library_object = icloud.photos.shared_libraries[library]
1289+
else:
1290+
logger.error("Unknown library: %s", library)
1291+
return 1
13211292

13221293
photos = library_object.albums[album] if album else library_object.all
13231294

@@ -1468,6 +1439,8 @@ def should_break(counter: Counter) -> bool:
14681439

14691440
if only_print_filenames:
14701441
return 0
1442+
else:
1443+
pass
14711444

14721445
if status_exchange.get_progress().cancel:
14731446
logger.info("Iteration was cancelled")
@@ -1481,8 +1454,45 @@ def should_break(counter: Counter) -> bool:
14811454

14821455
if auto_delete:
14831456
autodelete_photos(
1484-
logger, dry_run, library_object, folder_structure, directory, primary_sizes
1457+
logger,
1458+
dry_run,
1459+
library_object,
1460+
folder_structure,
1461+
directory,
1462+
primary_sizes,
14851463
)
1464+
else:
1465+
pass
1466+
except PyiCloudAPIResponseException as error:
1467+
if error.code == "503":
1468+
logger.info("Apple iCloud is temporary refusing to serve icloudpd")
1469+
# it not watching then return error
1470+
if not watch_interval:
1471+
return 1
1472+
else:
1473+
pass
1474+
else:
1475+
raise
1476+
except TwoStepAuthRequiredError:
1477+
if notification_script is not None:
1478+
subprocess.call([notification_script])
1479+
else:
1480+
pass
1481+
if smtp_username is not None or notification_email is not None:
1482+
send_2sa_notification(
1483+
logger,
1484+
username,
1485+
smtp_username,
1486+
smtp_password,
1487+
smtp_host,
1488+
smtp_port,
1489+
smtp_no_tls,
1490+
notification_email,
1491+
notification_email_from,
1492+
)
1493+
else:
1494+
pass
1495+
return 1
14861496

14871497
if watch_interval: # pragma: no cover
14881498
logger.info(f"Waiting for {watch_interval} sec...")

src/pyicloud_ipd/session.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ def request(self, method: str, url, **kwargs): # type: ignore
7272

7373
if response.status_code == 503:
7474
api_error = PyiCloudAPIResponseException(response.reason, str(response.status_code))
75-
LOGGER.error(api_error)
7675
raise api_error
7776

7877
for header, value in HEADER_DATA.items():

tests/test_authentication.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ def test_failed_auth_503(self) -> None:
368368
"ERROR Failed to login with srp, falling back to old raw password authentication.",
369369
self._caplog.text,
370370
)
371-
self.assertIn("ERROR Service Temporary Unavailable (503)", self._caplog.text)
371+
self.assertIn("INFO Apple iCloud is temporary refusing to serve icloudpd", self._caplog.text)
372372
assert result.exit_code == 1
373373

374374
def test_failed_auth_503_watch(self) -> None:
@@ -402,7 +402,7 @@ def test_failed_auth_503_watch(self) -> None:
402402
self._caplog.text,
403403
)
404404
self.assertEqual(
405-
2, self._caplog.text.count("ERROR Service Temporary Unavailable (503)")
405+
2, self._caplog.text.count("INFO Apple iCloud is temporary refusing to serve icloudpd")
406406
)
407407
self.assertEqual(2, self._caplog.text.count("INFO Waiting for 1 sec..."))
408408
# self.assertTrue("Can't overwrite existing cassette" in str(context.exception))

0 commit comments

Comments
 (0)