taglib-simple
TagLib::MediaFile provides an idiomatic Ruby interface over TagLib's simple, abstract APIs for audio file tags.
Install
gem install taglib-simple
or include in your Gemfile
gem 'taglib-simple'
Usage - taglib.rb
Ruby script that prints tag information for a file or directory
$ taglib.rb test.mp3
{:title=>"Test Title",
:artist=>"Artist",
:album=>"Album",
:genre=>"Heavy Metal",
:year=>2011,
:track=>1,
:comment=>"Comments",
"ALBUM"=>["Album"],
"ALBUMARTIST"=>["Album Artist"],
"ALBUMARTISTSORT"=>["Sort Album Artist"],
"ALBUMSORT"=>["Sort Album"],
"ARTIST"=>["Artist"],
"ARTISTSORT"=>["Sort Artist"],
"COMMENT"=>["Comments"],
"COMPILATION"=>["1"],
"DATE"=>["2011"],
"DISCNUMBER"=>["1/2"],
"GENRE"=>["Heavy Metal"],
"LYRICS"=>["Lyrics"],
"SUBTITLE"=>["Description"],
"TITLE"=>["Test Title"],
"TRACKNUMBER"=>["1/10"],
:path=>"test.mp3"}
Usage - in ruby code
General Read/Write
require 'taglib_simple'
TagLib::MediaFile.open(filename) do |media_file|
# TagLib::Tag - specific well known tags
media_file.tag # => <AudioTag> { title: 'The title', artist: 'An Artist', album: nil, ...}
# Attribute like interface
media_file.title # => 'The title'
media_file.year # => 2024
media_file.title = 'New Title' # => 'New Title' (writer)
# Hash interface (Symbol keys)
media_file[:title] # => 'The title'
# TagLib::PropertyMap - arbitrary tags with normalised structure across formats
media_file.properties # { 'TITLE' => ['The title'], 'ARTIST' => ['An Artist']}
# Hash interface (String keys)
media_file['LANGUAGE'] # => 'English'
media_file['MUSICBRAINZ_ALBUMID'] # => 'ID1234567890'
media_file['TITLE'] = 'A new title' # => ['A new title'] (writer)
media_file['ARTISTS'] = 'Artist1', 'Artist2' # => [ 'Artist1', 'Artist2' ] (writer)
media_file.delete('ARTISTS') # => [ 'Artist1', 'Artist2' ] (delete a property, return previous value)
media_file['ARTISTS', all: true] # => [ 'Artist1', 'Artist2' ] (multi-value reader)
media_file.fetch_all('ARTISTS', []) # => [ 'Artist1', 'Artist2' ] or [] if not property for 'ARTISTS'
# including 'complex' properties like cover art
media_file['PICTURE'] # => { 'data' => "<binary data", 'mimeType' => "image/png" }
# Arbitrary method like interface over the properties hash
media_file.language # => 'English'
media_file.musicbrainz__album_id # => 'ID1234567890'
media_file.all_artists # => ['Artist1', 'Artist2']
media_file.artists = 'Artist1', 'Artist2' # => ['Artist1', 'Artist2'] (writer)
end
Note that #save! is called automatically if the media_file is #modified? within the block, and #close is ensured as the block exits.
Read only usage
For read-only operations, TagLib::MediaFile.read ensures the file is closed, and memory held within the underlying TagLib library is released, before the requested information is returned.
Default retrieves Tag and PropertyMap from Taglib, closes the file and returns the MediaFile in read-only mode
mf = TagLib::MediaFile.read(filename)
mf.tag # => <AudioTag> { title: 'title' ...}
mf.title # => 'title'
mf.properties # => { 'TITLE' => 'title', 'LYRICS' => 'la la la'}
mf.lyrics # => 'la la la'
mf.complex_properties # => {} (not retrieved from taglib)
mf.audio_properties # => nil (not retrieved from taglib)
mf.closed? # => true
mf.writable? # => false
mf.title = 'New Title' # Error! not writable.
Read including cover art as a complex property
mf = TagLib::MediaFile.read(filename, complex_property_keys: ['PICTURE'])
mf.title # => 'A title'
mf.picture # => { 'data' => "<binary data", 'mimeType' => "image/png" }
Read everything taglib has about a file
mf = TagLib::MediaFile.read(filename, all: true)
mf.tag # => <AudioTag>
mf.properties # => { 'TITLE' => 'title' ...}
mf.complex_properties # => { 'PICTURE' => { 'data' => "<binary data", 'mimeType' => "image/png" } ...}
mf.audio_properties # => <AudioProperties>
mf.sample_rate # 44100
Read using just the Tag API
tag = TagLib::AudioTag.read(filename) # => <AudioTag>
tag.title # => 'A Title'
tag.year # => 1983
Advanced: Working with IO Objects
In addition to String based file names TagLib::MediaFile also supports general File and IO objects.
Read tags from standard input
$stdin.binmode
JSON.pretty_generate(TagLib::MediaFile.read($stdin).to_h)
Why? (OR: why not taglib-ruby)
The existing taglib-ruby gem provides a more or less direct wrapping of the full TagLib C++ library via SWIG but does not yet support the PropertyMap interface.
Benefits:
- Simple, idiomatic ruby interface.
- Uses TagLib's builtin auto-detection capabilities to work with any audio format TagLib supports
- Supports complex properties - album covers embedded in tags
- Supports Ruby IO objects in addition to plain files
- Simplified memory management - no native TagLib objects are exposed to Ruby
Limitations:
No access to TagLib's "format specific APIs for advanced API users", ie no understanding of the underlying type or structure of a file or its tags, and no access to manipulate other stream data.