bannerbear 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +249 -12
- data/lib/bannerbear/v5/client.rb +181 -3
- data/lib/bannerbear/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 29845579050c36919da99fcffdf6ec4d5577dbe243fbf114812500636969b05d
|
|
4
|
+
data.tar.gz: e13320ddb5d91bb4f957cefa72eb4292035f07a0c11f804d6f2b8e5ead471189
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2977c792ce41055fb8248ff4941ab5cccbdc2265c9589004124381c66163ddbcc1ab7a5a49ac811cbee75bef91780483fad8843e09cb26d1c5e5f520c37feaf0
|
|
7
|
+
data.tar.gz: 829e80632d438b428f6f8ed18d3009e0593fa480f96056200623f8b578658117fc5f626dbe5786e8333faa7adeafbb600659cb03a6b1c19d2878a0f6247970e1
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -31,6 +31,13 @@ For the **legacy V2 API**, see [Usage](#usage) below — that section is unchang
|
|
|
31
31
|
- [Account (V5)](#account-v5)
|
|
32
32
|
- [Image Templates (V5)](#image-templates-v5)
|
|
33
33
|
- [Images (V5)](#images-v5)
|
|
34
|
+
- [Animation Templates (V5)](#animation-templates-v5)
|
|
35
|
+
- [Animations (V5)](#animations-v5)
|
|
36
|
+
- [Workflows (V5)](#workflows-v5)
|
|
37
|
+
- [Workflow Runs (V5)](#workflow-runs-v5)
|
|
38
|
+
- [Tools (V5)](#tools-v5)
|
|
39
|
+
- [Assets (V5)](#assets-v5)
|
|
40
|
+
- [Publications (V5)](#publications-v5)
|
|
34
41
|
- [Batches (V5)](#batches-v5)
|
|
35
42
|
- [Webhooks (V5)](#webhooks-v5)
|
|
36
43
|
- [Instant URLs (V5)](#instant-urls-v5)
|
|
@@ -55,14 +62,38 @@ bb.account
|
|
|
55
62
|
|
|
56
63
|
### Image Templates (V5)
|
|
57
64
|
|
|
58
|
-
V5 renames V2's `templates` resource to `image_templates`.
|
|
65
|
+
V5 renames V2's `templates` resource to `image_templates`. Templates can be created, updated, and deleted through the API — `config` holds the full canvas.
|
|
59
66
|
|
|
60
67
|
```ruby
|
|
61
68
|
bb.list_image_templates(page: 1)
|
|
62
69
|
bb.get_image_template("template uid")
|
|
70
|
+
|
|
71
|
+
bb.create_image_template(
|
|
72
|
+
name: "My Template",
|
|
73
|
+
description: "Created from the API",
|
|
74
|
+
tags: ["portrait"],
|
|
75
|
+
width: 1080,
|
|
76
|
+
height: 1080,
|
|
77
|
+
config: { objects: [
|
|
78
|
+
{ id: "bg", type: "rectangle", left: 0, top: 0, width: 1080, height: 1080, "background-color" => "#0f172a" },
|
|
79
|
+
{ id: "headline", type: "text", left: 80, top: 400, width: 920, text: "Hello World!", "font-size" => 72, color: "#ffffff" }
|
|
80
|
+
] }
|
|
81
|
+
)
|
|
82
|
+
|
|
63
83
|
bb.update_image_template("template uid", name: "New Name", description: "...", tags: ["portrait"])
|
|
84
|
+
bb.delete_image_template("template uid")
|
|
64
85
|
```
|
|
65
86
|
|
|
87
|
+
##### Options for `create_image_template` / `update_image_template`
|
|
88
|
+
|
|
89
|
+
- `name` *required for create* (`string`)
|
|
90
|
+
- `description` (`string`)
|
|
91
|
+
- `tags` (`array`)
|
|
92
|
+
- `width` / `height`: canvas size in pixels (`integer`)
|
|
93
|
+
- `config`: full canvas configuration, `{ objects: [...] }`. Passing it **replaces** the existing config in place (`hash`)
|
|
94
|
+
|
|
95
|
+
Deleting is a soft delete: images already rendered from the template stay intact, but the template no longer appears in list/get calls and cannot be used for new renders.
|
|
96
|
+
|
|
66
97
|
### Images (V5)
|
|
67
98
|
|
|
68
99
|
V5's `modifications` is an **object** with two sub-keys:
|
|
@@ -95,7 +126,7 @@ bb.create_image("template uid", sync: true, modifications: { objects: [...] })
|
|
|
95
126
|
- `scale`: scale multiplier, 1–4 (`integer`)
|
|
96
127
|
- `dpi`: DPI metadata (`integer`)
|
|
97
128
|
- `quality`: quality control (`integer`)
|
|
98
|
-
- `proxy`: proxy
|
|
129
|
+
- `proxy`: proxy and resize external images before rendering (`boolean`)
|
|
99
130
|
- `metadata`: include any metadata to reference at a later point (`string`)
|
|
100
131
|
- `version`: pin template version (`integer`)
|
|
101
132
|
- `sync`: route to the sync host (`boolean`; Ruby-only, not sent to the API)
|
|
@@ -105,13 +136,214 @@ bb.get_image("image uid")
|
|
|
105
136
|
bb.list_images(page: 1)
|
|
106
137
|
```
|
|
107
138
|
|
|
139
|
+
### Animation Templates (V5)
|
|
140
|
+
|
|
141
|
+
Animation templates render video instead of a still image. They carry a `frame_rate` and a `duration_seconds` in place of the image template's static canvas.
|
|
142
|
+
|
|
143
|
+
```ruby
|
|
144
|
+
bb.list_animation_templates(page: 1)
|
|
145
|
+
bb.get_animation_template("template uid")
|
|
146
|
+
|
|
147
|
+
bb.create_animation_template(
|
|
148
|
+
name: "My Animation",
|
|
149
|
+
description: "Created from the API",
|
|
150
|
+
tags: ["promo"],
|
|
151
|
+
width: 1080,
|
|
152
|
+
height: 1080,
|
|
153
|
+
frame_rate: 30
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
bb.update_animation_template("template uid", name: "New Name", frame_rate: 60)
|
|
157
|
+
bb.delete_animation_template("template uid")
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
##### Options for `create_animation_template` / `update_animation_template`
|
|
161
|
+
|
|
162
|
+
- `name` *required for create* (`string`)
|
|
163
|
+
- `description` (`string`)
|
|
164
|
+
- `tags` (`array`)
|
|
165
|
+
- `width` / `height`: canvas size in pixels, 100–3000 (`integer`)
|
|
166
|
+
- `frame_rate`: `24`, `30`, or `60` (`integer`)
|
|
167
|
+
|
|
168
|
+
### Animations (V5)
|
|
169
|
+
|
|
170
|
+
Rendering an animation is **always asynchronous** — there is no sync host for animations. Poll `get_animation` until the status is `"completed"` or `"failed"`, or subscribe to a webhook with the resource `"animation"`.
|
|
171
|
+
|
|
172
|
+
```ruby
|
|
173
|
+
animation = bb.create_animation("animation template uid",
|
|
174
|
+
modifications: {
|
|
175
|
+
template: { width: 1080, height: 1080, fps: 30 },
|
|
176
|
+
objects: [
|
|
177
|
+
{ name: "headline", text: "Hello World!" }
|
|
178
|
+
]
|
|
179
|
+
},
|
|
180
|
+
formats: ["mp4"]
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
animation = bb.get_animation(animation["uid"])
|
|
184
|
+
animation["status"] # => "queued" | "rendering" | "completed" | "failed"
|
|
185
|
+
animation["files"] # => { "mp4" => "https://..." } when completed
|
|
186
|
+
|
|
187
|
+
bb.list_animations(page: 1)
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
##### Options for `create_animation`
|
|
191
|
+
|
|
192
|
+
- `modifications`: V5 modifications object (`hash`)
|
|
193
|
+
- `formats`: `["mp4"]` or `["mov"]`. Ignored when `transparent` is set — that always yields MOV (`array`)
|
|
194
|
+
- `metadata`: include any metadata to reference at a later point (`string`)
|
|
195
|
+
|
|
196
|
+
Template-level modification keys for animations: `width`, `height`, `fps` (`24`, `30`, or `60`), and `transparent`. Setting `transparent` renders on a transparent background and forces a MOV output, so the alpha channel survives.
|
|
197
|
+
|
|
198
|
+
### Workflows (V5)
|
|
199
|
+
|
|
200
|
+
Workflows chain several steps into one named, re-runnable operation. They are read-only through the API — build them in the Bannerbear UI, then run them here.
|
|
201
|
+
|
|
202
|
+
```ruby
|
|
203
|
+
bb.list_workflows(page: 1)
|
|
204
|
+
|
|
205
|
+
workflow = bb.get_workflow("workflow uid")
|
|
206
|
+
workflow["inputs"] # the inputs this workflow declares
|
|
207
|
+
workflow["steps"]
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Workflow Runs (V5)
|
|
211
|
+
|
|
212
|
+
A run is **asynchronous**. Poll `get_workflow_run` until the status is `"completed"` or `"failed"`, or subscribe to a webhook with the resource `"workflow_run"`.
|
|
213
|
+
|
|
214
|
+
```ruby
|
|
215
|
+
run = bb.create_workflow_run("workflow uid",
|
|
216
|
+
inputs: { "headline" => "Hello World!", "photo" => "https://example.com/photo.jpg" }
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
run = bb.get_workflow_run(run["uid"])
|
|
220
|
+
run["status"] # => "queued" | "running" | "completed" | "failed"
|
|
221
|
+
run["outputs"] if run["status"] == "completed"
|
|
222
|
+
|
|
223
|
+
bb.list_workflow_runs(page: 1)
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
##### Options for `create_workflow_run`
|
|
227
|
+
|
|
228
|
+
- `inputs`: values for the workflow's declared inputs (`hash`)
|
|
229
|
+
|
|
230
|
+
### Tools (V5)
|
|
231
|
+
|
|
232
|
+
Tools are standalone media operations that do not use a template. Every tool is **asynchronous**: the call returns a pending *tool job*. Poll `get_tool_job` until the status is `"completed"` or `"failed"`, or subscribe to a webhook with the resource `"tool_job"`.
|
|
233
|
+
|
|
234
|
+
```ruby
|
|
235
|
+
job = bb.trim_video(video_url: "https://example.com/clip.mp4", start: 2.5, end: 10.0)
|
|
236
|
+
|
|
237
|
+
job = bb.get_tool_job(job["uid"])
|
|
238
|
+
job["status"] # => "pending" | "running" | "completed" | "failed"
|
|
239
|
+
job["outputs"]["video_url"] if job["status"] == "completed"
|
|
240
|
+
|
|
241
|
+
bb.list_tool_jobs(page: 1)
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
Every tool also accepts an optional `metadata` string.
|
|
245
|
+
|
|
246
|
+
| Method | Required | Optional | Output key |
|
|
247
|
+
| --- | --- | --- | --- |
|
|
248
|
+
| `remove_bg` | `image_url` | — | `image_url` |
|
|
249
|
+
| `create_pdf` | `urls` | — | `pdf_url` |
|
|
250
|
+
| `trim_video` | `video_url`, `start`, `end` | — | `video_url` |
|
|
251
|
+
| `concat_videos` | `video_urls` | `width`, `height`, `fps` | `video_url` |
|
|
252
|
+
| `resize_video` | `video_url`, `width`, `height` | `fit` | `video_url` |
|
|
253
|
+
| `crop_video` | `video_url`, `x`, `y`, `width`, `height` | — | `video_url` |
|
|
254
|
+
| `overlay_video` | `base_video_url`, `overlay_video_url` | `position`, `margin`, `x`, `y`, `scale`, `start` | `video_url` |
|
|
255
|
+
| `overlay_image` | `video_url`, `image_url` | `position`, `margin`, `x`, `y`, `opacity` | `video_url` |
|
|
256
|
+
| `subtitle_video` | `video_url` | `language`, `font`, `font_size`, `color`, `bold`, `italic`, `outline_color`, `outline_width`, `shadow_size`, `shadow_color`, `background_style`, `background_color`, `alignment` | `video_url` |
|
|
257
|
+
| `generate_voiceover` | `text`, `voice` | — | `audio_url` |
|
|
258
|
+
| `add_audio` | `video_url`, `audio_url`, `mode` | `volume`, `loop`, `ducking` | `video_url` |
|
|
259
|
+
| `add_cover_art` | `video_url`, `image_url` | — | `video_url` |
|
|
260
|
+
| `create_video_slideshow` | `image_urls` | `slide_duration`, `transition`, `transition_duration`, `width`, `height` | `video_url` |
|
|
261
|
+
| `apply_color_filter` | `video_url`, `filter` | — | `video_url` |
|
|
262
|
+
| `soften_video` | `video_url`, `strength` | — | `video_url` |
|
|
263
|
+
|
|
264
|
+
Place the two overlay tools with **either** `position` (plus an optional `margin`) **or** `x`/`y` — not both. `position` accepts `top_left`, `top_center`, `top_right`, `center`, `bottom_left`, `bottom_center`, and `bottom_right`. `resize_video` accepts a `fit` of `cover` (crops), `contain` (letterboxes), or `blur` (fills the bars with a blurred copy).
|
|
265
|
+
|
|
266
|
+
A few examples:
|
|
267
|
+
|
|
268
|
+
```ruby
|
|
269
|
+
bb.remove_bg(image_url: "https://example.com/product.png")
|
|
270
|
+
|
|
271
|
+
# Corner placement, 40px in from each edge
|
|
272
|
+
bb.overlay_image(
|
|
273
|
+
video_url: "https://example.com/clip.mp4",
|
|
274
|
+
image_url: "https://example.com/logo.png",
|
|
275
|
+
position: "bottom_right",
|
|
276
|
+
margin: 40,
|
|
277
|
+
opacity: 0.8
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
bb.subtitle_video(
|
|
281
|
+
video_url: "https://example.com/talk.mp4",
|
|
282
|
+
font: "montserrat",
|
|
283
|
+
font_size: 32,
|
|
284
|
+
color: "#ffffff",
|
|
285
|
+
background_style: "outline",
|
|
286
|
+
alignment: "2"
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
bb.generate_voiceover(text: "Welcome to Bannerbear.", voice: "rachel")
|
|
290
|
+
|
|
291
|
+
bb.create_video_slideshow(
|
|
292
|
+
image_urls: ["https://example.com/1.jpg", "https://example.com/2.jpg"],
|
|
293
|
+
slide_duration: 3,
|
|
294
|
+
transition: "fade",
|
|
295
|
+
width: 1280,
|
|
296
|
+
height: 720
|
|
297
|
+
)
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
`create_tool_job` calls any tool by name — the escape hatch for tools added after this release:
|
|
301
|
+
|
|
302
|
+
```ruby
|
|
303
|
+
bb.create_tool_job("remove_bg", image_url: "https://example.com/product.png")
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### Assets (V5)
|
|
307
|
+
|
|
308
|
+
Upload a file (max 5MB) and get back a durable CDN URL you can feed to image modifications or tools. Uploads are deduplicated per workspace by SHA-256, so re-uploading the same bytes returns the existing record instead of creating a duplicate.
|
|
309
|
+
|
|
310
|
+
```ruby
|
|
311
|
+
asset = bb.upload_asset(File.binread("logo.png"), "image/png")
|
|
312
|
+
asset["url"]
|
|
313
|
+
|
|
314
|
+
bb.get_asset("asset uid")
|
|
315
|
+
bb.list_assets(page: 1)
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
Accepted mime types: `image/jpeg`, `image/png`, `image/webp`, `image/gif`, `video/mp4`, `video/webm`, `video/quicktime`, `audio/mpeg`, `audio/wav`, `audio/mp4`, `audio/webm`, `audio/ogg`, `application/pdf`.
|
|
319
|
+
|
|
320
|
+
`check_assets` maps each SHA-256 content hash to its existing asset (or `nil`), so a syncing client can skip the upload round-trip for content it already pushed. Max 100 hashes per call.
|
|
321
|
+
|
|
322
|
+
```ruby
|
|
323
|
+
digest = OpenSSL::Digest::SHA256.hexdigest(File.binread("logo.png"))
|
|
324
|
+
found = bb.check_assets([digest])
|
|
325
|
+
bb.upload_asset(File.binread("logo.png"), "image/png") if found[digest].nil?
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### Publications (V5)
|
|
329
|
+
|
|
330
|
+
Publications are templates published to the public library. Installing one clones it into your workspace as a new image template.
|
|
331
|
+
|
|
332
|
+
```ruby
|
|
333
|
+
bb.list_publications(page: 1)
|
|
334
|
+
bb.get_publication("publication uid")
|
|
335
|
+
|
|
336
|
+
template = bb.install_publication("publication uid")
|
|
337
|
+
template["uid"]
|
|
338
|
+
```
|
|
339
|
+
|
|
108
340
|
### Batches (V5)
|
|
109
341
|
|
|
110
342
|
Generate multiple images in one request (up to 100).
|
|
111
343
|
|
|
112
344
|
```ruby
|
|
113
345
|
bb.create_batch(
|
|
114
|
-
type: "
|
|
346
|
+
type: "images",
|
|
115
347
|
items: [
|
|
116
348
|
{ template: "template uid 1", modifications: { objects: [...] } },
|
|
117
349
|
{ template: "template uid 2", modifications: { objects: [...] } }
|
|
@@ -127,13 +359,11 @@ Webhooks are managed as a first-class resource in V5 (instead of being a per-req
|
|
|
127
359
|
|
|
128
360
|
```ruby
|
|
129
361
|
hook = bb.create_webhook(
|
|
130
|
-
name:
|
|
131
|
-
url:
|
|
132
|
-
resource:
|
|
133
|
-
event:
|
|
134
|
-
status:
|
|
135
|
-
scope: "all",
|
|
136
|
-
templates: []
|
|
362
|
+
name: "my-webhook",
|
|
363
|
+
url: "https://example.com/hook",
|
|
364
|
+
resource: "image",
|
|
365
|
+
event: "completed",
|
|
366
|
+
status: "active"
|
|
137
367
|
)
|
|
138
368
|
|
|
139
369
|
# IMPORTANT: signing_key is ONLY returned in the create response. Store it now —
|
|
@@ -141,6 +371,14 @@ hook = bb.create_webhook(
|
|
|
141
371
|
puts hook["signing_key"]
|
|
142
372
|
```
|
|
143
373
|
|
|
374
|
+
##### Options for `create_webhook` / `update_webhook`
|
|
375
|
+
|
|
376
|
+
- `name` *required* (`string`)
|
|
377
|
+
- `url` *required* — the URL that receives the events (`string`)
|
|
378
|
+
- `resource`: `"image"`, `"batch"`, `"tool_job"`, `"animation"`, or `"workflow_run"` (`string`)
|
|
379
|
+
- `event`: `"all_events"`, `"completed"`, or `"failed"` (`string`)
|
|
380
|
+
- `status`: `"active"` or `"disabled"` (`string`)
|
|
381
|
+
|
|
144
382
|
CRUD:
|
|
145
383
|
|
|
146
384
|
```ruby
|
|
@@ -150,8 +388,7 @@ bb.update_webhook("webhook uid",
|
|
|
150
388
|
url: "https://example.com/hook",
|
|
151
389
|
resource: "image",
|
|
152
390
|
event: "completed",
|
|
153
|
-
status: "active"
|
|
154
|
-
scope: "all"
|
|
391
|
+
status: "active"
|
|
155
392
|
)
|
|
156
393
|
bb.delete_webhook("webhook uid")
|
|
157
394
|
bb.list_webhooks(page: 1)
|
data/lib/bannerbear/v5/client.rb
CHANGED
|
@@ -21,8 +21,16 @@ module Bannerbear
|
|
|
21
21
|
get_response "/image_templates/#{uid}"
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
+
def create_image_template(payload = {})
|
|
25
|
+
post_response "/image_templates", payload.slice(:name, :description, :tags, :width, :height, :config)
|
|
26
|
+
end
|
|
27
|
+
|
|
24
28
|
def update_image_template(uid, payload = {})
|
|
25
|
-
patch_response "/image_templates/#{uid}", payload.slice(:name, :description, :tags)
|
|
29
|
+
patch_response "/image_templates/#{uid}", payload.slice(:name, :description, :tags, :width, :height, :config)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def delete_image_template(uid)
|
|
33
|
+
delete_response "/image_templates/#{uid}"
|
|
26
34
|
end
|
|
27
35
|
|
|
28
36
|
# Images
|
|
@@ -39,6 +47,162 @@ module Bannerbear
|
|
|
39
47
|
post_response "/images", payload.slice(:modifications, :formats, :scale, :dpi, :quality, :proxy, :metadata, :version).merge({:template => uid}), payload[:sync]
|
|
40
48
|
end
|
|
41
49
|
|
|
50
|
+
# Animation Templates
|
|
51
|
+
|
|
52
|
+
def list_animation_templates(params = {})
|
|
53
|
+
get_response "/animation_templates?#{URI.encode_www_form(params.slice(:page))}"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def get_animation_template(uid)
|
|
57
|
+
get_response "/animation_templates/#{uid}"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def create_animation_template(payload = {})
|
|
61
|
+
post_response "/animation_templates", payload.slice(:name, :description, :tags, :width, :height, :frame_rate)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def update_animation_template(uid, payload = {})
|
|
65
|
+
patch_response "/animation_templates/#{uid}", payload.slice(:name, :description, :tags, :width, :height, :frame_rate)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def delete_animation_template(uid)
|
|
69
|
+
delete_response "/animation_templates/#{uid}"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Animations
|
|
73
|
+
#
|
|
74
|
+
# Rendering is always asynchronous — there is no synchronous host for
|
|
75
|
+
# animations. Poll get_animation until the status is "completed" or
|
|
76
|
+
# "failed", or subscribe to a webhook with the resource "animation".
|
|
77
|
+
|
|
78
|
+
def list_animations(params = {})
|
|
79
|
+
get_response "/animations?#{URI.encode_www_form(params.slice(:page))}"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def get_animation(uid)
|
|
83
|
+
get_response "/animations/#{uid}"
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def create_animation(uid, payload = {})
|
|
87
|
+
post_response "/animations", payload.slice(:modifications, :formats, :metadata).merge({:template => uid})
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Workflows
|
|
91
|
+
|
|
92
|
+
def list_workflows(params = {})
|
|
93
|
+
get_response "/workflows?#{URI.encode_www_form(params.slice(:page))}"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def get_workflow(uid)
|
|
97
|
+
get_response "/workflows/#{uid}"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Workflow Runs
|
|
101
|
+
#
|
|
102
|
+
# A run is asynchronous. Poll get_workflow_run until the status is
|
|
103
|
+
# "completed" or "failed", or subscribe to a webhook with the resource
|
|
104
|
+
# "workflow_run".
|
|
105
|
+
|
|
106
|
+
def list_workflow_runs(params = {})
|
|
107
|
+
get_response "/workflow_runs?#{URI.encode_www_form(params.slice(:page))}"
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def get_workflow_run(uid)
|
|
111
|
+
get_response "/workflow_runs/#{uid}"
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def create_workflow_run(uid, payload = {})
|
|
115
|
+
post_response "/workflow_runs", payload.slice(:inputs).merge({:workflow => uid})
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Tools
|
|
119
|
+
#
|
|
120
|
+
# Every tool is asynchronous: the POST returns a pending tool job. Poll
|
|
121
|
+
# get_tool_job until the status is "completed" or "failed", or subscribe
|
|
122
|
+
# to a webhook with the resource "tool_job".
|
|
123
|
+
|
|
124
|
+
TOOL_PARAMS = {
|
|
125
|
+
"remove_bg" => [:image_url],
|
|
126
|
+
"create_pdf" => [:urls],
|
|
127
|
+
"trim_video" => [:video_url, :start, :end],
|
|
128
|
+
"concat_videos" => [:video_urls, :width, :height, :fps],
|
|
129
|
+
"resize_video" => [:video_url, :width, :height, :fit],
|
|
130
|
+
"crop_video" => [:video_url, :x, :y, :width, :height],
|
|
131
|
+
# Place the overlay with either :position (+ optional :margin) or :x/:y,
|
|
132
|
+
# not both.
|
|
133
|
+
"overlay_video" => [:base_video_url, :overlay_video_url, :x, :y, :position, :margin, :scale, :start],
|
|
134
|
+
"overlay_image" => [:video_url, :image_url, :x, :y, :position, :margin, :opacity],
|
|
135
|
+
"subtitle_video" => [:video_url, :language, :font, :font_size, :color, :bold, :italic,
|
|
136
|
+
:outline_color, :outline_width, :shadow_size, :shadow_color,
|
|
137
|
+
:background_style, :background_color, :alignment],
|
|
138
|
+
"generate_voiceover" => [:text, :voice],
|
|
139
|
+
"add_audio" => [:video_url, :audio_url, :mode, :volume, :loop, :ducking],
|
|
140
|
+
"add_cover_art" => [:video_url, :image_url],
|
|
141
|
+
"create_video_slideshow" => [:image_urls, :slide_duration, :transition, :transition_duration, :width, :height],
|
|
142
|
+
"apply_color_filter" => [:video_url, :filter],
|
|
143
|
+
"soften_video" => [:video_url, :strength]
|
|
144
|
+
}.freeze
|
|
145
|
+
|
|
146
|
+
def create_tool_job(tool, payload = {})
|
|
147
|
+
allowed = TOOL_PARAMS[tool.to_s]
|
|
148
|
+
raise ArgumentError, "unknown tool: #{tool.inspect}" if allowed.nil?
|
|
149
|
+
post_response "/tools/#{tool}", payload.slice(*allowed, :metadata)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Defines one method per tool, e.g. remove_bg(payload) or trim_video(payload).
|
|
153
|
+
TOOL_PARAMS.each_key do |tool|
|
|
154
|
+
define_method(tool) { |payload = {}| create_tool_job(tool, payload) }
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Tool Jobs
|
|
158
|
+
|
|
159
|
+
def list_tool_jobs(params = {})
|
|
160
|
+
get_response "/tool_jobs?#{URI.encode_www_form(params.slice(:page))}"
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def get_tool_job(uid)
|
|
164
|
+
get_response "/tool_jobs/#{uid}"
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Assets
|
|
168
|
+
|
|
169
|
+
def list_assets(params = {})
|
|
170
|
+
get_response "/assets?#{URI.encode_www_form(params.slice(:page))}"
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def get_asset(uid)
|
|
174
|
+
get_response "/assets/#{uid}"
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Uploads raw file bytes (max 5MB). content_type must be the mime type of
|
|
178
|
+
# the data, e.g. "image/png" or "video/mp4". Uploads are deduplicated per
|
|
179
|
+
# workspace by SHA-256, so re-uploading the same bytes returns the
|
|
180
|
+
# existing asset instead of creating a duplicate.
|
|
181
|
+
def upload_asset(data, content_type)
|
|
182
|
+
upload_response "/assets", data, content_type
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Returns a map of SHA-256 content hash => asset (or nil when the hash is
|
|
186
|
+
# not stored in this workspace). Max 100 hashes per call.
|
|
187
|
+
def check_assets(content_hashes)
|
|
188
|
+
post_response "/assets/check", { :content_hashes => content_hashes }
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# Publications
|
|
192
|
+
|
|
193
|
+
def list_publications(params = {})
|
|
194
|
+
get_response "/publications?#{URI.encode_www_form(params.slice(:page))}"
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def get_publication(uid)
|
|
198
|
+
get_response "/publications/#{uid}"
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# Clones a publication into the workspace as a new image template.
|
|
202
|
+
def install_publication(uid)
|
|
203
|
+
post_response "/publications/#{uid}/install", {}
|
|
204
|
+
end
|
|
205
|
+
|
|
42
206
|
# Batches
|
|
43
207
|
|
|
44
208
|
def list_batches(params = {})
|
|
@@ -64,11 +228,11 @@ module Bannerbear
|
|
|
64
228
|
end
|
|
65
229
|
|
|
66
230
|
def create_webhook(payload = {})
|
|
67
|
-
post_response "/webhooks", payload.slice(:name, :url, :resource, :event, :status
|
|
231
|
+
post_response "/webhooks", payload.slice(:name, :url, :resource, :event, :status)
|
|
68
232
|
end
|
|
69
233
|
|
|
70
234
|
def update_webhook(uid, payload = {})
|
|
71
|
-
patch_response "/webhooks/#{uid}", payload.slice(:name, :url, :resource, :event, :status
|
|
235
|
+
patch_response "/webhooks/#{uid}", payload.slice(:name, :url, :resource, :event, :status)
|
|
72
236
|
end
|
|
73
237
|
|
|
74
238
|
def delete_webhook(uid)
|
|
@@ -183,6 +347,20 @@ module Bannerbear
|
|
|
183
347
|
return body
|
|
184
348
|
end
|
|
185
349
|
|
|
350
|
+
def upload_response(url, data, content_type)
|
|
351
|
+
response = HTTParty.post("#{BB_API_ENDPOINT}#{url}",
|
|
352
|
+
body: data,
|
|
353
|
+
timeout: 30,
|
|
354
|
+
headers: {
|
|
355
|
+
'Authorization' => "Bearer #{@api_key}",
|
|
356
|
+
'Content-Type' => content_type
|
|
357
|
+
}
|
|
358
|
+
)
|
|
359
|
+
body = JSON.parse(response.body)
|
|
360
|
+
return {"error" => body['message'], "code" => response.code} if response.code >= 400
|
|
361
|
+
return body
|
|
362
|
+
end
|
|
363
|
+
|
|
186
364
|
def delete_response(url)
|
|
187
365
|
response = HTTParty.delete("#{BB_API_ENDPOINT}#{url}",
|
|
188
366
|
timeout: 5,
|
data/lib/bannerbear/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bannerbear
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jon Yongfook
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-08-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: httparty
|