sportradar 0.0.16 → 0.0.18
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +32 -6
- data/lib/sportradar/nba/models/event.rb +302 -0
- data/lib/sportradar/nba/models/on_court_player.rb +41 -0
- data/lib/sportradar/nba/models/play_player_stat.rb +171 -0
- data/lib/sportradar/nba/models/quarter.rb +65 -0
- data/lib/sportradar/nba/models/scoring_play.rb +35 -0
- data/lib/sportradar/nba/models/scoring_player.rb +19 -0
- data/lib/sportradar/nba/parsers/play_by_play_parser.rb +68 -0
- data/lib/sportradar/nhl/parsers/boxscore_parser.rb +7 -6
- data/lib/sportradar/version.rb +1 -1
- data/lib/sportradar.rb +8 -0
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dfed0edeb60ac981cfc75a3090b9fae031fc829a
|
4
|
+
data.tar.gz: 0c0d9cb9998c042bbf34f5234f979f72a1786675
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 39c8209083d999e230aabecb122cb0f82fcda2a88f7c4ce68131e2e83d0891f8c50008ee507a9533fecc3be42f28cce923c9301287dc912cbc1177b3c09b417e
|
7
|
+
data.tar.gz: 40246f8814f4adf35bf1a7105b1709a134ff66380456bf63d04fc94a99f0dde06bed43fcaf71200dd42e9ffc90c57c46b818dd0526d780e6ce3c85487e1b1fd1
|
data/README.md
CHANGED
@@ -4,9 +4,9 @@ Simple API client for [Sportradar API](http://developer.sportradar.us/).
|
|
4
4
|
|
5
5
|
Currently supports
|
6
6
|
|
7
|
-
* a
|
8
|
-
* a
|
9
|
-
* a
|
7
|
+
* a major set of [Major League Baseball API](http://developer.sportradar.us/docs/MLB_API) endpoints
|
8
|
+
* a major set of [NBA Feed API](http://developer.sportradar.us/docs/read/NBA_API) endpoints
|
9
|
+
* a major set of [NHL Classic Feed API](http://developer.sportradar.us/docs/read/NHL_Classic) endpoints
|
10
10
|
* complete set of [NFL Classic Feed API](http://developer.sportradar.us/docs/read/NFL_Classic) endpoints
|
11
11
|
|
12
12
|
## Installation
|
@@ -14,7 +14,7 @@ Currently supports
|
|
14
14
|
Add this line to your application's Gemfile:
|
15
15
|
|
16
16
|
```ruby
|
17
|
-
gem 'sportradar', '>= 0.0.
|
17
|
+
gem 'sportradar', '>= 0.0.18'
|
18
18
|
```
|
19
19
|
|
20
20
|
And then execute:
|
@@ -101,6 +101,8 @@ Some helpers will call .save for each response as separate items.
|
|
101
101
|
|
102
102
|
Defaults to and supports NBA Classic API feed version 3 only (not Official).
|
103
103
|
|
104
|
+
Models and parsers can get plays, scoring plays, players on court, stoppages from NBA Play by Play json data.
|
105
|
+
|
104
106
|
#### API Requests
|
105
107
|
|
106
108
|
* `Sportradar::Nba::DailySchedule.new(date: Date.today).fetch`
|
@@ -110,12 +112,22 @@ Defaults to and supports NBA Classic API feed version 3 only (not Official).
|
|
110
112
|
* `Sportradar::Nba::Boxscore.new(event_id: '<game_guid>').fetch`
|
111
113
|
* `Sportradar::Nba::GameSummary.new(event_id: '<game_guid>').fetch`
|
112
114
|
|
113
|
-
|
114
|
-
|
115
115
|
* `Sportradar::Nba::TeamRosters.perform`
|
116
116
|
* `Sportradar::Nba::TeamRoster.new(team_id: '44151f7a-0f24-11e2-8525-18a905767e44').fetch`
|
117
117
|
* `Sportradar::Nba::Injuries.new().fetch`
|
118
118
|
|
119
|
+
#### Bulk Saves
|
120
|
+
|
121
|
+
To fetch and save all Play by Play for a season, one can:
|
122
|
+
|
123
|
+
```
|
124
|
+
json = Sportradar::Nba::LeagueSchedule.new(year: '2016', interval_type: 'pre').fetch
|
125
|
+
|
126
|
+
Sportradar::Nba::LeagueSchedule.games(json: json).each do |g|
|
127
|
+
Sportradar::Nba::PlayByPlay.new(event_id: g['id']).save
|
128
|
+
end
|
129
|
+
```
|
130
|
+
|
119
131
|
### Football/NFL
|
120
132
|
|
121
133
|
Defaults to and supports NFL Classic API feed version 1 only (not Official).
|
@@ -188,6 +200,8 @@ Some helpers will call `.save` for each response as separate items.
|
|
188
200
|
|
189
201
|
Defaults to and supports NHL Classic API feed version 3 only (not Official).
|
190
202
|
|
203
|
+
Models and parsers can get plays, scoring plays, players on court, stoppages from NHL Play by Play json data.
|
204
|
+
|
191
205
|
#### API Requests
|
192
206
|
|
193
207
|
* `Sportradar::Nhl::LeagueHierarchy.new().fetch`
|
@@ -760,6 +774,18 @@ Given game NFL Play by Play JSON, makes it easy to get the drives, quarters, and
|
|
760
774
|
|
761
775
|
* plays - game, drive, team, participants, summary, yardage, etc.
|
762
776
|
|
777
|
+
#### Hockey Play by Play
|
778
|
+
|
779
|
+
* `Sportradar::Nhl::Parsers::PlayByPlayParser.new(game_play_by_play: {})`
|
780
|
+
|
781
|
+
Given game NHL Play by Play JSON, makes it easy to get the periods, events, plays (with player stat), stoppages and scoring plays via a set of convenience methods.
|
782
|
+
|
783
|
+
#### Basketball Play by Play
|
784
|
+
|
785
|
+
* `Sportradar::Nba::Parsers::PlayByPlayParser.new(game_play_by_play: {})`
|
786
|
+
|
787
|
+
Given game NBA Play by Play JSON, makes it easy to get the quarters, events, plays (with player stat), stoppages, players on court for each play, and scoring plays via a set of convenience methods.
|
788
|
+
|
763
789
|
#### Play Summary Model
|
764
790
|
|
765
791
|
Given game NFL Play Summary JSON, makes it easy to get at the start and end situations, players, scroing info for each play summmary.
|
@@ -0,0 +1,302 @@
|
|
1
|
+
module Sportradar
|
2
|
+
module Nba
|
3
|
+
module Models
|
4
|
+
class Event
|
5
|
+
def initialize(quarter:, attributes:)
|
6
|
+
@quarter = quarter
|
7
|
+
@attributes = attributes
|
8
|
+
build_statistics
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
[].tap do |sentence_parts|
|
13
|
+
sentence_parts << quarter_number
|
14
|
+
sentence_parts << clock
|
15
|
+
sentence_parts << team_name if has_team?
|
16
|
+
sentence_parts << team_basket if has_team?
|
17
|
+
sentence_parts << event_type
|
18
|
+
sentence_parts << description
|
19
|
+
sentence_parts << free_throw_attempt
|
20
|
+
sentence_parts << free_throw_attempt_of
|
21
|
+
sentence_parts << turnover_type
|
22
|
+
sentence_parts << "[#{coordinate_x}, #{coordinate_y}]" if coordinates?
|
23
|
+
end.compact.
|
24
|
+
join(' - ')
|
25
|
+
end
|
26
|
+
|
27
|
+
def id
|
28
|
+
@attributes['id']
|
29
|
+
end
|
30
|
+
|
31
|
+
def game_id
|
32
|
+
quarter.game_id
|
33
|
+
end
|
34
|
+
|
35
|
+
def possession?
|
36
|
+
possession.present?
|
37
|
+
end
|
38
|
+
|
39
|
+
def possession
|
40
|
+
@attributes['possession'] || {}
|
41
|
+
end
|
42
|
+
|
43
|
+
def possession_team_id
|
44
|
+
possession.dig('id')
|
45
|
+
end
|
46
|
+
|
47
|
+
def possession_team_name
|
48
|
+
possession.dig('name')
|
49
|
+
end
|
50
|
+
|
51
|
+
def team
|
52
|
+
@attributes['attribution'] || {}
|
53
|
+
end
|
54
|
+
|
55
|
+
def team_id
|
56
|
+
team.dig('id')
|
57
|
+
end
|
58
|
+
|
59
|
+
def team_name
|
60
|
+
team.dig('name')
|
61
|
+
end
|
62
|
+
|
63
|
+
def team_basket
|
64
|
+
team.dig('team_basket')
|
65
|
+
end
|
66
|
+
|
67
|
+
def has_team?
|
68
|
+
!team_id.nil?
|
69
|
+
end
|
70
|
+
|
71
|
+
def quarter
|
72
|
+
@quarter
|
73
|
+
end
|
74
|
+
|
75
|
+
def quarter_id
|
76
|
+
@quarter.id
|
77
|
+
end
|
78
|
+
|
79
|
+
def quarter_number
|
80
|
+
@quarter.number
|
81
|
+
end
|
82
|
+
|
83
|
+
def time_code
|
84
|
+
min, sec = clock.split(':').map(&:to_i)
|
85
|
+
"PT#{min}M#{sec}S"
|
86
|
+
end
|
87
|
+
|
88
|
+
def clock
|
89
|
+
@attributes['clock'] || '0'
|
90
|
+
end
|
91
|
+
|
92
|
+
def clock_secs
|
93
|
+
begin
|
94
|
+
if clock && clock.include?(':')
|
95
|
+
mins, secs = clock.split(':').map(&:to_i)
|
96
|
+
Time.parse("00:#{mins}:#{secs}").
|
97
|
+
seconds_since_midnight.to_i
|
98
|
+
end
|
99
|
+
rescue => e
|
100
|
+
return 0
|
101
|
+
end
|
102
|
+
end
|
103
|
+
alias_method :quarter_seconds, :clock_secs
|
104
|
+
|
105
|
+
def id
|
106
|
+
@attributes['id']
|
107
|
+
end
|
108
|
+
|
109
|
+
def attempt_in_words
|
110
|
+
@attributes['attempt']
|
111
|
+
end
|
112
|
+
|
113
|
+
def attempt_matches
|
114
|
+
/(\d) of (\d)/.match(attempt_in_words)
|
115
|
+
end
|
116
|
+
|
117
|
+
def free_throw_attempt
|
118
|
+
if matches = attempt_matches
|
119
|
+
matches[0].to_i
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def free_throw_attempt_of
|
124
|
+
if matches = attempt_matches
|
125
|
+
matches[1].to_i
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def description
|
130
|
+
@attributes['description'] || 0
|
131
|
+
end
|
132
|
+
|
133
|
+
def event_type
|
134
|
+
@attributes['event_type']
|
135
|
+
end
|
136
|
+
|
137
|
+
def coordinates
|
138
|
+
@attributes['location'] || {}
|
139
|
+
end
|
140
|
+
|
141
|
+
def coordinates?
|
142
|
+
@attributes['location'].present?
|
143
|
+
end
|
144
|
+
|
145
|
+
def coordinate_x
|
146
|
+
coordinates['coord_x']
|
147
|
+
end
|
148
|
+
|
149
|
+
def coordinate_y
|
150
|
+
coordinates['coord_y']
|
151
|
+
end
|
152
|
+
|
153
|
+
def turnover_type
|
154
|
+
@attributes['turnover_type']
|
155
|
+
end
|
156
|
+
|
157
|
+
def updated_at
|
158
|
+
@attributes['updated']
|
159
|
+
end
|
160
|
+
|
161
|
+
def statistics
|
162
|
+
@attributes['statistics'] || []
|
163
|
+
end
|
164
|
+
|
165
|
+
def field_goal?
|
166
|
+
two_pointer? || three_pointer?
|
167
|
+
end
|
168
|
+
|
169
|
+
def field_goal
|
170
|
+
self if field_goal?
|
171
|
+
end
|
172
|
+
|
173
|
+
def three_pointer?
|
174
|
+
event_type.include?('threepoint')
|
175
|
+
end
|
176
|
+
|
177
|
+
def three_pointer
|
178
|
+
self if three_pointer?
|
179
|
+
end
|
180
|
+
|
181
|
+
def two_pointer?
|
182
|
+
event_type.include?('twopoint')
|
183
|
+
end
|
184
|
+
|
185
|
+
def two_pointer
|
186
|
+
self if two_pointer?
|
187
|
+
end
|
188
|
+
|
189
|
+
def foul?
|
190
|
+
event_type.include?('foul') || event_type.include?('flagrant')
|
191
|
+
end
|
192
|
+
|
193
|
+
def foul
|
194
|
+
self if foul?
|
195
|
+
end
|
196
|
+
|
197
|
+
def free_throw?
|
198
|
+
event_type.include?('free_throw')
|
199
|
+
end
|
200
|
+
|
201
|
+
def free_throw
|
202
|
+
self if free_throw?
|
203
|
+
end
|
204
|
+
|
205
|
+
def made?
|
206
|
+
event_type.include?('made')
|
207
|
+
end
|
208
|
+
|
209
|
+
def miss?
|
210
|
+
event_type.include?('miss')
|
211
|
+
end
|
212
|
+
|
213
|
+
def scoring_play?
|
214
|
+
event_type.include?('made')
|
215
|
+
end
|
216
|
+
|
217
|
+
def scoring_play
|
218
|
+
self if scoring_play?
|
219
|
+
end
|
220
|
+
|
221
|
+
def stoppage?
|
222
|
+
%w(endperiod delay officialtimeout review teamtimeout tvtimeout).include?(event_type)
|
223
|
+
end
|
224
|
+
|
225
|
+
def stoppage
|
226
|
+
self if stoppage?
|
227
|
+
end
|
228
|
+
|
229
|
+
def turnover?
|
230
|
+
event_type.include?('turnover')
|
231
|
+
end
|
232
|
+
|
233
|
+
def turnover
|
234
|
+
self if turnover?
|
235
|
+
end
|
236
|
+
|
237
|
+
def play_player_stats
|
238
|
+
@play_player_stats ||= []
|
239
|
+
end
|
240
|
+
|
241
|
+
def scoring_players
|
242
|
+
@scoring_players ||= []
|
243
|
+
end
|
244
|
+
|
245
|
+
def on_court_players
|
246
|
+
@on_court_players ||= on_court_away_players + on_court_home_players
|
247
|
+
end
|
248
|
+
|
249
|
+
def on_court_away_team_id
|
250
|
+
@on_court_away_team_id ||= @attributes.dig('on_court', 'away', 'id')
|
251
|
+
end
|
252
|
+
|
253
|
+
def on_court_away_team_name
|
254
|
+
@on_court_away_team_name ||= @attributes.dig('on_court', 'away', 'name')
|
255
|
+
end
|
256
|
+
|
257
|
+
def on_court_away_players
|
258
|
+
(@attributes.dig('on_court', 'away', 'players') || {}).map do |player|
|
259
|
+
Models::OnCourtPlayer.new(
|
260
|
+
player.reverse_merge({
|
261
|
+
'event_id' => id,
|
262
|
+
'player_id' => player['id'],
|
263
|
+
'team_id' => on_court_away_team_id,
|
264
|
+
'team_name' => on_court_away_team_name,
|
265
|
+
})
|
266
|
+
)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
def on_court_home_team_id
|
271
|
+
@on_court_home_team_id ||= @attributes.dig('on_court', 'home', 'id')
|
272
|
+
end
|
273
|
+
|
274
|
+
def on_court_home_team_name
|
275
|
+
@on_court_home_team_name ||= @attributes.dig('on_court', 'home', 'name')
|
276
|
+
end
|
277
|
+
|
278
|
+
def on_court_home_players
|
279
|
+
(@attributes.dig('on_court', 'home', 'players') || {}).map do |player|
|
280
|
+
Models::OnCourtPlayer.new(
|
281
|
+
player.reverse_merge({
|
282
|
+
'event_id' => id,
|
283
|
+
'player_id' => player['id'],
|
284
|
+
'team_id' => on_court_home_team_id,
|
285
|
+
'team_name' => on_court_home_team_name,
|
286
|
+
})
|
287
|
+
)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
private
|
292
|
+
|
293
|
+
def build_statistics
|
294
|
+
statistics.each do |statistic|
|
295
|
+
play_player_stats << Models::PlayPlayerStat.new(event: self, attributes: statistic)
|
296
|
+
scoring_players << Models::ScoringPlayer.new(event: self, attributes: statistic) if scoring_play?
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Sportradar
|
2
|
+
module Nba
|
3
|
+
module Models
|
4
|
+
class OnCourtPlayer
|
5
|
+
def initialize(attributes = {})
|
6
|
+
@attributes = attributes
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_s
|
10
|
+
[].tap do |sentence_parts|
|
11
|
+
sentence_parts << event_id
|
12
|
+
sentence_parts << player_id
|
13
|
+
sentence_parts << full_name
|
14
|
+
sentence_parts << team_id
|
15
|
+
sentence_parts << team_name
|
16
|
+
end.join(' - ')
|
17
|
+
end
|
18
|
+
|
19
|
+
def event_id
|
20
|
+
@attributes.dig('event_id')
|
21
|
+
end
|
22
|
+
|
23
|
+
def player_id
|
24
|
+
@attributes.dig('player_id')
|
25
|
+
end
|
26
|
+
|
27
|
+
def full_name
|
28
|
+
@attributes.dig('full_name')
|
29
|
+
end
|
30
|
+
|
31
|
+
def team_id
|
32
|
+
@attributes.dig('team_id')
|
33
|
+
end
|
34
|
+
|
35
|
+
def team_name
|
36
|
+
@attributes.dig('team_name')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
module Sportradar
|
2
|
+
module Nba
|
3
|
+
module Models
|
4
|
+
class PlayPlayerStat
|
5
|
+
def initialize(event:, attributes:)
|
6
|
+
@event = event
|
7
|
+
@attributes = attributes
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
[
|
12
|
+
quarter_number,
|
13
|
+
clock,
|
14
|
+
description,
|
15
|
+
team_name,
|
16
|
+
full_name,
|
17
|
+
stat,
|
18
|
+
].join(' ')
|
19
|
+
end
|
20
|
+
|
21
|
+
def event
|
22
|
+
@event
|
23
|
+
end
|
24
|
+
|
25
|
+
def event_id
|
26
|
+
@event.id
|
27
|
+
end
|
28
|
+
|
29
|
+
def description
|
30
|
+
@event.description
|
31
|
+
end
|
32
|
+
|
33
|
+
def quarter
|
34
|
+
@event.quarter
|
35
|
+
end
|
36
|
+
|
37
|
+
def quarter_number
|
38
|
+
quarter.number
|
39
|
+
end
|
40
|
+
|
41
|
+
def clock
|
42
|
+
@event.clock
|
43
|
+
end
|
44
|
+
|
45
|
+
def player
|
46
|
+
@attributes.dig('player') || {}
|
47
|
+
end
|
48
|
+
|
49
|
+
def player_id
|
50
|
+
player.dig('id')
|
51
|
+
end
|
52
|
+
|
53
|
+
def jersey
|
54
|
+
player.dig('jersey')
|
55
|
+
end
|
56
|
+
|
57
|
+
def full_name
|
58
|
+
player.dig('full_name')
|
59
|
+
end
|
60
|
+
|
61
|
+
def team
|
62
|
+
@attributes.dig('team') || {}
|
63
|
+
end
|
64
|
+
|
65
|
+
def team_id
|
66
|
+
team.dig('id')
|
67
|
+
end
|
68
|
+
|
69
|
+
def team_market
|
70
|
+
team.dig('market')
|
71
|
+
end
|
72
|
+
|
73
|
+
def team_name
|
74
|
+
team.dig('name')
|
75
|
+
end
|
76
|
+
|
77
|
+
def stat
|
78
|
+
{
|
79
|
+
player_id: player_id,
|
80
|
+
team_id: team_id,
|
81
|
+
made: made?,
|
82
|
+
free_throw_type: free_throw_type,
|
83
|
+
free_throw: free_throw?,
|
84
|
+
regular_free_throw: regular_free_throw?,
|
85
|
+
technical_free_throw: technical_free_throw?,
|
86
|
+
points: points,
|
87
|
+
rebound_type: rebound_type,
|
88
|
+
defensive_rebound: defensive_rebound?,
|
89
|
+
offensive_rebound: offensive_rebound?,
|
90
|
+
shot_type: shot_type,
|
91
|
+
shot_type_desc: shot_type_desc,
|
92
|
+
three_point_shot: three_point_shot?,
|
93
|
+
type: type,
|
94
|
+
}.compact
|
95
|
+
end
|
96
|
+
|
97
|
+
def made?
|
98
|
+
@attributes.dig('made') == true
|
99
|
+
end
|
100
|
+
|
101
|
+
def free_throw_type
|
102
|
+
@attributes.dig('free_throw_type')
|
103
|
+
end
|
104
|
+
|
105
|
+
def free_throw?
|
106
|
+
type == 'freethrow'
|
107
|
+
end
|
108
|
+
|
109
|
+
def regular_free_throw?
|
110
|
+
free_throw_type == 'regular'
|
111
|
+
end
|
112
|
+
|
113
|
+
def technical_free_throw?
|
114
|
+
free_throw_type == 'technical'
|
115
|
+
end
|
116
|
+
|
117
|
+
def points
|
118
|
+
@attributes.dig('points')
|
119
|
+
end
|
120
|
+
|
121
|
+
def defensive_rebound?
|
122
|
+
rebound_type == 'defensive'
|
123
|
+
end
|
124
|
+
|
125
|
+
def offensive_rebound?
|
126
|
+
rebound_type == 'offensive'
|
127
|
+
end
|
128
|
+
|
129
|
+
def rebound_type
|
130
|
+
@attributes.dig('rebound_type')
|
131
|
+
end
|
132
|
+
|
133
|
+
def shot_type
|
134
|
+
@attributes.dig('shot_type')
|
135
|
+
end
|
136
|
+
|
137
|
+
def shot_type_desc
|
138
|
+
@attributes.dig('shot_type_desc')
|
139
|
+
end
|
140
|
+
|
141
|
+
def three_point_shot?
|
142
|
+
@attributes.dig('three_point_shot') == true
|
143
|
+
end
|
144
|
+
|
145
|
+
def type
|
146
|
+
@attributes.dig('type')
|
147
|
+
end
|
148
|
+
|
149
|
+
def jump_shot?
|
150
|
+
shot_type == 'jump shot'
|
151
|
+
end
|
152
|
+
|
153
|
+
def layup?
|
154
|
+
shot_type == 'layup'
|
155
|
+
end
|
156
|
+
|
157
|
+
def dunk?
|
158
|
+
shot_type == 'dunk'
|
159
|
+
end
|
160
|
+
|
161
|
+
def hook?
|
162
|
+
shot_type == 'hook shot'
|
163
|
+
end
|
164
|
+
|
165
|
+
def tip?
|
166
|
+
shot_type == 'tip shot'
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Sportradar
|
2
|
+
module Nba
|
3
|
+
module Models
|
4
|
+
class Quarter
|
5
|
+
def initialize(game_id:, attributes:)
|
6
|
+
@game_id = game_id
|
7
|
+
@attributes = attributes
|
8
|
+
build_events
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
"Quarter #{number}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def abbreviation
|
16
|
+
"#{number}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def game_id
|
20
|
+
@game_id
|
21
|
+
end
|
22
|
+
|
23
|
+
def id
|
24
|
+
@id
|
25
|
+
end
|
26
|
+
|
27
|
+
def number
|
28
|
+
@attributes['number'] || 0
|
29
|
+
end
|
30
|
+
|
31
|
+
def events
|
32
|
+
@events ||= []
|
33
|
+
end
|
34
|
+
|
35
|
+
def events_data
|
36
|
+
@actions ||= @attributes.dig('events') || []
|
37
|
+
end
|
38
|
+
|
39
|
+
def fouls
|
40
|
+
events.collect(&:foul).compact
|
41
|
+
end
|
42
|
+
|
43
|
+
def scoring_plays
|
44
|
+
events.collect(&:scoring_play).compact
|
45
|
+
end
|
46
|
+
|
47
|
+
def stoppages
|
48
|
+
events.collect(&:stoppage).compact
|
49
|
+
end
|
50
|
+
|
51
|
+
def on_court_players
|
52
|
+
events.map(&:on_court_players).flatten
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def build_events
|
58
|
+
events_data.each do |event_data|
|
59
|
+
events << Models::Event.new(quarter: self, attributes: event_data)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Sportradar
|
2
|
+
module Nba
|
3
|
+
module Models
|
4
|
+
class ScoringPlay < Event
|
5
|
+
def scored_at
|
6
|
+
updated_at
|
7
|
+
end
|
8
|
+
|
9
|
+
def scoring_method
|
10
|
+
shot_type
|
11
|
+
end
|
12
|
+
|
13
|
+
def scoring_type
|
14
|
+
event_type
|
15
|
+
end
|
16
|
+
|
17
|
+
def scoring_how
|
18
|
+
event_type
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_h
|
22
|
+
{
|
23
|
+
id: id,
|
24
|
+
game_id: game_id,
|
25
|
+
points: points,
|
26
|
+
scored_at: scored_at,
|
27
|
+
scoring_method: scoring_method,
|
28
|
+
scoring_type: scoring_type,
|
29
|
+
scoring_how: scoring_how,
|
30
|
+
}.compact
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Sportradar
|
2
|
+
module Nba
|
3
|
+
module Parsers
|
4
|
+
class PlayByPlayParser
|
5
|
+
def initialize(game_play_by_play: {})
|
6
|
+
@game_play_by_play = game_play_by_play['game'] || game_play_by_play
|
7
|
+
end
|
8
|
+
|
9
|
+
def game_id
|
10
|
+
game_play_by_play['id']
|
11
|
+
end
|
12
|
+
|
13
|
+
def away
|
14
|
+
game_play_by_play['away'] || {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def away_team_id
|
18
|
+
away['id']
|
19
|
+
end
|
20
|
+
|
21
|
+
def home
|
22
|
+
game_play_by_play['home'] || {}
|
23
|
+
end
|
24
|
+
|
25
|
+
def quarters
|
26
|
+
@quarters ||= build_quarters || []
|
27
|
+
end
|
28
|
+
|
29
|
+
def has_quarters?
|
30
|
+
quarters.count > 0
|
31
|
+
end
|
32
|
+
|
33
|
+
def events
|
34
|
+
(quarters || []).map(&:events).flatten
|
35
|
+
end
|
36
|
+
|
37
|
+
def fouls
|
38
|
+
(quarters || []).map(&:fouls).flatten
|
39
|
+
end
|
40
|
+
|
41
|
+
def scoring_plays
|
42
|
+
(quarters || []).map(&:scoring_plays).flatten
|
43
|
+
end
|
44
|
+
|
45
|
+
def stoppages
|
46
|
+
(quarters || []).map(&:stoppages).flatten
|
47
|
+
end
|
48
|
+
|
49
|
+
def on_court_players
|
50
|
+
(quarters || []).map(&:on_court_players).flatten
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
attr_reader :game_play_by_play
|
56
|
+
|
57
|
+
def game_play_by_play_quarters
|
58
|
+
game_play_by_play.dig('periods') || []
|
59
|
+
end
|
60
|
+
|
61
|
+
def build_quarters
|
62
|
+
game_play_by_play_quarters.
|
63
|
+
map { |attributes| Models::Quarter.new(game_id: game_id, attributes: attributes) }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -139,23 +139,24 @@ module Sportradar
|
|
139
139
|
|
140
140
|
data.map do |scoring_data|
|
141
141
|
if period = scoring_data['number'].to_i
|
142
|
-
|
142
|
+
period_type = (scoring_data['type'] || 'period').downcase
|
143
|
+
|
144
|
+
if (period > 0 && period <= 3) && (period_type == 'period')
|
143
145
|
key = "goals_period_#{period}".to_sym
|
144
146
|
scoring_periods[key] =
|
145
147
|
scoring_data['points'].to_i
|
146
148
|
elsif period > 3
|
147
|
-
period_type = (scoring_data['type'] || 'period').downcase
|
148
149
|
if period_type == 'overtime'
|
149
150
|
key = "goals_#{period_type}_#{scoring_data['number'].to_i}".to_sym
|
150
151
|
scoring_periods[key] =
|
151
152
|
scoring_data['points'].to_i
|
152
153
|
overtime_points += scoring_data['points'].to_i
|
153
154
|
scoring_periods[:goals_overtime] = overtime_points
|
154
|
-
elsif period_type == 'shootout'
|
155
|
-
key = "goals_#{period_type}".to_sym
|
156
|
-
scoring_periods[key] =
|
157
|
-
scoring_data['points'].to_i
|
158
155
|
end
|
156
|
+
elsif period_type == 'shootout'
|
157
|
+
key = "goals_#{period_type}".to_sym
|
158
|
+
scoring_periods[key] =
|
159
|
+
scoring_data['points'].to_i
|
159
160
|
end
|
160
161
|
end
|
161
162
|
end
|
data/lib/sportradar/version.rb
CHANGED
data/lib/sportradar.rb
CHANGED
@@ -52,7 +52,15 @@ require 'sportradar/mlb/team_rosters'
|
|
52
52
|
require 'sportradar/mlb/team_statistics'
|
53
53
|
require 'sportradar/mlb/venues'
|
54
54
|
|
55
|
+
require 'sportradar/nba/models/event'
|
56
|
+
require 'sportradar/nba/models/quarter'
|
57
|
+
require 'sportradar/nba/models/on_court_player'
|
58
|
+
require 'sportradar/nba/models/play_player_stat'
|
59
|
+
require 'sportradar/nba/models/scoring_player'
|
60
|
+
require 'sportradar/nba/models/scoring_play'
|
61
|
+
|
55
62
|
require 'sportradar/nba/parsers/boxscore_parser'
|
63
|
+
require 'sportradar/nba/parsers/play_by_play_parser'
|
56
64
|
|
57
65
|
require 'sportradar/nba/daily_schedule'
|
58
66
|
require 'sportradar/nba/league_hierarchy'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sportradar
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.18
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stattleship
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-10-
|
12
|
+
date: 2016-10-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -206,7 +206,14 @@ files:
|
|
206
206
|
- lib/sportradar/nba/injuries.rb
|
207
207
|
- lib/sportradar/nba/league_hierarchy.rb
|
208
208
|
- lib/sportradar/nba/league_schedule.rb
|
209
|
+
- lib/sportradar/nba/models/event.rb
|
210
|
+
- lib/sportradar/nba/models/on_court_player.rb
|
211
|
+
- lib/sportradar/nba/models/play_player_stat.rb
|
212
|
+
- lib/sportradar/nba/models/quarter.rb
|
213
|
+
- lib/sportradar/nba/models/scoring_play.rb
|
214
|
+
- lib/sportradar/nba/models/scoring_player.rb
|
209
215
|
- lib/sportradar/nba/parsers/boxscore_parser.rb
|
216
|
+
- lib/sportradar/nba/parsers/play_by_play_parser.rb
|
210
217
|
- lib/sportradar/nba/play_by_play.rb
|
211
218
|
- lib/sportradar/nba/team_roster.rb
|
212
219
|
- lib/sportradar/nba/team_rosters.rb
|