lib/echonest/api.rb in ruby-echonest-0.0.6 vs lib/echonest/api.rb in ruby-echonest-0.1.1

- old
+ new

@@ -1,198 +1,144 @@ +# -*- coding: utf-8 -*- require 'digest/md5' require 'httpclient' +require 'json' module Echonest class Api - VERSION = '3' - BASE_URL = 'http://developer.echonest.com/api/' + BASE_URL = 'http://developer.echonest.com/api/v4/' USER_AGENT = '%s/%s' % ['ruby-echonest', ::Echonest::VERSION] + include TraditionalApiMethods + class Error < StandardError; end attr_reader :user_agent def initialize(api_key) @api_key = api_key @user_agent = HTTPClient.new(:agent_name => USER_AGENT) end - def get_bars(filename) - get_analysys(:get_bars, filename) do |analysis| - analysis.map do |bar| - Bar.new(bar.content.to_f, bar['confidence'].to_f) - end - end + def track + ApiMethods::Track.new(self) end - def get_beats(filename) - get_analysys(:get_beats, filename) do |analysis| - analysis.map do |beat| - Beat.new(beat.content.to_f, beat['confidence'].to_f) - end - end + def build_params(params) + params = params. + merge(:format => 'json'). + merge(:api_key => @api_key) end - def get_segments(filename) - get_analysys(:get_segments, filename) do |analysis| - analysis.map do |segment| - max_loudness = loudness = nil + def request(name, method, params, file = nil) + if file + query = build_params(params).sort_by do |param| + param[0].to_s + end.inject([]) do |m, param| + m << [URI.encode(param[0].to_s), URI.encode(param[1])].join('=') + end.join('&') - segment.find('loudness/dB').map do |db| - if db['type'] == 'max' - max_loudness = Loudness.new(db['time'].to_f, db.content.to_f) - else - loudness = Loudness.new(db['time'].to_f, db.content.to_f) - end - end + uri = URI.join(BASE_URL, name.to_s) + uri.query = query - pitches = segment.find('pitches/pitch').map do |pitch| - pitch.content.to_f - end - - timbre = segment.find('timbre/coeff').map do |coeff| - coeff.content.to_f - end - - Segment.new( - segment['start'].to_f, - segment['duration'].to_f, - loudness, - max_loudness, - pitches, - timbre - ) - end + response_body = @user_agent.__send__( + method.to_s + '_content', + uri, + file.read, + { + 'Content-Type' => 'application/octet-stream' + }) + else + response_body = @user_agent.__send__( + method.to_s + '_content', + URI.join(BASE_URL, name.to_s), + build_params(params)) end - end - def get_tempo(filename) - get_analysys(:get_tempo, filename) do |analysis| - analysis.first.content.to_f + response = Response.new(response_body) + unless response.success? + raise Error.new(response.status.message) end - end - def get_sections(filename) - get_analysys(:get_sections, filename) do |analysis| - analysis.map do |section| - Section.new( - section['start'].to_f, - section['duration'].to_f - ) - end - end + response + rescue HTTPClient::BadResponseError => e + raise Error.new('%s: %s' % [name, e.message]) end + end - def get_duration(filename) - get_analysys(:get_duration, filename) do |analysis| - analysis.first.content.to_f + module ApiMethods + class Base + def initialize(api) + @api = api end end - def get_end_of_fade_in(filename) - get_analysys(:get_end_of_fade_in, filename) do |analysis| - analysis.first.content.to_f + class Track < Base + def profile(options) + @api.request('track/profile', + :get, + options.merge(:bucket => 'audio_summary')) end - end - def get_key(filename) - get_analysys(:get_key, filename) do |analysis| - ValueWithConfidence.new(analysis.first.content.to_i, analysis.first['confidence'].to_f) + def analyze(options) + @api.request('track/analyze', + :post, + options.merge(:bucket => 'audio_summary')) end - end - def get_loudness(filename) - get_analysys(:get_loudness, filename) do |analysis| - analysis.first.content.to_f - end - end + def upload(options) + options.update(:bucket => 'audio_summary') - def get_metadata(filename) - get_analysys(:get_metadata, filename) do |analysis| - analysis.inject({}) do |memo, key| - memo[key.name] = key.content - memo - end - end - end + if options.has_key?(:filename) + filename = options.delete(:filename) + filetype = filename.to_s.match(/\.(mp3|au|ogg)$/)[1] - def get_mode(filename) - get_analysys(:get_mode, filename) do |analysis| - ValueWithConfidence.new(analysis.first.content.to_i, analysis.first['confidence'].to_f) - end - end - - def get_start_of_fade_out(filename) - get_analysys(:get_start_of_fade_out, filename) do |analysis| - analysis.first.content.to_f - end - end - - def get_tatums(filename) - get_analysys(:get_tatums, filename) do |analysis| - analysis.map do |tatum| - Tatum.new(tatum.content.to_f, tatum['confidence'].to_f) + open(filename) do |f| + @api.request('track/upload', + :post, + options.merge(:filetype => filetype), + f) + end + else + @api.request('track/upload', :post, options) end end - end - def get_time_signature(filename) - get_analysys(:get_time_signature, filename) do |analysis| - ValueWithConfidence.new(analysis.first.content.to_i, analysis.first['confidence'].to_f) + def analysis(filename) + analysis_url = analysis_url(filename) + Analysis.new_from_url(analysis_url) end - end - def build_params(params) - params = params. - merge(:version => VERSION). - merge(:api_key => @api_key) - end + def analysis_url(filename) + md5 = Digest::MD5.hexdigest(open(filename).read) - def get_analysys(method, filename) - get_trackinfo(method, filename) do |response| - yield response.xml.find_first('/response/analysis') - end - end + while true + begin + response = profile(:md5 => md5) + rescue Api::Error => e + if e.message =~ /^The Identifier specified does not exist/ + response = upload(:filename => filename) + else + raise + end + end - def get_trackinfo(method, filename, &block) - content = open(filename).read - md5 = Digest::MD5.hexdigest(content) + case response.body.track.status + when 'unknown' + upload(:filename => filename) + when 'pending' + sleep 60 + when 'complete' + return response.body.track.audio_summary.analysis_url + when 'error' + raise Error.new(response.body.track.status) + when 'unavailable' + analyze(:md5 => md5) + end - begin - response = request(method, :md5 => md5) - - block.call(response) - rescue Echonest::Api::Error => e - case e.message - when /Analysis not ready/ - sleep 20 # wait for serverside analysis - get_trackinfo(method, filename, &block) - when 'Invalid parameter: unknown MD5 file hash' - upload(filename) - sleep 60 # wait for serverside analysis - get_trackinfo(method, filename, &block) - else - raise + sleep 5 end end - end - - def upload(filename) - open(filename) do |f| - request(:upload, :file => f) - end - end - - def request(name, params) - method = (name == :upload ? 'post' : 'get') - response_body = @user_agent.__send__(method + '_content', URI.join(BASE_URL, name.to_s), build_params(params)) - response = Response.new(response_body) - - unless response.success? - raise Error.new(response.status.message) - end - - response end end end class HTTPClient