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 @@ -237,6 +237,7 @@ Provider and query may be given as positionals after `s` / `-s`, or with `-P` /
| `deviantart` | [DeviantArt](https://deviantart.com) | Creative reference photos, stock imagery, and digital art | Direct image downloads via Wixmp CDN. |
| `negativespace` | [NegativeSpace](https://negativespace.co) | Free high-resolution CC0 stock photography | Direct master full-resolution photo downloads. |
| `skitterphoto` | [Skitterphoto](https://skitterphoto.com) | 100% free CC0 public domain photography | Direct high-resolution photo downloads. |
| `libreshot` | [LibreShot](https://libreshot.com) | Free CC0 stock photos by Martin Vorel | Direct master full-resolution photo downloads. |

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

Expand Down Expand Up @@ -302,6 +303,7 @@ src/
deviantart.zig
negativespace.zig
skitterphoto.zig
libreshot.zig
assets/ README banner and static assets
docs/ Provider implementation notes
install.sh curl | bash installer (Linux release binaries)
Expand Down
13 changes: 13 additions & 0 deletions docs/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,3 +195,16 @@ This document summarizes the network endpoints, transport models, and image down
* High-resolution photo asset path extracted directly (`/photos/skitterphoto-{id}-default.jpg`).
* **Download**: Direct GET on high-resolution image URL.
* **License**: CC0 / 100% Free Public Domain.

---

## 17. LibreShot (`libreshot.com`)

* **Search**: `GET https://libreshot.com/?s={query}`
* **Format**: WordPress photography feed by Martin Vorel with lazy-loaded image cards.
* **Extraction**:
* Title extracted and HTML unescaped from image `alt` attribute.
* Slug ID parsed from post permalink.
* Master full-resolution URL extracted by stripping geometry suffixes (`-508x339`, `-508x300`) from `wp-content/uploads/` image URLs.
* **Download**: Direct GET on original full-resolution master photo JPEG/PNG (up to 10+ MB).
* **License**: CC0 / Free Public Domain Stock Photos.
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**: 13 (`unsplash`, `isorepublic`, `picjumbo`, `foodiesfeed`, `picography`, `gratisography`, `startupstockphotos`, `burst`, `jaymantri`, `publicdomainarchive`, `magdeleine`, `splitshire`, `deviantart`)
- *(Additional Providers Implemented in `ast`)*: `aura` ([Aura.build](https://www.aura.build)), `negativespace` ([NegativeSpace.co](https://negativespace.co)), `skitterphoto` ([Skitterphoto.com](https://skitterphoto.com))
- *(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))
- **Unimplemented / Blocked / Pending**: 11

---
Expand Down
9 changes: 9 additions & 0 deletions src/commands/search.zig
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const splitshire = @import("../providers/splitshire.zig");
const deviantart = @import("../providers/deviantart.zig");
const negativespace = @import("../providers/negativespace.zig");
const skitterphoto = @import("../providers/skitterphoto.zig");
const libreshot = @import("../providers/libreshot.zig");
const stdio = @import("../stdio.zig");
const Allocator = std.mem.Allocator;
const Io = std.Io;
Expand Down Expand Up @@ -88,6 +89,9 @@ fn doSearch(
if (std.ascii.eqlIgnoreCase(provider_id, "skitterphoto")) {
return skitterphoto.search(client, allocator, query, limit);
}
if (std.ascii.eqlIgnoreCase(provider_id, "libreshot")) {
return libreshot.search(client, allocator, query, limit);
}
return error.UnknownProvider;
}

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

Expand All @@ -167,6 +174,7 @@ fn doPrompt(provider_id: []const u8, a: Asset) ?[]const u8 {
if (std.ascii.eqlIgnoreCase(provider_id, "deviantart")) return deviantart.getPrompt(a);
if (std.ascii.eqlIgnoreCase(provider_id, "negativespace")) return negativespace.getPrompt(a);
if (std.ascii.eqlIgnoreCase(provider_id, "skitterphoto")) return skitterphoto.getPrompt(a);
if (std.ascii.eqlIgnoreCase(provider_id, "libreshot")) return libreshot.getPrompt(a);
return a.prompt orelse a.description;
}

Expand All @@ -187,6 +195,7 @@ fn doUrl(provider_id: []const u8, a: Asset) ?[]const u8 {
if (std.ascii.eqlIgnoreCase(provider_id, "deviantart")) return deviantart.getUrl(a);
if (std.ascii.eqlIgnoreCase(provider_id, "negativespace")) return negativespace.getUrl(a);
if (std.ascii.eqlIgnoreCase(provider_id, "skitterphoto")) return skitterphoto.getUrl(a);
if (std.ascii.eqlIgnoreCase(provider_id, "libreshot")) return libreshot.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 @@ -19,6 +19,7 @@ const splitshire = @import("providers/splitshire.zig");
const deviantart = @import("providers/deviantart.zig");
const negativespace = @import("providers/negativespace.zig");
const skitterphoto = @import("providers/skitterphoto.zig");
const libreshot = @import("providers/libreshot.zig");
const registry = @import("providers/registry.zig");
const stdio = @import("stdio.zig");
const Allocator = std.mem.Allocator;
Expand Down Expand Up @@ -85,6 +86,9 @@ fn searchProvider(
if (std.ascii.eqlIgnoreCase(provider_id, "skitterphoto")) {
return skitterphoto.search(client, allocator, query, config.default_limit);
}
if (std.ascii.eqlIgnoreCase(provider_id, "libreshot")) {
return libreshot.search(client, allocator, query, config.default_limit);
}
return error.UnknownProvider;
}

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

Expand All @@ -163,6 +170,7 @@ fn promptOf(provider_id: []const u8, a: Asset) ?[]const u8 {
if (std.ascii.eqlIgnoreCase(provider_id, "deviantart")) return deviantart.getPrompt(a);
if (std.ascii.eqlIgnoreCase(provider_id, "negativespace")) return negativespace.getPrompt(a);
if (std.ascii.eqlIgnoreCase(provider_id, "skitterphoto")) return skitterphoto.getPrompt(a);
if (std.ascii.eqlIgnoreCase(provider_id, "libreshot")) return libreshot.getPrompt(a);
return a.prompt;
}

Expand All @@ -183,6 +191,7 @@ fn urlOf(provider_id: []const u8, a: Asset) ?[]const u8 {
if (std.ascii.eqlIgnoreCase(provider_id, "deviantart")) return deviantart.getUrl(a);
if (std.ascii.eqlIgnoreCase(provider_id, "negativespace")) return negativespace.getUrl(a);
if (std.ascii.eqlIgnoreCase(provider_id, "skitterphoto")) return skitterphoto.getUrl(a);
if (std.ascii.eqlIgnoreCase(provider_id, "libreshot")) return libreshot.getUrl(a);
return a.image_url;
}

Expand Down
Loading
Loading