node-sonos-http-api icon indicating copy to clipboard operation
node-sonos-http-api copied to clipboard

How to call sayall from own app and getting around invalid uri error?

Open jzajac2 opened this issue 5 years ago • 8 comments

I'm trying to figure out how to use the sayall function with a rails app using uri's open, for example

uri = URI.parse(URI.encode("#{HOST}:#{PORT}/sayall/#{speak_what}"))
response = open(uri).read

Here's an example request with a 302:

Request URL: http://localhost:3000/text_to_speech?utf8=%E2%9C%93&text_to_speak=go+to+sleep
Request Method: GET
Status Code: 302 Found

I'm assuming I have to URI.encode it otherwise I get

URI::InvalidURIError (bad URI(is not URI?): myhost:5005/sayall/go to sleep) There are other methods:

Addressable::URI.parse
CGI::escape
HTMLEntities.new.decode

However since sayall uses decodeURIComponent(), I don't know what I need to do to get the request through in a raw format similar to what a browser will accept (with spaces), which seems to be necessary for sayall, correct?

I may have to resort to javascript XMLHttpRequest I had that working fine with a raw javascript app, having hard time mapping what that does to the 'railsy' way.

Any suggestions?

jzajac2 avatar May 26 '19 14:05 jzajac2

I think you are going about it wrong. Do note that you should only encode the actual phrase, because what you are actually doing is converting a string to be passed as an argument (or, as a path folder name), which means that if you send in a full url for encoding, it will try to escape everything in it to be able to send it as a query parameter. Here is the distinction, query strings can take + as space, whereas a URL path can not (and this API uses a URL path).

I'm not familiar with Ruby, but a quick googling gives me that ERB::Util.url_encode would work correctly, CGI::Util.escape won't work. HTML entities is something different, it's for escaping into markup.

jishi avatar May 27 '19 09:05 jishi

You are correct, I should be encoding just the string. Fixed. I am still confused. Lets take my code out of the picture first. When I simply use the node-sonos-http-api from the browser like /sayall/go%20to%20sleep it returns 302 but does not actually say through the speakers. if use it like http://192.168.1.26:5005/sayall/go to sleep it works (not sure what the browser is doing under the hood here). Am I correct in that we want the escape characters in the request (thus the point of using ERB::Util.url_encode ?

Here's my updated code for more context.

def speak
    speak_what = params[:text_to_speak]
    # speak_what = 'go to sleep'
    puts "speak_what=#{speak_what}"
    if !speak_what.present? then return end
    speak_what_encoded = ERB::Util.url_encode(speak_what)
    puts "speak_what_encoded=#{speak_what_encoded}"
    uri = "#{HOST}:#{PORT}/sayall/#{speak_what_encoded}"
    begin
      puts "uri=#{uri}"
      response = open(uri).read     
    rescue ActionController::UnknownFormat => e
      if e.include? '204'
        # do nothing
      else
        raise e
      end
    end
    redirect_to :controller => 'presets', :action => 'display'
  end

which results in

Started GET "/text_to_speech?utf8=%E2%9C%93&text_to_speak=go+to+sleep" for ::1 at 2019-05-27 16:51:04 -0500
Processing by TextToSpeechController#speak as HTML
  Parameters: {"utf8"=>"✓", "text_to_speak"=>"go to sleep"}
speak_what=go to sleep
speak_what_encoded=go%20to%20sleep
uri=http://192.168.1.26:5005/sayall/go%20to%20sleep
Redirected to http://localhost:3000/

Now, some of that in the log above shows my controller being called, but my controller is making a get request to the uri (that .26 is the node-sonos-http-api server)

I'll have to dig deeper and probably just use javascript XMLHttpRequest for now but if you have any other suggestions/advice much appreciated

jzajac2 avatar May 27 '19 22:05 jzajac2

Yoy shouldn't get a 302 and definitely not be redirected to port 3000 on localhost. Something is off with the machine you are invoking it from... Does it have a proxy configured or something?

On Tue, 28 May 2019, 00:03 jzajac2, [email protected] wrote:

You are correct, I should be encoding just the string. Fixed. I am still confused. Lets take my code out of the picture first. When I simply use the node-sonos-http-api from the browser like /sayall/go%20to%20sleep it returns 302 but does not actually say through the speakers. if use it like http://192.168.1.26:5005/sayall/go to sleep it works (not sure what the browser is doing under the hood here). Am I correct in that we want the escape characters in the request (thus the point of using ERB::Util.url_encode ?

Here's my updated code for more context.

def speak

speak_what = params[:text_to_speak]

# speak_what = 'go to sleep'

puts "speak_what=#{speak_what}"

if !speak_what.present? then return end

speak_what_encoded = ERB::Util.url_encode(speak_what)

puts "speak_what_encoded=#{speak_what_encoded}"

uri = "#{HOST}:#{PORT}/sayall/#{speak_what_encoded}"

begin

  puts "uri=#{uri}"

  response = open(uri).read

rescue ActionController::UnknownFormat => e

  if e.include? '204'

    # do nothing

  else

    raise e

  end

end

redirect_to :controller => 'presets', :action => 'display'

end

which results in

Started GET "/text_to_speech?utf8=%E2%9C%93&text_to_speak=go+to+sleep" for ::1 at 2019-05-27 16:51:04 -0500

Processing by TextToSpeechController#speak as HTML

Parameters: {"utf8"=>"✓", "text_to_speak"=>"go to sleep"}

speak_what=go to sleep

speak_what_encoded=go%20to%20sleep

uri=http://192.168.1.26:5005/sayall/go%20to%20sleep

Redirected to http://localhost:3000/

Now, some of that in the log above shows my controller being called, but my controller is making a get request to the uri (that .26 is the node-sonos-http-api server)

I'll have to dig deeper and probably just use javascript XMLHttpRequest for now but if you have any other suggestions/advice much appreciated

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/jishi/node-sonos-http-api/issues/696?email_source=notifications&email_token=AAYE2IYIFXCHOKJ6VSKXSS3PXRLB5A5CNFSM4HPWZRK2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODWKSARY#issuecomment-496312391, or mute the thread https://github.com/notifications/unsubscribe-auth/AAYE2I6EWLQ7JN4HCIPCBADPXRLB5ANCNFSM4HPWZRKQ .

jishi avatar May 28 '19 07:05 jishi

the redirection is intentional (and temporary for now) and port 3000 as well (default for puma/webrick based servers I guess). Let me make sure I have all the latest code running first :)

jzajac2 avatar May 28 '19 11:05 jzajac2

Aha, now I understand what you mean. But either way, the url http://192.168.1.26:5005/sayall/go%20to%20sleep looks correct, no? are you saying it doesn't work? Try using curl or similar, if that works, you are doing something weird in ruby.

jishi avatar May 28 '19 11:05 jishi

Well, I'm saying even when I put http://192.168.1.26:5005/sayall/go%20to%20sleep in the browser, same result - I would get a 'success' but nothing coming out of the speakers, I'm really trying to keep my application out of it right now. I haven't updated / merged your updates to my fork in...quite a while, although I didn't see anything specific to sayall I should. Yes it's possible also something weird in ruby (rails) as fun and easy as it is to work with well, there's a cost to the magic. Yep I'll try curl

jzajac2 avatar May 28 '19 13:05 jzajac2

curl http://192.168.1.26:5005/sayall/go%20to%20sleep and I do not hear it through the speakers although I get success :(. :

 jzajac$ curl http://192.168.1.26:5005/sayall/go%20to%20sleep
{"status":"success"}

I'll dig more though

jzajac2 avatar Jun 04 '19 03:06 jzajac2

after updating some npm modules per github's security request the same curl request now produces:

curl http://192.168.1.26:5005/sayall/go%20to%20sleep {"status":"error","error":"Buffer.alloc is not a function","stack":"TypeError: Buffer.alloc is not a function\n at FileTokenizer.AbstractTokenizer (/home/pi/code/node-sonos-http-api/node_modules/strtok3/lib/AbstractTokenizer.js:7:33)\n at new FileTokenizer (/home/pi/code/node-sonos-http-api/node_modules/strtok3/lib/FileTokenizer.js:23:28)\n at /home/pi/code/node-sonos-http-api/node_modules/strtok3/lib/index.js:38:24\n at invokeCallback (/home/pi/code/node-sonos-http-api/node_modules/es6-promise/dist/es6-promise.js:408:15)\n at publish (/home/pi/code/node-sonos-http-api/node_modules/es6-promise/dist/es6-promise.js:391:7)\n at flush (/home/pi/code/node-sonos-http-api/node_modules/es6-promise/dist/es6-promise.js:128:5)\n at doNTCallback0 (node.js:417:9)\n at process._tickDomainCallback (node.js:387:13)"} Raise separate issue?

jzajac2 avatar Jun 30 '19 01:06 jzajac2