require_relative 'core_ext/hash.rb' require 'httparty' require 'hashie' require 'active_support/core_ext/string/inflections' class Nike::Client include HTTParty # debug_output $stdout LOGIN_URL = 'https://secure-nikeplus.nike.com/nsl/services/user/login' BASE_URL = 'http://nikeplus.nike.com/plus' APP_KEY = 'b31990e7-8583-4251-808f-9dc67b40f5d2' FORMAT = :json # service urls # RUN_ACTIVITIES_URL = '/activity/running/[user_id]/lifetime/activities' HR_ACTIVITIES_URL = '/activity/running/[user_id]/heartrate/lifetime/activities' ACTIVITY_URL = '/running/ajax' ACTIVITIES_URLS = { run: RUN_ACTIVITIES_URL, hr: HR_ACTIVITIES_URL } format FORMAT base_uri BASE_URL default_params format: FORMAT, app: APP_KEY attr_accessor :caching def initialize(email, password, opts = {}) @email, @password, @user_id = email, password, nil @caching, @cache = opts[:caching] || true, {} end def activity(id) fetch_activity_data(id.to_s).activity end def activities(opts = {}) fetch_user_data(opts).activities.map { |a| a.activity } end def detailed_activities(opts = {}) activities(opts).map { |a| activity(a.activity_id) } end [:lifetime_totals, :time_span_metrics, :time_of_day_metrics, :terrains, :paces, :homepage_stats].each do |m| eval %( def #{m}(opts = {}) fetch_user_data(opts).send(:#{m}) end ) end def method_missing(method_name, *args, &block) if /(.*)!$/ === method_name && self.respond_to?(method_name.to_s.chop) no_cache { self.send($1, *args, &block) } else super end end def respond_to_missing?(method_name, include_private = false) method_name.to_s.end_with?('!') && self.respond_to?(method_name.to_s.chop) end private # data def fetch_activity_data(id) cache(id) do wrap get_authorized(ACTIVITY_URL + "/#{id}") end end def fetch_user_data(opts) type = opts[:type].to_sym || :run cache(type) do wrap get_authorized(ACTIVITIES_URLS[type], query: { indexStart: 0, indexEnd: 999999}) end end # auth def get_authorized(url, opts = {}) login_if_unauthenticated raise "Authentication failed!" unless logged_in? self.class.get(personify_url(url), opts).to_hash end def login_if_unauthenticated return if logged_in? response = self.class.login(@email, @password) @user_id = response['serviceResponse']['body']['User']['screenName'] end def self.login(email, password) response = post(LOGIN_URL, query: { email: email, password: password }) self.default_cookies.add_cookies(response.headers['set-cookie']) response end def logged_in? !@user_id.nil? && !self.class.cookies[:slCheck].nil? end # caching def cache(key) @caching ? @cache[key] ||= yield : yield end def no_cache caching = @caching @caching = false yield ensure @caching = caching end # helpers def personify_url(url) vars = url.scan(/\[[^\]]*\]/) vars.inject(url){ |u, v| u.gsub(v, self.instance_variable_get("@#{v[1..-2]}").to_s) } end def wrap(response) Nike::Mash.new(response.underscore_keys) end end