sportradar 0.0.11 → 0.0.12
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 +4 -4
- data/.ruby-version +1 -1
- data/Gemfile +1 -1
- data/README.md +11 -0
- data/lib/sportradar.rb +16 -0
- data/lib/sportradar/nfl/team_rosters.rb +2 -2
- data/lib/sportradar/nhl/boxscore.rb +17 -0
- data/lib/sportradar/nhl/daily_schedule.rb +13 -0
- data/lib/sportradar/nhl/game_summary.rb +17 -0
- data/lib/sportradar/nhl/models/event.rb +171 -0
- data/lib/sportradar/nhl/models/penalty.rb +63 -0
- data/lib/sportradar/nhl/models/period.rb +70 -0
- data/lib/sportradar/nhl/models/play_player_stat.rb +124 -0
- data/lib/sportradar/nhl/models/scoring_play.rb +76 -0
- data/lib/sportradar/nhl/models/scoring_player.rb +25 -0
- data/lib/sportradar/nhl/parsers/boxscore_parser.rb +223 -0
- data/lib/sportradar/nhl/parsers/play_by_play_parser.rb +65 -0
- data/lib/sportradar/nhl/team_roster.rb +17 -0
- data/lib/sportradar/nhl/team_rosters.rb +29 -0
- data/lib/sportradar/nhl/teams_request.rb +39 -0
- data/lib/sportradar/version.rb +1 -1
- metadata +16 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4bc168b82f0579a852d39bb5c7f8b37deb2fa3ee
|
|
4
|
+
data.tar.gz: 027a52c50e00e65ac48b8e8cd9a8dd3fef3fd741
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 45ececc3591c930e81699f5fa872a256d29e5ab979309e9eb882bec11bc9340d11a999573f53b342c767160c52ac2ba825cd2517f11469c7c0469780e0e326d1
|
|
7
|
+
data.tar.gz: 0995270a287da7e020a13f89670db2c63b9ccb0c056dfab3aa78ee27fb9d47270893715d51e96252f03f79e2e801dd3956b53bb9a3109e493033e2fa4a31b315
|
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.3.
|
|
1
|
+
2.3.1
|
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -182,8 +182,19 @@ Defaults to and supports NHL Classic API feed version 3 only (not Official).
|
|
|
182
182
|
#### API Requests
|
|
183
183
|
|
|
184
184
|
* `Sportradar::Nhl::LeagueHierarchy.new().fetch`
|
|
185
|
+
* `Sportradar::Nhl::DailySchedule.new(date: Date.today).fetch`
|
|
185
186
|
* `Sportradar::Nhl::LeagueSchedule.new(year: '2016', interval_type: <reg|pre|pst>).fetch`
|
|
187
|
+
* `Sportradar::Nhl::Boxscore.new(event_id: '<game_guid>').fetch`
|
|
188
|
+
* `Sportradar::Nhl::GameSummary.new(event_id: '<game_guid>').fetch`
|
|
186
189
|
* `Sportradar::Nhl::PlayByPlay.new(event_id: '<game_guid>').fetch`
|
|
190
|
+
* `Sportradar::Nhl::TeamRoster.perform`
|
|
191
|
+
* `Sportradar::Nhl::TeamRoster.new(team_id: '44151f7a-0f24-11e2-8525-18a905767e44').fetch`
|
|
192
|
+
|
|
193
|
+
#### Bulk Saves
|
|
194
|
+
|
|
195
|
+
Some helpers will call `.save` for each response as separate items.
|
|
196
|
+
|
|
197
|
+
* `Sportradar::Nhl::TeamRosters.perform`
|
|
187
198
|
|
|
188
199
|
### Model Helpers
|
|
189
200
|
|
data/lib/sportradar.rb
CHANGED
|
@@ -98,9 +98,25 @@ require 'sportradar/nfl/rankings'
|
|
|
98
98
|
require 'sportradar/nfl/standings'
|
|
99
99
|
require 'sportradar/nfl/season_statistics'
|
|
100
100
|
|
|
101
|
+
require 'sportradar/nhl/models/event'
|
|
102
|
+
require 'sportradar/nhl/models/period'
|
|
103
|
+
require 'sportradar/nhl/models/play_player_stat'
|
|
104
|
+
require 'sportradar/nhl/models/scoring_player'
|
|
105
|
+
require 'sportradar/nhl/models/scoring_play'
|
|
106
|
+
require 'sportradar/nhl/models/penalty'
|
|
107
|
+
|
|
108
|
+
require 'sportradar/nhl/parsers/boxscore_parser'
|
|
109
|
+
require 'sportradar/nhl/parsers/play_by_play_parser'
|
|
110
|
+
|
|
111
|
+
require 'sportradar/nhl/boxscore'
|
|
112
|
+
require 'sportradar/nhl/daily_schedule'
|
|
113
|
+
require 'sportradar/nhl/game_summary'
|
|
101
114
|
require 'sportradar/nhl/league_hierarchy'
|
|
102
115
|
require 'sportradar/nhl/league_schedule'
|
|
103
116
|
require 'sportradar/nhl/play_by_play'
|
|
117
|
+
require 'sportradar/nhl/teams_request'
|
|
118
|
+
require 'sportradar/nhl/team_roster'
|
|
119
|
+
require 'sportradar/nhl/team_rosters'
|
|
104
120
|
|
|
105
121
|
Oj.default_options = {}
|
|
106
122
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Sportradar
|
|
2
|
+
module Nhl
|
|
3
|
+
class Boxscore < Sportradar::ApiRequest
|
|
4
|
+
def initialize(event_id:)
|
|
5
|
+
@event_id = event_id
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def path
|
|
9
|
+
"games/#{event_id}/boxscore.json"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
attr_reader :event_id
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Sportradar
|
|
2
|
+
module Nhl
|
|
3
|
+
class GameSummary < Sportradar::ApiRequest
|
|
4
|
+
def initialize(event_id:)
|
|
5
|
+
@event_id = event_id
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def path
|
|
9
|
+
"games/#{event_id}/summary.json"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
attr_reader :event_id
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
module Sportradar
|
|
2
|
+
module Nhl
|
|
3
|
+
module Models
|
|
4
|
+
class Event
|
|
5
|
+
|
|
6
|
+
EVENT_TYPES = %w(emptynetgoal endperiod endshootoutperiod evenstrength faceoff giveaway goal goaliechange hit penalty penaltygoal penaltyshotmissed penaltyshotsaved powerplay shootoutgoal shootoutshotmissed shootoutshotsaved shotmissed shotsaved startshootoutperiod stoppage takeaway teamtimeout tvtimeout)
|
|
7
|
+
PLAY_TYPES = %w(emptynetgoal faceoff giveaway goal hit penalty penaltygoal penaltyshotmissed penaltyshotsaved powerplay shootoutgoal shootoutshotmissed shootoutshotsaved shotmissed shotsaved takeaway)
|
|
8
|
+
STOPPAGE_TYPES = %w(stoppage teamtimeout tvtimeout endperiod)
|
|
9
|
+
SCORING_PLAY_TYPES = %w(goal penaltygoal shootoutgoal)
|
|
10
|
+
PENALTY_TYPES = %w(penalty)
|
|
11
|
+
|
|
12
|
+
def initialize(period:, attributes:)
|
|
13
|
+
@period = period
|
|
14
|
+
@attributes = attributes
|
|
15
|
+
build_statistics
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def to_s
|
|
19
|
+
if coordinates?
|
|
20
|
+
"#{period_number} - #{clock} - #{event_type}: #{description} [#{coordinate_x}, #{coordinate_y}]"
|
|
21
|
+
else
|
|
22
|
+
"#{period_number} - #{clock} - #{event_type}: #{description}"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def id
|
|
27
|
+
@attributes['id']
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def game_id
|
|
31
|
+
period.game_id
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def team
|
|
35
|
+
@attributes['attribution'] || {}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def team_id
|
|
39
|
+
team.dig('id')
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def team_goal_side
|
|
43
|
+
team.dig('team_goal')
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def has_team?
|
|
47
|
+
!team_id.nil?
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def period
|
|
51
|
+
@period
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def period_id
|
|
55
|
+
@period.id
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def period_number
|
|
59
|
+
@period.number
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def time_code
|
|
63
|
+
min, sec = clock.split(':').map(&:to_i)
|
|
64
|
+
"PT#{min}M#{sec}S"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def clock
|
|
68
|
+
@attributes['clock'] || '0'
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def clock_secs
|
|
72
|
+
begin
|
|
73
|
+
if clock && clock.include?(':')
|
|
74
|
+
mins, secs = clock.split(':').map(&:to_i)
|
|
75
|
+
Time.parse("00:#{mins}:#{secs}").
|
|
76
|
+
seconds_since_midnight.to_i
|
|
77
|
+
end
|
|
78
|
+
rescue => e
|
|
79
|
+
return 0
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
alias_method :period_seconds, :clock_secs
|
|
83
|
+
|
|
84
|
+
def id
|
|
85
|
+
@attributes['id']
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def description
|
|
89
|
+
@attributes['description'] || 0
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def event_type
|
|
93
|
+
@attributes['event_type']
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def coordinates
|
|
97
|
+
@attributes['location'] || {}
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def coordinates?
|
|
101
|
+
@attributes['location'].present?
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def coordinate_x
|
|
105
|
+
coordinates['coord_x']
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def coordinate_y
|
|
109
|
+
coordinates['coord_y']
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def official
|
|
113
|
+
@attributes['official']
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def strength
|
|
117
|
+
@attributes['strength']
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def wall_clock
|
|
121
|
+
@attributes['wall_clock']
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def zone
|
|
125
|
+
@attributes['zone']
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def updated_at
|
|
129
|
+
@attributes['updated']
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def statistics
|
|
133
|
+
@attributes['statistics'] || []
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def play_player_stats
|
|
137
|
+
@play_player_stats ||= []
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def scoring_players
|
|
141
|
+
@scoring_players ||= []
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def penalty?
|
|
145
|
+
PENALTY_TYPES.include?(event_type)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def play?
|
|
149
|
+
PLAY_TYPES.include?(event_type)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def scoring_play?
|
|
153
|
+
SCORING_PLAY_TYPES.include?(event_type)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def stoppage?
|
|
157
|
+
STOPPAGE_TYPES.include?(event_type)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
private
|
|
161
|
+
|
|
162
|
+
def build_statistics
|
|
163
|
+
statistics.each do |statistic|
|
|
164
|
+
play_player_stats << Models::PlayPlayerStat.new(event: self, attributes: statistic)
|
|
165
|
+
scoring_players << Models::ScoringPlayer.new(event: self, attributes: statistic) if scoring_play?
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
module Sportradar
|
|
2
|
+
module Nhl
|
|
3
|
+
module Models
|
|
4
|
+
class Penalty < Event
|
|
5
|
+
def to_s
|
|
6
|
+
"#{super} - #{minutes} mins - #{label}"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def duration
|
|
10
|
+
@attributes.dig('duration')
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def minutes
|
|
14
|
+
duration.to_i
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def name
|
|
18
|
+
ActiveSupport::Inflector.parameterize(penalty_type)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def penalty_type
|
|
22
|
+
@attributes.dig('penalty_type')
|
|
23
|
+
end
|
|
24
|
+
alias_method :label, :penalty_type
|
|
25
|
+
|
|
26
|
+
def player_id
|
|
27
|
+
play_player_stats.each do |stat|
|
|
28
|
+
if stat.penalty? && !stat.player_id.nil?
|
|
29
|
+
return stat.player_id
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
nil
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def seconds
|
|
37
|
+
minutes * 60
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def team_penalty
|
|
41
|
+
false
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def to_h
|
|
45
|
+
{
|
|
46
|
+
id: id,
|
|
47
|
+
game_id: game_id,
|
|
48
|
+
player_id: player_id,
|
|
49
|
+
team_id: team_id,
|
|
50
|
+
minutes: minutes,
|
|
51
|
+
name: name,
|
|
52
|
+
period_number: period_number,
|
|
53
|
+
period_seconds: period_seconds,
|
|
54
|
+
sports_ml_key: id,
|
|
55
|
+
team_penalty: team_penalty,
|
|
56
|
+
time_code: time_code,
|
|
57
|
+
seconds: seconds,
|
|
58
|
+
}
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module Sportradar
|
|
2
|
+
module Nhl
|
|
3
|
+
module Models
|
|
4
|
+
class Period
|
|
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
|
+
"Period #{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 penalties
|
|
40
|
+
@penalties ||= []
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def plays
|
|
44
|
+
@plays ||= []
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def scoring_plays
|
|
48
|
+
@scoring_plays ||= []
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def stoppages
|
|
52
|
+
@stoppages ||= []
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
def build_events
|
|
58
|
+
events_data.each do |event_data|
|
|
59
|
+
event = Models::Event.new(period: self, attributes: event_data)
|
|
60
|
+
events << event
|
|
61
|
+
plays << event if event.play?
|
|
62
|
+
stoppages << event if event.stoppage?
|
|
63
|
+
penalties << Models::Penalty.new(period: self, attributes: event_data) if event.penalty?
|
|
64
|
+
scoring_plays << Models::ScoringPlay.new(period: self, attributes: event_data) if event.scoring_play?
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
module Sportradar
|
|
2
|
+
module Nhl
|
|
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
|
+
period_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 period
|
|
34
|
+
@event.period
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def period_number
|
|
38
|
+
period.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
|
+
goal: goal?,
|
|
81
|
+
penalty: penalty?,
|
|
82
|
+
saved: saved?,
|
|
83
|
+
shootout: shootout?,
|
|
84
|
+
strength: strength,
|
|
85
|
+
type: type,
|
|
86
|
+
zone: zone,
|
|
87
|
+
}.compact
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def goal?
|
|
91
|
+
@attributes.dig('goal') == true
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def penalty?
|
|
95
|
+
type == 'penalty'
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def saved?
|
|
99
|
+
@attributes.dig('saved') == true
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def shootout?
|
|
103
|
+
@attributes.dig('shootout') == true
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def strength
|
|
107
|
+
@attributes.dig('strength')
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def type
|
|
111
|
+
@attributes.dig('type')
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def win?
|
|
115
|
+
@attributes.dig('win') == true
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def zone
|
|
119
|
+
@attributes.dig('zone')
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
module Sportradar
|
|
2
|
+
module Nhl
|
|
3
|
+
module Models
|
|
4
|
+
class ScoringPlay < Event
|
|
5
|
+
def points
|
|
6
|
+
1
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def scored_at
|
|
10
|
+
wall_clock
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def scoring_method
|
|
14
|
+
if empty_net? || penalty_goal? || shootout_goal?
|
|
15
|
+
'goal'
|
|
16
|
+
else
|
|
17
|
+
event_type
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def scoring_type
|
|
22
|
+
case strength
|
|
23
|
+
when 'even'
|
|
24
|
+
'ev'
|
|
25
|
+
when 'powerplay'
|
|
26
|
+
'pp'
|
|
27
|
+
when 'shorthanded'
|
|
28
|
+
'sh'
|
|
29
|
+
else
|
|
30
|
+
if shootout_goal?
|
|
31
|
+
'so'
|
|
32
|
+
else
|
|
33
|
+
strength
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def scoring_how
|
|
39
|
+
event_type
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def empty_net
|
|
43
|
+
event_type == 'emptynetgoal'
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def empty_net?
|
|
47
|
+
empty_net
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def penalty_goal
|
|
51
|
+
event_type == 'penaltygoal'
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def penalty_goal?
|
|
55
|
+
penalty_goal
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def shootout_goal?
|
|
59
|
+
event_type == 'shootoutgoal'
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def to_h
|
|
63
|
+
{
|
|
64
|
+
id: id,
|
|
65
|
+
game_id: game_id,
|
|
66
|
+
points: points,
|
|
67
|
+
scored_at: scored_at,
|
|
68
|
+
scoring_method: scoring_method,
|
|
69
|
+
scoring_type: scoring_type,
|
|
70
|
+
empty_net: empty_net,
|
|
71
|
+
}.compact
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Sportradar
|
|
2
|
+
module Nhl
|
|
3
|
+
module Models
|
|
4
|
+
class ScoringPlayer < PlayPlayerStat
|
|
5
|
+
def role
|
|
6
|
+
if goal? && type == 'shot'
|
|
7
|
+
'scorer'
|
|
8
|
+
elsif goal? && type == 'shotagainst' && !saved?
|
|
9
|
+
'goalie'
|
|
10
|
+
else
|
|
11
|
+
type
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def scoring_play_id
|
|
16
|
+
event.id
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def to_s
|
|
20
|
+
"#{super} - #{role}"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
module Sportradar
|
|
2
|
+
module Nhl
|
|
3
|
+
module Parsers
|
|
4
|
+
class BoxscoreParser
|
|
5
|
+
def initialize(json: {})
|
|
6
|
+
@json = json['game'] || json
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def game_id
|
|
10
|
+
json['id']
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def attendance
|
|
14
|
+
json['attendance']
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def period
|
|
18
|
+
json['period'].to_i
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def scheduled_at
|
|
22
|
+
json['scheduled'] && json['scheduled'].to_datetime
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def started_at
|
|
26
|
+
json['start_time'] && json['start_time'].to_datetime
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def ended_at
|
|
30
|
+
json['end_time'] && json['end_time'].to_datetime
|
|
31
|
+
end
|
|
32
|
+
alias_method :completed, :ended_at
|
|
33
|
+
|
|
34
|
+
def over?
|
|
35
|
+
status == 'closed'
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def status
|
|
39
|
+
json['status']
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def clock
|
|
43
|
+
json['clock']
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def clock_attributes
|
|
47
|
+
{
|
|
48
|
+
clock: clock,
|
|
49
|
+
clock_secs: clock_secs,
|
|
50
|
+
duration: duration_secs,
|
|
51
|
+
period: period,
|
|
52
|
+
ended_at: ended_at,
|
|
53
|
+
status: status,
|
|
54
|
+
}.compact
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def clock_secs
|
|
58
|
+
begin
|
|
59
|
+
if clock && clock.include?(':')
|
|
60
|
+
mins, secs = clock.split(':').map(&:to_i)
|
|
61
|
+
Time.parse("00:#{mins}:#{secs}").
|
|
62
|
+
seconds_since_midnight.to_i
|
|
63
|
+
end
|
|
64
|
+
rescue => e
|
|
65
|
+
puts e
|
|
66
|
+
return 0
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def duration
|
|
71
|
+
json['total_game_duration']
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def duration_secs
|
|
75
|
+
begin
|
|
76
|
+
if duration && duration.include?(':')
|
|
77
|
+
mins, secs = duration.split(':').map(&:to_i)
|
|
78
|
+
hours = mins / 60
|
|
79
|
+
mins = mins % 60
|
|
80
|
+
Time.parse("#{hours}:#{mins}:#{secs}").
|
|
81
|
+
seconds_since_midnight.to_i
|
|
82
|
+
end
|
|
83
|
+
rescue => e
|
|
84
|
+
return 0
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def home_team_json
|
|
89
|
+
json['home'] || {}
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def home_team_id
|
|
93
|
+
home_team_json['id']
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def home_team_scoring_data
|
|
97
|
+
home_team_json['scoring'] || {}
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def home_team_scoring
|
|
101
|
+
{
|
|
102
|
+
goals: home_team_json['points'],
|
|
103
|
+
}.merge(home_team_scoring_periods).
|
|
104
|
+
compact
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def home_team_scoring_periods
|
|
108
|
+
team_scoring_periods(data: home_team_scoring_data)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def away_team_json
|
|
112
|
+
json['away'] || {}
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def away_team_id
|
|
116
|
+
away_team_json['id']
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def away_team_scoring_data
|
|
120
|
+
away_team_json['scoring'] || {}
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def away_team_scoring
|
|
124
|
+
{
|
|
125
|
+
goals: away_team_json['points'],
|
|
126
|
+
}.merge(away_team_scoring_periods).
|
|
127
|
+
compact
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def away_team_scoring_periods
|
|
131
|
+
team_scoring_periods(data: away_team_scoring_data)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def team_scoring_periods(data:)
|
|
135
|
+
{}.tap do |scoring_periods|
|
|
136
|
+
overtime_points = 0
|
|
137
|
+
scoring_periods[:goals_overtime] = overtime_points
|
|
138
|
+
scoring_periods[:goals_shootout] = 0
|
|
139
|
+
|
|
140
|
+
data.map do |scoring_data|
|
|
141
|
+
if period = scoring_data['sequence'].to_i
|
|
142
|
+
if period > 0 && period <= 3
|
|
143
|
+
key = "goals_period_#{period}".to_sym
|
|
144
|
+
scoring_periods[key] =
|
|
145
|
+
scoring_data['points'].to_i
|
|
146
|
+
elsif period > 3
|
|
147
|
+
period_type = (scoring_data['type'] || 'period').downcase
|
|
148
|
+
if period_type == 'overtime'
|
|
149
|
+
key = "goals_#{period_type}_#{scoring_data['number'].to_i}".to_sym
|
|
150
|
+
scoring_periods[key] =
|
|
151
|
+
scoring_data['points'].to_i
|
|
152
|
+
overtime_points += scoring_data['points'].to_i
|
|
153
|
+
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
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
scoring_periods[:goals_overtime] = overtime_points
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def game_scoring_attributes
|
|
167
|
+
{
|
|
168
|
+
attendance: attendance,
|
|
169
|
+
home_team_outcome: home_team_outcome,
|
|
170
|
+
home_team_score: home_team_score,
|
|
171
|
+
away_team_outcome: away_team_outcome,
|
|
172
|
+
away_team_score: away_team_score,
|
|
173
|
+
}
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def home_team_score
|
|
177
|
+
home_team_scoring[:goals] || 0
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def home_team_outcome
|
|
181
|
+
if over?
|
|
182
|
+
if home_team_score > away_team_score
|
|
183
|
+
'win'
|
|
184
|
+
elsif home_team_score < away_team_score
|
|
185
|
+
'loss'
|
|
186
|
+
else
|
|
187
|
+
'tie'
|
|
188
|
+
end
|
|
189
|
+
else
|
|
190
|
+
'undecided'
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def away_team_score
|
|
195
|
+
away_team_scoring[:goals] || 0
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def away_team_outcome
|
|
199
|
+
if over?
|
|
200
|
+
if home_team_score < away_team_score
|
|
201
|
+
'win'
|
|
202
|
+
elsif home_team_score > away_team_score
|
|
203
|
+
'loss'
|
|
204
|
+
else
|
|
205
|
+
'tie'
|
|
206
|
+
end
|
|
207
|
+
else
|
|
208
|
+
'undecided'
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def game_attributes
|
|
213
|
+
clock_attributes.merge(game_scoring_attributes).
|
|
214
|
+
compact
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
private
|
|
218
|
+
|
|
219
|
+
attr_reader :json
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
module Sportradar
|
|
2
|
+
module Nhl
|
|
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 periods
|
|
26
|
+
@periods ||= build_periods || []
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def has_periods?
|
|
30
|
+
periods.count > 0
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def events
|
|
34
|
+
(periods || []).map(&:events).flatten
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def penalties
|
|
38
|
+
(periods || []).map(&:penalties).flatten
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def plays
|
|
42
|
+
(periods || []).map(&:plays).flatten
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def scoring_plays
|
|
46
|
+
(periods || []).map(&:scoring_plays).flatten
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def stoppages
|
|
50
|
+
(periods || []).map(&:stoppages).flatten
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
attr_reader :game_play_by_play
|
|
56
|
+
|
|
57
|
+
def build_periods
|
|
58
|
+
game_play_by_play.
|
|
59
|
+
dig('periods').
|
|
60
|
+
map { |attributes| Models::Period.new(game_id: game_id, attributes: attributes) }
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Sportradar
|
|
2
|
+
module Nhl
|
|
3
|
+
class TeamRosters < Sportradar::Nhl::TeamsRequest
|
|
4
|
+
def self.fetch
|
|
5
|
+
new.fetch
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def fetch
|
|
9
|
+
team_rosters = []
|
|
10
|
+
|
|
11
|
+
team_ids.each do |team_ids|
|
|
12
|
+
team_rosters << TeamRoster.new(team_id: team_ids).fetch
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
{ 'teams' => team_rosters }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.perform
|
|
19
|
+
new.perform
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def perform
|
|
23
|
+
team_ids.each do |team_id|
|
|
24
|
+
TeamRoster.new(team_id: team_id).save
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module Sportradar
|
|
2
|
+
module Nhl
|
|
3
|
+
class TeamsRequest
|
|
4
|
+
private
|
|
5
|
+
|
|
6
|
+
def team_ids
|
|
7
|
+
teams.map { |team| team['id'] }.sort
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def hierarchy
|
|
11
|
+
_hierarchy ||= LeagueHierarchy.new.fetch
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def conferences
|
|
15
|
+
conferences ||= hierarchy['conferences']
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def divisions
|
|
19
|
+
@divisions = []
|
|
20
|
+
|
|
21
|
+
conferences.each do |league|
|
|
22
|
+
@divisions << league['divisions']
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
@divisions.flatten
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def teams
|
|
29
|
+
@teams = []
|
|
30
|
+
|
|
31
|
+
divisions.each do |division|
|
|
32
|
+
@teams << division['teams']
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
@teams.flatten
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
data/lib/sportradar/version.rb
CHANGED
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.12
|
|
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-
|
|
12
|
+
date: 2016-10-11 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: bundler
|
|
@@ -242,9 +242,23 @@ files:
|
|
|
242
242
|
- lib/sportradar/nfl/weekly_leaders.rb
|
|
243
243
|
- lib/sportradar/nfl/weekly_play_by_play.rb
|
|
244
244
|
- lib/sportradar/nfl/weekly_schedule.rb
|
|
245
|
+
- lib/sportradar/nhl/boxscore.rb
|
|
246
|
+
- lib/sportradar/nhl/daily_schedule.rb
|
|
247
|
+
- lib/sportradar/nhl/game_summary.rb
|
|
245
248
|
- lib/sportradar/nhl/league_hierarchy.rb
|
|
246
249
|
- lib/sportradar/nhl/league_schedule.rb
|
|
250
|
+
- lib/sportradar/nhl/models/event.rb
|
|
251
|
+
- lib/sportradar/nhl/models/penalty.rb
|
|
252
|
+
- lib/sportradar/nhl/models/period.rb
|
|
253
|
+
- lib/sportradar/nhl/models/play_player_stat.rb
|
|
254
|
+
- lib/sportradar/nhl/models/scoring_play.rb
|
|
255
|
+
- lib/sportradar/nhl/models/scoring_player.rb
|
|
256
|
+
- lib/sportradar/nhl/parsers/boxscore_parser.rb
|
|
257
|
+
- lib/sportradar/nhl/parsers/play_by_play_parser.rb
|
|
247
258
|
- lib/sportradar/nhl/play_by_play.rb
|
|
259
|
+
- lib/sportradar/nhl/team_roster.rb
|
|
260
|
+
- lib/sportradar/nhl/team_rosters.rb
|
|
261
|
+
- lib/sportradar/nhl/teams_request.rb
|
|
248
262
|
- lib/sportradar/version.rb
|
|
249
263
|
- sample.env
|
|
250
264
|
- sportradar.gemspec
|