strava 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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;
|