Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ Provider and query may be given as positionals after `s` / `-s`, or with `-P` /
| `goodfreephotos` | [Good Free Photos](https://goodfreephotos.com) | Free CC0 public domain photos, state parks, and landmarks by Yinan Chen | Direct master full-resolution photo downloads. |
| `wikimedia` | [Wikimedia Commons](https://commons.wikimedia.org) | Freely licensed and public domain educational & stock media repository | Direct master full-resolution image downloads. |
| `vecteezy` | [Vecteezy](https://vecteezy.com) | Free high-resolution stock photography and design assets | Direct master full-resolution photo downloads (up to 15+ MB). |
| `nasa` | [NASA Image Library](https://images.nasa.gov) | Public domain space exploration, aeronautics, and astronomical imagery | Direct master full-resolution photo & vector asset downloads. |

List providers at runtime via `ast help` (printed under **PROVIDERS**).

Expand Down Expand Up @@ -316,6 +317,7 @@ src/
goodfreephotos.zig
wikimedia.zig
vecteezy.zig
nasa.zig
assets/ README banner and static assets
docs/ Provider implementation notes
install.sh curl | bash installer (Linux release binaries)
Expand Down
15 changes: 15 additions & 0 deletions docs/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,3 +288,18 @@ This document summarizes the network endpoints, transport models, and image down
* Master full-resolution URLs constructed by replacing `/non_2x/` previews with `/original/` master assets on Vecteezy CDN.
* **Download**: Direct GET on master original camera photo JPEG files (up to 15+ MB) with automated preview fallback.
* **License**: Vecteezy Free License.

---

## 24. NASA Image Library (`images.nasa.gov`)

* **Search**: `GET https://images-api.nasa.gov/search?q={query}&media_type=image`
* **Format**: Official NASA Image and Video Library REST API.
* **Extraction**:
* Clean sanitized image IDs formatted as `nasa-{nasa_id}`.
* Descriptive titles from `data[0].title`.
* Attribution formatted from `photographer` or `center` (e.g. `NASA / JPL`).
* Master full-resolution media URLs resolved from `links`: prefers original JPEG/PNG (`~orig.jpg`), falling back to `~large.jpg` or `~medium.jpg` when the original is an uncompressed TIFF.
* Preview thumbnails from `~thumb.jpg`.
* **Download**: Direct GET on master full-resolution media via `images-assets.nasa.gov` CDN.
* **License**: Public Domain / Free for commercial and non-commercial educational use without copyright restriction.
2 changes: 1 addition & 1 deletion docs/stock_photo_sites.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ This document tracks all 24 stock photo websites listed in the [GrayGrids 21+ Be

- **Total Sites Listed**: 24
- **Implemented & Working**: 14 (`unsplash`, `isorepublic`, `picjumbo`, `foodiesfeed`, `picography`, `gratisography`, `startupstockphotos`, `burst`, `jaymantri`, `publicdomainarchive`, `magdeleine`, `splitshire`, `deviantart`, `vecteezy`)
- *(Additional Providers Implemented in `ast`)*: `aura` ([Aura.build](https://www.aura.build)), `negativespace` ([NegativeSpace.co](https://negativespace.co)), `skitterphoto` ([Skitterphoto.com](https://skitterphoto.com)), `libreshot` ([LibreShot.com](https://libreshot.com)), `moveast` ([Moveast.me](https://moveast.me)), `cupcake` ([Cupcake](https://cupcake.nilssonlee.se)), `freenaturestock` ([FreeNatureStock](https://freenaturestock.com)), `goodfreephotos` ([Good Free Photos](https://goodfreephotos.com)), `wikimedia` ([Wikimedia Commons](https://commons.wikimedia.org))
- *(Additional Providers Implemented in `ast`)*: `aura` ([Aura.build](https://www.aura.build)), `negativespace` ([NegativeSpace.co](https://negativespace.co)), `skitterphoto` ([Skitterphoto.com](https://skitterphoto.com)), `libreshot` ([LibreShot.com](https://libreshot.com)), `moveast` ([Moveast.me](https://moveast.me)), `cupcake` ([Cupcake](https://cupcake.nilssonlee.se)), `freenaturestock` ([FreeNatureStock](https://freenaturestock.com)), `goodfreephotos` ([Good Free Photos](https://goodfreephotos.com)), `wikimedia` ([Wikimedia Commons](https://commons.wikimedia.org)), `nasa` ([NASA Image Library](https://images.nasa.gov))
- **Unimplemented / Blocked / Pending**: 10

---
Expand Down
9 changes: 9 additions & 0 deletions src/commands/search.zig
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const freenaturestock = @import("../providers/freenaturestock.zig");
const goodfreephotos = @import("../providers/goodfreephotos.zig");
const wikimedia = @import("../providers/wikimedia.zig");
const vecteezy = @import("../providers/vecteezy.zig");
const nasa = @import("../providers/nasa.zig");
const stdio = @import("../stdio.zig");
const Allocator = std.mem.Allocator;
const Io = std.Io;
Expand Down Expand Up @@ -116,6 +117,9 @@ fn doSearch(
if (std.ascii.eqlIgnoreCase(provider_id, "vecteezy")) {
return vecteezy.search(client, allocator, query, limit);
}
if (std.ascii.eqlIgnoreCase(provider_id, "nasa")) {
return nasa.search(client, allocator, query, limit);
}
return error.UnknownProvider;
}

Expand Down Expand Up @@ -196,6 +200,9 @@ fn doDownload(
if (std.ascii.eqlIgnoreCase(provider_id, "vecteezy")) {
return vecteezy.download(client, allocator, io, a, output_dir);
}
if (std.ascii.eqlIgnoreCase(provider_id, "nasa")) {
return nasa.download(client, allocator, io, a, output_dir);
}
return error.UnknownProvider;
}

Expand Down Expand Up @@ -223,6 +230,7 @@ fn doPrompt(provider_id: []const u8, a: Asset) ?[]const u8 {
if (std.ascii.eqlIgnoreCase(provider_id, "goodfreephotos")) return goodfreephotos.getPrompt(a);
if (std.ascii.eqlIgnoreCase(provider_id, "wikimedia")) return wikimedia.getPrompt(a);
if (std.ascii.eqlIgnoreCase(provider_id, "vecteezy")) return vecteezy.getPrompt(a);
if (std.ascii.eqlIgnoreCase(provider_id, "nasa")) return nasa.getPrompt(a);
return a.prompt orelse a.description;
}

Expand Down Expand Up @@ -250,6 +258,7 @@ fn doUrl(provider_id: []const u8, a: Asset) ?[]const u8 {
if (std.ascii.eqlIgnoreCase(provider_id, "goodfreephotos")) return goodfreephotos.getUrl(a);
if (std.ascii.eqlIgnoreCase(provider_id, "wikimedia")) return wikimedia.getUrl(a);
if (std.ascii.eqlIgnoreCase(provider_id, "vecteezy")) return vecteezy.getUrl(a);
if (std.ascii.eqlIgnoreCase(provider_id, "nasa")) return nasa.getUrl(a);
return a.image_url;
}

Expand Down
9 changes: 9 additions & 0 deletions src/interactive.zig
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const freenaturestock = @import("providers/freenaturestock.zig");
const goodfreephotos = @import("providers/goodfreephotos.zig");
const wikimedia = @import("providers/wikimedia.zig");
const vecteezy = @import("providers/vecteezy.zig");
const nasa = @import("providers/nasa.zig");
const registry = @import("providers/registry.zig");
const stdio = @import("stdio.zig");
const Allocator = std.mem.Allocator;
Expand Down Expand Up @@ -113,6 +114,9 @@ fn searchProvider(
if (std.ascii.eqlIgnoreCase(provider_id, "vecteezy")) {
return vecteezy.search(client, allocator, query, config.default_limit);
}
if (std.ascii.eqlIgnoreCase(provider_id, "nasa")) {
return nasa.search(client, allocator, query, config.default_limit);
}
return error.UnknownProvider;
}

Expand Down Expand Up @@ -192,6 +196,9 @@ fn downloadAsset(
if (std.ascii.eqlIgnoreCase(provider_id, "vecteezy")) {
return vecteezy.download(client, allocator, io, a, config.default_output_dir);
}
if (std.ascii.eqlIgnoreCase(provider_id, "nasa")) {
return nasa.download(client, allocator, io, a, config.default_output_dir);
}
return error.UnknownProvider;
}

Expand Down Expand Up @@ -219,6 +226,7 @@ fn promptOf(provider_id: []const u8, a: Asset) ?[]const u8 {
if (std.ascii.eqlIgnoreCase(provider_id, "goodfreephotos")) return goodfreephotos.getPrompt(a);
if (std.ascii.eqlIgnoreCase(provider_id, "wikimedia")) return wikimedia.getPrompt(a);
if (std.ascii.eqlIgnoreCase(provider_id, "vecteezy")) return vecteezy.getPrompt(a);
if (std.ascii.eqlIgnoreCase(provider_id, "nasa")) return nasa.getPrompt(a);
return a.prompt;
}

Expand Down Expand Up @@ -246,6 +254,7 @@ fn urlOf(provider_id: []const u8, a: Asset) ?[]const u8 {
if (std.ascii.eqlIgnoreCase(provider_id, "goodfreephotos")) return goodfreephotos.getUrl(a);
if (std.ascii.eqlIgnoreCase(provider_id, "wikimedia")) return wikimedia.getUrl(a);
if (std.ascii.eqlIgnoreCase(provider_id, "vecteezy")) return vecteezy.getUrl(a);
if (std.ascii.eqlIgnoreCase(provider_id, "nasa")) return nasa.getUrl(a);
return a.image_url;
}

Expand Down
Loading
Loading