strava 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.travis.yml +6 -0
- data/.yardopts +1 -0
- data/Gemfile +12 -0
- data/LICENSE.txt +21 -0
- data/README.md +302 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/strava.rb +79 -0
- data/lib/strava/activity.rb +224 -0
- data/lib/strava/adapters/httparty_adapter.rb +9 -0
- data/lib/strava/athlete.rb +378 -0
- data/lib/strava/base.rb +86 -0
- data/lib/strava/client.rb +65 -0
- data/lib/strava/club.rb +164 -0
- data/lib/strava/club_announcement.rb +28 -0
- data/lib/strava/comment.rb +36 -0
- data/lib/strava/error.rb +15 -0
- data/lib/strava/gear.rb +41 -0
- data/lib/strava/group_event.rb +62 -0
- data/lib/strava/lap.rb +39 -0
- data/lib/strava/leaderboard.rb +57 -0
- data/lib/strava/leaderboard_entry.rb +48 -0
- data/lib/strava/photo.rb +50 -0
- data/lib/strava/route.rb +51 -0
- data/lib/strava/running_race.rb +50 -0
- data/lib/strava/segment.rb +100 -0
- data/lib/strava/segment_effort.rb +45 -0
- data/lib/strava/stream.rb +33 -0
- data/lib/strava/stream_set.rb +62 -0
- data/lib/strava/usage.rb +38 -0
- data/lib/strava/version.rb +4 -0
- data/strava.gemspec +29 -0
- metadata +135 -0
data/lib/strava/lap.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
module Strava
|
2
|
+
# Laps for an activity
|
3
|
+
#
|
4
|
+
# Usage:
|
5
|
+
#
|
6
|
+
# ca = Strava::Athlete.current_athlete;
|
7
|
+
# activity = ca.activities.first;
|
8
|
+
# lap = activity.laps.first
|
9
|
+
#
|
10
|
+
# @see https://strava.github.io/api/v3/activities/#laps Strava Docs - Activity Laps
|
11
|
+
class Lap < Base
|
12
|
+
|
13
|
+
def update(data, **opts)
|
14
|
+
@response = data
|
15
|
+
@id = data['id']
|
16
|
+
@resource_state = data["resource_state"]
|
17
|
+
@name = data["name"]
|
18
|
+
@activity = data["activity"]
|
19
|
+
@athlete = data["athlete"]
|
20
|
+
@elapsed_time = data["elapsed_time"]
|
21
|
+
@moving_time = data["moving_time"]
|
22
|
+
@start_date = data["start_date"]
|
23
|
+
@start_date_local = data["start_date_local"]
|
24
|
+
@distance = data["distance"]
|
25
|
+
@start_index = data["start_index"]
|
26
|
+
@end_index = data["end_index"]
|
27
|
+
@total_elevation_gain = data["total_elevation_gain"]
|
28
|
+
@average_speed = data["average_speed"]
|
29
|
+
@max_speed = data["max_speed"]
|
30
|
+
@average_cadence = data["average_cadence"]
|
31
|
+
@average_heartrate = data["average_heartrate"]
|
32
|
+
@max_heartrate = data["max_heartrate"]
|
33
|
+
@lap_index = data["lap_index"]
|
34
|
+
@split = data["split"]
|
35
|
+
@pace_zone = data["pace_zone"]
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Strava
|
2
|
+
class Leaderboard < Base
|
3
|
+
# Class to represent Strava Activity
|
4
|
+
# https://strava.github.io/api/v3/activities/
|
5
|
+
# Your code goes here...
|
6
|
+
|
7
|
+
def set_ivars
|
8
|
+
@entries = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def standings
|
12
|
+
@entries.values.sort { |a, b| a.rank <=> b.rank }
|
13
|
+
end
|
14
|
+
alias :entries :standings
|
15
|
+
|
16
|
+
def update(data, **opts)
|
17
|
+
@response = data
|
18
|
+
@segment_id = data['segment_id'] if data['segment_id']
|
19
|
+
|
20
|
+
@entry_count = data['entry_count'] if data['entry_count']
|
21
|
+
if data['entries']
|
22
|
+
data['entries'].each { |hash| hash['id'] = hash['effort_id'] }
|
23
|
+
parse_data(@entries, data['entries'], klass: LeaderboardEntry, client: @client)
|
24
|
+
end
|
25
|
+
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
def get_details
|
30
|
+
return self if detailed?
|
31
|
+
res = client.get(path_base).to_h
|
32
|
+
update(res)
|
33
|
+
res
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_standings(per_page: nil, page: nil, **params)
|
37
|
+
res = client.get(path_base, per_page: per_page, page: page, **params).to_h
|
38
|
+
update(res)
|
39
|
+
end
|
40
|
+
|
41
|
+
def path_base
|
42
|
+
"segments/#{@segment_id}/leaderboard"
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
__END__
|
50
|
+
|
51
|
+
ca = Strava::Athlete.current_athlete;
|
52
|
+
rlk = ca.friends.detect{|a| a.id == 3635502 };
|
53
|
+
segments = rlk.starred_segments;
|
54
|
+
seg = segments.first
|
55
|
+
seg.leaderboard
|
56
|
+
seg.leaderboard.get_standings;
|
57
|
+
seg.leaderboard.standings
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Strava
|
2
|
+
class LeaderboardEntry < Base
|
3
|
+
# Class to represent Strava Activity
|
4
|
+
# https://strava.github.io/api/v3/activities/
|
5
|
+
attr_reader :rank
|
6
|
+
|
7
|
+
def set_ivars
|
8
|
+
@entries = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def athlete
|
12
|
+
@athlete ||= Athlete.new({'id' => @athlete_id}, client: @client)
|
13
|
+
end
|
14
|
+
|
15
|
+
def activity
|
16
|
+
@activity ||= Activity.new({'id' => @activity_id}, client: @client)
|
17
|
+
end
|
18
|
+
|
19
|
+
def effort
|
20
|
+
@effort ||= SegmentEffort.new({'id' => @effort_id}, client: @client)
|
21
|
+
end
|
22
|
+
|
23
|
+
def update(data, **opts)
|
24
|
+
@response = data
|
25
|
+
|
26
|
+
@athlete_name = data["athlete_name"] # => "Jim Whimpey",
|
27
|
+
@athlete_id = data["athlete_id"] # => 123529,
|
28
|
+
@athlete_gender = data["athlete_gender"] # => "M",
|
29
|
+
@average_hr = data["average_hr"] # => 190.5,
|
30
|
+
@average_watts = data["average_watts"] # => 460.8,
|
31
|
+
@distance = data["distance"] # => 2659.89,
|
32
|
+
@elapsed_time = data["elapsed_time"] # => 360,
|
33
|
+
@moving_time = data["moving_time"] # => 360,
|
34
|
+
@start_date = data["start_date"] # => "2013-03-29T13:49:35Z",
|
35
|
+
@start_date_local = data["start_date_local"] # => "2013-03-29T06:49:35Z",
|
36
|
+
@activity_id = data["activity_id"] # => 46320211,
|
37
|
+
@effort_id = data["effort_id"] # => 801006623,
|
38
|
+
@rank = data["rank"] # => 1,
|
39
|
+
@athlete_profile = data["athlete_profile"] # => "http://pics.com/227615/large.jpg"
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
__END__
|
47
|
+
|
48
|
+
ca = Strava::Athlete.current_athlete;
|
data/lib/strava/photo.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
module Strava
|
2
|
+
# Strava allows for attaching photos to activities. These photos can come from either Instagram or be uploaded directly to Strava.
|
3
|
+
# Initially, only Instagram was supported. Later, Strava began storing photos on its own.
|
4
|
+
#
|
5
|
+
# Example:
|
6
|
+
#
|
7
|
+
# ca = Strava::Athlete.current_athlete
|
8
|
+
# activity = ca.activities.detect{ |a| a.total_photo_count > 0 } # Find activity with any photos, Strava or Instagram.
|
9
|
+
# activity = ca.activities.detect{ |a| a.photo_count > 0 } # Check for Instagram photos only
|
10
|
+
# activity.photos # Array of `Photo` objects
|
11
|
+
#
|
12
|
+
# @see https://strava.github.io/api/v3/activity_photos/ Strava Docs - Activity Photos
|
13
|
+
class Photo < Base
|
14
|
+
|
15
|
+
# Updates photo with passed data attributes.
|
16
|
+
#
|
17
|
+
# @private
|
18
|
+
# @param data [Hash] data hash containing photo data
|
19
|
+
# @return [self]
|
20
|
+
def update(data, **opts)
|
21
|
+
@resource_state = data['resource_state']
|
22
|
+
@activity_id = data['activity_id']
|
23
|
+
@ref = data["ref"]
|
24
|
+
@uid = data["uid"]
|
25
|
+
@caption = data["caption"]
|
26
|
+
@type = data["type"]
|
27
|
+
@uploaded_at = data["uploaded_at"]
|
28
|
+
@created_at = data["created_at"]
|
29
|
+
@location = data["location"]
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
__END__
|
36
|
+
|
37
|
+
ca = Strava::Athlete.current_athlete;
|
38
|
+
ca.activities;
|
39
|
+
ca.activities(page: 1, per_page: 200);
|
40
|
+
ca.activities(page: 2, per_page: 200);
|
41
|
+
ca.activities(page: 3, per_page: 200);
|
42
|
+
ca.activities(page: 4, per_page: 200);
|
43
|
+
ca.activities(page: 5, per_page: 200);
|
44
|
+
ca.activities(page: 6, per_page: 200);
|
45
|
+
ca.activities(page: 7, per_page: 200);
|
46
|
+
ca = Strava::Athlete.current_athlete;
|
47
|
+
activity = ca.activities.detect{ |a| a.response['photo_count'] > 0 } # insta only
|
48
|
+
activity = ca.activities.detect{ |a| a.response['total_photo_count'] > 0 } # include strava photos
|
49
|
+
activity.photos
|
50
|
+
activity.comments
|
data/lib/strava/route.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
module Strava
|
2
|
+
class Route < Base
|
3
|
+
# Class to represent Strava Activity
|
4
|
+
# https://strava.github.io/api/v3/activities/
|
5
|
+
|
6
|
+
def set_ivars
|
7
|
+
@streams = StreamSet.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def update(data, **opts)
|
11
|
+
@response = data
|
12
|
+
@id = data["id"]
|
13
|
+
@resource_state = data['resource_state']
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def streams(**params)
|
18
|
+
get_streams(**params) if @streams.empty?
|
19
|
+
@streams
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_details
|
23
|
+
return self if detailed?
|
24
|
+
res = client.get(path_base).to_h
|
25
|
+
update(res)
|
26
|
+
res
|
27
|
+
end
|
28
|
+
|
29
|
+
def get_streams(**params)
|
30
|
+
res = client.get(path_streams, **params).to_a
|
31
|
+
@streams.update(res)
|
32
|
+
end
|
33
|
+
|
34
|
+
def path_base
|
35
|
+
"routes/#{id}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def path_streams
|
39
|
+
"#{path_base}/streams/"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
__END__
|
45
|
+
|
46
|
+
ca = Strava::Athlete.current_athlete;
|
47
|
+
rlk = ca.friends.detect{|a| a.id == 3635502 }
|
48
|
+
r = rlk.routes.first
|
49
|
+
rlk.get_routes
|
50
|
+
r = rlk.routes.first
|
51
|
+
r.get_details
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Strava
|
2
|
+
class RunningRace < Base
|
3
|
+
|
4
|
+
def update(data, **opts)
|
5
|
+
@response = data
|
6
|
+
@id = data['id']
|
7
|
+
@resource_state = data['resource_state']
|
8
|
+
|
9
|
+
@name = data["name"]
|
10
|
+
@start_date_local = data["start_date_local"]
|
11
|
+
@distance = data["distance"]
|
12
|
+
@city = data["city"]
|
13
|
+
@state = data["state"]
|
14
|
+
@country = data["country"]
|
15
|
+
@measurement_preference = data["measurement_preference"]
|
16
|
+
@running_race_type = data["running_race_type"]
|
17
|
+
@url = data["url"]
|
18
|
+
@resource_state = data["resource_state"]
|
19
|
+
@status = data["status"]
|
20
|
+
@website_url = data["website_url"]
|
21
|
+
@route_ids = data["route_ids"]
|
22
|
+
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_details
|
27
|
+
return self if detailed?
|
28
|
+
res = client.get(path_base).to_h
|
29
|
+
update(res)
|
30
|
+
res
|
31
|
+
end
|
32
|
+
def path_base
|
33
|
+
"running_races/#{id}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.list_races(client, year = Time.now.year)
|
37
|
+
res = client.get("running_races", year: year).to_a
|
38
|
+
res.map { |hash| new(hash, client: client) }
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
__END__
|
46
|
+
|
47
|
+
ca = Strava::Athlete.current_athlete;
|
48
|
+
races = ca.list_races;
|
49
|
+
rr = races.first;
|
50
|
+
rr.get_details
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module Strava
|
2
|
+
class Segment < Base
|
3
|
+
# Class to represent Strava Activity
|
4
|
+
# https://strava.github.io/api/v3/activities/
|
5
|
+
# Your code goes here...
|
6
|
+
attr_reader :leaderboard
|
7
|
+
|
8
|
+
def set_ivars
|
9
|
+
@efforts = {}
|
10
|
+
@streams = StreamSet.new
|
11
|
+
end
|
12
|
+
def leaderboard
|
13
|
+
@leaderboard ||= Leaderboard.new({'segment_id' => id}, client: @client)
|
14
|
+
end
|
15
|
+
|
16
|
+
def update(data, **opts)
|
17
|
+
@response = data
|
18
|
+
@id = data["id"]
|
19
|
+
@resource_state = data['resource_state']
|
20
|
+
end
|
21
|
+
|
22
|
+
def efforts(per_page: nil, page: nil, **params)
|
23
|
+
# paginate('efforts', struct: Array, per_page: per_page, page: page)
|
24
|
+
if page || per_page || !params.empty?
|
25
|
+
get_efforts(per_page: per_page, page: page, **params)
|
26
|
+
else
|
27
|
+
get_efforts if @efforts.empty?
|
28
|
+
@efforts.values
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# don't know if this really works or not. doesn't seem to work
|
33
|
+
def star
|
34
|
+
res = client.put(path_star, star: true).to_h
|
35
|
+
end
|
36
|
+
|
37
|
+
def unstar
|
38
|
+
res = client.put(path_star, star: false).to_h
|
39
|
+
end
|
40
|
+
|
41
|
+
def streams(types = [:distance, :altitude, :latlng], **params)
|
42
|
+
get_streams(types, **params) if @streams.empty?
|
43
|
+
@streams
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def get_details
|
48
|
+
return self if detailed?
|
49
|
+
res = client.get(path_base).to_h
|
50
|
+
update(res)
|
51
|
+
res
|
52
|
+
end
|
53
|
+
|
54
|
+
def get_streams(types = '', **params)
|
55
|
+
res = client.get(path_streams + types.join(','), **params).to_a
|
56
|
+
@streams.update(res)
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
private def get_efforts(per_page: nil, page: nil)
|
61
|
+
res = client.get(path_efforts, per_page: per_page, page: page).to_a
|
62
|
+
parse_data(@efforts, res, klass: SegmentEffort, client: @client)
|
63
|
+
end
|
64
|
+
|
65
|
+
def path_base
|
66
|
+
"segments/#{id}"
|
67
|
+
end
|
68
|
+
|
69
|
+
def path_efforts
|
70
|
+
"#{path_base}/all_efforts"
|
71
|
+
end
|
72
|
+
|
73
|
+
def path_star
|
74
|
+
"#{path_base}/starred"
|
75
|
+
end
|
76
|
+
|
77
|
+
def path_streams
|
78
|
+
"#{path_base}/streams/"
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.explorer(client, bounds = '37.821362,-122.505373,37.842038,-122.465977')
|
82
|
+
res = client.get("segments/explore", bounds: bounds).to_h
|
83
|
+
res['segments'].map { |hash| new(hash, client: client) }
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
__END__
|
90
|
+
|
91
|
+
ca = Strava::Athlete.current_athlete;
|
92
|
+
ca.segment_explorer
|
93
|
+
rlk = ca.friends.detect{|a| a.id == 3635502 };
|
94
|
+
segments = rlk.starred_segments;
|
95
|
+
seg = segments.first
|
96
|
+
seg.star
|
97
|
+
seg.unstar
|
98
|
+
seg.leaderboard
|
99
|
+
seg.leaderboard.standings
|
100
|
+
seg.efforts
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Strava
|
2
|
+
class SegmentEffort < Base
|
3
|
+
# Class to represent Strava Activity
|
4
|
+
# https://strava.github.io/api/v3/activities/
|
5
|
+
attr_reader :segment
|
6
|
+
|
7
|
+
def set_ivars
|
8
|
+
@streams = StreamSet.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def update(data, **opts)
|
12
|
+
@response = data
|
13
|
+
@id = data["id"]
|
14
|
+
@resource_state = data['resource_state']
|
15
|
+
@segment = Segment.new(data['segment'], client: @client) if data['segment']
|
16
|
+
end
|
17
|
+
|
18
|
+
def streams(types = [:time, :distance, :latlng], **params)
|
19
|
+
get_streams(types, **params) if @streams.empty?
|
20
|
+
@streams
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_details
|
24
|
+
return self if detailed?
|
25
|
+
res = client.get(path_base).to_h
|
26
|
+
update(res)
|
27
|
+
res
|
28
|
+
end
|
29
|
+
|
30
|
+
def get_streams(types = '', **params)
|
31
|
+
res = client.get(path_streams + types.join(','), **params).to_a
|
32
|
+
@streams.update(res)
|
33
|
+
end
|
34
|
+
def path_base
|
35
|
+
"segment_efforts/#{id}"
|
36
|
+
end
|
37
|
+
def path_streams
|
38
|
+
"#{path_base}/streams/"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
__END__
|
44
|
+
|
45
|
+
ca = Strava::Athlete.current_athlete;
|