Calling system from a post in sinatra - ruby

I made a very small app for the raspberry pi, that uses Sinatra:
https://github.com/khebbie/SpeakPi
The app lets the user input some text in a textarea and asks Google to create an mp3 file for it.
In there I have a shell script called speech2.sh which calls Google and plays the mp3 file:
#!/bin/bash
say() {
wget -q -U Mozilla -O out.mp3 "http://translate.google.com/translate_tts?tl=da&q=$*";
local IFS=+;omxplayer out.mp3;
}
say $*
When I call speech.sh from the commandline like so:
./speech2.sh %C3%A6sel
It pronounces %C3%A6 like the danish letter 'æ', which is correct!
I call speech2.sh from a Sinatra route like so:
post '/say' do
message = params[:body]
system('/home/pi/speech2.sh '+ message)
haml :index
end
And when I do so Google pronounces some very weird chars like 'a broken pipe...' which is wrong!
All chars a-z are pronounced correctly
I have tried some URL encoding and decoding, nothing worked.
I tried outputting the message to the command-line and it was exactly "%C3%A6" that certainly did not make sense.
Do you have any idea what I am doing wrong?
EDIT
To Sum it up and simplify - if I type like so in bash:
./speech2.sh %C3%A6sel
It works
If I start an irb session and type:
system('/home/pi/speech2.sh', '%C3%A6sel')
It does not work!

Since it is handling UTF-8, make sure that the encoding remains right the way through the process by adding the # encoding: UTF-8 magic comment at the top of the Ruby script and passing the ie=UTF-8 parameter in the query string when calling Google Translate.

Related

How to deal with shell commands that never stops

Here is the case;
There is this app called "termux" on android which allows me to use a terminal on android, and one of the addons are androids API's like sensors, tts engines, etc.
I wanted to make a script in ruby using this app, specifically this api, but there is a catch:
The script:
require('json')
JSON.parse(%x'termux-sensor -s "BMI160 Gyro" -n 1')
-s = Name or partially the name of the sensor
-n = Count of times the command will run
returns me:
{
"BMI160 Gyroscope" => {
"values" => [
-0.03...,
0.00...,
1.54...
]
}
}
I didn't copied and pasted the values, but that's not the point, the point is that this command takes almost a full second the load, but there is a way to "make it faster"
If I use the argument "-d" and not use "-n", I can specify the time in milliseconds to delay between data being sent in STDOUT, it also takes a full second to load, but when it loads, the delay works like charm
And since I didn't specify a 'n' number of times, it never stops, and there is the problem
How can I retrieve the data continuously in ruby??
I thought about using another thread so it won't stop my program, but how can I tell ruby to return the last X lines of the STDOUT from a command that hasn't and will not ever stop since "%x'command'" in ruby waits for a return?
If I understood you need to connect to stdout from a long running process.
see if this works for your scenario using IO.popen:
# by running this program
# and open another terminal
# and start writing some data into data.txt
# you will see it appearing in this program output
# $ date >> data.txt
io_obj = IO.popen('tail -f ./data.txt')
while !io_obj.eof?
puts io_obj.readline
end
I found out a built in module that saved me called PTY and the spawn#method plus thread management helped me to keep a variable updated with the command values each time the command outputted new bytes

How do I get 'puts' messages and standard output sent to a file while using RSpec / parallel_rspec?

This is the contents of my .rspec_parallel file. I am using parallel_tests gem to run tests in multiple browser instances. To my knowledge, the gem uses the same formatter options available in RSpec.
--format html --out results<%= ENV['TEST_ENV_NUMBER'] %>.html
This works fantastic and I'm able to get the HTML output I normally see from RSpec. However, all of the 'puts' messages and basic standard output is logged to my console window, and not to the HTML files.
How can I get this output into each individual HTML file that I have set up?
puts will output to $stdout where as output is actually an instance variable of the RSpec::Core::Formatters::BaseFormatter class. output is defaulted to $stdout but when you pass in a string it determines that it should create a new StringIO and then output this to the given file name. Thus puts will not append to the #output variable.
You could do something ugly like create a runner file like
File.open('some_file_name.html','w+') do |file|
file << `rspec spec --format html`
end
Then this file will have the output from $stdoutbut your puts code will not be html formatted in this case. Other than that you could try building your own Custom Formatter but it will probably take quite a bit of source searching to make sure you can capture everything appropriately.
That being said it does seem the reporter was exposed for adding custom messages but I am uncertain of how to use this appropriately See Pull Request 1866
Seems it would be something like
it "has a name" do |ex|
ex.reporter.message("Custom Message Here")
#actual test
end
but the html formatter seems to ignore this. I can see the output in $stdout but not in the html file itself.
Best of luck.

How to prevent capistrano replacing newlines?

I want to run some shell scripts remotely as part of my capistrano setup. To test that functionality, I use this code:
execute <<SHELL
cat <<TEST
something
TEST
SHELL
However, that is actually running /usr/bin/env cat <<TEST; something; TEST which is obviously not going to work. How do I tell capistrano to execute the heredoc as I have written it, without converting the newlines into semicolons?
I have Capistrano Version: 3.2.1 (Rake Version: 10.3.2) and do not know ruby particularly well, so there might be something obvious I missed.
I think it might work to just specify the arguments to cat as a second, er, argument to execute:
cat_args = <<SHELL
<<TEST
something
TEST
SHELL
execute "cat", cat_args
From the code #DavidGrayson posted, it looks like only the command (the first argument to execute) is sanitized.
I agree with David, though, that the simpler way might be to put the data in a file, which is what the SSHKit documentation suggests:
Upload a file from a stream
on hosts do |host|
file = File.open('/config/database.yml')
io = StringIO.new(....)
upload! file, '/opt/my_project/shared/database.yml'
upload! io, '/opt/my_project/shared/io.io.io'
end
The IO streaming is useful for uploading something rather than "cat"ing it, for example
on hosts do |host|
contents = StringIO.new('ALL ALL = (ALL) NOPASSWD: ALL')
upload! contents, '/etc/sudoers.d/yolo'
end
This spares one from having to figure out the correct escaping sequences for something like "echo(:cat, '...?...', '> /etc/sudoers.d/yolo')".
This seems like it would work perfectly for your use case.
The code responsible for this sanitization can be found in SSHKit::Command#sanitize_command!, which is called by that class's initialize method. You can see the source code here:
https://github.com/capistrano/sshkit/blob/9ac8298c6a62582455b1b55b5e742fd9e948cefe/lib/sshkit/command.rb#L216-226
You might consider monkeypatching it to do nothing by adding something like this to the top of your Rakefile:
SSHKit::Command # force the class to load so we can re-open it
class SSHKit::Command
def sanitize_command!
return if some_condition
super
end
end
This is risky and could introduce problems in other places; for example there might be parts of Capistrano that assume that the command has no newlines.
You are probably better off making a shell script that contains the heredoc or putting the heredoc in a file somewhere.
Ok, so this is the solution I figured out myself, in case it's useful for someone else:
str = %x(
base64 <<TEST
some
thing
TEST
).delete("\n")
execute "echo #{str} | base64 -d | cat -"
As you can see, I'm base64 encoding my command, sending it through, then decoding it on the server side where it can be evaluated intact. This works, but it's a real ugly hack - I hope someone can come up with a better solution.

Problems running FFprobe with Ruby

I am fairly new to Ruby and programming, less than a year experience. This is ruby 1.9.3 and the newest ffmpeg for Ubuntu from FFmpeg. Files I am using are basic .avi, some v210 .mov, other quicktime/finalcutpro types of files.
I am trying to write an automated probing tool that will help lessen the manual work load for me when I start testing with and dealing with lots of media files. Basically the script goes through a directory and probes each file, extracting the info I need, and writes it out to csv.
Currently, everytime I run it, the actual capture on command line is failing.
def prober(file)
#the_file = file
stdout,stderr,status = Open3.capture3("ffprobe -v quiet -print_format json - show_format -show_streams #{#the_file}")
STDERR.puts stderr
if status.success?
out = stdout
else
STDERR.puts "There was a problem, please try again."
end
#raw_output = JSON.parse(out)
end
I don't know if it is something to do with how I am running the command (I don't really fully understand I/O streams), or something with ffprobe. When it does make it past the probe it is returning #raw_output as nil, which causes JSON parsing to puke, or my other methods for splitting and parsing the metadata fail on nil.
Any help at all would great, I have been stuck on this for a while. Thanks! I can provide more code if needed for clarification,.
After the holidays I came back fresh and found the problem. The filepath string needs to have quotes around it when fed to the stdin for ffprobe, but when I aggregated the files it stripped the quotes. The fix? add quotes around the filepath in the string.
I hope this helps someone, apparently I am the only person in the whole internet to have this problem.

passing arguaments to a system call in Rails, but not plain ruby program

Ubuntu 12.04
Sinatra 1.3.3
Why does passing an argument to a ruby system call (%x[] or ``) give me a 'not found' error in my sinatra app? The same code works fine in a normal ruby script running from the same directory.
I have a file test.rb like this
output = %x["ls"]
p output
When I run it with "ruby test.rb" I get the contents of the current directory in the console, as expected.
If I modify the program to give an argument to the system call like so:
output = %x["ls sub_dir/"]
p output
I get the contents of sub_dir, which sits in the current directory, as expected.
So far so good.
Now if I make a Sintra app with a post method:
require 'rubygems'
require 'bundler/setup'
require 'sinatra'
post "/" do
output = x["ls"]
return output
end
The response to a Post call to "/" returns the contents of the current directory, which includes 'sub_dir', as expected.
If I try to add the argument to the system call to the sinatra app like so:
require 'rubygems'
require 'bundler/setup'
require 'sinatra'
post "/" do
output = x["ls sub_dir/"]
return output
end
the response is nil and there is an error in the console:
sh: 1: ls sub_dir/: not found
Why does adding a parameter to a system call in my sinatra app cause it to crash, when the same code called from a plain ruby script, run from the same location works perfectly.
By the way, the 'ls' example shown here is not the command I really need to run, so please don't explain a different way to get this information. I have an executable file that takes a file name as a parameter that I need to run, which behaves exactly the same way.
Thanks in advance!
If you want to specify a path in relation to the application, you could use something like this:
post "/" do
path = File.join(File.dirname(__FILE__), "sub_dir")
%x[ls #{path}]
end
However, if you want to list the contents of a directory, why not do it in Ruby?
I rewrote the sinatra app in another file in the same directory.
Everything works as expected.
I did not find the reason and I deleted the original file so that I won't lose anymore time trying to figure it out.

Resources