Skip to content

Commit b0713c8

Browse files
committed
feat: add max_listings and max_offers with dynamic limits, improve pagination logic for OpenSea
1 parent 0d70224 commit b0713c8

1 file changed

Lines changed: 47 additions & 9 deletions

File tree

blockapi/v2/api/nft/opensea.py

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from decimal import Decimal
44
from typing import Callable, Iterable, Optional, Tuple
55

6-
from blockapi.utils.num import raw_to_decimals
76
from blockapi.v2.base import (
87
ApiException,
98
BlockchainApi,
@@ -98,6 +97,8 @@ def __init__(
9897
blockchain: Blockchain,
9998
sleep_provider: ISleepProvider = None,
10099
limit: Optional[int] = None,
100+
max_listings=500,
101+
max_offers=500,
101102
):
102103
super().__init__(api_key)
103104

@@ -110,6 +111,9 @@ def __init__(
110111
self._sleep_provider = sleep_provider or SleepProvider()
111112
self._limit = limit
112113

114+
self.max_listings = max_listings
115+
self.max_offers = max_offers
116+
113117
def fetch_nfts(self, address: str, cursor: Optional[str] = None) -> FetchResult:
114118
logger.info(f'Fetch nfts from {address}, cursor={cursor}')
115119
return self._coalesce(self._yield_nfts(address, cursor))
@@ -256,17 +260,32 @@ def _yield_fetch_data(
256260
self, fetch_method: Callable, key: str, cursor: Optional[str] = None
257261
) -> Iterable[Tuple[FetchResult, Optional[str]]]:
258262
cursors = set()
263+
page_count = 0
264+
item_count = 0
259265

260-
count = 0
261266
while True:
262267
self._sleep_provider.sleep(self.base_url, self.api_options.rate_limit)
263-
count += 1
264-
logger.debug(f'Fetching page {count} of {key} from {cursor}')
268+
page_count += 1
269+
logger.debug(f'Fetching page {page_count} of {key} from {cursor}')
265270
fetched, next_cursor = fetch_method(key, cursor)
266271
if self._should_retry(fetched):
267-
count -= 1
272+
page_count -= 1
268273
continue
269274

275+
# Count items for dynamic limiting
276+
item_limit = None
277+
if fetched.data:
278+
current_items = 0
279+
if 'offers' in fetched.data:
280+
current_items = len(fetched.data['offers'])
281+
item_limit = self.max_offers
282+
elif 'listings' in fetched.data:
283+
current_items = len(fetched.data['listings'])
284+
item_limit = self.max_listings
285+
# skip `'nfts' in fetched.data`, because it doesn't have a limit
286+
287+
item_count += current_items
288+
270289
yield fetched, next_cursor
271290

272291
if not next_cursor:
@@ -278,13 +297,19 @@ def _yield_fetch_data(
278297

279298
cursors.add(cursor)
280299

281-
if self._limit and count >= self._limit:
300+
# Check both page and item limits
301+
if self._limit and page_count >= self._limit:
302+
break
303+
304+
if item_limit and item_count >= item_limit:
282305
break
283306

284307
def _fetch_offers_page(
285308
self, method: str, collection: str, cursor: Optional[str] = None
286309
) -> tuple[FetchResult, Optional[str]]:
287-
params = dict(next=cursor) if cursor else dict()
310+
params = {'limit': 100} # the max limit allowed is 100 items per page
311+
if cursor:
312+
params['next'] = cursor
288313

289314
fetched = self.get_data(
290315
method,
@@ -567,15 +592,17 @@ def _get_type(item_type) -> Optional[OfferItemType]:
567592

568593
return OFFER_ITEM_TYPES.get(item_type)
569594

570-
@staticmethod
571-
def _coalesce(fetch_results: Iterable[Tuple[FetchResult, Optional[str]]]):
595+
def _coalesce(self, fetch_results: Iterable[Tuple[FetchResult, Optional[str]]]):
596+
"""Simple aggregator - no limiting logic needed here."""
572597
data = []
573598
errors = []
574599
last = None
575600
last_cursor = None
601+
576602
for item, cursor in fetch_results:
577603
last_cursor = cursor
578604
last = item
605+
579606
if item.data:
580607
data.append(item.data)
581608

@@ -636,3 +663,14 @@ def _should_retry(self, data):
636663
return True
637664

638665
return False
666+
667+
668+
if __name__ == '__main__':
669+
col = 'ever-fragments-of-civitas'
670+
o = OpenSeaApi(
671+
'6c0e52527b124aeeb0bebbcfbaf2e7b6', Blockchain.ETHEREUM, max_listings=100
672+
)
673+
# offers = o.fetch_offers(col)
674+
listings = o.fetch_listings(col)
675+
676+
assert True

0 commit comments

Comments
 (0)