Table of Contents
- Ruby SDK Guide
- Installation
- Quick Start
- Basic Configuration
- Configure the client
- Alternative: Initialize client directly
- Your First Conversion
- Create a conversion job
- New micro-precision API (recommended)
- Or using backward-compatible cents field in API response
- Core Classes
- MediaConvert::ConversionJob
- Create a job
- Check job status
- Wait for completion
- Access results
- New micro-precision API (recommended)
- Or using backward-compatible cents field in API response
- MediaConvert::Account
- Get account details
- Check usage
- Rails Integration
- ActiveJob Integration
- app/jobs/media_conversion_job.rb
- Usage
- Model Integration
- app/models/video.rb
- Webhook Integration
- config/routes.rb
- app/controllers/webhooks_controller.rb
- Error Handling
- Batch Processing
- Usage
- Add multiple jobs
- Process all jobs
- Testing
- Test Helpers
- spec/support/mediaconvert_helpers.rb
- Example Tests
- spec/jobs/media_conversion_job_spec.rb
- Configuration Options
- Global Configuration
- Common Patterns
- S3 Presigned URL Generation
- Usage
- Progress Monitoring
- Usage
- Webhook Signature Verification
- Usage in controller
- Advanced Configuration with Circuit Breaker
- Usage with circuit breaker
- Performance Tips
- Connection Pooling
- Use persistent connections for high-throughput applications
- Async Processing
- Don't wait for completion in web requests
- Next Steps
- Support
Ruby SDK Guide
The MediaConvert.io Ruby SDK provides a convenient way to integrate media conversion into your Ruby applications. This guide covers installation, configuration, and common usage patterns.
Installation
Add the gem to your Gemfile:
ruby
gem 'mediaconvert', '~> 1.0'
Then run:
bash
bundle install
Or install directly:
bash
gem install mediaconvert
Quick Start
Basic Configuration
ruby
require 'mediaconvert'
# Configure the client
MediaConvert.configure do |config|
config.api_token = ENV['MEDIACONVERT_API_TOKEN']
config.api_base_url = 'https://mediaconvert.io/api/v1'
config.timeout = 30
config.retries = 3
end
# Alternative: Initialize client directly
client = MediaConvert::Client.new(
api_token: ENV['MEDIACONVERT_API_TOKEN']
)
Your First Conversion
ruby
# Create a conversion job
job = MediaConvert::ConversionJob.create(
job_type: 'video',
input_url: 'https://bucket.s3.amazonaws.com/input.mp4?...',
output_url: 'https://bucket.s3.amazonaws.com/output.webm?...',
input_format: 'mp4',
output_format: 'webm',
input_size_bytes: 52428800,
webhook_url: 'https://your-app.com/webhooks/mediaconvert'
)
puts "Job created: #{job.id}"
puts "Status: #{job.status}"
# New micro-precision API (recommended)
puts "Estimated cost: €#{job.estimated_cost_micros / 1_000_000.0}"
# Or using backward-compatible cents field in API response
puts "Estimated cost: €#{job.estimated_cost_cents / 100.0}"
Core Classes
MediaConvert::ConversionJob
The main class for managing conversion jobs:
ruby
# Create a job
job = MediaConvert::ConversionJob.create(
job_type: 'video',
input_url: input_presigned_url,
output_url: output_presigned_url,
input_format: 'mp4',
output_format: 'webm',
input_size_bytes: file_size_bytes
)
# Check job status
job.reload
puts job.status # => "processing"
puts job.progress_percentage # => 45
# Wait for completion
job.wait_until_complete do |current_job|
puts "Progress: #{current_job.progress_percentage}%"
end
# Access results
puts "Processing time: #{job.processing_time_seconds}s"
puts "Output size: #{job.output_size_bytes} bytes"
# New micro-precision API (recommended)
puts "Total cost: €#{job.cost_micros / 1_000_000.0}"
# Or using backward-compatible cents field in API response
puts "Total cost: €#{job.cost_cents / 100.0}"
MediaConvert::Account
Manage your account information:
ruby
# Get account details
account = MediaConvert::Account.current
puts account.email
puts account.tier
puts "Credits: €#{account.credits_balance_cents / 100.0}"
# Check usage
usage = account.usage_summary
puts "Jobs this month: #{usage.jobs_count}"
puts "Data processed: #{usage.total_mb_processed} MB"
puts "Total spent: €#{usage.total_cost_micros / 1_000_000.0}"
Rails Integration
ActiveJob Integration
Integrate with Rails background jobs:
ruby
# app/jobs/media_conversion_job.rb
class MediaConversionJob < ApplicationJob
queue_as :default
retry_on MediaConvert::RateLimitError, wait: :exponentially_longer
retry_on MediaConvert::APIError, attempts: 3
def perform(user, input_url, output_url, options = {})
job = MediaConvert::ConversionJob.create({
input_url: input_url,
output_url: output_url,
webhook_url: webhook_url_for(user)
}.merge(options))
# Store job reference
user.media_conversions.create!(
external_id: job.id,
status: job.status,
input_url: input_url,
output_url: output_url
)
end
private
def webhook_url_for(user)
Rails.application.routes.url_helpers.webhooks_mediaconvert_url(
host: Rails.application.config.action_mailer.default_url_options[:host]
)
end
end
# Usage
MediaConversionJob.perform_later(
current_user,
input_presigned_url,
output_presigned_url,
job_type: 'video',
output_format: 'webm'
)
Model Integration
Integrate with your models:
ruby
# app/models/video.rb
class Video < ApplicationRecord
belongs_to :user
has_one_attached :original_file
after_create :enqueue_conversion
enum status: {
pending: 0,
processing: 1,
completed: 2,
failed: 3
}
def enqueue_conversion
return unless original_file.attached?
input_url = generate_presigned_url(original_file, :get)
output_key = "converted/#{id}/output.webm"
output_url = generate_presigned_url_for_key(output_key, :put)
MediaConversionJob.perform_later(
user,
input_url,
output_url,
job_type: 'video',
output_format: 'webm'
)
end
private
def generate_presigned_url(attachment, method)
attachment.service.send(
:presigned_url,
attachment.key,
method: method,
expires_in: 1.hour
)
end
def generate_presigned_url_for_key(key, method)
original_file.service.send(
:presigned_url,
key,
method: method,
expires_in: 1.hour
)
end
end
Webhook Integration
Handle webhook notifications in Rails:
ruby
# config/routes.rb
post '/webhooks/mediaconvert', to: 'webhooks#mediaconvert'
# app/controllers/webhooks_controller.rb
class WebhooksController < ApplicationController
protect_from_forgery except: [:mediaconvert]
def mediaconvert
# Verify webhook signature
unless verify_signature(request.raw_post, request.headers['X-MediaConvert-Signature'])
head :unauthorized
return
end
# Process the webhook
case params[:status]
when 'completed'
handle_completed_job(params[:job_id])
when 'failed'
handle_failed_job(params[:job_id], params[:error_message])
when 'processing'
update_job_progress(params[:job_id], params[:progress_percentage])
end
head :ok
end
private
def verify_signature(payload, signature)
expected = OpenSSL::HMAC.hexdigest(
'sha256',
ENV['MEDIACONVERT_WEBHOOK_SECRET'],
payload
)
Rack::Utils.secure_compare(signature, expected)
end
def handle_completed_job(job_id)
# Process completed conversion
job = MediaConvertJob.find_by(external_id: job_id)
job.update(status: 'completed', completed_at: Time.current)
# Notify user
ConversionCompleteJob.perform_later(job.user, job)
end
end
Error Handling
Robust error handling for production applications:
ruby
begin
job = MediaConvert::ConversionJob.create(
job_type: 'video',
input_url: input_url,
output_url: output_url,
input_format: 'mp4',
output_format: 'webm'
)
job.wait_until_complete
rescue MediaConvert::AuthenticationError
puts "Authentication failed - check your API token"
rescue MediaConvert::InsufficientCreditsError => e
puts "Need €#{e.required_credits_micros / 1_000_000.0} but only have €#{e.available_credits_micros / 1_000_000.0}"
rescue MediaConvert::ValidationError => e
puts "Validation failed: #{e.errors.join(', ')}"
rescue MediaConvert::ConversionError => e
puts "Conversion failed: #{e.message}"
rescue MediaConvert::RateLimitError => e
puts "Rate limited. Retry after #{e.retry_after} seconds"
sleep(e.retry_after)
retry
rescue MediaConvert::APIError => e
puts "API error: #{e.message} (#{e.http_status})"
end
Batch Processing
Process multiple files efficiently:
ruby
class BatchProcessor
def initialize
@jobs = []
end
def add_job(input_url, output_url, options = {})
job = MediaConvert::ConversionJob.create({
input_url: input_url,
output_url: output_url
}.merge(options))
@jobs << job
job
end
def wait_for_completion
completed = []
failed = []
@jobs.each do |job|
begin
job.wait_until_complete
completed << job
rescue MediaConvert::ConversionError => e
failed << { job: job, error: e }
end
end
{ completed: completed, failed: failed }
end
end
# Usage
processor = BatchProcessor.new
# Add multiple jobs
processor.add_job(input_url_1, output_url_1, output_format: 'webm')
processor.add_job(input_url_2, output_url_2, output_format: 'mp4')
processor.add_job(input_url_3, output_url_3, output_format: 'webp')
# Process all jobs
results = processor.wait_for_completion
puts "#{results[:completed].size} completed, #{results[:failed].size} failed"
Testing
Test Helpers
ruby
# spec/support/mediaconvert_helpers.rb
module MediaConvertHelpers
def stub_mediaconvert_job_creation
WebMock.stub_request(:post, 'https://mediaconvert.io/api/v1/conversion_jobs')
.to_return(
status: 201,
headers: { 'Content-Type' => 'application/json' },
body: {
id: 'job_test123',
status: 'pending',
job_type: 'video',
estimated_cost_micros: 150_000 # €0.15
}.to_json
)
end
def stub_mediaconvert_job_status(job_id, status, progress = 0)
WebMock.stub_request(:get, "https://mediaconvert.io/api/v1/conversion_jobs/#{job_id}")
.to_return(
status: 200,
headers: { 'Content-Type' => 'application/json' },
body: {
id: job_id,
status: status,
progress_percentage: progress
}.to_json
)
end
end
RSpec.configure do |config|
config.include MediaConvertHelpers
end
Example Tests
ruby
# spec/jobs/media_conversion_job_spec.rb
RSpec.describe MediaConversionJob, type: :job do
let(:user) { create(:user) }
let(:input_url) { 'https://bucket.s3.amazonaws.com/input.mp4' }
let(:output_url) { 'https://bucket.s3.amazonaws.com/output.webm' }
before do
stub_mediaconvert_job_creation
end
it 'creates a conversion job' do
expect {
described_class.perform_now(user, input_url, output_url)
}.to change(user.media_conversions, :count).by(1)
end
it 'handles API errors gracefully' do
WebMock.stub_request(:post, 'https://mediaconvert.io/api/v1/conversion_jobs')
.to_return(status: 402, body: { error: 'insufficient_credits' }.to_json)
expect {
described_class.perform_now(user, input_url, output_url)
}.to raise_error(MediaConvert::InsufficientCreditsError) do |error|
expect(error.required_credits_micros).to eq(3_150_000)
expect(error.available_credits_micros).to eq(500_000)
end
end
end
Configuration Options
Global Configuration
ruby
MediaConvert.configure do |config|
# Required
config.api_token = ENV['MEDIACONVERT_API_TOKEN']
# Optional settings
config.api_base_url = 'https://mediaconvert.io/api/v1' # Default
config.timeout = 30 # Default: 30 seconds
config.open_timeout = 10 # Default: 10 seconds
config.retries = 3 # Default: 3
config.retry_delay = 1 # Default: 1 second
config.user_agent = 'MyApp/1.0' # Custom user agent
# Webhook settings
config.webhook_secret = ENV['MEDIACONVERT_WEBHOOK_SECRET']
# Logging
config.logger = Rails.logger # Default: Logger.new(STDOUT)
config.log_level = :info # Default: :info
end
Common Patterns
S3 Presigned URL Generation
ruby
class S3UrlGenerator
def initialize(bucket, region = 'us-east-1')
@s3 = Aws::S3::Client.new(region: region)
@bucket = bucket
end
def input_url(key, expires_in = 3600)
@s3.presigned_url(:get_object,
bucket: @bucket,
key: key,
expires_in: expires_in
)
end
def output_url(key, expires_in = 3600)
@s3.presigned_url(:put_object,
bucket: @bucket,
key: key,
expires_in: expires_in
)
end
end
# Usage
generator = S3UrlGenerator.new('my-bucket')
input_url = generator.input_url('videos/input.mp4')
output_url = generator.output_url('videos/output.webm')
job = MediaConvert::ConversionJob.create(
job_type: 'video',
input_url: input_url,
output_url: output_url,
input_format: 'mp4',
output_format: 'webm'
)
Progress Monitoring
ruby
class ConversionMonitor
def initialize(job)
@job = job
end
def monitor_progress
loop do
@job.reload
puts "Status: #{@job.status}"
puts "Progress: #{@job.progress_percentage}%" if @job.progress_percentage
case @job.status
when 'completed'
puts "✅ Conversion completed!"
puts "Processing time: #{@job.processing_time_seconds}s"
puts "Cost: €#{@job.cost_micros / 1_000_000.0}"
break
when 'failed'
puts "❌ Conversion failed: #{@job.error_message}"
break
when 'cancelled'
puts "🚫 Conversion cancelled"
break
end
sleep(5) # Check every 5 seconds
end
end
end
# Usage
job = MediaConvert::ConversionJob.create(conversion_params)
monitor = ConversionMonitor.new(job)
monitor.monitor_progress
### Webhook Signature Verification
```ruby
class MediaConvertWebhookVerifier
def initialize(webhook_secret)
@webhook_secret = webhook_secret
end
def verify_signature(payload, signature)
expected = OpenSSL::HMAC.hexdigest('sha256', @webhook_secret, payload)
expected_with_prefix = "sha256=#{expected}"
Rack::Utils.secure_compare(signature, expected_with_prefix)
end
def process_webhook(request)
payload = request.raw_post
signature = request.headers['X-MediaConvert-Signature']
unless verify_signature(payload, signature)
raise MediaConvert::WebhookSignatureError, 'Invalid webhook signature'
end
JSON.parse(payload)
end
end
# Usage in controller
class WebhooksController < ApplicationController
before_action :verify_webhook_signature
private
def verify_webhook_signature
verifier = MediaConvertWebhookVerifier.new(ENV['MEDIACONVERT_WEBHOOK_SECRET'])
@webhook_data = verifier.process_webhook(request)
rescue MediaConvert::WebhookSignatureError => e
head :unauthorized
end
def mediaconvert
case @webhook_data['status']
when 'completed'
handle_completed_job(@webhook_data)
when 'failed'
handle_failed_job(@webhook_data)
when 'processing'
update_job_progress(@webhook_data)
end
head :ok
end
end
Advanced Configuration with Circuit Breaker
ruby
class MediaConvertCircuitBreaker
def initialize(failure_threshold: 5, recovery_timeout: 60)
@failure_threshold = failure_threshold
@recovery_timeout = recovery_timeout
@failure_count = 0
@last_failure_time = nil
@state = :closed # :closed, :open, :half_open
end
def call(&block)
case @state
when :open
if Time.current - @last_failure_time > @recovery_timeout
@state = :half_open
attempt_request(&block)
else
raise MediaConvert::CircuitBreakerOpenError, 'Circuit breaker is open'
end
when :half_open
attempt_request(&block)
when :closed
attempt_request(&block)
end
end
private
def attempt_request(&block)
result = block.call
reset_failure_count
result
rescue MediaConvert::APIError => e
record_failure
raise e
end
def record_failure
@failure_count += 1
@last_failure_time = Time.current
if @failure_count >= @failure_threshold
@state = :open
Rails.logger.error "[MediaConvert] Circuit breaker opened after #{@failure_count} failures"
end
end
def reset_failure_count
@failure_count = 0
@state = :closed
end
end
# Usage with circuit breaker
class RobustMediaConvertService
def initialize
@circuit_breaker = MediaConvertCircuitBreaker.new
end
def convert_with_protection(options)
@circuit_breaker.call do
MediaConvert::ConversionJob.create(options)
end
rescue MediaConvert::CircuitBreakerOpenError => e
Rails.logger.warn "[MediaConvert] Circuit breaker open, using fallback"
# Implement fallback behavior (queue for later, use alternative service, etc.)
queue_for_later_processing(options)
end
end
text
## Performance Tips
### Connection Pooling
```ruby
# Use persistent connections for high-throughput applications
MediaConvert.configure do |config|
config.api_token = ENV['MEDIACONVERT_API_TOKEN']
config.adapter = :net_http_persistent # Reuse connections
config.pool_size = 10 # Connection pool size
end
Async Processing
ruby
# Don't wait for completion in web requests
def convert_video
job = MediaConvert::ConversionJob.create(
job_type: 'video',
input_url: params[:input_url],
output_url: params[:output_url],
webhook_url: webhook_url
)
# Return immediately
render json: { job_id: job.id, status: job.status }
end
Next Steps
- Authentication Guide - Advanced authentication patterns
- First Conversion Tutorial - Step-by-step walkthrough
- API Reference - Complete API documentation
- Webhook Guide - Real-time notifications
Support
- GitHub Issues: github.com/mediaconvert-io/ruby-sdk
- Gem Documentation: rubydoc.info/gems/mediaconvert
- Email Support: support@mediaconvert.io