diff --git a/backend/app/services/patreon_client.py b/backend/app/services/patreon_client.py index 98d8134..b896c4b 100644 --- a/backend/app/services/patreon_client.py +++ b/backend/app/services/patreon_client.py @@ -405,21 +405,19 @@ class PatreonClient: return candidate return None - def _media_item( - self, attrs: dict, kind: str, post_id: str, *, require_file_name: bool - ) -> MediaItem: + def _media_item(self, attrs: dict, kind: str, post_id: str) -> MediaItem: url = self._media_url(attrs) if not url: raise PatreonDriftError( f"Patreon media (post {post_id}, kind={kind}) had no resolvable URL " f"(no download_url / image_urls)" ) + # file_name is OPTIONAL: Patreon legitimately serves some gallery images + # without it (operator-flagged 2026-06-07, BlenderKnight post 73665615), + # and the URL basename is a fine fallback — the same thing gallery-dl + # uses. A genuine schema change shows up as no URL (above) or a media id + # absent from `included` (caller), not a missing name. file_name = attrs.get("file_name") - if require_file_name and not (isinstance(file_name, str) and file_name): - raise PatreonDriftError( - f"Patreon media resource (post {post_id}, kind={kind}) missing " - f"'file_name'" - ) filename = file_name if isinstance(file_name, str) and file_name else _basename_from_url(url) return MediaItem( url=url, @@ -452,11 +450,7 @@ class PatreonClient: f"Patreon post {post_id} references media {mid} " f"({rel_name}) not present in 'included'" ) - items.append( - self._media_item( - media_attrs, kind, post_id, require_file_name=True - ) - ) + items.append(self._media_item(media_attrs, kind, post_id)) # 1. gallery images _resolve_rel("images", "images") diff --git a/tests/test_patreon_client.py b/tests/test_patreon_client.py index 0426147..fe46b91 100644 --- a/tests/test_patreon_client.py +++ b/tests/test_patreon_client.py @@ -159,9 +159,10 @@ def test_non_list_data_raises_drift(client): client._validate_response({"data": {"id": "1"}}) -def test_media_missing_file_name_raises_drift(client): - # A media resource referenced by a gallery relationship but lacking - # file_name is drift from the contract. +def test_media_missing_file_name_falls_back_to_url_basename(client): + # A gallery image with a valid URL but no file_name is NOT drift — Patreon + # serves these (operator-flagged 2026-06-07, BlenderKnight post 73665615); + # fall back to the URL basename like gallery-dl does. post = { "id": "2000", "type": "post", @@ -175,8 +176,10 @@ def test_media_missing_file_name_raises_drift(client): + "/x.jpg" } } - with pytest.raises(PatreonDriftError): - client.extract_media(post, index) + items = client.extract_media(post, index) + assert len(items) == 1 + assert items[0].filename == "x.jpg" + assert items[0].kind == "images" def test_media_referenced_but_absent_raises_drift(client):