if err
callback err
else
- callback null, JSON.parse data
+ auth = JSON.parse data
+ callback null, auth
# elements look like: ['name', {attr: value, attr2: value2,...}, [contents]]
# text nodes look like elements with blank names: ['', {}, 'foo']
exports.parse_xml = parse_xml
+# pass the js representation (nested arrays, etc)
+# returns the lfm object or null
+find_lfm_element = (parsed, callback) ->
+ for element in parsed
+ if element[0] is 'lfm'
+ return element
+ return null
+
# returns just the "lfm" element of xml (as described in parse_xml) or fires an error
# callback(err, array)
parse_lfm_xml = (text, callback) ->
parse_xml text, (err, parsed) ->
- if err
- # parse error
+ if err?
+ # report this parse error
callback err
return
- for element in parsed
- if element[0] is 'lfm'
- callback null, element
- return
- callback "Couldn't find lfm element in server response"
- return
+ lfm = find_lfm_element parsed
+ if lfm?
+ callback null, lfm
+ else
+ callback "Couldn't find lfm element in server response"
return
# login and get a session key
req.write args
req.end()
+# FIXME call tune automatically or remove "tag" argument
+get_playlist = (tag, callback) ->
+ login_cached (err, sk) ->
+ return callback(err) if err?
+
+ tune tag, (err)->
+ return callback(err) if err?
+
+ console.log "getting playlist with sk=#{sk}"
+ http.get { host: 'alpha.libre.fm', port: 80, path: "/2.0/?method=radio.getPlaylist&sk=#{sk}"}, (res) ->
+ if res.statusCode != 200
+ callback "getPlaylist http response code: #{res.statusCode}"
+ return
+
+ res.setEncoding 'utf8'
+ response_text = ''
+ res.on 'data', (chunk) ->
+ response_text += chunk
+ res.on 'end', ->
+ # while testing, got response_text === "BADSESSION"
+ console.log "server responded"
+ # console.log "server said: #{response_text}"
+ parse_xml response_text, (err, response) ->
+ if err?
+ return callback "Error while parsing server reply while requesting playlist: #{err}"
+ for element in response
+ if element[0] is 'playlist'
+ # FIXME write this bit
+ console.log 'Yay we got a playlist!'
+ console.log JSON.stringify element[0]
+ else if element[0] is 'lfm'
+ if element[1].status isnt 'failed'
+ callback "Server responded to our playlist request with #{JSON.stringify response}"
+ return
+
+ # FIXME search for "error" element instead of assuming it's first
+ code = element[2][0]?.code
+ if code is 4 # invalid authentication token
+ delay = 0
+ sk_age = now_ms() - auth.sk_date
+ if sk_age < 30000
+ console.log "Server said our auth token was invalid only #{sk_age}ms after we got it."
+ delay = 30000 - sk_age
+ console.log "Waiting another #{delay}ms before requesting another one."
+ # get new auth token
+ timeout delay, ->
+ login (err, sk) ->
+ if err
+ callback err
+ return
+ get_playlist tag, callback
+ return
+ else
+ if typeof element[2][0]?[2] is 'string'
+ message = JSON.stringify element[2][0][2]
+ console.log "server response from tune: code #{code} message: #{message}"
+ callback "Error during tune: code #{code} message: #{message}"
+ return
+ # looked through all elements, and didn't find one with name "error"
+ callback "Error during tune: server responded without success or error message"
+
+test = (tag, callback) ->
+ get_playlist tag, ->
+ if err?
+ console.log err
+ callback err
+ return
+ console.log 'yay'
+ callback()
+
+exports.test = test
+exports.get_playlist = get_playlist
exports.tune = tune
exports.login = login # fixme remove this from the API and call it automatically
exports.new_auth_token = new_auth_token