Prompt — public_domain gem como retriever de contenido rasterizable

Fecha: 2026-08-03 Repo destino: github.com/[usuario]/public_domain_gem Consumidor: ~/nef/archive-lending-clone (lector de préstamo con spread de dos páginas) Para qué: que poblar el catálogo del lector deje de ser artesanal.

Pegar de aquí abajo.


Contexto

Estoy usando este gem como retriever de contenido de dominio público para un lector web que muestra páginas escaneadas en un spread de dos hojas. El gem ya resuelve búsqueda y metadata. Le falta exactamente lo que el lector necesita para decidir si un item se puede paginar y cómo pedir cada página.

Hoy Archive::Item y Archive::Result exponen iiif_manifest_url, pero un consumidor no puede saber, sin trabajo extra, si el item realmente sirve imágenes de página ni cuántas hay. Eso es lo que quiero cerrar.

Qué agregar

Tres cosas, en lib/public_domain/archive/item.rb y su equivalente en result.rb donde aplique:

1. #rasterizable?

True si el item tiene derivados de imagen servibles por IIIF.

Heurística verificada: la presencia de un archivo cuyo nombre termina en _jp2.zip en la lista de files. Comprobado contra tres items:

identifier_jp2.zipIIIF sirve páginas
donquijote00cervuoftsísí
parasoperdidop01miltuoftsísí
manualpaleografia00riveuoftnono — 404 en toda página, 500 en el manifiesto

Esto se resuelve con la metadata que Item.fetch ya trae. No pidas el manifiesto solo para esto.

2. #page_count

Número real de páginas paginables.

Trampa importante: NO uses metadata["imagecount"]. No coincide con el número de canvases del manifiesto IIIF:

identifierimagecountcanvases reales
donquijote00cervuoft910906
parasoperdidop01miltuoft392388

Confiar en imagecount produce 404 en las últimas páginas. El número bueno es items.length del manifiesto (IIIF Presentation 3 — es items, no sequences[].canvases de la v2).

Como el manifiesto es caro y a veces falla, page_count debe pedirlo de forma diferida y memoizada, y devolver nil si el item no es rasterizable? o si el manifiesto falla. nil significa “no paginable”, no cero.

3. #page_image_url(index, height: nil, width: nil)

Constructor de URL de una página. Patrón verificado, sin necesidad de leer el manifiesto:

https://iiif.archive.org/iiif/<identifier>$<index>/full/,<height>/0/default.jpg
  • index es 0-indexed. Documentalo en el método: es la fuente más probable de bugs off-by-one en los consumidores.
  • Sin height ni width, usa /full/max/0/default.jpg.
  • Escapa el identifier.

Robustez que quiero

  • Un manifiesto que devuelve 500 no debe reventar nada: manualpaleografia00riveuoft es un caso real y vivo. Debe degradar a page_count → nil, no a excepción.
  • Nada de peticiones de red en el constructor. page_count es lazy; el resto sale de la metadata que ya se tiene.

Tests

Sigue el estilo de test/archive/item_test.rb con fixtures en test/fixtures/. Casos mínimos:

  • item con _jp2.zip → rasterizable? true
  • item sin _jp2.zip → rasterizable? false, page_count nil, sin pedir red
  • manifiesto 500 → page_count nil, sin levantar excepción
  • page_count memoizado: dos llamadas, una sola petición
  • page_image_url(0) genera índice $0, no $1
  • page_image_url con y sin height

Ojo: los identifiers de los fixtures actuales (elingeniosohidalgo, audioquijote) son ficticios y devuelven metadata vacía contra la API real. Si agregas fixtures nuevos, cápturalos de items reales.

Fuera de alcance

No toques el modelo de búsqueda, ni Europeana/Wikisource/OAI, ni agregues un cliente IIIF completo. Solo lo que hace falta para paginar un item de Archive.

Extra, si sale barato

Un #to_h que ya incluya rasterizable, page_count e identifier me deja generar el catálogo del lector directo desde una búsqueda, sin pegamento intermedio.


Por qué estos campos y no otros

Lo que consume el lector para decidir el modo de render:

  • rasterizable? → usa imágenes IIIF (rápido, sin bajar el PDF)
  • si no → cae al PDF, que en Archive.org no tiene CORS, así que solo puede ir en un <iframe>, no rasterizarse con pdf.js
  • page_count → arma el spread y calcula el límite final

Detalle que motivó todo esto: archive.org/download/ no manda Access-Control-Allow-Origin, pero iiif.archive.org manda *. Por eso el camino de imágenes es el único rasterizable del lado cliente para este origen.