Miniradio Server is Simple Ruby HLS Server for MP3s
This is a basic HTTP Live Streaming (HLS) server written in Ruby using the Rack interface. It serves MP3 audio files by converting them on-the-fly into HLS format (M3U8 playlist and MP3 segment files) using ffmpeg
. Converted files are cached for subsequent requests.
This server is designed for simplicity and primarily targets Video on Demand (VOD) scenarios where you want to stream existing MP3 files via HLS without pre-converting them.
Prerequisites
Before running the server, ensure you have the following installed:
- Ruby: Version 3.1 or later (tested on 3.4).
-
Dependency Gems: Install using
bundle
. -
FFmpeg: A recent version of
ffmpeg
must be installed and accessible in your system's PATH. You can download it from ffmpeg.org or install it via your system's package manager (e.g.,apt install ffmpeg
,brew install ffmpeg
).
Setup
-
Install Gems:
gem install miniradio_server
-
Create MP3 Directory: Create a directory named
mp3_files
in the same location as the script.(Alternatively, change themkdir mp3_files
MP3_SRC_DIR
constant in the script). -
Add MP3 Files: Place the MP3 files you want to stream into the
mp3_files
directory.-
Important: Use simple, URL-safe filenames for your MP3s (e.g., letters, numbers, underscores, hyphens). Spaces or special characters might cause issues. Example:
my_cool_song.mp3
,podcast_episode_1.mp3
.
-
Important: Use simple, URL-safe filenames for your MP3s (e.g., letters, numbers, underscores, hyphens). Spaces or special characters might cause issues. Example:
-
Cache Directory: The script will automatically create a
hls_cache
directory (or the directory specified byHLS_CACHE_DIR
) when the first conversion occurs. Ensure the script has write permissions in its parent directory.
Running the Server
Navigate to the directory containing the script in your terminal and run:
bin/miniradio_server
Info: ffmpeg found.
Starting HLS conversion and streaming server on port 9292...
MP3 Source Directory: /path/to/your/project/mp3_files
HLS Cache Directory: /path/to/your/project/hls_cache
Default External Encoding: UTF-8
Using Handler: Rackup::Handler::WEBrick
Example Streaming URL: http://localhost:9292/stream/{mp3_filename_without_extension}/playlist.m3u8
e.g., If mp3_files/ contains my_music.mp3 -> http://localhost:9292/stream/my_music/playlist.m3u8
Press Ctrl+C to stop.
The server will run in the foreground. Press Ctrl+C to stop it.
Usage: Accessing the Index Page
You can access the index page listing available MP3 files by navigating to http://localhost:{SERVER_PORT}/
in your web browser.
Usage: Accessing Streams
Once the server is running, you can access the HLS streams using an HLS-compatible player (like VLC, QuickTime Player on macOS/iOS, Safari, or web players using hls.js).
The URL format is:
http://localhost:{SERVER_PORT}/stream/{mp3_filename_without_extension}/playlist.m3u8
Example:
If you have an MP3 file named mp3_files/awesome_track.mp3 and the server is running on the default port 9292, the streaming URL would be:
http://localhost:9292/stream/awesome_track/playlist.m3u8
Note: The first time you request a specific stream, the server will run ffmpeg to convert the MP3. This might take a few seconds depending on the file size. Subsequent requests for the same stream will be served instantly from the cache.
Configuration
You can modify the following constants at the top of the script (miniradio_server.rb):
- MP3_SRC_DIR: Path to the directory containing your original MP3 files.
- HLS_CACHE_DIR: Path to the directory where HLS segments and playlists will be cached.
- SERVER_PORT: The network port the server listens on.
- FFMPEG_COMMAND: The command used to execute ffmpeg (change if it's not in your PATH).
- HLS_SEGMENT_DURATION: The target duration (in seconds) for each HLS segment.
How it Works
- A client requests an M3U8 playlist URL (e.g., /stream/my_song/playlist.m3u8).
- The server checks if the corresponding HLS files (hls_cache/my_song/playlist.m3u8 and segments) exist in the cache directory.
- If the cache does not exist:
- It verifies the original mp3_files/my_song.mp3 exists.
- It acquires a lock specific to my_song to prevent simultaneous conversions.
- It runs ffmpeg to convert my_song.mp3 into hls_cache/my_song/playlist.m3u8 and hls_cache/my_song/segmentXXX.mp3.
- The lock is released.
- If the cache does exist (or after successful conversion), the server serves the requested playlist.m3u8 file.
- The client parses the M3U8 playlist and requests the individual MP3 segment files listed within it (e.g., /stream/my_song/segment000.mp3, /stream/my_song/segment001.mp3, etc.).
- The server serves these segment files directly from the cache directory.
Limitations
- VOD Only: This server is designed for Video on Demand (pre-existing files) and does not support live streaming.
- Basic Caching: Cache is persistent but simple. There's no automatic cache invalidation if the source MP3 changes. You would need to manually clear the corresponding subdirectory in hls_cache.
- Security: Basic checks against directory traversal are included, but it's not hardened for production use against malicious requests. No authentication/authorization is implemented.
- Performance: Relies on ffmpeg execution per file (first request only). Uses Ruby's WEBrick via rackup, which is single-threaded by default and not ideal for high-concurrency production loads.
- Error Handling: Basic error handling is implemented, but complex ffmpeg issues or edge cases might not be handled gracefully.
- Resource Usage: Conversion can be CPU-intensive (though -c:a copy helps significantly) and disk I/O intensive during the first request for a file.
Development
Install from git repository:
git clone https://github.com/koichiro/miniradio_server.git
cd miniradio_server
bundle
bin/miniradio_server
After checking out the repo, run bin/setup
to install dependencies. Then, run rake test
to run the tests. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and the created tag, and push the .gem
file to rubygems.org.
ToDo
- Continuous playback of multiple Music tracks
- ✅
Use hls.js to support playback in Chrome. - ✅
Rendering of the Delivered Music list page - ✅
Multilingual support for file names.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/koichiro/miniradio_server.
License
This project is licensed under the MIT License - see the LICENSE file for details (or assume MIT if no LICENSE file is present).