← back to Ventura Claw

server/connectors/cleveland.js

47 lines

// Cleveland Museum of Art — Open Access. No API key.
// https://openaccess-api.clevelandart.org/
const BASE = "https://openaccess-api.clevelandart.org/api";
async function call(path) {
  const r = await fetch(`${BASE}${path}`, {
    headers: { "User-Agent": "VenturaClaw/1.0", Accept: "application/json" },
    signal: AbortSignal.timeout(15_000),
  });
  if (!r.ok) throw new Error(`cleveland ${r.status}`);
  return r.json();
}
module.exports = {
  meta: { id: "cleveland", name: "Cleveland Museum of Art", category: "data", docsUrl: "https://openaccess-api.clevelandart.org/", auth: "none", realImpl: true },
  fields: [],
  configured() { return true; },
  async health() {
    try {
      const d = await call("/artworks?limit=1");
      return { ok: true, label: `${(d.info?.total ?? 0).toLocaleString()} artworks · CC0 + open access` };
    } catch (e) { return { ok: false, reason: e.message }; }
  },
  actions: {
    async "search"({ q, hasImage, cc0only, limit }) {
      const qs = new URLSearchParams();
      if (q) qs.set("q", q);
      if (hasImage) qs.set("has_image", "1");
      if (cc0only) qs.set("cc0", "1");
      qs.set("limit", String(Math.min(limit || 25, 100)));
      const d = await call(`/artworks?${qs}`);
      return {
        total: d.info?.total || 0,
        artworks: (d.data || []).map(a => ({
          id: a.id, accession_number: a.accession_number,
          title: a.title, creators: (a.creators || []).map(c => c.description).join(" · "),
          date: a.creation_date, medium: a.technique, image: a.images?.web?.url || a.images?.print?.url,
          url: a.url, license: a.share_license_status,
        })),
      };
    },
    async "artwork"({ id }) {
      if (!id) throw new Error("id required");
      const d = await call(`/artworks/${id}`);
      return d.data;
    },
  },
};