← back to Animate Museum Posts

src/fetchFromAIC.js

105 lines

import axios from 'axios';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const AIC_API_BASE = 'https://api.artic.edu/api/v1';
const IIIF_BASE = 'https://www.artic.edu/iiif/2';

export async function fetchFromAIC() {
  try {
    console.log('Fetching from Art Institute of Chicago...');

    // Search for public domain artworks with images
    const response = await axios.get(`${AIC_API_BASE}/artworks/search`, {
      params: {
        q: '*',
        query: {
          bool: {
            must: [
              { term: { is_public_domain: true } },
              { exists: { field: 'image_id' } }
            ]
          }
        },
        fields: 'id,title,artist_title,date_display,image_id,thumbnail,medium_display,dimensions,credit_line,place_of_origin,style_title',
        limit: 100
      },
      timeout: 30000
    });

    if (!response.data || !response.data.data || response.data.data.length === 0) {
      throw new Error('No artworks found from Art Institute of Chicago');
    }

    const artworks = response.data.data.filter(a => a.image_id);
    if (artworks.length === 0) {
      throw new Error('No artworks with images found');
    }

    // Pick random artwork
    const artwork = artworks[Math.floor(Math.random() * artworks.length)];

    // Construct IIIF image URL (843px wide is good quality)
    const imageUrl = `${IIIF_BASE}/${artwork.image_id}/full/843,/0/default.jpg`;

    console.log(`Downloading: ${artwork.title}`);
    const imageResponse = await axios.get(imageUrl, {
      responseType: 'arraybuffer',
      timeout: 30000,
      headers: {
        'User-Agent': 'Mozilla/5.0 (compatible; MuseumBot/1.0)'
      }
    });

    if (!imageResponse.data || imageResponse.data.length < 1000) {
      throw new Error('Failed to download image');
    }

    // Save to output directory
    const outputDir = path.join(__dirname, '..', 'output');
    if (!fs.existsSync(outputDir)) {
      fs.mkdirSync(outputDir, { recursive: true });
    }

    const timestamp = Date.now();
    const fileName = `aic_${timestamp}.jpg`;
    const filePath = path.join(outputDir, fileName);
    fs.writeFileSync(filePath, imageResponse.data);

    // Return normalized metadata
    const metadata = {
      title: artwork.title || 'Untitled',
      artist: artwork.artist_title || 'Unknown Artist',
      year: artwork.date_display || 'Date Unknown',
      description: artwork.medium_display || '',
      objectNumber: `AIC-${artwork.id}`,
      imageUrl: imageUrl,
      localPath: filePath,
      fileName: fileName,
      museum: 'Art Institute of Chicago',
      creditLine: artwork.credit_line || 'Art Institute of Chicago (Public Domain)',
      dimensions: artwork.dimensions ? [artwork.dimensions] : [],
      style: artwork.style_title,
      origin: artwork.place_of_origin
    };

    console.log(`AIC: Fetched "${metadata.title}" by ${metadata.artist}`);
    return metadata;

  } catch (error) {
    console.error('AIC fetch failed:', error.message);
    throw error;
  }
}

// Test if run directly
if (process.argv[1] === fileURLToPath(import.meta.url)) {
  fetchFromAIC()
    .then(m => console.log('Success:', JSON.stringify(m, null, 2)))
    .catch(e => console.error('Failed:', e.message));
}