rubytaglib-ruby

Convert supposed seconds to duration?


I'm new to Ruby so I'm probably going about this completely wrong, but using taglib-ruby I keep getting a wrong result unless it's a wrong amount of seconds maybe nanoseconds?

I tried with bash and mediainfo a different movie but worked ok ...

$(date -ud "@$(($seconds/1000))" +'%_H:%M')
def get_duration_hrs_and_mins(milliseconds)
    return '' unless milliseconds

    hours, milliseconds   = milliseconds.divmod(1000 * 60 * 60)
    minutes, milliseconds = milliseconds.divmod(1000 * 60)
    seconds, milliseconds = milliseconds.divmod(1000)
    "#{hours}h #{minutes}m #{seconds}s #{milliseconds}ms"
end

TagLib::MP4::File.open("filename.mp4") do |mp4|
    seconds = mp4.length
    puts get_duration_hrs_and_mins(seconds)
end

The amount of seconds is 1932993085 and the duration should be roughly 2 h 15 min.


Solution

  • I'm afraid you are misinformed. The length attribute of a TagLib::MP4::File object is inherited from the regular File class and just tells you the size of the file in bytes; it has nothing to do with the duration of the contained media:

    $ ls -l test.mp4
    -rw-r--r--@ 1 user  staff  39001360 Aug 14  2015 test.mp4
    $ ruby -rtaglib -e 'TagLib::MP4::File.open("test.mp4"){|f|puts f.length}'
    39001360
    

    The particular file I'm examining in the above code snippet happens to be 25 seconds long, but there's no way to tell that from the fact that it's about 39 megabytes in size.

    What you want is the #length method of the TagLib::MP4::Properties object, not the ::File one. You can get that by calling #audio_properties on the File object:

    TagLib::MP4::File.open("filename.mp4") do |mp4|
      seconds = mp4.audio_properties.length
      puts get_duration_hrs_and_mins(seconds)
    end
    

    That return value is seconds, not milliseconds, so you need to adjust your get_duration method accordingly. Really you just want something like this:

    total_seconds = mp4.audio_properties.length
    total_minutes, seconds = total_seconds.divmod(60)
    total_hours, minutes = total_minutes.divmod(60)
    days, hours = total_hours.divmod(24)
    
    puts "Duration is #{days}d#{hours}h#{minutes}m#{seconds}s"