mtrc
mtrc

Reputation: 1345

Ruby Gem works on commandline and irb - fails when run as ruby script or via Java Process

I've been trying to get a certain Google API to work for two days now. Three different projects have been tried - one in Perl (which died very early on) one in Python (crashed and burnt at the last hurdle) and finally one in Ruby. The Ruby one actually works when called from the commandline as a standard command, i.e.:

speech2text somefile.wav

It even works if you open up irb and put in the sample code found on the project site:

require 'speech'
audio = Speech::AudioToText.new("i-like-pickles.wav")
puts audio.to_text.inspect

However, a Ruby .rb file with the above in will not work when executed with ruby -rubygems somescript.rb. It exits with this:

/Library/Ruby/Gems/1.8/gems/speech2text-0.3.4/lib/speech/audio_inspector.rb:50:in `initialize': undefined method `first' for nil:NilClass (NoMethodError)
from /Library/Ruby/Gems/1.8/gems/speech2text-0.3.4/lib/speech/audio_splitter.rb:77:in `new'
from /Library/Ruby/Gems/1.8/gems/speech2text-0.3.4/lib/speech/audio_splitter.rb:77:in `initialize'
from /Library/Ruby/Gems/1.8/gems/speech2text-0.3.4/lib/speech/audio_to_text.rb:15:in `new'
from /Library/Ruby/Gems/1.8/gems/speech2text-0.3.4/lib/speech/audio_to_text.rb:15:in `to_text'
from script/test_s2t.rb:6

Attempting to use the commandline binary speech2text from Java as a runtime process results in the same error message being fed back. The offending line it complains about is:

    def initialize(file)
  self.duration = Duration.new(`ffmpeg -i #{file} 2>&1`.strip.scan(/Duration: (.*),/).first.first)
end

But the idea of there actually being a problem in there seems unlikely to me, given that it works perfectly when executed in either irb or via the binary on a terminal.

The real problem here is that I don't know Ruby at all - I work in Java, and I simply need this API to function. The fact that it runs in some methods tells me I probably installed it correctly, but unless I can get a .rb script to work or get it to execute externally, I can't see how to use it. I've had JRuby recommended to me, but that might be too complicated for me, as it seems it would require a manual installation of the ruby gem for JRuby, which I don't know how to do (or at least, I don't think I know how to do it!)

Any advice on the core error message much appreciated, but if you see a clear sidestep to the problem do let me know.

EDIT - It was, indeed, a path problem - at least on the face of it. Ruby was having trouble locating the exact files involved, and speech2text/ffmpeg was failing rather obscurely as a result. Thanks!

Upvotes: 0

Views: 826

Answers (2)

the Tin Man
the Tin Man

Reputation: 160551

Your use of backticks can be masking the problem:

`ffmpeg -i #{file} 2>&1`.strip.scan(/Duration: (.*),/).first.first

If you get nothing back, or your results don't contain "Duration: " followed by something, you will get the error you saw.

First, confirm that your path is correct. Any embedded spaces will break your command because ffmpeg will receive the file name as multiple parameters, not a full file path. You can use any of the system calls or popen to protect against that, or escape any embedded spaces and single/double quotes. At a minimum, try:

`ffmpeg -i "#{file}" 2>&1`

or

`ffmpeg -i '#{file}' 2>&1`

Consider breaking your call to ffmpeg into multiple steps, to write defensively, and get some visibility into what is going on. This is untested code but should give you the idea:

ffmpeg_results = `ffmpeg -i #{ file } 2>&1`
if (!ffmpeg_results.strip.empty?)
  duration = ffmpeg_results.strip[/Duration: (.*),/, 1]
  if (!duration.strip.empty? && duration.to_i > 0)
    ...
  end
else
  puts "ffmpeg_results are empty"
end  

You want to try each step, before continuing, at least until you are sure your process is bulletproof, or as bulletproof as you need.

Upvotes: 0

Holger Just
Holger Just

Reputation: 55758

This smells like a path issue. You should always specify the full path to the file as other processes can change their working directory to other locations internally. Another possibility would be a changed $PATH so that ffmpeg can not be resolved to an absolute path.

Generally, you should try to specify your paths as absolute as possible.

Upvotes: 1

Related Questions