diff --git a/.env.example b/.env.example index add60a4..69b2f37 100644 --- a/.env.example +++ b/.env.example @@ -9,3 +9,4 @@ IMAGE_DIR=./data/images # Optional — enable extra museum search in fetch-missing-images / search-missing-paintings # SMITHSONIAN_API_KEY= # HARVARD_ART_API_KEY= +# FETCH_MAX_WAIT_SEC=10 diff --git a/Documentation/data-and-images.md b/Documentation/data-and-images.md index c930e8d..3f5bddc 100644 --- a/Documentation/data-and-images.md +++ b/Documentation/data-and-images.md @@ -150,14 +150,26 @@ Extend the data file to add lineage chains (e.g. Giotto → Masaccio → Michela | Harvard Art Museums | Optional (`HARVARD_ART_API_KEY` in `.env`) | ```bash -npm run fetch-images # all missing (~hours; rate-limited) -npm run fetch-images -- --limit=50 # batch of 50 -npm run fetch-images -- --artist="Albrecht Dürer" +npm run fetch-images # all missing, catalog order (~hours) +npm run fetch-images -- --limit=50 # random sample of 50; 10s max per painting +npm run fetch-images -- --limit=920 # random sample up to N missing works +npm run fetch-images -- --limit=50 --max-wait=120 # slower, more thorough lookup per painting +npm run fetch-images -- --artist="Albrecht Dürer" # one artist, catalog order npm run fetch-images -- --discover-only --limit=20 # fix wikipedia_title only npm run fetch-images -- --web-search-only --limit=50 # DuckDuckGo + Commons + multilingual Wikipedia ``` -When a better Wikipedia article is found, `wikipedia_title` in the DB is updated automatically. +| Flag | Effect | +|------|--------| +| `--limit=N` | Process at most **N** paintings. Queue is a **random sample** of all works missing local files (not alphabetical). | +| `--max-wait=N` | Stop each painting after **N** seconds (default **10**). Logs `⏱ timeout` and continues. | +| `--artist="Name"` | Only that artist’s missing works, in catalog order (`sort_order`, `year`). | +| `--discover-only` | Update `wikipedia_title` via search; no download. | +| `--web-search-only` | Skip museum APIs; use web search + Commons + multilingual Wikipedia. | + +Each limited batch run stops per painting after **`--max-wait` seconds** (default **10**), including source lookup and download. While a batch deadline is active, inter-request throttling is skipped and each HTTP call times out at the **remaining** budget (not the full 15s on-demand limit). Override the default via `FETCH_MAX_WAIT_SEC` in `.env` or `--max-wait=N`. On-demand fetches in the web UI keep their separate 15s API timeout and are unaffected. + +Re-run the same command to pick a new random batch until the missing count reaches zero. ## On-demand image resolution @@ -174,7 +186,7 @@ When a painting has no local file, `GET /api/paintings/:id/image` triggers `ensu Separate Wikipedia/Commons thumbnail URLs often resolve to the **wrong work** (e.g. a different painting with a similar title). Thumbnails are always derived locally from the downloaded full image via `sharp` in `scripts/image-fetcher.js`. -Requests are deduplicated (`inflight` map) and timeout after 15 seconds. A ~2.5 s delay between external requests reduces rate-limit risk. +Requests are deduplicated (`inflight` map) and timeout after 15 seconds. On-demand resolution uses a ~2.5 s delay between external requests to reduce rate-limit risk; batch `fetch-images` runs skip that delay while the per-painting deadline is active. ## Preload before 3D gallery diff --git a/Documentation/setup.md b/Documentation/setup.md index fdadfc3..0038509 100644 --- a/Documentation/setup.md +++ b/Documentation/setup.md @@ -29,6 +29,7 @@ Optional script tuning: | Variable | Used by | Description | |----------|---------|-------------| | `MIN_PAINTINGS` | `expand-catalog` | Minimum paintings per artist (default `6`) | +| `FETCH_MAX_WAIT_SEC` | `fetch-images` | Max seconds per painting in batch runs (default `10`) | `.env` is git-ignored; never commit passwords. @@ -64,11 +65,12 @@ After a fresh seed, run these to match a fully populated local install: npm run fetch-artist-bios # bio_short / bio_full from Wikipedia npm run expand-catalog # famous works for artists below MIN_PAINTINGS npm run update-influences # painting influence graph for detail view + hall exits -npm run fetch-images -- --artist="Gustav Klimt" # repeat per artist or omit --artist for all +npm run fetch-images -- --limit=50 # random sample; 10s max per painting (default) +npm run fetch-images -- --limit=50 --max-wait=120 # same batch size, longer lookup per work cd client && npm run build && cd .. ``` -Image fetch is rate-limited (~3.5 s between external requests) and can take hours for the full catalog. Fetch per artist, or rely on on-demand resolution when viewing a painting in the detail view. +Image fetch can take hours for the full catalog (~900+ missing works after seed). Use **`npm run fetch-images -- --limit=N`** for random batches (10s per painting by default), **`--artist="…"`** for one artist in catalog order, or on-demand resolution when viewing a painting in the detail view. ## Run @@ -99,8 +101,9 @@ Open http://localhost:3001 (or your configured `PORT`). | `npm run expand-catalog -- --fetch-images` | ↑ | Also download images for new rows (slow) | | `npm run fetch-images` | `scripts/fetch-missing-images.js` | Search Wikipedia, Commons, museums for missing files | | `npm run search-missing-paintings` | ↑ (alias) | Same as `fetch-images` | -| `npm run fetch-images -- --artist="Name"` | ↑ | Limit to one artist | -| `npm run fetch-images -- --limit=50` | ↑ | Process at most N paintings | +| `npm run fetch-images -- --artist="Name"` | ↑ | Limit to one artist (catalog order) | +| `npm run fetch-images -- --limit=50` | ↑ | Random sample of N missing paintings | +| `npm run fetch-images -- --limit=50 --max-wait=120` | ↑ | Random batch; 120s cap per painting | | `npm run fetch-images -- --discover-only --limit=20` | ↑ | Fix `wikipedia_title` via search only | | `npm run regenerate-thumbnails` | `scripts/regenerate-thumbnails.js` | Rebuild all thumbs from full local files | | `npm run audit-painting-images` | `scripts/audit-painting-images.js` | List thumb/full aspect-ratio mismatches | @@ -143,7 +146,8 @@ After clone: copy `.env.example` → `.env`, install dependencies, run `npm run | 500 on all `/api/*` | Wrong `.env` or Postgres down | Check connection, logs | | “Biographical information not yet available” | Bios not fetched | `npm run fetch-artist-bios` | | Artist hall has only 1–2 paintings | Catalog not expanded | `npm run expand-catalog`; extend `famous-paintings-data.js` | -| Black frames / canvas covers in 3D gallery | No local image for painting | `npm run fetch-images -- --artist="…"` or `POST …/preload-images` after fetch | +| Black frames / canvas covers in 3D gallery | No local image for painting | `npm run fetch-images -- --limit=50` or `--artist="…"`; then `POST …/preload-images` | +| Many `⏱ timeout` lines in fetch batch | Default 10s cap too short for hard works | `--max-wait=120` or raise `FETCH_MAX_WAIT_SEC` | | White/grey flicker on frames | Texture loading or z-fighting with wall | Rebuild client (`cd client && npm run build`); ensure latest `VirtualGallery.tsx` | | Wrong painting in 3D gallery frame | Stale or mismatched thumbnail file | `npm run regenerate-thumbnails`; gallery prefers full `image_path` | | Wrong painting image (fetch) | Bad museum / search match on first download | Add entry to `DIRECT_IMAGE_OVERRIDES` in `scripts/image-fetcher.js`, re-fetch file | diff --git a/README.md b/README.md index a8fb000..9ec77d0 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,8 @@ Interactive virtual art gallery: zoomable historical timeline, art movement band npm run fetch-artist-bios # Wikipedia biographies for all artists npm run expand-catalog # add famous works for artists with thin catalogs npm run update-influences # art-history lineage links between paintings - npm run fetch-images -- --artist="Claude Monet" # images per artist (slow; repeat) + npm run fetch-images -- --limit=50 # random batch of missing images (10s per work) + npm run fetch-images -- --artist="Claude Monet" # one artist in catalog order ``` 5. Build the client and start the server: diff --git a/data/images/paintings/Alexander_Rodchenko_Girl_with_a_Leica.jpg b/data/images/paintings/Alexander_Rodchenko_Girl_with_a_Leica.jpg new file mode 100644 index 0000000..76f25c0 Binary files /dev/null and b/data/images/paintings/Alexander_Rodchenko_Girl_with_a_Leica.jpg differ diff --git a/data/images/paintings/Andy_Warhol_Brillo_Box.jpg b/data/images/paintings/Andy_Warhol_Brillo_Box.jpg new file mode 100644 index 0000000..a5c1779 Binary files /dev/null and b/data/images/paintings/Andy_Warhol_Brillo_Box.jpg differ diff --git a/data/images/paintings/Andy_Warhol_Green_Coca-Cola_Bottles.jpg b/data/images/paintings/Andy_Warhol_Green_Coca-Cola_Bottles.jpg new file mode 100644 index 0000000..a5c1779 Binary files /dev/null and b/data/images/paintings/Andy_Warhol_Green_Coca-Cola_Bottles.jpg differ diff --git a/data/images/paintings/Andy_Warhol_Shot_Sage_Blue_Marilyn.jpg b/data/images/paintings/Andy_Warhol_Shot_Sage_Blue_Marilyn.jpg new file mode 100644 index 0000000..a5c1779 Binary files /dev/null and b/data/images/paintings/Andy_Warhol_Shot_Sage_Blue_Marilyn.jpg differ diff --git a/data/images/paintings/Angelica_Kauffman_Cornelia__Mother_of_the_Gracchi.jpg b/data/images/paintings/Angelica_Kauffman_Cornelia__Mother_of_the_Gracchi.jpg new file mode 100644 index 0000000..0f752f1 Binary files /dev/null and b/data/images/paintings/Angelica_Kauffman_Cornelia__Mother_of_the_Gracchi.jpg differ diff --git a/data/images/paintings/Angelica_Kauffman_Portrait_of_Johann_Joachim_Winckelmann.jpg b/data/images/paintings/Angelica_Kauffman_Portrait_of_Johann_Joachim_Winckelmann.jpg new file mode 100644 index 0000000..942a1e1 Binary files /dev/null and b/data/images/paintings/Angelica_Kauffman_Portrait_of_Johann_Joachim_Winckelmann.jpg differ diff --git a/data/images/paintings/Angelica_Kauffman_Rinaldo_and_Armida.jpg b/data/images/paintings/Angelica_Kauffman_Rinaldo_and_Armida.jpg new file mode 100644 index 0000000..2eec32c Binary files /dev/null and b/data/images/paintings/Angelica_Kauffman_Rinaldo_and_Armida.jpg differ diff --git a/data/images/paintings/Angelica_Kauffman_Self-Portrait_of_the_Artist_Hesitating_Between_the_Arts_of_Music_and_Painting.jpg b/data/images/paintings/Angelica_Kauffman_Self-Portrait_of_the_Artist_Hesitating_Between_the_Arts_of_Music_and_Painting.jpg new file mode 100644 index 0000000..d3e6fb2 Binary files /dev/null and b/data/images/paintings/Angelica_Kauffman_Self-Portrait_of_the_Artist_Hesitating_Between_the_Arts_of_Music_and_Painting.jpg differ diff --git a/data/images/paintings/Angelica_Kauffman_Venus_Induces_Helen_to_Fall_in_Love_with_Paris.jpg b/data/images/paintings/Angelica_Kauffman_Venus_Induces_Helen_to_Fall_in_Love_with_Paris.jpg new file mode 100644 index 0000000..d539a8d Binary files /dev/null and b/data/images/paintings/Angelica_Kauffman_Venus_Induces_Helen_to_Fall_in_Love_with_Paris.jpg differ diff --git a/data/images/paintings/Apelles_Alexander_the_Great_Holding_a_Thunderbolt.JPG b/data/images/paintings/Apelles_Alexander_the_Great_Holding_a_Thunderbolt.JPG new file mode 100644 index 0000000..36adc11 Binary files /dev/null and b/data/images/paintings/Apelles_Alexander_the_Great_Holding_a_Thunderbolt.JPG differ diff --git a/data/images/paintings/Apelles_Aphrodite_Anadyomene.JPG b/data/images/paintings/Apelles_Aphrodite_Anadyomene.JPG new file mode 100644 index 0000000..36adc11 Binary files /dev/null and b/data/images/paintings/Apelles_Aphrodite_Anadyomene.JPG differ diff --git a/data/images/paintings/Apelles_Calumny_of_Apelles.jpg b/data/images/paintings/Apelles_Calumny_of_Apelles.jpg new file mode 100644 index 0000000..4598358 Binary files /dev/null and b/data/images/paintings/Apelles_Calumny_of_Apelles.jpg differ diff --git a/data/images/paintings/Apelles_Campaspe.JPG b/data/images/paintings/Apelles_Campaspe.JPG new file mode 100644 index 0000000..36adc11 Binary files /dev/null and b/data/images/paintings/Apelles_Campaspe.JPG differ diff --git a/data/images/paintings/Apelles_Portrait_of_Alexander.JPG b/data/images/paintings/Apelles_Portrait_of_Alexander.JPG new file mode 100644 index 0000000..36adc11 Binary files /dev/null and b/data/images/paintings/Apelles_Portrait_of_Alexander.JPG differ diff --git a/data/images/paintings/Apelles_Venus_Anadyomene.jpg b/data/images/paintings/Apelles_Venus_Anadyomene.jpg new file mode 100644 index 0000000..16717db Binary files /dev/null and b/data/images/paintings/Apelles_Venus_Anadyomene.jpg differ diff --git a/data/images/paintings/Artemisia_Gentileschi_Esther_before_Ahasuerus.jpg b/data/images/paintings/Artemisia_Gentileschi_Esther_before_Ahasuerus.jpg new file mode 100644 index 0000000..8e1d0b8 Binary files /dev/null and b/data/images/paintings/Artemisia_Gentileschi_Esther_before_Ahasuerus.jpg differ diff --git a/data/images/paintings/Artemisia_Gentileschi_Judith_Slaying_Holofernes.jpg b/data/images/paintings/Artemisia_Gentileschi_Judith_Slaying_Holofernes.jpg new file mode 100644 index 0000000..f7b93c6 Binary files /dev/null and b/data/images/paintings/Artemisia_Gentileschi_Judith_Slaying_Holofernes.jpg differ diff --git a/data/images/paintings/Artemisia_Gentileschi_Judith_and_Her_Maidservant.jpg b/data/images/paintings/Artemisia_Gentileschi_Judith_and_Her_Maidservant.jpg new file mode 100644 index 0000000..f68a48b Binary files /dev/null and b/data/images/paintings/Artemisia_Gentileschi_Judith_and_Her_Maidservant.jpg differ diff --git a/data/images/paintings/Artemisia_Gentileschi_Mary_Magdalene.jpg b/data/images/paintings/Artemisia_Gentileschi_Mary_Magdalene.jpg new file mode 100644 index 0000000..c319341 Binary files /dev/null and b/data/images/paintings/Artemisia_Gentileschi_Mary_Magdalene.jpg differ diff --git a/data/images/paintings/Artemisia_Gentileschi_Self-Portrait_as_the_Allegory_of_Painting.jpg b/data/images/paintings/Artemisia_Gentileschi_Self-Portrait_as_the_Allegory_of_Painting.jpg new file mode 100644 index 0000000..fa7f921 Binary files /dev/null and b/data/images/paintings/Artemisia_Gentileschi_Self-Portrait_as_the_Allegory_of_Painting.jpg differ diff --git a/data/images/paintings/Artemisia_Gentileschi_Susanna_and_the_Elders.jpg b/data/images/paintings/Artemisia_Gentileschi_Susanna_and_the_Elders.jpg new file mode 100644 index 0000000..1ae64ce Binary files /dev/null and b/data/images/paintings/Artemisia_Gentileschi_Susanna_and_the_Elders.jpg differ diff --git a/data/images/paintings/Aubrey_Beardsley_J_ai_bais__ta_bouche.jpg b/data/images/paintings/Aubrey_Beardsley_J_ai_bais__ta_bouche.jpg new file mode 100644 index 0000000..7bb1dc4 Binary files /dev/null and b/data/images/paintings/Aubrey_Beardsley_J_ai_bais__ta_bouche.jpg differ diff --git a/data/images/paintings/Aubrey_Beardsley_The_Black_Cape.jpg b/data/images/paintings/Aubrey_Beardsley_The_Black_Cape.jpg new file mode 100644 index 0000000..af95d0c Binary files /dev/null and b/data/images/paintings/Aubrey_Beardsley_The_Black_Cape.jpg differ diff --git a/data/images/paintings/Aubrey_Beardsley_The_Dancer_s_Reward.jpg b/data/images/paintings/Aubrey_Beardsley_The_Dancer_s_Reward.jpg new file mode 100644 index 0000000..7bb1dc4 Binary files /dev/null and b/data/images/paintings/Aubrey_Beardsley_The_Dancer_s_Reward.jpg differ diff --git a/data/images/paintings/Aubrey_Beardsley_The_Peacock_Skirt.PNG b/data/images/paintings/Aubrey_Beardsley_The_Peacock_Skirt.PNG new file mode 100644 index 0000000..5accdf3 Binary files /dev/null and b/data/images/paintings/Aubrey_Beardsley_The_Peacock_Skirt.PNG differ diff --git a/data/images/paintings/Aubrey_Beardsley_The_Rape_of_the_Lock.jpg b/data/images/paintings/Aubrey_Beardsley_The_Rape_of_the_Lock.jpg new file mode 100644 index 0000000..7bb1dc4 Binary files /dev/null and b/data/images/paintings/Aubrey_Beardsley_The_Rape_of_the_Lock.jpg differ diff --git a/data/images/paintings/Aubrey_Beardsley_The_Yellow_Book.jpg b/data/images/paintings/Aubrey_Beardsley_The_Yellow_Book.jpg new file mode 100644 index 0000000..83b6911 Binary files /dev/null and b/data/images/paintings/Aubrey_Beardsley_The_Yellow_Book.jpg differ diff --git a/data/images/paintings/Bronzino_An_Allegory_with_Venus_and_Cupid.jpg b/data/images/paintings/Bronzino_An_Allegory_with_Venus_and_Cupid.jpg new file mode 100644 index 0000000..28a3973 Binary files /dev/null and b/data/images/paintings/Bronzino_An_Allegory_with_Venus_and_Cupid.jpg differ diff --git a/data/images/paintings/Bronzino_Holy_Family_with_St__Anne_and_the_Infant_St__John.jpg b/data/images/paintings/Bronzino_Holy_Family_with_St__Anne_and_the_Infant_St__John.jpg new file mode 100644 index 0000000..b787b4c Binary files /dev/null and b/data/images/paintings/Bronzino_Holy_Family_with_St__Anne_and_the_Infant_St__John.jpg differ diff --git a/data/images/paintings/Bronzino_Portrait_of_Cosimo_I_de__Medici_in_Armour.jpg b/data/images/paintings/Bronzino_Portrait_of_Cosimo_I_de__Medici_in_Armour.jpg new file mode 100644 index 0000000..f027633 Binary files /dev/null and b/data/images/paintings/Bronzino_Portrait_of_Cosimo_I_de__Medici_in_Armour.jpg differ diff --git a/data/images/paintings/Bronzino_Portrait_of_Eleonora_di_Toledo_with_her_son_Giovanni.jpg b/data/images/paintings/Bronzino_Portrait_of_Eleonora_di_Toledo_with_her_son_Giovanni.jpg new file mode 100644 index 0000000..f027633 Binary files /dev/null and b/data/images/paintings/Bronzino_Portrait_of_Eleonora_di_Toledo_with_her_son_Giovanni.jpg differ diff --git a/data/images/paintings/Bronzino_Portrait_of_a_Young_Man_with_a_Book.jpg b/data/images/paintings/Bronzino_Portrait_of_a_Young_Man_with_a_Book.jpg new file mode 100644 index 0000000..f027633 Binary files /dev/null and b/data/images/paintings/Bronzino_Portrait_of_a_Young_Man_with_a_Book.jpg differ diff --git a/data/images/paintings/Bronzino_Venus__Cupid__Folly_and_Time.jpg b/data/images/paintings/Bronzino_Venus__Cupid__Folly_and_Time.jpg new file mode 100644 index 0000000..9002b59 Binary files /dev/null and b/data/images/paintings/Bronzino_Venus__Cupid__Folly_and_Time.jpg differ diff --git a/data/images/paintings/Camille_Pissarro_Apple_Picking_at__ragny-sur-Epte.jpg b/data/images/paintings/Camille_Pissarro_Apple_Picking_at__ragny-sur-Epte.jpg new file mode 100644 index 0000000..2c2b83f Binary files /dev/null and b/data/images/paintings/Camille_Pissarro_Apple_Picking_at__ragny-sur-Epte.jpg differ diff --git a/data/images/paintings/Camille_Pissarro_Boulevard_Montmartre.jpg b/data/images/paintings/Camille_Pissarro_Boulevard_Montmartre.jpg new file mode 100644 index 0000000..ffd3fc9 Binary files /dev/null and b/data/images/paintings/Camille_Pissarro_Boulevard_Montmartre.jpg differ diff --git a/data/images/paintings/Camille_Pissarro_Lordship_Lane_Station.jpg b/data/images/paintings/Camille_Pissarro_Lordship_Lane_Station.jpg new file mode 100644 index 0000000..2c2b83f Binary files /dev/null and b/data/images/paintings/Camille_Pissarro_Lordship_Lane_Station.jpg differ diff --git a/data/images/paintings/Camille_Pissarro_The_Harvest.jpg b/data/images/paintings/Camille_Pissarro_The_Harvest.jpg new file mode 100644 index 0000000..00e42f0 Binary files /dev/null and b/data/images/paintings/Camille_Pissarro_The_Harvest.jpg differ diff --git a/data/images/paintings/Caravaggio_Bacchus.jpg b/data/images/paintings/Caravaggio_Bacchus.jpg new file mode 100644 index 0000000..903384c Binary files /dev/null and b/data/images/paintings/Caravaggio_Bacchus.jpg differ diff --git a/data/images/paintings/Caravaggio_David_with_the_Head_of_Goliath.jpg b/data/images/paintings/Caravaggio_David_with_the_Head_of_Goliath.jpg new file mode 100644 index 0000000..95c5781 Binary files /dev/null and b/data/images/paintings/Caravaggio_David_with_the_Head_of_Goliath.jpg differ diff --git a/data/images/paintings/Caravaggio_Judith_Beheading_Holofernes.jpg b/data/images/paintings/Caravaggio_Judith_Beheading_Holofernes.jpg new file mode 100644 index 0000000..6ca1205 Binary files /dev/null and b/data/images/paintings/Caravaggio_Judith_Beheading_Holofernes.jpg differ diff --git a/data/images/paintings/Caravaggio_Medusa.jpg b/data/images/paintings/Caravaggio_Medusa.jpg new file mode 100644 index 0000000..39932b1 Binary files /dev/null and b/data/images/paintings/Caravaggio_Medusa.jpg differ diff --git a/data/images/paintings/Caravaggio_The_Calling_of_Saint_Matthew.jpg b/data/images/paintings/Caravaggio_The_Calling_of_Saint_Matthew.jpg new file mode 100644 index 0000000..97f6f11 Binary files /dev/null and b/data/images/paintings/Caravaggio_The_Calling_of_Saint_Matthew.jpg differ diff --git a/data/images/paintings/Caravaggio_The_Supper_at_Emmaus.jpeg b/data/images/paintings/Caravaggio_The_Supper_at_Emmaus.jpeg new file mode 100644 index 0000000..d572085 Binary files /dev/null and b/data/images/paintings/Caravaggio_The_Supper_at_Emmaus.jpeg differ diff --git a/data/images/paintings/Cimabue_Crucifixion_of_Peter.jpg b/data/images/paintings/Cimabue_Crucifixion_of_Peter.jpg new file mode 100644 index 0000000..f182c84 Binary files /dev/null and b/data/images/paintings/Cimabue_Crucifixion_of_Peter.jpg differ diff --git a/data/images/paintings/Cimabue_Madonna_Enthroned_with_the_Child__St_Francis_and_Four_Angels.jpg b/data/images/paintings/Cimabue_Madonna_Enthroned_with_the_Child__St_Francis_and_Four_Angels.jpg new file mode 100644 index 0000000..bbb9871 Binary files /dev/null and b/data/images/paintings/Cimabue_Madonna_Enthroned_with_the_Child__St_Francis_and_Four_Angels.jpg differ diff --git a/data/images/paintings/Cimabue_Madonna_and_Child_Enthroned_with_Angels_and_Prophets___Santa_Trinit__Maest__.jpg b/data/images/paintings/Cimabue_Madonna_and_Child_Enthroned_with_Angels_and_Prophets___Santa_Trinit__Maest__.jpg new file mode 100644 index 0000000..c93c8e6 Binary files /dev/null and b/data/images/paintings/Cimabue_Madonna_and_Child_Enthroned_with_Angels_and_Prophets___Santa_Trinit__Maest__.jpg differ diff --git a/data/images/paintings/Cimabue_Martyrdom_of_Saint_Paul.jpg b/data/images/paintings/Cimabue_Martyrdom_of_Saint_Paul.jpg new file mode 100644 index 0000000..fb14ef6 Binary files /dev/null and b/data/images/paintings/Cimabue_Martyrdom_of_Saint_Paul.jpg differ diff --git a/data/images/paintings/Cimabue_Saint_Francis.jpg b/data/images/paintings/Cimabue_Saint_Francis.jpg new file mode 100644 index 0000000..d398497 Binary files /dev/null and b/data/images/paintings/Cimabue_Saint_Francis.jpg differ diff --git a/data/images/paintings/Cimabue_Santa_Trinita_Maest_.jpg b/data/images/paintings/Cimabue_Santa_Trinita_Maest_.jpg new file mode 100644 index 0000000..efd7ed7 Binary files /dev/null and b/data/images/paintings/Cimabue_Santa_Trinita_Maest_.jpg differ diff --git a/data/images/paintings/Cimabue_St_Michael_and_the_Dragon_by_Cimabue.jpg b/data/images/paintings/Cimabue_St_Michael_and_the_Dragon_by_Cimabue.jpg new file mode 100644 index 0000000..89c1cf0 Binary files /dev/null and b/data/images/paintings/Cimabue_St_Michael_and_the_Dragon_by_Cimabue.jpg differ diff --git a/data/images/paintings/Cimabue_The_Flagellation_of_Christ.jpg b/data/images/paintings/Cimabue_The_Flagellation_of_Christ.jpg new file mode 100644 index 0000000..7bafedd Binary files /dev/null and b/data/images/paintings/Cimabue_The_Flagellation_of_Christ.jpg differ diff --git a/data/images/paintings/Cimabue_The_Virgin_and_Child_with_Two_Angels.jpg b/data/images/paintings/Cimabue_The_Virgin_and_Child_with_Two_Angels.jpg new file mode 100644 index 0000000..11dfef2 Binary files /dev/null and b/data/images/paintings/Cimabue_The_Virgin_and_Child_with_Two_Angels.jpg differ diff --git a/data/images/paintings/Cimabue_Vision_of_Angels_at_the_Four_Corners_of_the_Earth.jpg b/data/images/paintings/Cimabue_Vision_of_Angels_at_the_Four_Corners_of_the_Earth.jpg new file mode 100644 index 0000000..22fb1a1 Binary files /dev/null and b/data/images/paintings/Cimabue_Vision_of_Angels_at_the_Four_Corners_of_the_Earth.jpg differ diff --git a/data/images/paintings/Cimabue_Vision_of_Saint_John_at_Patmos.jpg b/data/images/paintings/Cimabue_Vision_of_Saint_John_at_Patmos.jpg new file mode 100644 index 0000000..22fb1a1 Binary files /dev/null and b/data/images/paintings/Cimabue_Vision_of_Saint_John_at_Patmos.jpg differ diff --git a/data/images/paintings/Cimabue_Vision_of_the_Throne.jpg b/data/images/paintings/Cimabue_Vision_of_the_Throne.jpg new file mode 100644 index 0000000..98f49fb Binary files /dev/null and b/data/images/paintings/Cimabue_Vision_of_the_Throne.jpg differ diff --git a/data/images/paintings/Domenico_Ghirlandaio_Archangel_Saint_Michael_and_the_Angels_at_War_with_the_Devil.jpg b/data/images/paintings/Domenico_Ghirlandaio_Archangel_Saint_Michael_and_the_Angels_at_War_with_the_Devil.jpg new file mode 100644 index 0000000..984a2d4 Binary files /dev/null and b/data/images/paintings/Domenico_Ghirlandaio_Archangel_Saint_Michael_and_the_Angels_at_War_with_the_Devil.jpg differ diff --git a/data/images/paintings/Domenico_Ghirlandaio_Madonna_and_Child.jpg b/data/images/paintings/Domenico_Ghirlandaio_Madonna_and_Child.jpg new file mode 100644 index 0000000..9fa6342 Binary files /dev/null and b/data/images/paintings/Domenico_Ghirlandaio_Madonna_and_Child.jpg differ diff --git a/data/images/paintings/Domenico_Ghirlandaio_Portrait_of_a_Man.jpg b/data/images/paintings/Domenico_Ghirlandaio_Portrait_of_a_Man.jpg new file mode 100644 index 0000000..463fc0d Binary files /dev/null and b/data/images/paintings/Domenico_Ghirlandaio_Portrait_of_a_Man.jpg differ diff --git a/data/images/paintings/Domenico_Ghirlandaio_The_Nativity.jpg b/data/images/paintings/Domenico_Ghirlandaio_The_Nativity.jpg new file mode 100644 index 0000000..187e17f Binary files /dev/null and b/data/images/paintings/Domenico_Ghirlandaio_The_Nativity.jpg differ diff --git a/data/images/paintings/Duccio_Christ_Washes_the_Apostles__Feet__top___Last_Supper__bottom_.jpg b/data/images/paintings/Duccio_Christ_Washes_the_Apostles__Feet__top___Last_Supper__bottom_.jpg new file mode 100644 index 0000000..487ca2e Binary files /dev/null and b/data/images/paintings/Duccio_Christ_Washes_the_Apostles__Feet__top___Last_Supper__bottom_.jpg differ diff --git a/data/images/paintings/Fra_Angelico_Madonna_and_Child_with_Four__ngels.jpg b/data/images/paintings/Fra_Angelico_Madonna_and_Child_with_Four__ngels.jpg new file mode 100644 index 0000000..e5f6228 Binary files /dev/null and b/data/images/paintings/Fra_Angelico_Madonna_and_Child_with_Four__ngels.jpg differ diff --git a/data/images/paintings/Fra_Angelico_The_Crucifixion.jpg b/data/images/paintings/Fra_Angelico_The_Crucifixion.jpg new file mode 100644 index 0000000..a27de8a Binary files /dev/null and b/data/images/paintings/Fra_Angelico_The_Crucifixion.jpg differ diff --git a/data/images/paintings/Francisco_Goya_Portrait_of_the_Duke_of_Wellington.jpg b/data/images/paintings/Francisco_Goya_Portrait_of_the_Duke_of_Wellington.jpg new file mode 100644 index 0000000..1b17033 Binary files /dev/null and b/data/images/paintings/Francisco_Goya_Portrait_of_the_Duke_of_Wellington.jpg differ diff --git a/data/images/paintings/Francisco_Goya_Witches__Sabbath.jpg b/data/images/paintings/Francisco_Goya_Witches__Sabbath.jpg new file mode 100644 index 0000000..43ff07e Binary files /dev/null and b/data/images/paintings/Francisco_Goya_Witches__Sabbath.jpg differ diff --git a/data/images/paintings/Georges_Seurat_The_Circus.jpg b/data/images/paintings/Georges_Seurat_The_Circus.jpg new file mode 100644 index 0000000..38cc460 Binary files /dev/null and b/data/images/paintings/Georges_Seurat_The_Circus.jpg differ diff --git a/data/images/paintings/Giacomo_Balla_Street_Light.jpg b/data/images/paintings/Giacomo_Balla_Street_Light.jpg new file mode 100644 index 0000000..b7c608a Binary files /dev/null and b/data/images/paintings/Giacomo_Balla_Street_Light.jpg differ diff --git a/data/images/paintings/Giotto_Confirmation_of_the_Rule.jpg b/data/images/paintings/Giotto_Confirmation_of_the_Rule.jpg new file mode 100644 index 0000000..fedfa35 Binary files /dev/null and b/data/images/paintings/Giotto_Confirmation_of_the_Rule.jpg differ diff --git a/data/images/paintings/Giotto_Institution_of_the_Crib_at_Greccio.jpg b/data/images/paintings/Giotto_Institution_of_the_Crib_at_Greccio.jpg new file mode 100644 index 0000000..fedfa35 Binary files /dev/null and b/data/images/paintings/Giotto_Institution_of_the_Crib_at_Greccio.jpg differ diff --git a/data/images/paintings/Hieronymus_Bosch_Battle_of_the_Birds_and_Mammals.jpg b/data/images/paintings/Hieronymus_Bosch_Battle_of_the_Birds_and_Mammals.jpg new file mode 100644 index 0000000..43231f8 Binary files /dev/null and b/data/images/paintings/Hieronymus_Bosch_Battle_of_the_Birds_and_Mammals.jpg differ diff --git a/data/images/paintings/Hieronymus_Bosch_Head_of_a_Halberdier.jpg b/data/images/paintings/Hieronymus_Bosch_Head_of_a_Halberdier.jpg new file mode 100644 index 0000000..ea5a023 Binary files /dev/null and b/data/images/paintings/Hieronymus_Bosch_Head_of_a_Halberdier.jpg differ diff --git a/data/images/paintings/Ivan_Klyun_Dynamic_Color_Composition.jpg b/data/images/paintings/Ivan_Klyun_Dynamic_Color_Composition.jpg new file mode 100644 index 0000000..e28ed7c Binary files /dev/null and b/data/images/paintings/Ivan_Klyun_Dynamic_Color_Composition.jpg differ diff --git a/data/images/paintings/Jackson_Pollock_Number_1__1950__Lavender_Mist_.jpg b/data/images/paintings/Jackson_Pollock_Number_1__1950__Lavender_Mist_.jpg new file mode 100644 index 0000000..49f30c8 Binary files /dev/null and b/data/images/paintings/Jackson_Pollock_Number_1__1950__Lavender_Mist_.jpg differ diff --git a/data/images/paintings/Jan_van_Eyck_Adam.jpg b/data/images/paintings/Jan_van_Eyck_Adam.jpg new file mode 100644 index 0000000..fa9e7b9 Binary files /dev/null and b/data/images/paintings/Jan_van_Eyck_Adam.jpg differ diff --git a/data/images/paintings/Jan_van_Eyck_Birth_of_John_the_Baptist.jpg b/data/images/paintings/Jan_van_Eyck_Birth_of_John_the_Baptist.jpg new file mode 100644 index 0000000..8b5f84a Binary files /dev/null and b/data/images/paintings/Jan_van_Eyck_Birth_of_John_the_Baptist.jpg differ diff --git a/data/images/paintings/Jan_van_Eyck_Portrait_of_Isabella_of_Portugal.jpg b/data/images/paintings/Jan_van_Eyck_Portrait_of_Isabella_of_Portugal.jpg new file mode 100644 index 0000000..84bd9bd Binary files /dev/null and b/data/images/paintings/Jan_van_Eyck_Portrait_of_Isabella_of_Portugal.jpg differ diff --git a/data/images/paintings/Jan_van_Eyck_Saint_Jerome_in_His_Study.jpg b/data/images/paintings/Jan_van_Eyck_Saint_Jerome_in_His_Study.jpg new file mode 100644 index 0000000..dd7127f Binary files /dev/null and b/data/images/paintings/Jan_van_Eyck_Saint_Jerome_in_His_Study.jpg differ diff --git a/data/images/paintings/Kazimir_Malevich_Suprematist_Composition.jpg b/data/images/paintings/Kazimir_Malevich_Suprematist_Composition.jpg new file mode 100644 index 0000000..2e1a7de Binary files /dev/null and b/data/images/paintings/Kazimir_Malevich_Suprematist_Composition.jpg differ diff --git a/data/images/paintings/Leonardo_da_Vinci_Allegory_of_Fame_attacking_Envy.jpg b/data/images/paintings/Leonardo_da_Vinci_Allegory_of_Fame_attacking_Envy.jpg new file mode 100644 index 0000000..80c1c4f Binary files /dev/null and b/data/images/paintings/Leonardo_da_Vinci_Allegory_of_Fame_attacking_Envy.jpg differ diff --git a/data/images/paintings/Leonardo_da_Vinci_Anatomical_Studies_of_the_Facial_Nerves.jpg b/data/images/paintings/Leonardo_da_Vinci_Anatomical_Studies_of_the_Facial_Nerves.jpg new file mode 100644 index 0000000..80c1c4f Binary files /dev/null and b/data/images/paintings/Leonardo_da_Vinci_Anatomical_Studies_of_the_Facial_Nerves.jpg differ diff --git a/data/images/paintings/Marcel_Duchamp_The_Bride_Stripped_Bare_by_Her_Bachelors__Even.jpg b/data/images/paintings/Marcel_Duchamp_The_Bride_Stripped_Bare_by_Her_Bachelors__Even.jpg new file mode 100644 index 0000000..4d8e8b6 Binary files /dev/null and b/data/images/paintings/Marcel_Duchamp_The_Bride_Stripped_Bare_by_Her_Bachelors__Even.jpg differ diff --git a/data/images/paintings/Masaccio_The_agony_of_Christ_in_the_garden_of_Gethsemane__St__Jerome_as_penitent.jpg b/data/images/paintings/Masaccio_The_agony_of_Christ_in_the_garden_of_Gethsemane__St__Jerome_as_penitent.jpg new file mode 100644 index 0000000..bca8bf4 Binary files /dev/null and b/data/images/paintings/Masaccio_The_agony_of_Christ_in_the_garden_of_Gethsemane__St__Jerome_as_penitent.jpg differ diff --git a/data/images/paintings/Michelangelo_Manchester_Madonna.JPG b/data/images/paintings/Michelangelo_Manchester_Madonna.JPG new file mode 100644 index 0000000..e2f3dd0 Binary files /dev/null and b/data/images/paintings/Michelangelo_Manchester_Madonna.JPG differ diff --git a/data/images/paintings/Paul_Gauguin_Vision_After_the_Sermon.jpg b/data/images/paintings/Paul_Gauguin_Vision_After_the_Sermon.jpg new file mode 100644 index 0000000..0d5c991 Binary files /dev/null and b/data/images/paintings/Paul_Gauguin_Vision_After_the_Sermon.jpg differ diff --git a/data/images/paintings/Peter_Paul_Rubens_Massacre_of_the_Innocents.JPG b/data/images/paintings/Peter_Paul_Rubens_Massacre_of_the_Innocents.JPG new file mode 100644 index 0000000..fdb87c2 Binary files /dev/null and b/data/images/paintings/Peter_Paul_Rubens_Massacre_of_the_Innocents.JPG differ diff --git a/data/images/paintings/Peter_Paul_Rubens_The_Descent_from_the_Cross.jpg b/data/images/paintings/Peter_Paul_Rubens_The_Descent_from_the_Cross.jpg new file mode 100644 index 0000000..b02b386 Binary files /dev/null and b/data/images/paintings/Peter_Paul_Rubens_The_Descent_from_the_Cross.jpg differ diff --git a/data/images/paintings/Peter_Paul_Rubens_The_Raising_of_the_Cross.jpg b/data/images/paintings/Peter_Paul_Rubens_The_Raising_of_the_Cross.jpg new file mode 100644 index 0000000..b02b386 Binary files /dev/null and b/data/images/paintings/Peter_Paul_Rubens_The_Raising_of_the_Cross.jpg differ diff --git a/data/images/paintings/Sandro_Botticelli_Annunciation_to_Mary.jpg b/data/images/paintings/Sandro_Botticelli_Annunciation_to_Mary.jpg new file mode 100644 index 0000000..4110a4d Binary files /dev/null and b/data/images/paintings/Sandro_Botticelli_Annunciation_to_Mary.jpg differ diff --git a/data/images/paintings/Sandro_Botticelli_Birth_of_Christ.jpg b/data/images/paintings/Sandro_Botticelli_Birth_of_Christ.jpg new file mode 100644 index 0000000..4110a4d Binary files /dev/null and b/data/images/paintings/Sandro_Botticelli_Birth_of_Christ.jpg differ diff --git a/data/images/paintings/Sandro_Botticelli_Portrait_of_a_Young_Man.jpg b/data/images/paintings/Sandro_Botticelli_Portrait_of_a_Young_Man.jpg new file mode 100644 index 0000000..463fc0d Binary files /dev/null and b/data/images/paintings/Sandro_Botticelli_Portrait_of_a_Young_Man.jpg differ diff --git a/data/images/paintings/Sandro_Botticelli_St_Jerome.jpg b/data/images/paintings/Sandro_Botticelli_St_Jerome.jpg new file mode 100644 index 0000000..4110a4d Binary files /dev/null and b/data/images/paintings/Sandro_Botticelli_St_Jerome.jpg differ diff --git a/data/images/paintings/Simone_Martini_A_Saint_Holding_a_Book.jpg b/data/images/paintings/Simone_Martini_A_Saint_Holding_a_Book.jpg new file mode 100644 index 0000000..96edd3e Binary files /dev/null and b/data/images/paintings/Simone_Martini_A_Saint_Holding_a_Book.jpg differ diff --git a/data/images/paintings/Titian_Jacopo_Pesaro__Bishop_of_Paphos__being_presented_by_Pope_Alexander_VI_to_Saint_Peter.jpg b/data/images/paintings/Titian_Jacopo_Pesaro__Bishop_of_Paphos__being_presented_by_Pope_Alexander_VI_to_Saint_Peter.jpg new file mode 100644 index 0000000..e774f24 Binary files /dev/null and b/data/images/paintings/Titian_Jacopo_Pesaro__Bishop_of_Paphos__being_presented_by_Pope_Alexander_VI_to_Saint_Peter.jpg differ diff --git a/data/images/paintings/thumbs/Alexander_Rodchenko_Girl_with_a_Leica_thumb.jpg b/data/images/paintings/thumbs/Alexander_Rodchenko_Girl_with_a_Leica_thumb.jpg new file mode 100644 index 0000000..98057e8 Binary files /dev/null and b/data/images/paintings/thumbs/Alexander_Rodchenko_Girl_with_a_Leica_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Andy_Warhol_Brillo_Box_thumb.jpg b/data/images/paintings/thumbs/Andy_Warhol_Brillo_Box_thumb.jpg new file mode 100644 index 0000000..9618419 Binary files /dev/null and b/data/images/paintings/thumbs/Andy_Warhol_Brillo_Box_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Andy_Warhol_Green_Coca-Cola_Bottles_thumb.jpg b/data/images/paintings/thumbs/Andy_Warhol_Green_Coca-Cola_Bottles_thumb.jpg new file mode 100644 index 0000000..9618419 Binary files /dev/null and b/data/images/paintings/thumbs/Andy_Warhol_Green_Coca-Cola_Bottles_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Andy_Warhol_Shot_Sage_Blue_Marilyn_thumb.jpg b/data/images/paintings/thumbs/Andy_Warhol_Shot_Sage_Blue_Marilyn_thumb.jpg new file mode 100644 index 0000000..9618419 Binary files /dev/null and b/data/images/paintings/thumbs/Andy_Warhol_Shot_Sage_Blue_Marilyn_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Angelica_Kauffman_Cornelia__Mother_of_the_Gracchi_thumb.jpg b/data/images/paintings/thumbs/Angelica_Kauffman_Cornelia__Mother_of_the_Gracchi_thumb.jpg new file mode 100644 index 0000000..8cee0a4 Binary files /dev/null and b/data/images/paintings/thumbs/Angelica_Kauffman_Cornelia__Mother_of_the_Gracchi_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Angelica_Kauffman_Portrait_of_Johann_Joachim_Winckelmann_thumb.jpg b/data/images/paintings/thumbs/Angelica_Kauffman_Portrait_of_Johann_Joachim_Winckelmann_thumb.jpg new file mode 100644 index 0000000..9e36626 Binary files /dev/null and b/data/images/paintings/thumbs/Angelica_Kauffman_Portrait_of_Johann_Joachim_Winckelmann_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Angelica_Kauffman_Rinaldo_and_Armida_thumb.jpg b/data/images/paintings/thumbs/Angelica_Kauffman_Rinaldo_and_Armida_thumb.jpg new file mode 100644 index 0000000..59bbdd2 Binary files /dev/null and b/data/images/paintings/thumbs/Angelica_Kauffman_Rinaldo_and_Armida_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Angelica_Kauffman_Self-Portrait_of_the_Artist_Hesitating_Between_the_Arts_of_Music_and_Painting_thumb.jpg b/data/images/paintings/thumbs/Angelica_Kauffman_Self-Portrait_of_the_Artist_Hesitating_Between_the_Arts_of_Music_and_Painting_thumb.jpg new file mode 100644 index 0000000..d2f1993 Binary files /dev/null and b/data/images/paintings/thumbs/Angelica_Kauffman_Self-Portrait_of_the_Artist_Hesitating_Between_the_Arts_of_Music_and_Painting_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Angelica_Kauffman_Venus_Induces_Helen_to_Fall_in_Love_with_Paris_thumb.jpg b/data/images/paintings/thumbs/Angelica_Kauffman_Venus_Induces_Helen_to_Fall_in_Love_with_Paris_thumb.jpg new file mode 100644 index 0000000..8d97609 Binary files /dev/null and b/data/images/paintings/thumbs/Angelica_Kauffman_Venus_Induces_Helen_to_Fall_in_Love_with_Paris_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Apelles_Alexander_the_Great_Holding_a_Thunderbolt_thumb.jpg b/data/images/paintings/thumbs/Apelles_Alexander_the_Great_Holding_a_Thunderbolt_thumb.jpg new file mode 100644 index 0000000..44c7bd0 Binary files /dev/null and b/data/images/paintings/thumbs/Apelles_Alexander_the_Great_Holding_a_Thunderbolt_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Apelles_Aphrodite_Anadyomene_thumb.jpg b/data/images/paintings/thumbs/Apelles_Aphrodite_Anadyomene_thumb.jpg new file mode 100644 index 0000000..44c7bd0 Binary files /dev/null and b/data/images/paintings/thumbs/Apelles_Aphrodite_Anadyomene_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Apelles_Calumny_of_Apelles_thumb.jpg b/data/images/paintings/thumbs/Apelles_Calumny_of_Apelles_thumb.jpg new file mode 100644 index 0000000..8c78d8c Binary files /dev/null and b/data/images/paintings/thumbs/Apelles_Calumny_of_Apelles_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Apelles_Campaspe_thumb.jpg b/data/images/paintings/thumbs/Apelles_Campaspe_thumb.jpg new file mode 100644 index 0000000..44c7bd0 Binary files /dev/null and b/data/images/paintings/thumbs/Apelles_Campaspe_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Apelles_Portrait_of_Alexander_thumb.jpg b/data/images/paintings/thumbs/Apelles_Portrait_of_Alexander_thumb.jpg new file mode 100644 index 0000000..44c7bd0 Binary files /dev/null and b/data/images/paintings/thumbs/Apelles_Portrait_of_Alexander_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Apelles_Venus_Anadyomene_thumb.jpg b/data/images/paintings/thumbs/Apelles_Venus_Anadyomene_thumb.jpg new file mode 100644 index 0000000..a3555ee Binary files /dev/null and b/data/images/paintings/thumbs/Apelles_Venus_Anadyomene_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Artemisia_Gentileschi_Esther_before_Ahasuerus_thumb.jpg b/data/images/paintings/thumbs/Artemisia_Gentileschi_Esther_before_Ahasuerus_thumb.jpg new file mode 100644 index 0000000..0862886 Binary files /dev/null and b/data/images/paintings/thumbs/Artemisia_Gentileschi_Esther_before_Ahasuerus_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Artemisia_Gentileschi_Judith_Slaying_Holofernes_thumb.jpg b/data/images/paintings/thumbs/Artemisia_Gentileschi_Judith_Slaying_Holofernes_thumb.jpg new file mode 100644 index 0000000..3dc3ecf Binary files /dev/null and b/data/images/paintings/thumbs/Artemisia_Gentileschi_Judith_Slaying_Holofernes_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Artemisia_Gentileschi_Judith_and_Her_Maidservant_thumb.jpg b/data/images/paintings/thumbs/Artemisia_Gentileschi_Judith_and_Her_Maidservant_thumb.jpg new file mode 100644 index 0000000..4edbca9 Binary files /dev/null and b/data/images/paintings/thumbs/Artemisia_Gentileschi_Judith_and_Her_Maidservant_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Artemisia_Gentileschi_Mary_Magdalene_thumb.jpg b/data/images/paintings/thumbs/Artemisia_Gentileschi_Mary_Magdalene_thumb.jpg new file mode 100644 index 0000000..0689b19 Binary files /dev/null and b/data/images/paintings/thumbs/Artemisia_Gentileschi_Mary_Magdalene_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Artemisia_Gentileschi_Self-Portrait_as_the_Allegory_of_Painting_thumb.jpg b/data/images/paintings/thumbs/Artemisia_Gentileschi_Self-Portrait_as_the_Allegory_of_Painting_thumb.jpg new file mode 100644 index 0000000..d7621ec Binary files /dev/null and b/data/images/paintings/thumbs/Artemisia_Gentileschi_Self-Portrait_as_the_Allegory_of_Painting_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Artemisia_Gentileschi_Susanna_and_the_Elders_thumb.jpg b/data/images/paintings/thumbs/Artemisia_Gentileschi_Susanna_and_the_Elders_thumb.jpg new file mode 100644 index 0000000..1971197 Binary files /dev/null and b/data/images/paintings/thumbs/Artemisia_Gentileschi_Susanna_and_the_Elders_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Aubrey_Beardsley_J_ai_bais__ta_bouche_thumb.jpg b/data/images/paintings/thumbs/Aubrey_Beardsley_J_ai_bais__ta_bouche_thumb.jpg new file mode 100644 index 0000000..20cb0a6 Binary files /dev/null and b/data/images/paintings/thumbs/Aubrey_Beardsley_J_ai_bais__ta_bouche_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Aubrey_Beardsley_The_Black_Cape_thumb.jpg b/data/images/paintings/thumbs/Aubrey_Beardsley_The_Black_Cape_thumb.jpg new file mode 100644 index 0000000..b91d755 Binary files /dev/null and b/data/images/paintings/thumbs/Aubrey_Beardsley_The_Black_Cape_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Aubrey_Beardsley_The_Dancer_s_Reward_thumb.jpg b/data/images/paintings/thumbs/Aubrey_Beardsley_The_Dancer_s_Reward_thumb.jpg new file mode 100644 index 0000000..20cb0a6 Binary files /dev/null and b/data/images/paintings/thumbs/Aubrey_Beardsley_The_Dancer_s_Reward_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Aubrey_Beardsley_The_Peacock_Skirt_thumb.jpg b/data/images/paintings/thumbs/Aubrey_Beardsley_The_Peacock_Skirt_thumb.jpg new file mode 100644 index 0000000..bef6a1e Binary files /dev/null and b/data/images/paintings/thumbs/Aubrey_Beardsley_The_Peacock_Skirt_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Aubrey_Beardsley_The_Rape_of_the_Lock_thumb.jpg b/data/images/paintings/thumbs/Aubrey_Beardsley_The_Rape_of_the_Lock_thumb.jpg new file mode 100644 index 0000000..20cb0a6 Binary files /dev/null and b/data/images/paintings/thumbs/Aubrey_Beardsley_The_Rape_of_the_Lock_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Aubrey_Beardsley_The_Yellow_Book_thumb.jpg b/data/images/paintings/thumbs/Aubrey_Beardsley_The_Yellow_Book_thumb.jpg new file mode 100644 index 0000000..77527ef Binary files /dev/null and b/data/images/paintings/thumbs/Aubrey_Beardsley_The_Yellow_Book_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Bronzino_An_Allegory_with_Venus_and_Cupid_thumb.jpg b/data/images/paintings/thumbs/Bronzino_An_Allegory_with_Venus_and_Cupid_thumb.jpg new file mode 100644 index 0000000..a766c14 Binary files /dev/null and b/data/images/paintings/thumbs/Bronzino_An_Allegory_with_Venus_and_Cupid_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Bronzino_Holy_Family_with_St__Anne_and_the_Infant_St__John_thumb.jpg b/data/images/paintings/thumbs/Bronzino_Holy_Family_with_St__Anne_and_the_Infant_St__John_thumb.jpg new file mode 100644 index 0000000..22b1cf0 Binary files /dev/null and b/data/images/paintings/thumbs/Bronzino_Holy_Family_with_St__Anne_and_the_Infant_St__John_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Bronzino_Portrait_of_Cosimo_I_de__Medici_in_Armour_thumb.jpg b/data/images/paintings/thumbs/Bronzino_Portrait_of_Cosimo_I_de__Medici_in_Armour_thumb.jpg new file mode 100644 index 0000000..f185675 Binary files /dev/null and b/data/images/paintings/thumbs/Bronzino_Portrait_of_Cosimo_I_de__Medici_in_Armour_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Bronzino_Portrait_of_Eleonora_di_Toledo_with_her_son_Giovanni_thumb.jpg b/data/images/paintings/thumbs/Bronzino_Portrait_of_Eleonora_di_Toledo_with_her_son_Giovanni_thumb.jpg new file mode 100644 index 0000000..f185675 Binary files /dev/null and b/data/images/paintings/thumbs/Bronzino_Portrait_of_Eleonora_di_Toledo_with_her_son_Giovanni_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Bronzino_Portrait_of_a_Young_Man_with_a_Book_thumb.jpg b/data/images/paintings/thumbs/Bronzino_Portrait_of_a_Young_Man_with_a_Book_thumb.jpg new file mode 100644 index 0000000..f185675 Binary files /dev/null and b/data/images/paintings/thumbs/Bronzino_Portrait_of_a_Young_Man_with_a_Book_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Bronzino_Venus__Cupid__Folly_and_Time_thumb.jpg b/data/images/paintings/thumbs/Bronzino_Venus__Cupid__Folly_and_Time_thumb.jpg new file mode 100644 index 0000000..6ce9d7d Binary files /dev/null and b/data/images/paintings/thumbs/Bronzino_Venus__Cupid__Folly_and_Time_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Camille_Pissarro_Apple_Picking_at__ragny-sur-Epte_thumb.jpg b/data/images/paintings/thumbs/Camille_Pissarro_Apple_Picking_at__ragny-sur-Epte_thumb.jpg new file mode 100644 index 0000000..8f2ff2a Binary files /dev/null and b/data/images/paintings/thumbs/Camille_Pissarro_Apple_Picking_at__ragny-sur-Epte_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Camille_Pissarro_Boulevard_Montmartre_thumb.jpg b/data/images/paintings/thumbs/Camille_Pissarro_Boulevard_Montmartre_thumb.jpg new file mode 100644 index 0000000..89a4950 Binary files /dev/null and b/data/images/paintings/thumbs/Camille_Pissarro_Boulevard_Montmartre_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Camille_Pissarro_Jalais_Hill__Pontoise_thumb.jpg b/data/images/paintings/thumbs/Camille_Pissarro_Jalais_Hill__Pontoise_thumb.jpg index 6de438d..b2e42e6 100644 Binary files a/data/images/paintings/thumbs/Camille_Pissarro_Jalais_Hill__Pontoise_thumb.jpg and b/data/images/paintings/thumbs/Camille_Pissarro_Jalais_Hill__Pontoise_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Camille_Pissarro_Lordship_Lane_Station_thumb.jpg b/data/images/paintings/thumbs/Camille_Pissarro_Lordship_Lane_Station_thumb.jpg new file mode 100644 index 0000000..8f2ff2a Binary files /dev/null and b/data/images/paintings/thumbs/Camille_Pissarro_Lordship_Lane_Station_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Camille_Pissarro_Red_Roofs_thumb.jpg b/data/images/paintings/thumbs/Camille_Pissarro_Red_Roofs_thumb.jpg index 6129fba..8f2ff2a 100644 Binary files a/data/images/paintings/thumbs/Camille_Pissarro_Red_Roofs_thumb.jpg and b/data/images/paintings/thumbs/Camille_Pissarro_Red_Roofs_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Camille_Pissarro_The_Harvest_thumb.jpg b/data/images/paintings/thumbs/Camille_Pissarro_The_Harvest_thumb.jpg new file mode 100644 index 0000000..0b0474b Binary files /dev/null and b/data/images/paintings/thumbs/Camille_Pissarro_The_Harvest_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Caravaggio_Bacchus_thumb.jpg b/data/images/paintings/thumbs/Caravaggio_Bacchus_thumb.jpg new file mode 100644 index 0000000..0df652c Binary files /dev/null and b/data/images/paintings/thumbs/Caravaggio_Bacchus_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Caravaggio_David_with_the_Head_of_Goliath_thumb.jpg b/data/images/paintings/thumbs/Caravaggio_David_with_the_Head_of_Goliath_thumb.jpg new file mode 100644 index 0000000..4465907 Binary files /dev/null and b/data/images/paintings/thumbs/Caravaggio_David_with_the_Head_of_Goliath_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Caravaggio_Judith_Beheading_Holofernes_thumb.jpg b/data/images/paintings/thumbs/Caravaggio_Judith_Beheading_Holofernes_thumb.jpg new file mode 100644 index 0000000..8caf7e0 Binary files /dev/null and b/data/images/paintings/thumbs/Caravaggio_Judith_Beheading_Holofernes_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Caravaggio_Medusa_thumb.jpg b/data/images/paintings/thumbs/Caravaggio_Medusa_thumb.jpg new file mode 100644 index 0000000..ab6048a Binary files /dev/null and b/data/images/paintings/thumbs/Caravaggio_Medusa_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Caravaggio_The_Calling_of_Saint_Matthew_thumb.jpg b/data/images/paintings/thumbs/Caravaggio_The_Calling_of_Saint_Matthew_thumb.jpg new file mode 100644 index 0000000..43f9074 Binary files /dev/null and b/data/images/paintings/thumbs/Caravaggio_The_Calling_of_Saint_Matthew_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Caravaggio_The_Supper_at_Emmaus_thumb.jpg b/data/images/paintings/thumbs/Caravaggio_The_Supper_at_Emmaus_thumb.jpg new file mode 100644 index 0000000..a6c3072 Binary files /dev/null and b/data/images/paintings/thumbs/Caravaggio_The_Supper_at_Emmaus_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Cimabue_Crucifix_by_Cimabue__San_Domenico__Arezzo__thumb.jpg b/data/images/paintings/thumbs/Cimabue_Crucifix_by_Cimabue__San_Domenico__Arezzo__thumb.jpg new file mode 100644 index 0000000..06fa82a Binary files /dev/null and b/data/images/paintings/thumbs/Cimabue_Crucifix_by_Cimabue__San_Domenico__Arezzo__thumb.jpg differ diff --git a/data/images/paintings/thumbs/Cimabue_Crucifix_by_Cimabue__Santa_Croce_thumb.jpg b/data/images/paintings/thumbs/Cimabue_Crucifix_by_Cimabue__Santa_Croce_thumb.jpg new file mode 100644 index 0000000..06fa82a Binary files /dev/null and b/data/images/paintings/thumbs/Cimabue_Crucifix_by_Cimabue__Santa_Croce_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Cimabue_Crucifixion_of_Peter_thumb.jpg b/data/images/paintings/thumbs/Cimabue_Crucifixion_of_Peter_thumb.jpg new file mode 100644 index 0000000..4e9a236 Binary files /dev/null and b/data/images/paintings/thumbs/Cimabue_Crucifixion_of_Peter_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Cimabue_Madonna_Enthroned_with_the_Child__St_Francis_and_Four_Angels_thumb.jpg b/data/images/paintings/thumbs/Cimabue_Madonna_Enthroned_with_the_Child__St_Francis_and_Four_Angels_thumb.jpg new file mode 100644 index 0000000..ab10dd8 Binary files /dev/null and b/data/images/paintings/thumbs/Cimabue_Madonna_Enthroned_with_the_Child__St_Francis_and_Four_Angels_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Cimabue_Madonna_and_Child_Enthroned_with_Angels_and_Prophets___Santa_Trinit__Maest___thumb.jpg b/data/images/paintings/thumbs/Cimabue_Madonna_and_Child_Enthroned_with_Angels_and_Prophets___Santa_Trinit__Maest___thumb.jpg new file mode 100644 index 0000000..0b8a41f Binary files /dev/null and b/data/images/paintings/thumbs/Cimabue_Madonna_and_Child_Enthroned_with_Angels_and_Prophets___Santa_Trinit__Maest___thumb.jpg differ diff --git a/data/images/paintings/thumbs/Cimabue_Martyrdom_of_Saint_Paul_thumb.jpg b/data/images/paintings/thumbs/Cimabue_Martyrdom_of_Saint_Paul_thumb.jpg new file mode 100644 index 0000000..1936228 Binary files /dev/null and b/data/images/paintings/thumbs/Cimabue_Martyrdom_of_Saint_Paul_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Cimabue_Saint_Francis_thumb.jpg b/data/images/paintings/thumbs/Cimabue_Saint_Francis_thumb.jpg new file mode 100644 index 0000000..7ae1393 Binary files /dev/null and b/data/images/paintings/thumbs/Cimabue_Saint_Francis_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Cimabue_Santa_Trinita_Maest__thumb.jpg b/data/images/paintings/thumbs/Cimabue_Santa_Trinita_Maest__thumb.jpg new file mode 100644 index 0000000..00772ce Binary files /dev/null and b/data/images/paintings/thumbs/Cimabue_Santa_Trinita_Maest__thumb.jpg differ diff --git a/data/images/paintings/thumbs/Cimabue_St_Michael_and_the_Dragon_by_Cimabue_thumb.jpg b/data/images/paintings/thumbs/Cimabue_St_Michael_and_the_Dragon_by_Cimabue_thumb.jpg new file mode 100644 index 0000000..83b3852 Binary files /dev/null and b/data/images/paintings/thumbs/Cimabue_St_Michael_and_the_Dragon_by_Cimabue_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Cimabue_The_Flagellation_of_Christ_thumb.jpg b/data/images/paintings/thumbs/Cimabue_The_Flagellation_of_Christ_thumb.jpg new file mode 100644 index 0000000..277fafb Binary files /dev/null and b/data/images/paintings/thumbs/Cimabue_The_Flagellation_of_Christ_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Cimabue_The_Mocking_of_Christ_thumb.jpg b/data/images/paintings/thumbs/Cimabue_The_Mocking_of_Christ_thumb.jpg new file mode 100644 index 0000000..0f94203 Binary files /dev/null and b/data/images/paintings/thumbs/Cimabue_The_Mocking_of_Christ_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Cimabue_The_Virgin_and_Child_with_Two_Angels_thumb.jpg b/data/images/paintings/thumbs/Cimabue_The_Virgin_and_Child_with_Two_Angels_thumb.jpg new file mode 100644 index 0000000..a98934a Binary files /dev/null and b/data/images/paintings/thumbs/Cimabue_The_Virgin_and_Child_with_Two_Angels_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Cimabue_Vision_of_Angels_at_the_Four_Corners_of_the_Earth_thumb.jpg b/data/images/paintings/thumbs/Cimabue_Vision_of_Angels_at_the_Four_Corners_of_the_Earth_thumb.jpg new file mode 100644 index 0000000..88bbceb Binary files /dev/null and b/data/images/paintings/thumbs/Cimabue_Vision_of_Angels_at_the_Four_Corners_of_the_Earth_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Cimabue_Vision_of_Saint_John_at_Patmos_thumb.jpg b/data/images/paintings/thumbs/Cimabue_Vision_of_Saint_John_at_Patmos_thumb.jpg new file mode 100644 index 0000000..88bbceb Binary files /dev/null and b/data/images/paintings/thumbs/Cimabue_Vision_of_Saint_John_at_Patmos_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Cimabue_Vision_of_the_Throne_thumb.jpg b/data/images/paintings/thumbs/Cimabue_Vision_of_the_Throne_thumb.jpg new file mode 100644 index 0000000..b2d2a63 Binary files /dev/null and b/data/images/paintings/thumbs/Cimabue_Vision_of_the_Throne_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Domenico_Ghirlandaio_Madonna_and_Child_thumb.jpg b/data/images/paintings/thumbs/Domenico_Ghirlandaio_Madonna_and_Child_thumb.jpg new file mode 100644 index 0000000..d3ae017 Binary files /dev/null and b/data/images/paintings/thumbs/Domenico_Ghirlandaio_Madonna_and_Child_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Domenico_Ghirlandaio_Portrait_of_a_Man_thumb.jpg b/data/images/paintings/thumbs/Domenico_Ghirlandaio_Portrait_of_a_Man_thumb.jpg new file mode 100644 index 0000000..719af23 Binary files /dev/null and b/data/images/paintings/thumbs/Domenico_Ghirlandaio_Portrait_of_a_Man_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Domenico_Ghirlandaio_The_Nativity_thumb.jpg b/data/images/paintings/thumbs/Domenico_Ghirlandaio_The_Nativity_thumb.jpg new file mode 100644 index 0000000..c7555f7 Binary files /dev/null and b/data/images/paintings/thumbs/Domenico_Ghirlandaio_The_Nativity_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Duccio_Christ_Washes_the_Apostles__Feet__top___Last_Supper__bottom__thumb.jpg b/data/images/paintings/thumbs/Duccio_Christ_Washes_the_Apostles__Feet__top___Last_Supper__bottom__thumb.jpg new file mode 100644 index 0000000..e2fff98 Binary files /dev/null and b/data/images/paintings/thumbs/Duccio_Christ_Washes_the_Apostles__Feet__top___Last_Supper__bottom__thumb.jpg differ diff --git a/data/images/paintings/thumbs/Fra_Angelico_Madonna_and_Child_with_Four__ngels_thumb.jpg b/data/images/paintings/thumbs/Fra_Angelico_Madonna_and_Child_with_Four__ngels_thumb.jpg new file mode 100644 index 0000000..72f8fe2 Binary files /dev/null and b/data/images/paintings/thumbs/Fra_Angelico_Madonna_and_Child_with_Four__ngels_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Fra_Angelico_The_Crucifixion_thumb.jpg b/data/images/paintings/thumbs/Fra_Angelico_The_Crucifixion_thumb.jpg new file mode 100644 index 0000000..dcbf618 Binary files /dev/null and b/data/images/paintings/thumbs/Fra_Angelico_The_Crucifixion_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Francisco_Goya_Portrait_of_the_Duke_of_Wellington_thumb.jpg b/data/images/paintings/thumbs/Francisco_Goya_Portrait_of_the_Duke_of_Wellington_thumb.jpg new file mode 100644 index 0000000..36e7eb7 Binary files /dev/null and b/data/images/paintings/thumbs/Francisco_Goya_Portrait_of_the_Duke_of_Wellington_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Francisco_Goya_Witches__Sabbath_thumb.jpg b/data/images/paintings/thumbs/Francisco_Goya_Witches__Sabbath_thumb.jpg new file mode 100644 index 0000000..b94c840 Binary files /dev/null and b/data/images/paintings/thumbs/Francisco_Goya_Witches__Sabbath_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Georges_Seurat_The_Circus_thumb.jpg b/data/images/paintings/thumbs/Georges_Seurat_The_Circus_thumb.jpg new file mode 100644 index 0000000..621fd98 Binary files /dev/null and b/data/images/paintings/thumbs/Georges_Seurat_The_Circus_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Giacomo_Balla_Street_Light_thumb.jpg b/data/images/paintings/thumbs/Giacomo_Balla_Street_Light_thumb.jpg new file mode 100644 index 0000000..1422bee Binary files /dev/null and b/data/images/paintings/thumbs/Giacomo_Balla_Street_Light_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Giotto_Confirmation_of_the_Rule_thumb.jpg b/data/images/paintings/thumbs/Giotto_Confirmation_of_the_Rule_thumb.jpg new file mode 100644 index 0000000..3056b35 Binary files /dev/null and b/data/images/paintings/thumbs/Giotto_Confirmation_of_the_Rule_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Giotto_Institution_of_the_Crib_at_Greccio_thumb.jpg b/data/images/paintings/thumbs/Giotto_Institution_of_the_Crib_at_Greccio_thumb.jpg new file mode 100644 index 0000000..3056b35 Binary files /dev/null and b/data/images/paintings/thumbs/Giotto_Institution_of_the_Crib_at_Greccio_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Henri_Privat-Livemont_La_Dame___la_Licorne_thumb.jpg b/data/images/paintings/thumbs/Henri_Privat-Livemont_La_Dame___la_Licorne_thumb.jpg new file mode 100644 index 0000000..9e199ca Binary files /dev/null and b/data/images/paintings/thumbs/Henri_Privat-Livemont_La_Dame___la_Licorne_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Hieronymus_Bosch_Battle_of_the_Birds_and_Mammals_thumb.jpg b/data/images/paintings/thumbs/Hieronymus_Bosch_Battle_of_the_Birds_and_Mammals_thumb.jpg new file mode 100644 index 0000000..b7053f2 Binary files /dev/null and b/data/images/paintings/thumbs/Hieronymus_Bosch_Battle_of_the_Birds_and_Mammals_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Hieronymus_Bosch_Head_of_a_Halberdier_thumb.jpg b/data/images/paintings/thumbs/Hieronymus_Bosch_Head_of_a_Halberdier_thumb.jpg new file mode 100644 index 0000000..266a6a7 Binary files /dev/null and b/data/images/paintings/thumbs/Hieronymus_Bosch_Head_of_a_Halberdier_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Hieronymus_Bosch_Saint_Jerome_thumb.jpg b/data/images/paintings/thumbs/Hieronymus_Bosch_Saint_Jerome_thumb.jpg index 156dbab..5f546a1 100644 Binary files a/data/images/paintings/thumbs/Hieronymus_Bosch_Saint_Jerome_thumb.jpg and b/data/images/paintings/thumbs/Hieronymus_Bosch_Saint_Jerome_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Ivan_Klyun_Dynamic_Color_Composition_thumb.jpg b/data/images/paintings/thumbs/Ivan_Klyun_Dynamic_Color_Composition_thumb.jpg new file mode 100644 index 0000000..e61af01 Binary files /dev/null and b/data/images/paintings/thumbs/Ivan_Klyun_Dynamic_Color_Composition_thumb.jpg differ diff --git a/data/images/paintings/thumbs/J__M__W__Turner_Rain__Steam_and_Speed_thumb.jpg b/data/images/paintings/thumbs/J__M__W__Turner_Rain__Steam_and_Speed_thumb.jpg index 6dc4ca8..f09fcb0 100644 Binary files a/data/images/paintings/thumbs/J__M__W__Turner_Rain__Steam_and_Speed_thumb.jpg and b/data/images/paintings/thumbs/J__M__W__Turner_Rain__Steam_and_Speed_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Jackson_Pollock_Number_1__1950__Lavender_Mist__thumb.jpg b/data/images/paintings/thumbs/Jackson_Pollock_Number_1__1950__Lavender_Mist__thumb.jpg new file mode 100644 index 0000000..d33f25b Binary files /dev/null and b/data/images/paintings/thumbs/Jackson_Pollock_Number_1__1950__Lavender_Mist__thumb.jpg differ diff --git a/data/images/paintings/thumbs/Jan_van_Eyck_Adam_thumb.jpg b/data/images/paintings/thumbs/Jan_van_Eyck_Adam_thumb.jpg new file mode 100644 index 0000000..c9122a9 Binary files /dev/null and b/data/images/paintings/thumbs/Jan_van_Eyck_Adam_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Jan_van_Eyck_Birth_of_John_the_Baptist_thumb.jpg b/data/images/paintings/thumbs/Jan_van_Eyck_Birth_of_John_the_Baptist_thumb.jpg new file mode 100644 index 0000000..c3bcc82 Binary files /dev/null and b/data/images/paintings/thumbs/Jan_van_Eyck_Birth_of_John_the_Baptist_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Jan_van_Eyck_Portrait_of_Isabella_of_Portugal_thumb.jpg b/data/images/paintings/thumbs/Jan_van_Eyck_Portrait_of_Isabella_of_Portugal_thumb.jpg new file mode 100644 index 0000000..4702e21 Binary files /dev/null and b/data/images/paintings/thumbs/Jan_van_Eyck_Portrait_of_Isabella_of_Portugal_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Jan_van_Eyck_Saint_Jerome_in_His_Study_thumb.jpg b/data/images/paintings/thumbs/Jan_van_Eyck_Saint_Jerome_in_His_Study_thumb.jpg new file mode 100644 index 0000000..5f546a1 Binary files /dev/null and b/data/images/paintings/thumbs/Jan_van_Eyck_Saint_Jerome_in_His_Study_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Kazimir_Malevich_Suprematist_Composition_thumb.jpg b/data/images/paintings/thumbs/Kazimir_Malevich_Suprematist_Composition_thumb.jpg new file mode 100644 index 0000000..6773d3c Binary files /dev/null and b/data/images/paintings/thumbs/Kazimir_Malevich_Suprematist_Composition_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Leonardo_da_Vinci_Allegory_of_Fame_attacking_Envy_thumb.jpg b/data/images/paintings/thumbs/Leonardo_da_Vinci_Allegory_of_Fame_attacking_Envy_thumb.jpg new file mode 100644 index 0000000..827c598 Binary files /dev/null and b/data/images/paintings/thumbs/Leonardo_da_Vinci_Allegory_of_Fame_attacking_Envy_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Leonardo_da_Vinci_Anatomical_Studies_of_the_Facial_Nerves_thumb.jpg b/data/images/paintings/thumbs/Leonardo_da_Vinci_Anatomical_Studies_of_the_Facial_Nerves_thumb.jpg new file mode 100644 index 0000000..827c598 Binary files /dev/null and b/data/images/paintings/thumbs/Leonardo_da_Vinci_Anatomical_Studies_of_the_Facial_Nerves_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Marcel_Duchamp_The_Bride_Stripped_Bare_by_Her_Bachelors__Even_thumb.jpg b/data/images/paintings/thumbs/Marcel_Duchamp_The_Bride_Stripped_Bare_by_Her_Bachelors__Even_thumb.jpg new file mode 100644 index 0000000..b658bbf Binary files /dev/null and b/data/images/paintings/thumbs/Marcel_Duchamp_The_Bride_Stripped_Bare_by_Her_Bachelors__Even_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Masaccio_The_agony_of_Christ_in_the_garden_of_Gethsemane__St__Jerome_as_penitent_thumb.jpg b/data/images/paintings/thumbs/Masaccio_The_agony_of_Christ_in_the_garden_of_Gethsemane__St__Jerome_as_penitent_thumb.jpg new file mode 100644 index 0000000..2e0c2b8 Binary files /dev/null and b/data/images/paintings/thumbs/Masaccio_The_agony_of_Christ_in_the_garden_of_Gethsemane__St__Jerome_as_penitent_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Michelangelo_Manchester_Madonna_thumb.jpg b/data/images/paintings/thumbs/Michelangelo_Manchester_Madonna_thumb.jpg new file mode 100644 index 0000000..5c9a163 Binary files /dev/null and b/data/images/paintings/thumbs/Michelangelo_Manchester_Madonna_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Michelangelo_Uzziah__Jotham_and_Ahaz_thumb.jpg b/data/images/paintings/thumbs/Michelangelo_Uzziah__Jotham_and_Ahaz_thumb.jpg new file mode 100644 index 0000000..3c03b5f Binary files /dev/null and b/data/images/paintings/thumbs/Michelangelo_Uzziah__Jotham_and_Ahaz_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Paul_Gauguin_Vision_After_the_Sermon_thumb.jpg b/data/images/paintings/thumbs/Paul_Gauguin_Vision_After_the_Sermon_thumb.jpg new file mode 100644 index 0000000..ee9f8de Binary files /dev/null and b/data/images/paintings/thumbs/Paul_Gauguin_Vision_After_the_Sermon_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Peter_Paul_Rubens_Massacre_of_the_Innocents_thumb.jpg b/data/images/paintings/thumbs/Peter_Paul_Rubens_Massacre_of_the_Innocents_thumb.jpg new file mode 100644 index 0000000..288f336 Binary files /dev/null and b/data/images/paintings/thumbs/Peter_Paul_Rubens_Massacre_of_the_Innocents_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Peter_Paul_Rubens_The_Descent_from_the_Cross_thumb.jpg b/data/images/paintings/thumbs/Peter_Paul_Rubens_The_Descent_from_the_Cross_thumb.jpg new file mode 100644 index 0000000..4ae2743 Binary files /dev/null and b/data/images/paintings/thumbs/Peter_Paul_Rubens_The_Descent_from_the_Cross_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Peter_Paul_Rubens_The_Raising_of_the_Cross_thumb.jpg b/data/images/paintings/thumbs/Peter_Paul_Rubens_The_Raising_of_the_Cross_thumb.jpg new file mode 100644 index 0000000..4ae2743 Binary files /dev/null and b/data/images/paintings/thumbs/Peter_Paul_Rubens_The_Raising_of_the_Cross_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Sandro_Botticelli_Annunciation_to_Mary_thumb.jpg b/data/images/paintings/thumbs/Sandro_Botticelli_Annunciation_to_Mary_thumb.jpg new file mode 100644 index 0000000..e4f1e91 Binary files /dev/null and b/data/images/paintings/thumbs/Sandro_Botticelli_Annunciation_to_Mary_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Sandro_Botticelli_Birth_of_Christ_thumb.jpg b/data/images/paintings/thumbs/Sandro_Botticelli_Birth_of_Christ_thumb.jpg new file mode 100644 index 0000000..e4f1e91 Binary files /dev/null and b/data/images/paintings/thumbs/Sandro_Botticelli_Birth_of_Christ_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Sandro_Botticelli_Portrait_of_a_Young_Man_thumb.jpg b/data/images/paintings/thumbs/Sandro_Botticelli_Portrait_of_a_Young_Man_thumb.jpg new file mode 100644 index 0000000..719af23 Binary files /dev/null and b/data/images/paintings/thumbs/Sandro_Botticelli_Portrait_of_a_Young_Man_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Sandro_Botticelli_St_Jerome_thumb.jpg b/data/images/paintings/thumbs/Sandro_Botticelli_St_Jerome_thumb.jpg new file mode 100644 index 0000000..e4f1e91 Binary files /dev/null and b/data/images/paintings/thumbs/Sandro_Botticelli_St_Jerome_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Simone_Martini_A_Saint_Holding_a_Book_thumb.jpg b/data/images/paintings/thumbs/Simone_Martini_A_Saint_Holding_a_Book_thumb.jpg new file mode 100644 index 0000000..b477717 Binary files /dev/null and b/data/images/paintings/thumbs/Simone_Martini_A_Saint_Holding_a_Book_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Theophanes_the_Greek_Our_Lady_of_the_Don_thumb.jpg b/data/images/paintings/thumbs/Theophanes_the_Greek_Our_Lady_of_the_Don_thumb.jpg new file mode 100644 index 0000000..0680bda Binary files /dev/null and b/data/images/paintings/thumbs/Theophanes_the_Greek_Our_Lady_of_the_Don_thumb.jpg differ diff --git a/data/images/paintings/thumbs/Titian_Jacopo_Pesaro__Bishop_of_Paphos__being_presented_by_Pope_Alexander_VI_to_Saint_Peter_thumb.jpg b/data/images/paintings/thumbs/Titian_Jacopo_Pesaro__Bishop_of_Paphos__being_presented_by_Pope_Alexander_VI_to_Saint_Peter_thumb.jpg new file mode 100644 index 0000000..7d78cb0 Binary files /dev/null and b/data/images/paintings/thumbs/Titian_Jacopo_Pesaro__Bishop_of_Paphos__being_presented_by_Pope_Alexander_VI_to_Saint_Peter_thumb.jpg differ diff --git a/scripts/fetch-missing-images.js b/scripts/fetch-missing-images.js index 3acb795..c76e796 100644 --- a/scripts/fetch-missing-images.js +++ b/scripts/fetch-missing-images.js @@ -7,6 +7,13 @@ const { savePaintingImages } = require('./image-fetcher'); const IMAGE_DIR = path.resolve(process.env.IMAGE_DIR || path.join(__dirname, '../data/images')); const LIMIT = parseInt(process.argv.find((a) => a.startsWith('--limit='))?.split('=')[1] || '0', 10); const ARTIST = process.argv.find((a) => a.startsWith('--artist='))?.split('=')[1]; +const MAX_WAIT_SEC = parseInt( + process.argv.find((a) => a.startsWith('--max-wait='))?.split('=')[1] || + process.env.FETCH_MAX_WAIT_SEC || + '10', + 10 +); +const MAX_WAIT_MS = MAX_WAIT_SEC * 1000; const DISCOVER_ONLY = process.argv.includes('--discover-only'); const WEB_SEARCH_ONLY = process.argv.includes('--web-search-only'); @@ -15,6 +22,15 @@ function localExists(relPath) { return fs.existsSync(path.join(IMAGE_DIR, relPath)); } +function shuffleArray(items) { + const arr = [...items]; + for (let i = arr.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [arr[i], arr[j]] = [arr[j], arr[i]]; + } + return arr; +} + async function main() { let query = ` SELECT p.id, p.title, p.wikipedia_title, p.image_path, p.thumbnail_path, a.name AS artist_name @@ -31,9 +47,11 @@ async function main() { const { rows } = await pool.query(query, params); const missing = rows.filter((r) => !localExists(r.image_path) && !localExists(r.thumbnail_path)); - const targets = LIMIT > 0 ? missing.slice(0, LIMIT) : missing; + const targets = + LIMIT > 0 ? shuffleArray(missing).slice(0, LIMIT) : missing; console.log( `Missing local files: ${missing.length}, processing: ${targets.length}` + + `${LIMIT > 0 ? ' (random sample)' : ''}` + `${DISCOVER_ONLY ? ' (discover-only)' : ''}` + `${WEB_SEARCH_ONLY ? ' (web-search-only)' : ''}` ); @@ -44,6 +62,7 @@ async function main() { (process.env.SMITHSONIAN_API_KEY ? ', Smithsonian' : '') + (process.env.HARVARD_ART_API_KEY ? ', Harvard' : '') ); + console.log(`Max wait per painting: ${MAX_WAIT_SEC}s`); let ok = 0; let fail = 0; @@ -57,6 +76,7 @@ async function main() { artistName: row.artist_name, paintingTitle: row.title, webSearchOnly: WEB_SEARCH_ONLY, + maxWaitMs: MAX_WAIT_MS, }); if (saved.resolvedWikiTitle && saved.resolvedWikiTitle !== row.wikipedia_title) { @@ -105,7 +125,11 @@ async function main() { } } catch (err) { fail += 1; - console.warn(`✗ ${row.artist_name} — ${row.title}: ${err.message}`); + if (err.code === 'FETCH_TIME_LIMIT') { + console.warn(`⏱ timeout (${MAX_WAIT_SEC}s): ${row.artist_name} — ${row.title}`); + } else { + console.warn(`✗ ${row.artist_name} — ${row.title}: ${err.message}`); + } } } diff --git a/scripts/image-fetcher.js b/scripts/image-fetcher.js index 24dd343..4be1371 100644 --- a/scripts/image-fetcher.js +++ b/scripts/image-fetcher.js @@ -27,6 +27,8 @@ const TRUSTED_IMAGE_HOSTS = [ let lastRequestTime = 0; const MIN_DELAY_MS = 2500; +const REQUEST_TIMEOUT_MS = 15000; +const DEFAULT_BATCH_MAX_WAIT_MS = 10000; const THUMB_WIDTH = 400; const FULL_WIDTH = 1600; @@ -137,9 +139,64 @@ function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } +class FetchDeadline { + constructor(maxMs) { + this.deadline = maxMs ? Date.now() + maxMs : null; + } + + get active() { + return this.deadline !== null; + } + + expired() { + return this.deadline !== null && Date.now() >= this.deadline; + } + + remainingMs() { + return this.deadline ? Math.max(0, this.deadline - Date.now()) : Infinity; + } + + throwIfExpired() { + if (this.expired()) { + const err = new Error('Painting fetch time limit exceeded'); + err.code = 'FETCH_TIME_LIMIT'; + throw err; + } + } +} + +/** Per-operation deadline for batch fetches; cleared after savePaintingImages finishes. */ +let activeDeadline = null; + +function deadlineFromOptions(options = {}) { + if (options.deadline instanceof FetchDeadline) return options.deadline; + if (options.maxWaitMs) return new FetchDeadline(options.maxWaitMs); + return new FetchDeadline(null); +} + +function requestTimeoutMs() { + if (!activeDeadline?.active) return REQUEST_TIMEOUT_MS; + return Math.min(REQUEST_TIMEOUT_MS, Math.max(500, activeDeadline.remainingMs() - 50)); +} + +function attachRequestTimeout(req, reject) { + const timeoutMs = requestTimeoutMs(); + req.setTimeout(timeoutMs, () => { + req.destroy(); + reject(new Error('Request timeout')); + }); +} + async function throttle() { + if (activeDeadline?.expired()) activeDeadline.throwIfExpired(); const elapsed = Date.now() - lastRequestTime; - if (elapsed < MIN_DELAY_MS) await sleep(MIN_DELAY_MS - elapsed); + const minDelay = activeDeadline?.active ? 0 : MIN_DELAY_MS; + let wait = Math.max(0, minDelay - elapsed); + if (activeDeadline?.active) { + wait = Math.min(wait, activeDeadline.remainingMs() - 50); + if (wait <= 0) activeDeadline.throwIfExpired(); + } + if (wait > 0) await sleep(wait); lastRequestTime = Date.now(); } @@ -187,6 +244,7 @@ function fetchBuffer(url, redirectCount = 0, referer = null) { res.on('end', () => resolve(Buffer.concat(chunks))); } ); + attachRequestTimeout(req, reject); req.on('error', reject); }); } @@ -195,7 +253,7 @@ async function fetchJson(url) { await throttle(); return new Promise((resolve, reject) => { const client = url.startsWith('https') ? https : http; - client + const req = client .get(url, { headers: { 'User-Agent': USER_AGENT } }, (res) => { if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) { return fetchJson(res.headers.location).then(resolve).catch(reject); @@ -211,6 +269,7 @@ async function fetchJson(url) { }); }) .on('error', reject); + attachRequestTimeout(req, reject); }); } @@ -249,6 +308,7 @@ async function fetchHtml(url, options = {}) { }); } ); + attachRequestTimeout(req, reject); req.on('error', reject); if (body) req.write(body); req.end(); @@ -295,13 +355,22 @@ function extractImageUrlsFromText(text) { } async function withRetry(fn, retries = 6) { - for (let i = 0; i < retries; i++) { + const maxRetries = activeDeadline?.active ? Math.min(retries, 2) : retries; + for (let i = 0; i < maxRetries; i++) { + if (activeDeadline?.expired()) activeDeadline.throwIfExpired(); try { return await fn(); } catch (err) { - if (i === retries - 1) throw err; + if (err.code === 'FETCH_TIME_LIMIT') throw err; + if (i === maxRetries - 1) throw err; const wait = err.message.includes('429') ? 8000 * (i + 1) : 2000 * (i + 1); - await sleep(wait); + if (activeDeadline?.active) { + const capped = Math.min(wait, activeDeadline.remainingMs() - 50); + if (capped <= 0) activeDeadline.throwIfExpired(); + await sleep(capped); + } else { + await sleep(wait); + } } } } @@ -1015,6 +1084,7 @@ async function resolveFromLookupTitle(lookupTitle, options) { ]; for (const fn of sources) { + if (activeDeadline?.expired()) activeDeadline.throwIfExpired(); try { const result = await fn(); if (result?.fullUrl || result?.thumbUrl) { @@ -1025,7 +1095,9 @@ async function resolveFromLookupTitle(lookupTitle, options) { resolvedWikiTitle: lookupTitle, }; } - } catch {} + } catch (err) { + if (err.code === 'FETCH_TIME_LIMIT') throw err; + } } return null; } @@ -1060,12 +1132,16 @@ async function resolvePaintingImages(wikiTitle, options = {}) { } for (const title of lookupCandidates) { + if (activeDeadline?.expired()) activeDeadline.throwIfExpired(); const result = await resolveFromLookupTitle(title, options); if (result) return result; } + if (activeDeadline?.expired()) activeDeadline.throwIfExpired(); + const discovered = await searchWikipediaTitleMultilingual(artistName, searchTitle); if (discovered && !seen.has(discovered.title)) { + if (activeDeadline?.expired()) activeDeadline.throwIfExpired(); if (discovered.lang === 'en') { const result = await resolveFromLookupTitle(discovered.title, options); if (result) return { ...result, resolvedWikiTitle: discovered.title }; @@ -1080,9 +1156,13 @@ async function resolvePaintingImages(wikiTitle, options = {}) { } } + if (activeDeadline?.expired()) activeDeadline.throwIfExpired(); + const web = await searchWebForPaintingImages(artistName, searchTitle); if (web) return web; + if (activeDeadline?.expired()) activeDeadline.throwIfExpired(); + return null; } @@ -1121,60 +1201,73 @@ async function generateThumbnailFromFull(fullDest, thumbDest, width = THUMB_WIDT } async function savePaintingImages(wikiTitle, baseFilename, imageDir, options = {}) { - const resolved = await resolvePaintingImages(wikiTitle, options); - if (!resolved) return { imagePath: null, thumbnailPath: null, source: null, resolvedWikiTitle: null }; - - const paintingsDir = path.join(imageDir, 'paintings'); - const thumbsDir = path.join(imageDir, 'paintings', 'thumbs'); - if (!fs.existsSync(paintingsDir)) fs.mkdirSync(paintingsDir, { recursive: true }); - if (!fs.existsSync(thumbsDir)) fs.mkdirSync(thumbsDir, { recursive: true }); - - const safeBase = baseFilename.replace(/[^a-zA-Z0-9_-]/g, '_'); - const fullExt = pickExt(resolved.fullUrl); - - const fullDest = path.join(paintingsDir, safeBase + fullExt); - const thumbDest = path.join(thumbsDir, safeBase + '_thumb.jpg'); - - let imagePath = null; - let thumbnailPath = null; + const deadline = deadlineFromOptions(options); + activeDeadline = deadline.active ? deadline : null; try { - await downloadImageToFile(resolved.fullUrl, fullDest); - imagePath = path.join('paintings', safeBase + fullExt).replace(/\\/g, '/'); - } catch (err) { - console.warn(` Full image download failed: ${err.message}`); - } + const resolved = await resolvePaintingImages(wikiTitle, options); + if (!resolved) return { imagePath: null, thumbnailPath: null, source: null, resolvedWikiTitle: null }; - if (imagePath) { - try { - await generateThumbnailFromFull(fullDest, thumbDest); - thumbnailPath = path.join('paintings', 'thumbs', safeBase + '_thumb.jpg').replace(/\\/g, '/'); - } catch (err) { - console.warn(` Thumbnail generation failed: ${err.message}`); - thumbnailPath = imagePath; - } - } else { - try { - const thumbSrc = - resolved.thumbUrl !== resolved.fullUrl ? resolved.thumbUrl : resolved.fullUrl; - const thumbExt = pickExt(resolved.thumbUrl); - const fallbackThumbDest = path.join(thumbsDir, safeBase + '_thumb' + thumbExt); - await downloadImageToFile(thumbSrc, fallbackThumbDest); - thumbnailPath = path - .join('paintings', 'thumbs', safeBase + '_thumb' + thumbExt) - .replace(/\\/g, '/'); - imagePath = thumbnailPath; - } catch (err) { - console.warn(` Thumbnail download failed: ${err.message}`); - } - } + if (activeDeadline?.expired()) activeDeadline.throwIfExpired(); - return { - imagePath, - thumbnailPath, - source: resolved.source, - resolvedWikiTitle: resolved.resolvedWikiTitle || null, - }; + const paintingsDir = path.join(imageDir, 'paintings'); + const thumbsDir = path.join(imageDir, 'paintings', 'thumbs'); + if (!fs.existsSync(paintingsDir)) fs.mkdirSync(paintingsDir, { recursive: true }); + if (!fs.existsSync(thumbsDir)) fs.mkdirSync(thumbsDir, { recursive: true }); + + const safeBase = baseFilename.replace(/[^a-zA-Z0-9_-]/g, '_'); + const fullExt = pickExt(resolved.fullUrl); + + const fullDest = path.join(paintingsDir, safeBase + fullExt); + const thumbDest = path.join(thumbsDir, safeBase + '_thumb.jpg'); + + let imagePath = null; + let thumbnailPath = null; + + try { + await downloadImageToFile(resolved.fullUrl, fullDest); + imagePath = path.join('paintings', safeBase + fullExt).replace(/\\/g, '/'); + } catch (err) { + if (err.code === 'FETCH_TIME_LIMIT') throw err; + console.warn(` Full image download failed: ${err.message}`); + } + + if (activeDeadline?.expired()) activeDeadline.throwIfExpired(); + + if (imagePath) { + try { + await generateThumbnailFromFull(fullDest, thumbDest); + thumbnailPath = path.join('paintings', 'thumbs', safeBase + '_thumb.jpg').replace(/\\/g, '/'); + } catch (err) { + console.warn(` Thumbnail generation failed: ${err.message}`); + thumbnailPath = imagePath; + } + } else { + try { + const thumbSrc = + resolved.thumbUrl !== resolved.fullUrl ? resolved.thumbUrl : resolved.fullUrl; + const thumbExt = pickExt(resolved.thumbUrl); + const fallbackThumbDest = path.join(thumbsDir, safeBase + '_thumb' + thumbExt); + await downloadImageToFile(thumbSrc, fallbackThumbDest); + thumbnailPath = path + .join('paintings', 'thumbs', safeBase + '_thumb' + thumbExt) + .replace(/\\/g, '/'); + imagePath = thumbnailPath; + } catch (err) { + if (err.code === 'FETCH_TIME_LIMIT') throw err; + console.warn(` Thumbnail download failed: ${err.message}`); + } + } + + return { + imagePath, + thumbnailPath, + source: resolved.source, + resolvedWikiTitle: resolved.resolvedWikiTitle || wikiTitle, + }; + } finally { + activeDeadline = null; + } } async function saveImageForItem(wikiTitle, subdir, filename, imageDir, options = {}) { @@ -1220,5 +1313,7 @@ module.exports = { searchWebForPaintingImages, getGoogleArtsCultureImages, simplifyPaintingTitle, + DEFAULT_BATCH_MAX_WAIT_MS, + FetchDeadline, sleep, };