@@ -293,7 +293,7 @@ <h2 class="text-2xl font-light text-gray-800 mb-2">${collection.title}</h2>
293293 ]
294294 } ;
295295
296- // Simple working approach with fallback when API is down
296+ // Robust API fetching with rate limiting and retry logic
297297 async function getCuratedArtworks ( collectionKey ) {
298298 try {
299299 // Show loading state
@@ -302,13 +302,22 @@ <h2 class="text-2xl font-light text-gray-800 mb-2">${collection.title}</h2>
302302
303303 console . log ( 'Attempting to fetch from Met Museum API...' ) ;
304304
305- // Use the exact same approach as the working example
306- const response = await fetch ( 'https://collectionapi.metmuseum.org/public/collection/v1/search?isHighlight=true&hasImages=true&q=a' ) ;
305+ // Fetch search results with timeout
306+ const controller = new AbortController ( ) ;
307+ const timeoutId = setTimeout ( ( ) => controller . abort ( ) , 10000 ) ;
307308
309+ const response = await fetch ( 'https://collectionapi.metmuseum.org/public/collection/v1/search?isHighlight=true&hasImages=true&q=a' , {
310+ signal : controller . signal ,
311+ headers : {
312+ 'Accept' : 'application/json'
313+ }
314+ } ) ;
315+
316+ clearTimeout ( timeoutId ) ;
308317 console . log ( 'Response status:' , response . status , response . statusText ) ;
309318
310319 if ( ! response . ok ) {
311- throw new Error ( `HTTP ${ response . status } : ${ response . statusText } ` ) ;
320+ throw new Error ( `API returned ${ response . status } : ${ response . statusText } ` ) ;
312321 }
313322
314323 const data = await response . json ( ) ;
@@ -317,58 +326,96 @@ <h2 class="text-2xl font-light text-gray-800 mb-2">${collection.title}</h2>
317326 const objectIDs = data . objectIDs ;
318327
319328 if ( ! objectIDs || objectIDs . length === 0 ) {
320- throw new Error ( 'No artworks found in the Met Museum collection ' ) ;
329+ throw new Error ( 'No artworks found in search results ' ) ;
321330 }
322331
323- console . log ( `Found ${ objectIDs . length } artworks, fetching first 20 ...` ) ;
332+ console . log ( `Found ${ objectIDs . length } artworks, fetching first 15 details ...` ) ;
324333
325- // Fetch details for a selection of artworks (exactly like the working example)
326- const artworks = await Promise . all ( objectIDs . slice ( 0 , 20 ) . map ( async ( id ) => {
327- try {
328- const res = await fetch ( `https://collectionapi.metmuseum.org/public/collection/v1/objects/${ id } ` ) ;
329- if ( ! res . ok ) return null ;
330- return res . json ( ) ;
331- } catch ( err ) {
332- console . warn ( `Failed to fetch artwork ${ id } :` , err ) ;
333- return null ;
334+ // Fetch artwork details with rate limiting (staggered requests)
335+ const artworks = [ ] ;
336+ const batchSize = 5 ; // Smaller batches to respect rate limits
337+ const delay = ms => new Promise ( resolve => setTimeout ( resolve , ms ) ) ;
338+
339+ for ( let i = 0 ; i < Math . min ( 15 , objectIDs . length ) ; i += batchSize ) {
340+ const batch = objectIDs . slice ( i , i + batchSize ) ;
341+ console . log ( `Fetching batch ${ Math . floor ( i / batchSize ) + 1 } :` , batch ) ;
342+
343+ const batchPromises = batch . map ( async ( id ) => {
344+ try {
345+ const res = await fetch ( `https://collectionapi.metmuseum.org/public/collection/v1/objects/${ id } ` , {
346+ headers : { 'Accept' : 'application/json' }
347+ } ) ;
348+ if ( ! res . ok ) {
349+ console . warn ( `Failed to fetch artwork ${ id } : ${ res . status } ` ) ;
350+ return null ;
351+ }
352+ return await res . json ( ) ;
353+ } catch ( err ) {
354+ console . warn ( `Network error fetching artwork ${ id } :` , err . message ) ;
355+ return null ;
356+ }
357+ } ) ;
358+
359+ const batchResults = await Promise . all ( batchPromises ) ;
360+ artworks . push ( ...batchResults . filter ( artwork => artwork !== null ) ) ;
361+
362+ // Small delay between batches to respect rate limits
363+ if ( i + batchSize < Math . min ( 15 , objectIDs . length ) ) {
364+ await delay ( 100 ) ;
334365 }
335- } ) ) ;
366+ }
336367
337368 // Filter and display only artworks with images
338369 const validArtworks = artworks . filter ( artwork => artwork && artwork . primaryImageSmall ) ;
339- console . log ( `Found ${ validArtworks . length } artworks with images` ) ;
370+ console . log ( `Successfully loaded ${ validArtworks . length } artworks with images` ) ;
340371
341372 if ( validArtworks . length === 0 ) {
342- throw new Error ( 'No artworks with images available at this time ' ) ;
373+ throw new Error ( 'No artworks with images found in current batch ' ) ;
343374 }
344375
345376 displayArtworks ( validArtworks ) ;
346377
347378 } catch ( error ) {
348- console . error ( 'Error fetching artworks:' , error ) ;
349- console . log ( 'Falling back to sample artworks...' ) ;
350-
351- // Use sample artworks as fallback
352- const fallbackArtworks = sampleArtworks [ collectionKey ] || sampleArtworks . impressionist ;
379+ console . error ( 'Met Museum API Error:' , error ) ;
353380
354- // Add a notice that we're showing sample data
355- gallery . innerHTML = `
356- <div class="col-span-full mb-6">
357- <div class="bg-blue-50 border border-blue-200 rounded-lg p-4 text-center">
358- <i class="fas fa-info-circle text-blue-500 mr-2"></i>
359- <span class="text-blue-700 text-sm">
360- The Met Museum API is temporarily unavailable. Showing sample artworks to demonstrate the gallery.
361- </span>
362- </div>
363- </div>
364- ` ;
381+ // Only show fallback for actual API failures, not rate limiting issues
382+ if ( error . name === 'AbortError' ) {
383+ console . log ( 'Request timed out, showing fallback...' ) ;
384+ } else if ( error . message . includes ( 'Failed to fetch' ) ) {
385+ console . log ( 'Network error, showing fallback...' ) ;
386+ } else {
387+ console . log ( 'API error, showing fallback...' ) ;
388+ }
365389
366- displayArtworks ( fallbackArtworks , true ) ;
390+ showFallbackWithRetry ( collectionKey , error . message ) ;
367391 } finally {
368392 loadingIndicator . style . display = 'none' ;
369393 }
370394 }
371395
396+ function showFallbackWithRetry ( collectionKey , errorMessage ) {
397+ const fallbackArtworks = sampleArtworks [ collectionKey ] || sampleArtworks . impressionist ;
398+
399+ // Add a notice with retry option
400+ gallery . innerHTML = `
401+ <div class="col-span-full mb-6">
402+ <div class="bg-yellow-50 border border-yellow-200 rounded-lg p-4 text-center">
403+ <i class="fas fa-exclamation-triangle text-yellow-500 mr-2"></i>
404+ <div class="text-yellow-800 text-sm">
405+ <p class="mb-2">Unable to load live artworks from The Met Museum API.</p>
406+ <p class="mb-3 text-xs text-yellow-700">Error: ${ errorMessage } </p>
407+ <button onclick="getCuratedArtworks('${ collectionKey } ')"
408+ class="bg-yellow-500 hover:bg-yellow-600 text-white px-4 py-1 rounded text-xs transition-colors">
409+ <i class="fas fa-redo mr-1"></i>Try Again
410+ </button>
411+ </div>
412+ </div>
413+ </div>
414+ ` ;
415+
416+ displayArtworks ( fallbackArtworks , true ) ;
417+ }
418+
372419 function displayArtworks ( artworks , isFallback = false ) {
373420 // Don't clear gallery if we're adding fallback notice
374421 if ( ! isFallback ) {
0 commit comments