You have two options:
Place your TV show episode (.mp4, .mkv, .avi, etc.) anywhere on your computer. You'll reference the full path when running the conversion command.
Copy your video file to: storage/source_videos/
Example:
cp ~/Downloads/my-episode.mp4 storage/source_videos/- Make sure Solid Queue is running (in a separate terminal):
bin/jobs- Queue the conversion job:
# From anywhere on your system:
bin/rails media:convert[/path/to/your/episode.mp4,'Episode 1 - Pilot']
# Or from the storage directory:
bin/rails media:convert[storage/source_videos/episode.mp4,'My TV Show S01E01']- Monitor the conversion: The job will automatically:
- Create a Media record in the database
- Convert the video to HLS format with 3 quality variants:
- 720p (800kbps)
- 1080p (2.8Mbps)
- 4k (5Mbps)
- Store segments in
public/hls_output/{media_id}/ - Update the status to "ready" when complete
# Create a media record
media = Media.create!(title: "Episode 1", status: "pending")
# Queue the conversion job
ProcessVideoJob.perform_later(media.id, "/path/to/video.mp4")Once the conversion is complete (status: "ready"), you can stream the video:
curl http://localhost:3000/api/media/1curl http://localhost:3000/api/media/1/streamThis returns the master .m3u8 playlist that lists all quality variants.
# 720p variant
curl http://localhost:3000/api/media/1/stream/720p/index.m3u8
# 1080p variant
curl http://localhost:3000/api/media/1/stream/1080p_high/index.m3u8
# 4k variant
curl http://localhost:3000/api/media/1/stream/4k/index.m3u8curl http://localhost:3000/api/media/1/stream/720p/segment_000.ts
curl http://localhost:3000/api/media/1/stream/1080p_high/segment_001.tsbin/rails serverbin/jobsOr start both together:
bin/devbin/rails media:listbin/rails runner "puts SolidQueue::Job.all.map { |j| [j.class_name, j.arguments, j.finished_at].inspect }.join('\n')"tail -f log/development.log- Place your video file:
cp ~/Downloads/breaking-bad-s01e01.mp4 storage/source_videos/- Start background jobs:
bin/jobs- Queue conversion (in another terminal):
bin/rails media:convert[storage/source_videos/breaking-bad-s01e01.mp4,'Breaking Bad S01E01']- Wait for processing (watch the logs):
tail -f log/development.log- Once ready, test streaming:
curl http://localhost:3000/api/media/1/stream- Use in a video player (like VLC or a web player):
http://localhost:3000/api/media/1/stream
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/media |
List all media |
| GET | /api/media/:id |
Get media details |
| POST | /api/media |
Create media (with video_file) |
| PATCH | /api/media/:id |
Update media |
| DELETE | /api/media/:id |
Delete media |
| GET | /api/media/:id/stream |
Get master HLS playlist |
| GET | /api/media/:id/stream/*path |
Get HLS segments/variants |
Make sure FFmpeg is installed:
# macOS
brew install ffmpeg
# Ubuntu/Debian
sudo apt-get install ffmpeg
# Verify installation
ffmpeg -versionThe server is configured with proper CORS headers for iOS streaming:
- Content-Type:
application/vnd.apple.mpegurlfor.m3u8 - Content-Type:
video/mp2tfor.tssegments - CORS enabled for cross-origin requests
- Range request support for seeking
- Make sure
bin/jobsis running - Check logs:
tail -f log/development.log
- Install FFmpeg (see above)
- Verify with:
which ffmpeg
- Check media status:
curl http://localhost:3000/api/media/:id - Verify HLS files exist:
ls public/hls_output/:id/
- HLS files can be large (especially 4k)
- Consider reducing quality variants in
ProcessVideoJob