Spaces:
Running
Running
AuthorBot Cursor commited on
Commit ·
ecd655e
1
Parent(s): afad341
fix: don't collapse Amazon/BN format prices to single eBook label when credential set
Browse filesCredentialed price fetch previously short-circuited before the multi-format
HTML parser and mislabeled every price as eBook. Now Amazon/Barnes & Noble
always attempt the full format-swatch parse first (Hardcover/eBook/Audiobook),
with the credential single price only as a fallback. Also stop guessing an
eBook binding for print/mixed retailers on the credential path.
Co-authored-by: Cursor <cursoragent@cursor.com>
app/services/platform_pricing.py
CHANGED
|
@@ -467,11 +467,20 @@ async def fetch_listing_format_prices(
|
|
| 467 |
return await _fetch_apple_format_prices(client, listing_url, ctx)
|
| 468 |
|
| 469 |
# --- Credential-based platforms ---
|
| 470 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 471 |
from app.services.platform_api_registry import fetch_price_via_credential
|
| 472 |
hit = await fetch_price_via_credential(client, credential, platform_id, listing_url, ctx)
|
| 473 |
if hit:
|
| 474 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 475 |
return FormatPriceHit(
|
| 476 |
format_prices=norm,
|
| 477 |
formatted=hit.formatted,
|
|
@@ -536,9 +545,33 @@ async def fetch_listing_format_prices(
|
|
| 536 |
platform=platform_id,
|
| 537 |
error=str(exc)[:120],
|
| 538 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 539 |
return None
|
| 540 |
|
| 541 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 542 |
def _itunes_price_from_item(item: dict) -> tuple[str, str] | None:
|
| 543 |
"""Return (formatted_price, currency) from an iTunes lookup/search item."""
|
| 544 |
raw_price = item.get("formattedPrice")
|
|
|
|
| 467 |
return await _fetch_apple_format_prices(client, listing_url, ctx)
|
| 468 |
|
| 469 |
# --- Credential-based platforms ---
|
| 470 |
+
# Amazon / Barnes & Noble expose ALL formats on their product page, so we
|
| 471 |
+
# skip the single-price credential shortcut for them and let the HTML
|
| 472 |
+
# multi-format parser run below. Only use credential fetch as a fallback
|
| 473 |
+
# (handled after the HTML attempt) so we never collapse 3 formats into 1.
|
| 474 |
+
_MULTI_FORMAT_HTML = {"amazon", "barnes_noble"}
|
| 475 |
+
if credential is not None and platform_id not in _MULTI_FORMAT_HTML:
|
| 476 |
from app.services.platform_api_registry import fetch_price_via_credential
|
| 477 |
hit = await fetch_price_via_credential(client, credential, platform_id, listing_url, ctx)
|
| 478 |
if hit:
|
| 479 |
+
fmt_key = _single_price_credential_format(platform_id)
|
| 480 |
+
norm = (
|
| 481 |
+
canonical_format_prices({fmt_key: hit.formatted}, platform_id)
|
| 482 |
+
if fmt_key else {}
|
| 483 |
+
)
|
| 484 |
return FormatPriceHit(
|
| 485 |
format_prices=norm,
|
| 486 |
formatted=hit.formatted,
|
|
|
|
| 545 |
platform=platform_id,
|
| 546 |
error=str(exc)[:120],
|
| 547 |
)
|
| 548 |
+
|
| 549 |
+
# Amazon / BN HTML gave nothing (e.g. bot wall) — fall back to credential fetch.
|
| 550 |
+
if credential is not None and platform_id in _MULTI_FORMAT_HTML:
|
| 551 |
+
from app.services.platform_api_registry import fetch_price_via_credential
|
| 552 |
+
hit = await fetch_price_via_credential(client, credential, platform_id, listing_url, ctx)
|
| 553 |
+
if hit:
|
| 554 |
+
fmt_key = _single_price_credential_format(platform_id)
|
| 555 |
+
norm = (
|
| 556 |
+
canonical_format_prices({fmt_key: hit.formatted}, platform_id)
|
| 557 |
+
if fmt_key else {}
|
| 558 |
+
)
|
| 559 |
+
return FormatPriceHit(
|
| 560 |
+
format_prices=norm,
|
| 561 |
+
formatted=hit.formatted,
|
| 562 |
+
currency=hit.currency,
|
| 563 |
+
)
|
| 564 |
return None
|
| 565 |
|
| 566 |
|
| 567 |
+
def _single_price_credential_format(platform_id: str) -> str:
|
| 568 |
+
"""Best-effort format label for a single credential price (empty if unknown)."""
|
| 569 |
+
if platform_id in {"kobo", "google_books"}:
|
| 570 |
+
return "eBook"
|
| 571 |
+
# Print-focused / mixed retailers: don't guess a binding.
|
| 572 |
+
return ""
|
| 573 |
+
|
| 574 |
+
|
| 575 |
def _itunes_price_from_item(item: dict) -> tuple[str, str] | None:
|
| 576 |
"""Return (formatted_price, currency) from an iTunes lookup/search item."""
|
| 577 |
raw_price = item.get("formattedPrice")
|