convertorio-sdk 1.2.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 +7 -0
- data/CHANGELOG.md +107 -0
- data/LICENSE +21 -0
- data/README.md +547 -0
- data/lib/convertorio.rb +353 -0
- metadata +135 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 6b8ce9e583f4cb4a935ef71823e4599a7a3228ccff647e29fc002e57028bcefe
|
|
4
|
+
data.tar.gz: 1d4f19246026389a87b1d37d06c305609fc3fb93d67c6ee123efde14f9f0183d
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 7d925f1ffb56fff8351230e49c461acd0fcf0ea7d7bd739b6664c327f1a2477e8a668105f9eda35990f2d9fe6f3a39e385693793991dd300fb71d63d8b0de361
|
|
7
|
+
data.tar.gz: 06fb17ee887b5d8ec98b41ced91dde7e002b12dd995f4e9974ff5b79f6399c78587ce67aa752361ad23e4c9be1be9dc51e3375f9b7acb0877edb57df7d0ab1f9
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the Convertorio Ruby SDK will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.2.0] - 2025-01-21
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Initial release of the Convertorio Ruby SDK
|
|
12
|
+
- Core image conversion functionality
|
|
13
|
+
- Support for 20+ image formats (JPG, PNG, WebP, AVIF, HEIC, GIF, BMP, TIFF, ICO, etc.)
|
|
14
|
+
- Event-driven progress tracking with callbacks
|
|
15
|
+
- Automatic file upload and download
|
|
16
|
+
- Advanced conversion options:
|
|
17
|
+
- Aspect ratio control (original, 1:1, 4:3, 16:9, 9:16, 21:9, custom)
|
|
18
|
+
- Crop strategies (fit, crop-center, crop-top, crop-bottom, crop-left, crop-right)
|
|
19
|
+
- Quality control for lossy formats (1-100)
|
|
20
|
+
- ICO format with custom icon sizes (16, 32, 48, 64, 128, 256)
|
|
21
|
+
- Image resizing (resize_width, resize_height)
|
|
22
|
+
- Account management methods
|
|
23
|
+
- Get account information (`get_account`)
|
|
24
|
+
- List conversion jobs (`list_jobs`)
|
|
25
|
+
- Get job details (`get_job`)
|
|
26
|
+
- Comprehensive error handling with custom exception classes
|
|
27
|
+
- `Convertorio::Error` - Base error class
|
|
28
|
+
- `Convertorio::APIError` - API-related errors
|
|
29
|
+
- `Convertorio::FileNotFoundError` - File not found errors
|
|
30
|
+
- `Convertorio::ConversionTimeoutError` - Timeout errors
|
|
31
|
+
- Full documentation with examples
|
|
32
|
+
- RSpec test suite with WebMock
|
|
33
|
+
- YARD documentation support
|
|
34
|
+
|
|
35
|
+
### Features
|
|
36
|
+
- Simple, idiomatic Ruby API
|
|
37
|
+
- HTTParty for HTTP requests
|
|
38
|
+
- Thread-safe design
|
|
39
|
+
- Automatic output path generation
|
|
40
|
+
- Event system for progress tracking (start, progress, status, complete, error)
|
|
41
|
+
- Batch conversion support
|
|
42
|
+
- Poll-based job status checking with configurable intervals
|
|
43
|
+
|
|
44
|
+
### Documentation
|
|
45
|
+
- Comprehensive README with usage examples
|
|
46
|
+
- API reference documentation
|
|
47
|
+
- 5 example scripts:
|
|
48
|
+
- Basic conversion
|
|
49
|
+
- Event-driven conversion
|
|
50
|
+
- Batch conversion
|
|
51
|
+
- Account information
|
|
52
|
+
- Advanced options
|
|
53
|
+
- Complete test suite with 90%+ coverage
|
|
54
|
+
- Installation and setup guides
|
|
55
|
+
|
|
56
|
+
### Dependencies
|
|
57
|
+
- Ruby >= 2.7.0
|
|
58
|
+
- httparty ~> 0.21
|
|
59
|
+
- json ~> 2.6
|
|
60
|
+
|
|
61
|
+
### Development Dependencies
|
|
62
|
+
- bundler ~> 2.0
|
|
63
|
+
- rake ~> 13.0
|
|
64
|
+
- rspec ~> 3.12
|
|
65
|
+
- webmock ~> 3.18
|
|
66
|
+
|
|
67
|
+
## [Unreleased]
|
|
68
|
+
|
|
69
|
+
### Planned Features
|
|
70
|
+
- Async/parallel conversion support
|
|
71
|
+
- Progress bars for CLI usage
|
|
72
|
+
- Caching layer for repeated conversions
|
|
73
|
+
- Webhook support for job completion
|
|
74
|
+
- Bulk conversion with queue management
|
|
75
|
+
- Image metadata extraction
|
|
76
|
+
- Thumbnail generation helpers
|
|
77
|
+
- Cloud storage integrations (AWS S3, Google Cloud Storage, etc.)
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Version History
|
|
82
|
+
|
|
83
|
+
### Version Numbering
|
|
84
|
+
|
|
85
|
+
This project follows [Semantic Versioning](https://semver.org/):
|
|
86
|
+
- **MAJOR** version for incompatible API changes
|
|
87
|
+
- **MINOR** version for new functionality in a backward compatible manner
|
|
88
|
+
- **PATCH** version for backward compatible bug fixes
|
|
89
|
+
|
|
90
|
+
### Support Policy
|
|
91
|
+
|
|
92
|
+
- Latest version receives active development and bug fixes
|
|
93
|
+
- Previous minor version receives security fixes for 6 months
|
|
94
|
+
- Ruby version support follows Ruby's official EOL dates
|
|
95
|
+
|
|
96
|
+
### Migration Guides
|
|
97
|
+
|
|
98
|
+
#### From Future Versions
|
|
99
|
+
|
|
100
|
+
Migration guides will be added here when breaking changes are introduced.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
For more information, visit:
|
|
105
|
+
- Documentation: https://convertorio.com/docs
|
|
106
|
+
- Repository: https://github.com/SedeSoft/convertorio-sdk
|
|
107
|
+
- Support: support@convertorio.com
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Convertorio
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,547 @@
|
|
|
1
|
+
# Convertorio SDK for Ruby
|
|
2
|
+
|
|
3
|
+
Official Ruby SDK for the Convertorio API. Convert images between 20+ formats with just a few lines of code.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- ✅ Simple, clean Ruby API
|
|
8
|
+
- ✅ Event-driven progress tracking
|
|
9
|
+
- ✅ Automatic file upload and download
|
|
10
|
+
- ✅ Support for 20+ image formats
|
|
11
|
+
- ✅ Full YARD documentation
|
|
12
|
+
- ✅ Batch conversion support
|
|
13
|
+
- ✅ Comprehensive error handling
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
Add this line to your application's Gemfile:
|
|
18
|
+
|
|
19
|
+
```ruby
|
|
20
|
+
gem 'convertorio-sdk'
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
And then execute:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
bundle install
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Or install it yourself as:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
gem install convertorio-sdk
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Quick Start
|
|
36
|
+
|
|
37
|
+
```ruby
|
|
38
|
+
require 'convertorio'
|
|
39
|
+
|
|
40
|
+
# Initialize the client
|
|
41
|
+
client = Convertorio::Client.new(
|
|
42
|
+
api_key: 'your_api_key_here' # Get your API key from https://convertorio.com/account
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
# Convert an image
|
|
46
|
+
result = client.convert_file(
|
|
47
|
+
input_path: './image.png',
|
|
48
|
+
target_format: 'jpg'
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
puts "Converted! #{result[:output_path]}"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Configuration
|
|
55
|
+
|
|
56
|
+
### Creating a Client
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
client = Convertorio::Client.new(
|
|
60
|
+
api_key: 'your_api_key_here', # Required: Your API key
|
|
61
|
+
base_url: 'https://api.convertorio.com' # Optional: Custom API URL
|
|
62
|
+
)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Getting your API Key:**
|
|
66
|
+
1. Sign up at [convertorio.com](https://convertorio.com)
|
|
67
|
+
2. Go to your [Account Settings](https://convertorio.com/account)
|
|
68
|
+
3. Generate an API key
|
|
69
|
+
|
|
70
|
+
## API Reference
|
|
71
|
+
|
|
72
|
+
### `convert_file(options)`
|
|
73
|
+
|
|
74
|
+
Convert an image file from one format to another.
|
|
75
|
+
|
|
76
|
+
**Parameters:**
|
|
77
|
+
- `input_path` (String, required): Path to the input image file
|
|
78
|
+
- `target_format` (String, required): Target format (jpg, png, webp, avif, gif, bmp, tiff, ico, heic, etc.)
|
|
79
|
+
- `output_path` (String, optional): Custom output path. If not provided, uses the same directory as input with new extension
|
|
80
|
+
- `conversion_metadata` (Hash, optional): Advanced conversion options (see Advanced Options section below)
|
|
81
|
+
|
|
82
|
+
**Returns:** Hash with conversion result
|
|
83
|
+
|
|
84
|
+
**Example:**
|
|
85
|
+
|
|
86
|
+
```ruby
|
|
87
|
+
result = client.convert_file(
|
|
88
|
+
input_path: './photo.png',
|
|
89
|
+
target_format: 'webp',
|
|
90
|
+
output_path: './converted/photo.webp'
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
puts result
|
|
94
|
+
# {
|
|
95
|
+
# success: true,
|
|
96
|
+
# job_id: 'abc-123-def',
|
|
97
|
+
# input_path: './photo.png',
|
|
98
|
+
# output_path: './converted/photo.webp',
|
|
99
|
+
# source_format: 'png',
|
|
100
|
+
# target_format: 'webp',
|
|
101
|
+
# file_size: 45620,
|
|
102
|
+
# processing_time: 1250,
|
|
103
|
+
# download_url: 'https://...'
|
|
104
|
+
# }
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### `get_account()`
|
|
108
|
+
|
|
109
|
+
Get account information including points balance and usage.
|
|
110
|
+
|
|
111
|
+
**Returns:** Hash with account details
|
|
112
|
+
|
|
113
|
+
**Example:**
|
|
114
|
+
|
|
115
|
+
```ruby
|
|
116
|
+
account = client.get_account
|
|
117
|
+
|
|
118
|
+
puts account
|
|
119
|
+
# {
|
|
120
|
+
# 'id' => 'user-123',
|
|
121
|
+
# 'email' => 'user@example.com',
|
|
122
|
+
# 'name' => 'John Doe',
|
|
123
|
+
# 'plan' => 'free',
|
|
124
|
+
# 'points' => 100,
|
|
125
|
+
# 'daily_conversions_remaining' => 5,
|
|
126
|
+
# 'total_conversions' => 42
|
|
127
|
+
# }
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### `list_jobs(options)`
|
|
131
|
+
|
|
132
|
+
List your conversion jobs with optional filtering.
|
|
133
|
+
|
|
134
|
+
**Parameters:**
|
|
135
|
+
- `limit` (Integer, optional): Number of jobs to return (default: 50, max: 100)
|
|
136
|
+
- `offset` (Integer, optional): Offset for pagination (default: 0)
|
|
137
|
+
- `status` (String, optional): Filter by status ('completed', 'failed', 'processing', etc.)
|
|
138
|
+
|
|
139
|
+
**Returns:** Array of job hashes
|
|
140
|
+
|
|
141
|
+
**Example:**
|
|
142
|
+
|
|
143
|
+
```ruby
|
|
144
|
+
jobs = client.list_jobs(limit: 10, status: 'completed')
|
|
145
|
+
|
|
146
|
+
puts jobs
|
|
147
|
+
# [
|
|
148
|
+
# {
|
|
149
|
+
# 'id' => 'job-123',
|
|
150
|
+
# 'status' => 'completed',
|
|
151
|
+
# 'original_filename' => 'photo.png',
|
|
152
|
+
# 'source_format' => 'png',
|
|
153
|
+
# 'target_format' => 'jpg',
|
|
154
|
+
# 'processing_time_ms' => 1200,
|
|
155
|
+
# 'created_at' => '2025-01-20T10:30:00Z'
|
|
156
|
+
# },
|
|
157
|
+
# ...
|
|
158
|
+
# ]
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### `get_job(job_id)`
|
|
162
|
+
|
|
163
|
+
Get details for a specific conversion job.
|
|
164
|
+
|
|
165
|
+
**Parameters:**
|
|
166
|
+
- `job_id` (String, required): The job ID
|
|
167
|
+
|
|
168
|
+
**Returns:** Hash with job details
|
|
169
|
+
|
|
170
|
+
**Example:**
|
|
171
|
+
|
|
172
|
+
```ruby
|
|
173
|
+
job = client.get_job('job-123')
|
|
174
|
+
|
|
175
|
+
puts job
|
|
176
|
+
# {
|
|
177
|
+
# 'id' => 'job-123',
|
|
178
|
+
# 'status' => 'completed',
|
|
179
|
+
# 'original_filename' => 'photo.png',
|
|
180
|
+
# 'download_url' => 'https://...',
|
|
181
|
+
# ...
|
|
182
|
+
# }
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Events
|
|
186
|
+
|
|
187
|
+
The client supports event callbacks for tracking conversion progress:
|
|
188
|
+
|
|
189
|
+
### Event: `start`
|
|
190
|
+
|
|
191
|
+
Emitted when conversion starts.
|
|
192
|
+
|
|
193
|
+
```ruby
|
|
194
|
+
client.on(:start) do |data|
|
|
195
|
+
puts "Starting: #{data[:file_name]}"
|
|
196
|
+
puts "Converting #{data[:source_format]} to #{data[:target_format]}"
|
|
197
|
+
end
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Event: `progress`
|
|
201
|
+
|
|
202
|
+
Emitted at each step of the conversion process.
|
|
203
|
+
|
|
204
|
+
```ruby
|
|
205
|
+
client.on(:progress) do |data|
|
|
206
|
+
puts "Step: #{data[:step]}"
|
|
207
|
+
puts "Message: #{data[:message]}"
|
|
208
|
+
# data[:step] can be:
|
|
209
|
+
# - 'requesting-upload-url'
|
|
210
|
+
# - 'uploading'
|
|
211
|
+
# - 'confirming'
|
|
212
|
+
# - 'converting'
|
|
213
|
+
# - 'downloading'
|
|
214
|
+
end
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Event: `status`
|
|
218
|
+
|
|
219
|
+
Emitted during polling for job completion.
|
|
220
|
+
|
|
221
|
+
```ruby
|
|
222
|
+
client.on(:status) do |data|
|
|
223
|
+
puts "Status: #{data[:status]}"
|
|
224
|
+
puts "Attempt: #{data[:attempt]}/#{data[:max_attempts]}"
|
|
225
|
+
end
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Event: `complete`
|
|
229
|
+
|
|
230
|
+
Emitted when conversion completes successfully.
|
|
231
|
+
|
|
232
|
+
```ruby
|
|
233
|
+
client.on(:complete) do |result|
|
|
234
|
+
puts 'Conversion complete!'
|
|
235
|
+
puts "Output: #{result[:output_path]}"
|
|
236
|
+
puts "Size: #{result[:file_size]} bytes"
|
|
237
|
+
puts "Time: #{result[:processing_time]} ms"
|
|
238
|
+
end
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Event: `error`
|
|
242
|
+
|
|
243
|
+
Emitted when an error occurs.
|
|
244
|
+
|
|
245
|
+
```ruby
|
|
246
|
+
client.on(:error) do |data|
|
|
247
|
+
puts "Conversion failed: #{data[:error]}"
|
|
248
|
+
end
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Supported Formats
|
|
252
|
+
|
|
253
|
+
The SDK supports conversion between all formats supported by Convertorio:
|
|
254
|
+
|
|
255
|
+
**Common Formats:**
|
|
256
|
+
- JPG/JPEG
|
|
257
|
+
- PNG
|
|
258
|
+
- WebP
|
|
259
|
+
- AVIF
|
|
260
|
+
- GIF
|
|
261
|
+
- BMP
|
|
262
|
+
- TIFF
|
|
263
|
+
|
|
264
|
+
**Advanced Formats:**
|
|
265
|
+
- HEIC/HEIF (iPhone photos)
|
|
266
|
+
- ICO (icons)
|
|
267
|
+
- SVG (vectors)
|
|
268
|
+
- RAW formats (CR2, NEF, DNG)
|
|
269
|
+
- PDF
|
|
270
|
+
- PSD (Photoshop)
|
|
271
|
+
- AI (Adobe Illustrator)
|
|
272
|
+
- EPS
|
|
273
|
+
- JXL (JPEG XL)
|
|
274
|
+
|
|
275
|
+
## Advanced Conversion Options
|
|
276
|
+
|
|
277
|
+
You can control various aspects of the conversion process by passing a `conversion_metadata` hash:
|
|
278
|
+
|
|
279
|
+
### Aspect Ratio Control
|
|
280
|
+
|
|
281
|
+
Change the aspect ratio of the output image:
|
|
282
|
+
|
|
283
|
+
```ruby
|
|
284
|
+
client.convert_file(
|
|
285
|
+
input_path: './photo.jpg',
|
|
286
|
+
target_format: 'png',
|
|
287
|
+
conversion_metadata: {
|
|
288
|
+
aspect_ratio: '16:9', # Target aspect ratio
|
|
289
|
+
crop_strategy: 'crop-center' # How to handle the change
|
|
290
|
+
}
|
|
291
|
+
)
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
**Available aspect ratios:**
|
|
295
|
+
- `'original'` - Keep original aspect ratio (default)
|
|
296
|
+
- `'1:1'` - Square (Instagram, profile photos)
|
|
297
|
+
- `'4:3'` - Standard photo/video
|
|
298
|
+
- `'16:9'` - Widescreen video, HD
|
|
299
|
+
- `'9:16'` - Vertical/portrait video (TikTok, Stories)
|
|
300
|
+
- `'21:9'` - Ultra-widescreen
|
|
301
|
+
- Custom ratios like `'16:10'`, `'3:2'`, etc.
|
|
302
|
+
|
|
303
|
+
**Crop strategies:**
|
|
304
|
+
- `'fit'` - Contain image with padding (letterbox/pillarbox)
|
|
305
|
+
- `'crop-center'` - Crop from center
|
|
306
|
+
- `'crop-top'` - Crop aligned to top
|
|
307
|
+
- `'crop-bottom'` - Crop aligned to bottom
|
|
308
|
+
- `'crop-left'` - Crop aligned to left
|
|
309
|
+
- `'crop-right'` - Crop aligned to right
|
|
310
|
+
|
|
311
|
+
### Quality Control
|
|
312
|
+
|
|
313
|
+
Adjust compression quality for lossy formats (JPG, WebP, AVIF):
|
|
314
|
+
|
|
315
|
+
```ruby
|
|
316
|
+
client.convert_file(
|
|
317
|
+
input_path: './photo.png',
|
|
318
|
+
target_format: 'jpg',
|
|
319
|
+
conversion_metadata: {
|
|
320
|
+
quality: 90 # 1-100, default is 85
|
|
321
|
+
}
|
|
322
|
+
)
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
**Quality guidelines:**
|
|
326
|
+
- `90-100` - Excellent quality, large files
|
|
327
|
+
- `80-90` - High quality, good balance (recommended)
|
|
328
|
+
- `70-80` - Good quality, smaller files
|
|
329
|
+
- `50-70` - Medium quality, small files
|
|
330
|
+
- `1-50` - Low quality, very small files
|
|
331
|
+
|
|
332
|
+
### ICO Format Options
|
|
333
|
+
|
|
334
|
+
When converting to ICO format, specify the icon size:
|
|
335
|
+
|
|
336
|
+
```ruby
|
|
337
|
+
client.convert_file(
|
|
338
|
+
input_path: './logo.png',
|
|
339
|
+
target_format: 'ico',
|
|
340
|
+
conversion_metadata: {
|
|
341
|
+
icon_size: 32, # 16, 32, 48, 64, 128, or 256
|
|
342
|
+
crop_strategy: 'crop-center' # How to make it square
|
|
343
|
+
}
|
|
344
|
+
)
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
**Available icon sizes:** 16, 32, 48, 64, 128, 256 pixels
|
|
348
|
+
|
|
349
|
+
### Resize Control
|
|
350
|
+
|
|
351
|
+
Resize images to specific dimensions while maintaining aspect ratio:
|
|
352
|
+
|
|
353
|
+
```ruby
|
|
354
|
+
# Resize by width (height calculated automatically)
|
|
355
|
+
client.convert_file(
|
|
356
|
+
input_path: './photo.jpg',
|
|
357
|
+
target_format: 'jpg',
|
|
358
|
+
conversion_metadata: {
|
|
359
|
+
resize_width: 800 # Height will be calculated to maintain aspect ratio
|
|
360
|
+
}
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
# Resize by height (width calculated automatically)
|
|
364
|
+
client.convert_file(
|
|
365
|
+
input_path: './photo.jpg',
|
|
366
|
+
target_format: 'jpg',
|
|
367
|
+
conversion_metadata: {
|
|
368
|
+
resize_height: 600 # Width will be calculated to maintain aspect ratio
|
|
369
|
+
}
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
# Resize to exact dimensions (may distort image)
|
|
373
|
+
client.convert_file(
|
|
374
|
+
input_path: './photo.jpg',
|
|
375
|
+
target_format: 'jpg',
|
|
376
|
+
conversion_metadata: {
|
|
377
|
+
resize_width: 800,
|
|
378
|
+
resize_height: 600 # Forces exact dimensions
|
|
379
|
+
}
|
|
380
|
+
)
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
**Resize guidelines:**
|
|
384
|
+
- Specify only `resize_width` to scale by width (maintains aspect ratio)
|
|
385
|
+
- Specify only `resize_height` to scale by height (maintains aspect ratio)
|
|
386
|
+
- Specify both to force exact dimensions (may distort if ratios don't match)
|
|
387
|
+
- Range: 1-10000 pixels
|
|
388
|
+
- Can be combined with aspect ratio and crop strategy for advanced control
|
|
389
|
+
|
|
390
|
+
### Complete Example
|
|
391
|
+
|
|
392
|
+
```ruby
|
|
393
|
+
result = client.convert_file(
|
|
394
|
+
input_path: './photo.jpg',
|
|
395
|
+
target_format: 'webp',
|
|
396
|
+
output_path: './output/photo-optimized.webp',
|
|
397
|
+
conversion_metadata: {
|
|
398
|
+
aspect_ratio: '16:9',
|
|
399
|
+
crop_strategy: 'crop-center',
|
|
400
|
+
quality: 85,
|
|
401
|
+
resize_width: 1920 # Final width after aspect ratio change
|
|
402
|
+
}
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
puts "Converted with custom options! #{result}"
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
## Examples
|
|
409
|
+
|
|
410
|
+
### Basic Conversion
|
|
411
|
+
|
|
412
|
+
```ruby
|
|
413
|
+
require 'convertorio'
|
|
414
|
+
|
|
415
|
+
client = Convertorio::Client.new(api_key: 'your_api_key_here')
|
|
416
|
+
|
|
417
|
+
result = client.convert_file(
|
|
418
|
+
input_path: './input.png',
|
|
419
|
+
target_format: 'jpg'
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
puts "Done! #{result[:output_path]}"
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
### With Progress Events
|
|
426
|
+
|
|
427
|
+
```ruby
|
|
428
|
+
require 'convertorio'
|
|
429
|
+
|
|
430
|
+
client = Convertorio::Client.new(api_key: 'your_api_key_here')
|
|
431
|
+
|
|
432
|
+
client.on(:progress) do |data|
|
|
433
|
+
puts "[#{data[:step]}] #{data[:message]}"
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
client.on(:complete) do |result|
|
|
437
|
+
puts '✓ Conversion completed!'
|
|
438
|
+
puts "Output: #{result[:output_path]}"
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
client.convert_file(
|
|
442
|
+
input_path: './photo.png',
|
|
443
|
+
target_format: 'webp'
|
|
444
|
+
)
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
### Batch Conversion
|
|
448
|
+
|
|
449
|
+
```ruby
|
|
450
|
+
require 'convertorio'
|
|
451
|
+
|
|
452
|
+
client = Convertorio::Client.new(api_key: 'your_api_key_here')
|
|
453
|
+
|
|
454
|
+
# Get all PNG files
|
|
455
|
+
files = Dir.glob('./images/*.png')
|
|
456
|
+
|
|
457
|
+
# Convert all to WebP
|
|
458
|
+
files.each do |file|
|
|
459
|
+
client.convert_file(
|
|
460
|
+
input_path: file,
|
|
461
|
+
target_format: 'webp'
|
|
462
|
+
)
|
|
463
|
+
puts "Converted: #{file}"
|
|
464
|
+
end
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
### Error Handling
|
|
468
|
+
|
|
469
|
+
```ruby
|
|
470
|
+
require 'convertorio'
|
|
471
|
+
|
|
472
|
+
client = Convertorio::Client.new(api_key: 'your_api_key_here')
|
|
473
|
+
|
|
474
|
+
begin
|
|
475
|
+
result = client.convert_file(
|
|
476
|
+
input_path: './image.png',
|
|
477
|
+
target_format: 'jpg'
|
|
478
|
+
)
|
|
479
|
+
puts "Success: #{result[:output_path]}"
|
|
480
|
+
rescue Convertorio::FileNotFoundError => e
|
|
481
|
+
puts "Input file does not exist: #{e.message}"
|
|
482
|
+
rescue Convertorio::APIError => e
|
|
483
|
+
puts "API error: #{e.message}"
|
|
484
|
+
puts "Not enough points/credits" if e.message.include?('Insufficient')
|
|
485
|
+
rescue Convertorio::ConversionTimeoutError => e
|
|
486
|
+
puts "Conversion took too long: #{e.message}"
|
|
487
|
+
rescue Convertorio::Error => e
|
|
488
|
+
puts "Conversion failed: #{e.message}"
|
|
489
|
+
end
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
## Rate Limiting
|
|
493
|
+
|
|
494
|
+
The API has the following rate limits:
|
|
495
|
+
- **1 request per second** per IP address
|
|
496
|
+
- **5 concurrent jobs** maximum per user
|
|
497
|
+
|
|
498
|
+
The SDK automatically handles rate limiting by polling job status with appropriate delays.
|
|
499
|
+
|
|
500
|
+
## Error Handling
|
|
501
|
+
|
|
502
|
+
Common errors you might encounter:
|
|
503
|
+
|
|
504
|
+
| Error | Description | Solution |
|
|
505
|
+
|-------|-------------|----------|
|
|
506
|
+
| `Convertorio::Error` | API key missing | Provide your API key in the config |
|
|
507
|
+
| `Convertorio::FileNotFoundError` | File doesn't exist | Check the file path |
|
|
508
|
+
| `Convertorio::APIError` | API request failed | Check error message for details |
|
|
509
|
+
| `Convertorio::ConversionTimeoutError` | Job took too long | Try again or contact support |
|
|
510
|
+
|
|
511
|
+
**API Error Messages:**
|
|
512
|
+
- `Invalid API key` - Wrong or expired API key (verify in account settings)
|
|
513
|
+
- `Insufficient credits` - Not enough points (purchase more or use free tier)
|
|
514
|
+
- `File size exceeds limit` - Maximum file size is 20 MB
|
|
515
|
+
- `Unsupported format` - Format not supported
|
|
516
|
+
|
|
517
|
+
## Best Practices
|
|
518
|
+
|
|
519
|
+
1. **Reuse the client instance** - Don't create a new client for each conversion
|
|
520
|
+
2. **Use events for long conversions** - Monitor progress instead of just waiting
|
|
521
|
+
3. **Handle errors gracefully** - Always use rescue blocks for conversions
|
|
522
|
+
4. **Respect rate limits** - Use batch processing with delays if converting many files
|
|
523
|
+
5. **Check file sizes** - Maximum file size is 20 MB
|
|
524
|
+
6. **Validate formats** - Check that the target format is supported
|
|
525
|
+
|
|
526
|
+
## Development
|
|
527
|
+
|
|
528
|
+
After checking out the repo, run `bundle install` to install dependencies. Then, run `rake spec` to run the tests.
|
|
529
|
+
|
|
530
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
|
531
|
+
|
|
532
|
+
To release a new version, update the version number in `convertorio-sdk.gemspec`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
533
|
+
|
|
534
|
+
## Support
|
|
535
|
+
|
|
536
|
+
- **Documentation:** [https://convertorio.com/docs](https://convertorio.com/docs)
|
|
537
|
+
- **API Reference:** [https://convertorio.com/api-docs](https://convertorio.com/api-docs)
|
|
538
|
+
- **Support:** [support@convertorio.com](mailto:support@convertorio.com)
|
|
539
|
+
- **GitHub Issues:** [https://github.com/convertorio/sdk/issues](https://github.com/convertorio/sdk/issues)
|
|
540
|
+
|
|
541
|
+
## License
|
|
542
|
+
|
|
543
|
+
MIT License - see LICENSE file for details
|
|
544
|
+
|
|
545
|
+
## Contributing
|
|
546
|
+
|
|
547
|
+
Contributions are welcome! Please see [CONTRIBUTING.md](../../CONTRIBUTING.md) for guidelines.
|
data/lib/convertorio.rb
ADDED
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
require 'httparty'
|
|
2
|
+
require 'json'
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
|
|
5
|
+
module Convertorio
|
|
6
|
+
class Error < StandardError; end
|
|
7
|
+
class APIError < Error; end
|
|
8
|
+
class FileNotFoundError < Error; end
|
|
9
|
+
class ConversionTimeoutError < Error; end
|
|
10
|
+
|
|
11
|
+
# Main client class for Convertorio API
|
|
12
|
+
class Client
|
|
13
|
+
include HTTParty
|
|
14
|
+
|
|
15
|
+
attr_reader :api_key, :base_url
|
|
16
|
+
|
|
17
|
+
# Initialize a new Convertorio client
|
|
18
|
+
#
|
|
19
|
+
# @param api_key [String] Your Convertorio API key (required)
|
|
20
|
+
# @param base_url [String] API base URL (optional, defaults to https://api.convertorio.com)
|
|
21
|
+
#
|
|
22
|
+
# @example
|
|
23
|
+
# client = Convertorio::Client.new(api_key: 'your_api_key_here')
|
|
24
|
+
#
|
|
25
|
+
def initialize(api_key:, base_url: 'https://api.convertorio.com')
|
|
26
|
+
raise Error, 'API key is required. Get yours at https://convertorio.com/account' if api_key.nil? || api_key.empty?
|
|
27
|
+
|
|
28
|
+
@api_key = api_key
|
|
29
|
+
@base_url = base_url
|
|
30
|
+
@callbacks = {}
|
|
31
|
+
|
|
32
|
+
self.class.base_uri @base_url
|
|
33
|
+
self.class.headers(
|
|
34
|
+
'Authorization' => "Bearer #{@api_key}",
|
|
35
|
+
'Content-Type' => 'application/json'
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Register a callback for events
|
|
40
|
+
#
|
|
41
|
+
# @param event [Symbol] Event name (:start, :progress, :status, :complete, :error)
|
|
42
|
+
# @param block [Proc] Block to execute when event occurs
|
|
43
|
+
#
|
|
44
|
+
# @example
|
|
45
|
+
# client.on(:progress) { |data| puts "Progress: #{data[:message]}" }
|
|
46
|
+
#
|
|
47
|
+
def on(event, &block)
|
|
48
|
+
@callbacks[event] ||= []
|
|
49
|
+
@callbacks[event] << block
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Convert an image file
|
|
53
|
+
#
|
|
54
|
+
# @param input_path [String] Path to the input file (required)
|
|
55
|
+
# @param target_format [String] Target format (jpg, png, webp, avif, etc.) (required)
|
|
56
|
+
# @param output_path [String] Output path (optional, auto-generated if not provided)
|
|
57
|
+
# @param conversion_metadata [Hash] Advanced conversion options (optional)
|
|
58
|
+
# @option conversion_metadata [String] :aspect_ratio Target aspect ratio (original, 1:1, 4:3, 16:9, 9:16, 21:9, custom)
|
|
59
|
+
# @option conversion_metadata [String] :crop_strategy Crop strategy (fit, crop-center, crop-top, crop-bottom, crop-left, crop-right)
|
|
60
|
+
# @option conversion_metadata [Integer] :quality Compression quality 1-100 (for JPG, WebP, AVIF)
|
|
61
|
+
# @option conversion_metadata [Integer] :icon_size Icon size in pixels (for ICO format: 16, 32, 48, 64, 128, 256)
|
|
62
|
+
# @option conversion_metadata [Integer] :resize_width Target width in pixels (height calculated automatically)
|
|
63
|
+
# @option conversion_metadata [Integer] :resize_height Target height in pixels (width calculated automatically)
|
|
64
|
+
#
|
|
65
|
+
# @return [Hash] Conversion result with download URL and file path
|
|
66
|
+
#
|
|
67
|
+
# @example Basic conversion
|
|
68
|
+
# result = client.convert_file(
|
|
69
|
+
# input_path: './image.png',
|
|
70
|
+
# target_format: 'jpg'
|
|
71
|
+
# )
|
|
72
|
+
#
|
|
73
|
+
# @example With conversion options
|
|
74
|
+
# result = client.convert_file(
|
|
75
|
+
# input_path: './photo.jpg',
|
|
76
|
+
# target_format: 'webp',
|
|
77
|
+
# output_path: './output/photo.webp',
|
|
78
|
+
# conversion_metadata: {
|
|
79
|
+
# aspect_ratio: '16:9',
|
|
80
|
+
# crop_strategy: 'crop-center',
|
|
81
|
+
# quality: 85,
|
|
82
|
+
# resize_width: 1920
|
|
83
|
+
# }
|
|
84
|
+
# )
|
|
85
|
+
#
|
|
86
|
+
def convert_file(input_path: nil, target_format: nil, output_path: nil, conversion_metadata: {})
|
|
87
|
+
raise Error, 'input_path is required' if input_path.nil? || input_path.empty?
|
|
88
|
+
raise Error, 'target_format is required' if target_format.nil? || target_format.empty?
|
|
89
|
+
raise FileNotFoundError, "Input file not found: #{input_path}" unless File.exist?(input_path)
|
|
90
|
+
|
|
91
|
+
file_stats = File.stat(input_path)
|
|
92
|
+
file_name = File.basename(input_path)
|
|
93
|
+
source_format = File.extname(input_path).delete('.').downcase
|
|
94
|
+
|
|
95
|
+
emit(:start, {
|
|
96
|
+
file_name: file_name,
|
|
97
|
+
source_format: source_format,
|
|
98
|
+
target_format: target_format
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
begin
|
|
102
|
+
# Step 1: Request upload URL
|
|
103
|
+
emit(:progress, {
|
|
104
|
+
step: 'requesting-upload-url',
|
|
105
|
+
message: 'Requesting upload URL from server...'
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
request_body = {
|
|
109
|
+
filename: file_name,
|
|
110
|
+
source_format: source_format,
|
|
111
|
+
target_format: target_format.downcase,
|
|
112
|
+
file_size: file_stats.size
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
# Add conversion metadata if provided
|
|
116
|
+
request_body[:conversion_metadata] = conversion_metadata unless conversion_metadata.empty?
|
|
117
|
+
|
|
118
|
+
upload_response = self.class.post('/v1/convert/upload-url', body: request_body.to_json)
|
|
119
|
+
upload_data = parse_response(upload_response)
|
|
120
|
+
|
|
121
|
+
raise APIError, upload_data['error'] || 'Failed to get upload URL' unless upload_data['success']
|
|
122
|
+
|
|
123
|
+
job_id = upload_data['job_id']
|
|
124
|
+
upload_url = upload_data['upload_url']
|
|
125
|
+
|
|
126
|
+
emit(:progress, {
|
|
127
|
+
step: 'uploading',
|
|
128
|
+
message: 'Uploading file to cloud storage...',
|
|
129
|
+
job_id: job_id
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
# Step 2: Upload file to S3
|
|
133
|
+
file_content = File.binread(input_path)
|
|
134
|
+
HTTParty.put(upload_url, {
|
|
135
|
+
body: file_content,
|
|
136
|
+
headers: { 'Content-Type' => "image/#{source_format}" }
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
emit(:progress, {
|
|
140
|
+
step: 'confirming',
|
|
141
|
+
message: 'Confirming upload and queuing conversion...',
|
|
142
|
+
job_id: job_id
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
# Step 3: Confirm upload and queue conversion
|
|
146
|
+
confirm_response = self.class.post('/v1/convert/confirm', body: { job_id: job_id }.to_json)
|
|
147
|
+
confirm_data = parse_response(confirm_response)
|
|
148
|
+
|
|
149
|
+
raise APIError, confirm_data['error'] || 'Failed to confirm upload' unless confirm_data['success']
|
|
150
|
+
|
|
151
|
+
emit(:progress, {
|
|
152
|
+
step: 'converting',
|
|
153
|
+
message: 'Converting image...',
|
|
154
|
+
job_id: job_id,
|
|
155
|
+
status: confirm_data['status']
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
# Step 4: Poll for completion
|
|
159
|
+
job_result = poll_job_status(job_id)
|
|
160
|
+
|
|
161
|
+
emit(:progress, {
|
|
162
|
+
step: 'downloading',
|
|
163
|
+
message: 'Downloading converted file...',
|
|
164
|
+
job_id: job_id
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
# Step 5: Download converted file
|
|
168
|
+
final_output_path = output_path || generate_output_path(input_path, target_format)
|
|
169
|
+
download_file(job_result['download_url'], final_output_path)
|
|
170
|
+
|
|
171
|
+
conversion_result = {
|
|
172
|
+
success: true,
|
|
173
|
+
job_id: job_id,
|
|
174
|
+
input_path: input_path,
|
|
175
|
+
output_path: final_output_path,
|
|
176
|
+
source_format: source_format,
|
|
177
|
+
target_format: target_format.downcase,
|
|
178
|
+
file_size: File.size(final_output_path),
|
|
179
|
+
processing_time: job_result['processing_time_ms'],
|
|
180
|
+
download_url: job_result['download_url']
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
emit(:complete, conversion_result)
|
|
184
|
+
|
|
185
|
+
conversion_result
|
|
186
|
+
|
|
187
|
+
rescue => error
|
|
188
|
+
error_details = {
|
|
189
|
+
success: false,
|
|
190
|
+
error: error.message,
|
|
191
|
+
input_path: input_path,
|
|
192
|
+
target_format: target_format
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
emit(:error, error_details)
|
|
196
|
+
raise error
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# Get account information
|
|
201
|
+
#
|
|
202
|
+
# @return [Hash] Account details including points balance and usage
|
|
203
|
+
#
|
|
204
|
+
# @example
|
|
205
|
+
# account = client.get_account
|
|
206
|
+
# puts "Points: #{account['points']}"
|
|
207
|
+
#
|
|
208
|
+
def get_account
|
|
209
|
+
response = self.class.get('/v1/account')
|
|
210
|
+
data = parse_response(response)
|
|
211
|
+
|
|
212
|
+
raise APIError, data['error'] || 'Failed to get account info' unless data['success']
|
|
213
|
+
|
|
214
|
+
data['account']
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# List conversion jobs
|
|
218
|
+
#
|
|
219
|
+
# @param limit [Integer] Number of jobs to return (default: 50, max: 100)
|
|
220
|
+
# @param offset [Integer] Offset for pagination (default: 0)
|
|
221
|
+
# @param status [String] Filter by status (completed, failed, processing, etc.)
|
|
222
|
+
#
|
|
223
|
+
# @return [Array<Hash>] List of jobs
|
|
224
|
+
#
|
|
225
|
+
# @example
|
|
226
|
+
# jobs = client.list_jobs(limit: 10, status: 'completed')
|
|
227
|
+
# jobs.each { |job| puts "Job #{job['id']}: #{job['status']}" }
|
|
228
|
+
#
|
|
229
|
+
def list_jobs(limit: 50, offset: 0, status: nil)
|
|
230
|
+
query = { limit: limit, offset: offset }
|
|
231
|
+
query[:status] = status if status
|
|
232
|
+
|
|
233
|
+
response = self.class.get('/v1/jobs', query: query)
|
|
234
|
+
data = parse_response(response)
|
|
235
|
+
|
|
236
|
+
raise APIError, data['error'] || 'Failed to list jobs' unless data['success']
|
|
237
|
+
|
|
238
|
+
data['jobs']
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# Get job status
|
|
242
|
+
#
|
|
243
|
+
# @param job_id [String] Job ID
|
|
244
|
+
#
|
|
245
|
+
# @return [Hash] Job details
|
|
246
|
+
#
|
|
247
|
+
# @example
|
|
248
|
+
# job = client.get_job('job-123')
|
|
249
|
+
# puts "Status: #{job['status']}"
|
|
250
|
+
#
|
|
251
|
+
def get_job(job_id)
|
|
252
|
+
response = self.class.get("/v1/jobs/#{job_id}")
|
|
253
|
+
data = parse_response(response)
|
|
254
|
+
|
|
255
|
+
raise APIError, data['error'] || 'Failed to get job' unless data['success']
|
|
256
|
+
|
|
257
|
+
data['job']
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
private
|
|
261
|
+
|
|
262
|
+
# Poll job status until completion
|
|
263
|
+
#
|
|
264
|
+
# @param job_id [String] Job ID to poll
|
|
265
|
+
# @param max_attempts [Integer] Maximum polling attempts (default: 60)
|
|
266
|
+
# @param interval [Integer] Polling interval in seconds (default: 2)
|
|
267
|
+
#
|
|
268
|
+
# @return [Hash] Job result
|
|
269
|
+
#
|
|
270
|
+
def poll_job_status(job_id, max_attempts: 60, interval: 2)
|
|
271
|
+
attempts = 0
|
|
272
|
+
|
|
273
|
+
while attempts < max_attempts
|
|
274
|
+
attempts += 1
|
|
275
|
+
|
|
276
|
+
# Wait before polling (except first attempt)
|
|
277
|
+
sleep(interval) if attempts > 1
|
|
278
|
+
|
|
279
|
+
response = self.class.get("/v1/jobs/#{job_id}")
|
|
280
|
+
data = parse_response(response)
|
|
281
|
+
|
|
282
|
+
raise APIError, 'Failed to get job status' unless data['success']
|
|
283
|
+
|
|
284
|
+
job = data['job']
|
|
285
|
+
status = job['status']
|
|
286
|
+
|
|
287
|
+
emit(:status, {
|
|
288
|
+
job_id: job_id,
|
|
289
|
+
status: status,
|
|
290
|
+
attempt: attempts,
|
|
291
|
+
max_attempts: max_attempts
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
return job if status == 'completed'
|
|
295
|
+
raise APIError, job['error_message'] || 'Conversion failed' if status == 'failed'
|
|
296
|
+
raise APIError, 'Job expired' if status == 'expired'
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
raise ConversionTimeoutError, 'Conversion timeout - job did not complete in time'
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
# Download file from URL
|
|
303
|
+
#
|
|
304
|
+
# @param url [String] Download URL
|
|
305
|
+
# @param output_path [String] Output file path
|
|
306
|
+
#
|
|
307
|
+
def download_file(url, output_path)
|
|
308
|
+
response = HTTParty.get(url)
|
|
309
|
+
|
|
310
|
+
# Ensure output directory exists
|
|
311
|
+
output_dir = File.dirname(output_path)
|
|
312
|
+
FileUtils.mkdir_p(output_dir) unless File.directory?(output_dir)
|
|
313
|
+
|
|
314
|
+
File.binwrite(output_path, response.body)
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
# Generate output path based on input path and target format
|
|
318
|
+
#
|
|
319
|
+
# @param input_path [String] Input file path
|
|
320
|
+
# @param target_format [String] Target format
|
|
321
|
+
#
|
|
322
|
+
# @return [String] Output file path
|
|
323
|
+
#
|
|
324
|
+
def generate_output_path(input_path, target_format)
|
|
325
|
+
dir = File.dirname(input_path)
|
|
326
|
+
base_name = File.basename(input_path, File.extname(input_path))
|
|
327
|
+
File.join(dir, "#{base_name}.#{target_format.downcase}")
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
# Parse HTTP response
|
|
331
|
+
#
|
|
332
|
+
# @param response [HTTParty::Response] HTTP response
|
|
333
|
+
#
|
|
334
|
+
# @return [Hash] Parsed JSON response
|
|
335
|
+
#
|
|
336
|
+
def parse_response(response)
|
|
337
|
+
JSON.parse(response.body)
|
|
338
|
+
rescue JSON::ParserError
|
|
339
|
+
raise APIError, "Invalid API response: #{response.body}"
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
# Emit event to registered callbacks
|
|
343
|
+
#
|
|
344
|
+
# @param event [Symbol] Event name
|
|
345
|
+
# @param data [Hash] Event data
|
|
346
|
+
#
|
|
347
|
+
def emit(event, data)
|
|
348
|
+
return unless @callbacks[event]
|
|
349
|
+
|
|
350
|
+
@callbacks[event].each { |callback| callback.call(data) }
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: convertorio-sdk
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.2.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Convertorio
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: httparty
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0.21'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0.21'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: json
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '2.6'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '2.6'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: bundler
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '2.0'
|
|
47
|
+
type: :development
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '2.0'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: rake
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - "~>"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '13.0'
|
|
61
|
+
type: :development
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - "~>"
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '13.0'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: rspec
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - "~>"
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '3.12'
|
|
75
|
+
type: :development
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - "~>"
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '3.12'
|
|
82
|
+
- !ruby/object:Gem::Dependency
|
|
83
|
+
name: webmock
|
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - "~>"
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '3.18'
|
|
89
|
+
type: :development
|
|
90
|
+
prerelease: false
|
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - "~>"
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '3.18'
|
|
96
|
+
description: Ruby SDK for the Convertorio API. Convert images between 20+ formats
|
|
97
|
+
with just a few lines of code. Supports JPG, PNG, WebP, AVIF, HEIC, GIF, BMP, TIFF,
|
|
98
|
+
ICO, and more.
|
|
99
|
+
email:
|
|
100
|
+
- support@convertorio.com
|
|
101
|
+
executables: []
|
|
102
|
+
extensions: []
|
|
103
|
+
extra_rdoc_files: []
|
|
104
|
+
files:
|
|
105
|
+
- CHANGELOG.md
|
|
106
|
+
- LICENSE
|
|
107
|
+
- README.md
|
|
108
|
+
- lib/convertorio.rb
|
|
109
|
+
homepage: https://github.com/SedeSoft/convertorio-sdk
|
|
110
|
+
licenses:
|
|
111
|
+
- MIT
|
|
112
|
+
metadata:
|
|
113
|
+
homepage_uri: https://github.com/SedeSoft/convertorio-sdk
|
|
114
|
+
source_code_uri: https://github.com/SedeSoft/convertorio-sdk/tree/main/libs/ruby
|
|
115
|
+
changelog_uri: https://github.com/SedeSoft/convertorio-sdk/blob/main/libs/ruby/CHANGELOG.md
|
|
116
|
+
documentation_uri: https://github.com/SedeSoft/convertorio-sdk/tree/main/docs/ruby
|
|
117
|
+
bug_tracker_uri: https://github.com/SedeSoft/convertorio-sdk/issues
|
|
118
|
+
rdoc_options: []
|
|
119
|
+
require_paths:
|
|
120
|
+
- lib
|
|
121
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
122
|
+
requirements:
|
|
123
|
+
- - ">="
|
|
124
|
+
- !ruby/object:Gem::Version
|
|
125
|
+
version: 2.7.0
|
|
126
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
127
|
+
requirements:
|
|
128
|
+
- - ">="
|
|
129
|
+
- !ruby/object:Gem::Version
|
|
130
|
+
version: '0'
|
|
131
|
+
requirements: []
|
|
132
|
+
rubygems_version: 3.6.9
|
|
133
|
+
specification_version: 4
|
|
134
|
+
summary: Official Convertorio SDK for Ruby - Convert images easily with a simple API
|
|
135
|
+
test_files: []
|