Lipdub Ruby Client
A comprehensive Ruby client library for the Lipdub.ai API, providing easy access to AI-powered lip-dubbing functionality.
Table of Contents
- Features
- Installation
- Configuration
- Quick Start
- API Reference
- Usage Examples
- Complete Workflow Examples
- Supported File Formats
- Error Handling
- Rate Limits and Best Practices
- Troubleshooting
- Development
- Contributing
- License
Features
- Video Upload: Upload and process videos for lip-dubbing
- Audio Upload: Upload audio files for voice replacement
- Generation: Generate lip-dubbed videos with AI
- Status Monitoring: Track processing and generation progress
- File Management: Handle file uploads and downloads seamlessly
- Error Handling: Comprehensive error handling with custom exceptions
- Test Coverage: Full test suite with RSpec
Installation
Add this line to your application's Gemfile:
gem 'lipdub'
And then execute:
$ bundle install
Or install it yourself as:
$ gem install lipdub
Configuration
Configure the client with your API key:
require 'lipdub'
# Global configuration
Lipdub.configure do |config|
config.api_key = "your_api_key_here"
config.base_url = "https://api.lipdub.ai" # Optional, this is the default
config.timeout = 30 # Optional, default is 30 seconds
config.open_timeout = 10 # Optional, default is 10 seconds
end
# Or create a client with specific configuration
config = Lipdub::Configuration.new
config.api_key = "your_api_key_here"
client = Lipdub::Client.new(config)
Quick Start
Here's a minimal example to get you started with lip-dubbing:
require 'lipdub'
# Configure the client
Lipdub.configure do |config|
config.api_key = "your_api_key_here"
end
client = Lipdub.client
# Upload video and audio, then generate lip-dubbed video
video_response = client.videos.upload_complete("input/video.mp4")
shot_id = video_response.dig("data", "shot_id")
audio_response = client.audios.upload_complete("input/audio.mp3")
audio_id = audio_response.dig("data", "audio_id")
# Generate and download the result
result = client.shots.generate_and_wait(
shot_id: shot_id,
audio_id: audio_id,
output_filename: "dubbed_video.mp4"
)
generate_id = result.dig("data", "generate_id")
client.shots.download_file(shot_id, generate_id, "output/result.mp4")
API Reference
The Lipdub Ruby client provides four main resource classes for interacting with the API:
Videos
The Videos resource handles video file uploads and processing.
Methods
| Method | Description | Parameters | Returns |
|---|---|---|---|
upload(size_bytes:, file_name:, content_type:, video_source_url: nil) |
Initiate video upload process | size_bytes (Integer), file_name (String), content_type (String), video_source_url (String, optional) |
Hash with video_id, upload_url, success_url, failure_url |
upload_file(upload_url, file_content, content_type) |
Upload video file to provided URL | upload_url (String), file_content (String/IO), content_type (String) |
Hash |
upload_complete(file_path, content_type: nil) |
Complete upload workflow from file path | file_path (String), content_type (String, optional) |
Hash with shot_id and asset_type |
success(video_id) |
Mark video upload as successful | video_id (String) |
Hash with shot_id and asset_type |
failure(video_id) |
Mark video upload as failed | video_id (String) |
Hash |
status(video_id) |
Get video processing status | video_id (String) |
Hash with status information |
Endpoints
POST /v1/video- Initiate video uploadPOST /v1/video/success/{video_id}- Mark upload successfulPOST /v1/video/failure/{video_id}- Mark upload failedGET /v1/video/status/{video_id}- Get processing status
Audios
The Audios resource handles audio file uploads and management.
Methods
| Method | Description | Parameters | Returns |
|---|---|---|---|
upload(size_bytes:, file_name:, content_type:, audio_source_url: nil) |
Initiate audio upload process | size_bytes (Integer, 1-104857600), file_name (String), content_type (String), audio_source_url (String, optional) |
Hash with audio_id, upload_url, success_url, failure_url |
upload_file(upload_url, file_content, content_type) |
Upload audio file to provided URL | upload_url (String), file_content (String/IO), content_type (String) |
Hash |
upload_complete(file_path, content_type: nil) |
Complete upload workflow from file path | file_path (String), content_type (String, optional) |
Hash with upload result |
success(audio_id) |
Mark audio upload as successful | audio_id (String) |
Hash |
failure(audio_id) |
Mark audio upload as failed | audio_id (String) |
Hash |
status(audio_id) |
Get audio processing status | audio_id (String) |
Hash with status information |
list(page: 1, page_size: 10) |
List all audio files | page (Integer), page_size (Integer) |
Hash with audio list and pagination |
Endpoints
POST /v1/audio- Initiate audio uploadPOST /v1/audio/success/{audio_id}- Mark upload successfulPOST /v1/audio/failure/{audio_id}- Mark upload failedGET /v1/audio/status/{audio_id}- Get processing statusGET /v1/audio- List audio files
Supported Audio Formats
audio/mpeg(MP3)audio/wav(WAV)audio/mp4(MP4/M4A)
Shots
The Shots resource handles lip-dubbing generation, translation, and shot management.
Methods
| Method | Description | Parameters | Returns |
|---|---|---|---|
list(page: 1, per_page: 20) |
List available shots | page (Integer), per_page (Integer, max 100) |
Hash with shots list and count |
status(shot_id) |
Get shot processing status | shot_id (String/Integer) |
Hash with status information |
generate(shot_id:, audio_id:, output_filename:, **options) |
Generate lip-dubbed video | See generation options below | Hash with generate_id |
generation_status(shot_id, generate_id) |
Get generation progress | shot_id (String/Integer), generate_id (String) |
Hash with progress and status |
download(shot_id, generate_id) |
Get download URL for generated video | shot_id (String/Integer), generate_id (String) |
Hash with download_url |
download_file(shot_id, generate_id, file_path) |
Download generated video to local path | shot_id (String/Integer), generate_id (String), file_path (String) |
String (file path) |
generate_and_wait(shot_id:, audio_id:, output_filename:, **options) |
Generate and wait for completion | Same as generate + polling_interval (Integer), max_wait_time (Integer) |
Hash with final status |
actors(shot_id) |
Get actors for a shot | shot_id (String/Integer) |
Hash with actors information |
translate(shot_id:, source_language:, target_language:, full_resolution: nil) |
Translate a shot | shot_id (String/Integer), source_language (String), target_language (String), full_resolution (Boolean, optional) |
Hash with translation details |
generate_multi_actor(shot_id:, **params) |
Generate multi-actor lip-dub | shot_id (String/Integer), params (Hash) |
Hash with generation details |
Generation Options
| Parameter | Type | Description | Default |
|---|---|---|---|
shot_id |
String/Integer | Required. Unique identifier of the shot | - |
audio_id |
String | Required. Unique identifier of the audio file | - |
output_filename |
String | Required. Name for the output file | - |
language |
String | Language specification (ISO 639-1) | nil |
start_frame |
Integer | Frame number to start lip-sync from | 0 |
loop_video |
Boolean | Whether to loop video during rendering | false |
full_resolution |
Boolean | Whether to use full resolution | true |
callback_url |
String | HTTPS URL for completion callback | nil |
timecode_ranges |
Array | List of [start, end] timecode pairs for selective lip-dubbing |
nil |
Timecode Ranges for Selective Lip-dubbing
Timecode ranges allow you to lip-dub only specific parts of a video:
# Using seconds (float)
timecode_ranges: [[2.5, 4.2], [10.0, 12.5]]
# Using SMPTE format (HH:MM:SS:FF)
timecode_ranges: [["00:00:02:15", "00:00:04:06"], ["00:00:10:00", "00:00:12:15"]]
Helper Methods
| Method | Description | Parameters | Returns |
|---|---|---|---|
validate_timecode_ranges(ranges, video_duration: nil) |
Validate timecode ranges | ranges (Array), video_duration (Numeric, optional) |
Boolean or raises ArgumentError |
add_frame_buffer(ranges, buffer_frames: 10, fps: 30, video_duration: nil) |
Add frame buffer to ranges | ranges (Array), buffer_frames (Integer), fps (Integer), video_duration (Numeric, optional) |
Array of buffered ranges |
parse_timecode_to_seconds(timecode, fps: 30) |
Convert timecode to seconds | timecode (String/Numeric), fps (Integer) |
Float |
Endpoints
GET /v1/shots- List shotsGET /v1/shots/{shot_id}/status- Get shot statusPOST /v1/shots/{shot_id}/generate- Generate lip-dubbed videoGET /v1/shots/{shot_id}/generate/{generate_id}- Get generation statusGET /v1/shots/{shot_id}/generate/{generate_id}/download- Get download URLGET /v1/shots/{shot_id}/actors- Get shot actorsPOST /v1/shots/{shot_id}/translate- Translate shotPOST /v1/shots/{shot_id}/generate-multi-actor- Multi-actor generation
Projects
The Projects resource handles project management and listing.
Methods
| Method | Description | Parameters | Returns |
|---|---|---|---|
list(page: 1, per_page: 20) |
List all projects | page (Integer), per_page (Integer, max 100) |
Hash with projects list and count |
Endpoints
GET /v1/projects- List projects
Usage Examples
Video Upload
Simple Video Upload
client = Lipdub.client
# Upload a video file (handles the entire workflow)
response = client.videos.upload_complete("path/to/your/video.mp4")
# => {
# "data" => {
# "shot_id" => 123,
# "asset_type" => "dubbing-video"
# }
# }
shot_id = response.dig("data", "shot_id")
Manual Video Upload Process
# Step 1: Initiate upload
upload_response = client.videos.upload(
size_bytes: File.size("video.mp4"),
file_name: "my_video.mp4",
content_type: "video/mp4"
)
video_id = upload_response.dig("data", "video_id")
upload_url = upload_response.dig("data", "upload_url")
# Step 2: Upload the file
file_content = File.read("video.mp4")
client.videos.upload_file(upload_url, file_content, "video/mp4")
# Step 3: Mark as successful
success_response = client.videos.success(video_id)
shot_id = success_response.dig("data", "shot_id")
Check Video Status
status = client.videos.status(video_id)
# => {
# "data" => {
# "status" => "processing",
# "progress" => 50
# }
# }
Audio Upload
Simple Audio Upload
# Upload an audio file (handles the entire workflow)
response = client.audios.upload_complete("path/to/your/audio.mp3")
# Get the audio_id for generation
audio_id = response.dig("data", "audio_id")
Manual Audio Upload Process
# Step 1: Initiate upload
upload_response = client.audios.upload(
size_bytes: File.size("audio.mp3"),
file_name: "voiceover.mp3",
content_type: "audio/mpeg"
)
audio_id = upload_response.dig("data", "audio_id")
upload_url = upload_response.dig("data", "upload_url")
# Step 2: Upload the file
file_content = File.read("audio.mp3")
client.audios.upload_file(upload_url, file_content, "audio/mpeg")
# Step 3: Mark as successful
client.audios.success(audio_id)
List Audio Files
# List all audio files
audios = client.audios.list(page: 1, page_size: 20)
# => {
# "data" => [
# { "audio_id" => "audio_1", "file_name" => "voice1.mp3" },
# { "audio_id" => "audio_2", "file_name" => "voice2.wav" }
# ],
# "pagination" => { "page" => 1, "page_size" => 20, "total" => 50 }
# }
Shot Management
List Available Shots
# List all shots
shots = client.shots.list(page: 1, per_page: 50)
# => {
# "data" => [
# {
# "shot_id" => 99,
# "shot_label" => "api-full-test-new.mp4",
# "shot_project_id" => 37,
# "shot_scene_id" => 37,
# "shot_project_name" => "Lee Studios",
# "shot_scene_name" => "Under the tent"
# }
# ],
# "count" => 1
# }
Get Shot Actors
# Get actors for a specific shot
actors = client.shots.actors(shot_id)
Shot Generation
Generate Lip-Dubbed Video
# Start generation with all available options
generate_response = client.shots.generate(
shot_id: shot_id,
audio_id: audio_id,
output_filename: "final_dubbed_video.mp4",
language: "en-US", # Optional (ISO 639-1)
start_frame: 0, # Optional
loop_video: false, # Optional
full_resolution: true, # Optional
callback_url: "https://example.com/webhook", # Optional
timecode_ranges: [[0, 100], [200, 300]] # Optional
)
generate_id = generate_response["generate_id"]
Selective Lip-dubbing for Single Actors
For scenarios where you only want to lip-dub specific parts of a video (e.g., personalization where only a name needs to be replaced), you can use selective lip-dubbing with timecode_ranges:
# Basic selective lip-dubbing with time ranges in seconds
response = client.shots.generate(
shot_id: 123,
audio_id: "audio_abc123",
output_filename: "personalized_video.mp4",
timecode_ranges: [[0, 10], [20, 30]] # Replace seconds 0-10 and 20-30
)
# With SMPTE timecode format (be consistent with format)
response = client.shots.generate(
shot_id: 123,
audio_id: "audio_abc123",
output_filename: "personalized_video.mp4",
timecode_ranges: [["00:00:00:00", "00:00:10:00"], ["00:00:20:00", "00:00:30:00"]]
)
# Example: Replace a name greeting with proper buffering
# Calculate 10-frame buffer (assuming 30fps: 10/30 = 0.33 seconds)
name_start = 2.5 - 0.33 # Start 10 frames before
name_end = 4.2 + 0.33 # End 10 frames after
response = client.shots.generate(
shot_id: 123,
audio_id: "audio_with_new_name",
output_filename: "personalized_greeting.mp4",
timecode_ranges: [[name_start, name_end]],
language: "en-US"
)
Best Practices for Selective Lip-dubbing
- Match Original Region Length: Ensure replaced audio regions match the original region length to maintain sync
- Add Frame Buffer: Include a 10-frame buffer around start/end timecodes for seamless blending
- Normalize Audio: Normalize audio levels and isolate vocals from background noise for best results
- Audio Duration: The total audio duration must match the video duration
- Consistent Timecode Format: Use either seconds (float) or SMPTE format consistently
- Non-overlapping Ranges: Ensure timecode ranges don't overlap each other
Translation
# Translate a shot to different language
translation = client.shots.translate(
shot_id: shot_id,
source_language: "English",
target_language: "Spanish",
full_resolution: true # Optional
)
Multi-Actor Generation
# Generate with multiple actors
multi_result = client.shots.generate_multi_actor(
shot_id: shot_id,
actors: [
{ actor_id: 1, voice_id: "voice_1" },
{ actor_id: 2, voice_id: "voice_2" }
]
)
Monitor Generation Progress
# Check generation status
status = client.shots.generation_status(shot_id, generate_id)
# => {
# "data" => {
# "generate_id" => "gen_789",
# "status" => "processing",
# "progress" => 75
# }
# }
Generate and Wait for Completion
# Generate and automatically wait for completion
result = client.shots.generate_and_wait(
shot_id: shot_id,
audio_id: audio_id,
output_filename: "dubbed_video.mp4",
polling_interval: 10, # Check every 10 seconds
max_wait_time: 1800 # Wait up to 30 minutes
)
# => Returns when generation is complete or raises an error
Download Generated Video
# Get download URL
download_info = client.shots.download(shot_id, generate_id)
download_url = download_info.dig("data", "download_url")
# Or download directly to a file
local_path = client.shots.download_file(
shot_id,
generate_id,
"output/my_dubbed_video.mp4"
)
Project Management
List Projects
# List all projects
projects = client.projects.list(page: 1, per_page: 20)
# => {
# "data" => [
# {
# "project_id" => 123,
# "projects_tenant_id" => 1,
# "projects_user_id" => 47,
# "project_name" => "My Sample Project",
# "user_email" => "[email protected]",
# "created_at" => "2024-01-15T10:30:00Z",
# "updated_at" => nil,
# "source_language" => {
# "language_id" => 1,
# "name" => "English",
# "supported" => true
# },
# "project_identity_type" => "single_identity",
# "language_project_links" => []
# }
# ],
# "count" => 1
# }
Complete Workflow Examples
Basic Lip-dubbing Workflow
Here's a complete example that uploads a video and audio, generates a lip-dubbed video, and downloads the result:
require 'lipdub'
# Configure the client
Lipdub.configure do |config|
config.api_key = "your_api_key_here"
end
client = Lipdub.client
begin
# 0. List existing projects and shots (optional)
puts "Listing projects..."
projects = client.projects.list
puts "Found #{projects['count']} projects"
puts "Listing available shots..."
shots = client.shots.list
puts "Found #{shots['count']} shots"
# 1. Upload video
puts "Uploading video..."
video_response = client.videos.upload_complete("input/original_video.mp4")
shot_id = video_response.dig("data", "shot_id")
puts "Video uploaded, shot_id: #{shot_id}"
# 2. Upload audio
puts "Uploading audio..."
audio_response = client.audios.upload_complete("input/new_voice.mp3")
audio_id = audio_response.dig("data", "audio_id") || "audio_from_upload"
puts "Audio uploaded, audio_id: #{audio_id}"
# 3. Generate lip-dubbed video
puts "Starting generation..."
result = client.shots.generate_and_wait(
shot_id: shot_id,
audio_id: audio_id,
output_filename: "dubbed_output.mp4",
language: "en",
maintain_expression: true,
polling_interval: 15,
max_wait_time: 3600 # 1 hour
)
generate_id = result.dig("data", "generate_id")
puts "Generation complete, generate_id: #{generate_id}"
# 4. Download the result
puts "Downloading result..."
output_path = client.shots.download_file(
shot_id,
generate_id,
"output/final_dubbed_video.mp4"
)
puts "Video downloaded to: #{output_path}"
Selective Lip-dubbing Workflow
Here's an example showing how to use selective lip-dubbing for personalization (e.g., replacing just a name in a greeting):
require 'lipdub'
# Configure the client
Lipdub.configure do |config|
config.api_key = "your_api_key_here"
end
client = Lipdub.client
begin
# 1. Upload original video (done once)
video_response = client.videos.upload_complete(
file_path: "./original_greeting.mp4",
content_type: "video/mp4"
)
video_id = video_response.dig("data", "video_id")
# 2. Upload personalized audio (replace original audio with new name)
# NOTE: Audio duration must match the video duration exactly
personalized_audio = client.audios.upload_complete(
file_path: "./personalized_greeting_audio.mp3", # Contains new name
content_type: "audio/mp3"
)
audio_id = personalized_audio.dig("data", "audio_id")
# 3. Wait for video processing and get shot_id
loop do
status = client.videos.status(video_id: video_id)
if status.dig("data", "status") == "success"
shot_id = status.dig("data", "shot_id")
break
elsif status.dig("data", "status") == "failed"
raise "Video processing failed"
end
sleep 5
end
# 4. Define timecode ranges for selective replacement
# Example: Replace name at 2.5-4.2 seconds with 10-frame buffer
name_start = 2.5
name_end = 4.2
# Use helper method to add frame buffer (recommended)
timecode_ranges = client.shots.add_frame_buffer(
[[name_start, name_end]],
buffer_frames: 10,
fps: 30
)
# Validate ranges (optional but recommended)
client.shots.validate_timecode_ranges(
timecode_ranges,
video_duration: 30.0 # Your video duration
)
# 5. Generate selective lip-dub
generation = client.shots.generate(
shot_id: shot_id,
audio_id: audio_id,
output_filename: "personalized_greeting.mp4",
timecode_ranges: timecode_ranges, # Only lip-dub the name part
language: "en-US"
)
generate_id = generation["generate_id"]
# 6. Wait for generation to complete and download
client.shots.download_file(
shot_id,
generate_id,
"output/personalized_greeting.mp4"
)
puts "Personalized video with selective lip-dubbing saved!"
# Alternative: Multiple selective ranges (e.g., name + closing)
multiple_ranges = [
[2.5, 4.2], # Name replacement
[25.0, 27.5] # Closing replacement
]
buffered_ranges = client.shots.add_frame_buffer(
multiple_ranges,
buffer_frames: 10,
fps: 30,
video_duration: 30.0
)
# Generate with multiple selective ranges
multi_selective = client.shots.generate(
shot_id: shot_id,
audio_id: audio_id,
output_filename: "multi_personalized.mp4",
timecode_ranges: buffered_ranges
)
rescue Lipdub::AuthenticationError => e
puts "Authentication failed: #{e.}"
rescue Lipdub::ValidationError => e
puts "Validation error: #{e.}"
rescue Lipdub::TimeoutError => e
puts "Request timed out: #{e.}"
rescue Lipdub::APIError => e
puts "API error (#{e.status_code}): #{e.}"
rescue => e
puts "Unexpected error: #{e.}"
end
Supported File Formats
Video Formats
- MP4 (recommended: 1080p HD, 23.976 fps, H.264 codec) -
video/mp4 - MOV (QuickTime) -
video/quicktime - AVI (Audio Video Interleave) -
video/x-msvideo - WebM (Web Media) -
video/webm - MKV (Matroska Video) -
video/x-matroska
Audio Formats
- MP3 (MPEG Audio Layer III) -
audio/mpeg(1 byte to 100MB) - WAV (Waveform Audio File Format) -
audio/wav(1 byte to 100MB) - MP4/M4A (MPEG-4 Audio) -
audio/mp4(1 byte to 100MB)
Recommendations
- Video: Use MP4 with H.264 codec for best compatibility and processing speed
- Audio: Use MP3 or WAV for optimal lip-sync results
- Resolution: 1080p HD recommended for best quality output
- Frame Rate: 23.976 fps or 30 fps for smooth lip-sync
- Audio Quality: 44.1kHz sample rate, 16-bit depth minimum
Error Handling
The gem provides comprehensive error handling with specific exception types:
begin
client.videos.upload_complete("video.mp4")
rescue Lipdub::AuthenticationError => e
# API key is invalid or missing
puts "Authentication failed: #{e.}"
rescue Lipdub::ValidationError => e
# Request parameters are invalid
puts "Validation error: #{e.}"
puts "Status code: #{e.status_code}"
puts "Response body: #{e.response_body}"
rescue Lipdub::NotFoundError => e
# Resource not found
puts "Resource not found: #{e.}"
rescue Lipdub::RateLimitError => e
# Rate limit exceeded
puts "Rate limit exceeded: #{e.}"
rescue Lipdub::ServerError => e
# Server error (5xx)
puts "Server error: #{e.}"
rescue Lipdub::TimeoutError => e
# Request timed out
puts "Request timed out: #{e.}"
rescue Lipdub::ConnectionError => e
# Connection failed
puts "Connection failed: #{e.}"
rescue Lipdub::APIError => e
# Generic API error
puts "API error: #{e.}"
rescue Lipdub::ConfigurationError => e
# Configuration is invalid
puts "Configuration error: #{e.}"
end
Rate Limits and Best Practices
Rate Limits
The Lipdub API implements rate limiting to ensure fair usage:
- Upload endpoints: 10 requests per minute
- Generation endpoints: 5 requests per minute
- Status/List endpoints: 100 requests per minute
Best Practices
Performance Optimization
- Batch operations: Upload multiple files before starting generation
- Polling intervals: Use appropriate intervals (10-30 seconds) when polling for status
- File optimization: Compress videos and normalize audio before upload
- Concurrent uploads: Upload video and audio files in parallel when possible
Error Handling
- Retry logic: Implement exponential backoff for transient errors
- Validation: Validate file formats and sizes before upload
- Monitoring: Log API responses for debugging and monitoring
- Graceful degradation: Handle API failures gracefully in production
Security
- API key protection: Store API keys securely (environment variables, secrets management)
- HTTPS only: All API communications use HTTPS
- File validation: Validate uploaded files on your end before sending to API
- Webhook security: Verify webhook signatures if using callback URLs
Resource Management
- Cleanup: Remove temporary files after processing
- Storage: Monitor storage usage for large video files
- Timeouts: Set appropriate timeouts for long-running operations
- Memory: Stream large files instead of loading entirely into memory
Troubleshooting
Common Issues
Upload Failures
# Issue: File upload fails with timeout
# Solution: Increase timeout settings
Lipdub.configure do |config|
config.timeout = 120 # 2 minutes for large files
config.open_timeout = 30 # 30 seconds to establish connection
end
Generation Errors
# Issue: Generation fails with validation error
# Solution: Validate inputs before generation
begin
# Ensure audio duration matches video duration
client.shots.validate_timecode_ranges(ranges, video_duration: 30.0)
result = client.shots.generate(
shot_id: shot_id,
audio_id: audio_id,
output_filename: "output.mp4"
)
rescue Lipdub::ValidationError => e
puts "Validation failed: #{e.}"
# Handle validation error
end
Network Issues
# Issue: Connection timeouts or failures
# Solution: Implement retry logic with exponential backoff
def upload_with_retry(file_path, max_retries: 3)
retries = 0
begin
client.videos.upload_complete(file_path)
rescue Lipdub::TimeoutError, Lipdub::ConnectionError => e
retries += 1
if retries <= max_retries
sleep(2 ** retries) # Exponential backoff
retry
else
raise e
end
end
end
Debug Mode
Enable debug logging to troubleshoot issues:
# Enable debug logging (if supported by your HTTP client)
Lipdub.configure do |config|
config.api_key = "your_api_key"
config.debug = true # Enable debug mode
end
# Or use a custom logger
require 'logger'
logger = Logger.new(STDOUT)
logger.level = Logger::DEBUG
# Log API requests and responses
client = Lipdub.client
# Add logging middleware to your HTTP client if needed
Getting Help
- Documentation: Check this README and inline code documentation
- API Status: Monitor Lipdub API status page for service issues
- Support: Contact [email protected] for API-related issues
- Issues: Report bugs on GitHub Issues
Development
After checking out the repo, run:
bin/setup
To install dependencies. Then, run:
rake spec
To run the tests. You can also run:
bin/console
For an interactive prompt that will allow you to experiment.
Running Tests
# Run all tests
bundle exec rspec
# Run specific test file
bundle exec rspec spec/lipdub/client_spec.rb
# Run tests with coverage
bundle exec rspec --format documentation
# Run security audit
bundle exec rake audit
# Run all CI checks (tests + security audit)
bundle exec rake ci
# Optional: Run rubocop for linting (not included in CI)
bundle exec rubocop
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/upriser/lipdub-ruby.
- Fork it
- Create your feature branch (
git checkout -b my-new-feature) - Make your changes and add tests
- Run the test suite (
bundle exec rake ci) - Ensure security audit passes (
bundle exec rake audit) - Commit your changes (
git commit -am 'Add some feature') - Push to the branch (
git push origin my-new-feature) - Create new Pull Request
License
The gem is available as open source under the terms of the MIT License.