ahl_scraper 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.rubocop.yml +85 -0
- data/.ruby-version +1 -0
- data/.solargraph.yml +15 -0
- data/.travis.yml +6 -0
- data/.vscode/settings.json +11 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +25 -0
- data/Gemfile.lock +114 -0
- data/LICENSE.txt +21 -0
- data/README.md +235 -0
- data/Rakefile +8 -0
- data/ahl_scraper.gemspec +27 -0
- data/bin/console +16 -0
- data/bin/setup +8 -0
- data/lib/ahl_scraper.rb +55 -0
- data/lib/ahl_scraper/fetchers/division_data_fetcher.rb +19 -0
- data/lib/ahl_scraper/fetchers/game_data_fetcher.rb +29 -0
- data/lib/ahl_scraper/fetchers/game_event_data_fetcher.rb +19 -0
- data/lib/ahl_scraper/fetchers/player_data_fetcher.rb +25 -0
- data/lib/ahl_scraper/fetchers/player_games/data_fetcher.rb +30 -0
- data/lib/ahl_scraper/fetchers/playoff_bracket_data_fetcher.rb +19 -0
- data/lib/ahl_scraper/fetchers/season_data_fetcher.rb +15 -0
- data/lib/ahl_scraper/fetchers/season_end_date_fetcher.rb +34 -0
- data/lib/ahl_scraper/fetchers/season_game_ids_fetcher.rb +21 -0
- data/lib/ahl_scraper/fetchers/season_start_date_fetcher.rb +30 -0
- data/lib/ahl_scraper/fetchers/season_type_fetcher.rb +33 -0
- data/lib/ahl_scraper/fetchers/team_data_fetcher.rb +19 -0
- data/lib/ahl_scraper/fetchers/team_games/data_fetcher.rb +22 -0
- data/lib/ahl_scraper/fetchers/team_roster_data_fetcher.rb +67 -0
- data/lib/ahl_scraper/fixed_games/1001050.json +2182 -0
- data/lib/ahl_scraper/fixed_games/1018774.json +2573 -0
- data/lib/ahl_scraper/fixed_games/1020527.json +2483 -0
- data/lib/ahl_scraper/games.rb +46 -0
- data/lib/ahl_scraper/games/events.rb +8 -0
- data/lib/ahl_scraper/helpers/birthdate_helper.rb +27 -0
- data/lib/ahl_scraper/helpers/elapsed_time_helper.rb +24 -0
- data/lib/ahl_scraper/helpers/ice_time_helper.rb +18 -0
- data/lib/ahl_scraper/helpers/parameterize_helper.rb +35 -0
- data/lib/ahl_scraper/helpers/period_time_helper.rb +25 -0
- data/lib/ahl_scraper/helpers/season_dates_helper.rb +14 -0
- data/lib/ahl_scraper/player_games.rb +19 -0
- data/lib/ahl_scraper/players.rb +12 -0
- data/lib/ahl_scraper/playoff_brackets.rb +17 -0
- data/lib/ahl_scraper/resource.rb +38 -0
- data/lib/ahl_scraper/resources/game.rb +373 -0
- data/lib/ahl_scraper/resources/game_list_item.rb +57 -0
- data/lib/ahl_scraper/resources/games/coach.rb +23 -0
- data/lib/ahl_scraper/resources/games/events/shot.rb +10 -0
- data/lib/ahl_scraper/resources/games/goal.rb +161 -0
- data/lib/ahl_scraper/resources/games/goalie.rb +106 -0
- data/lib/ahl_scraper/resources/games/info.rb +83 -0
- data/lib/ahl_scraper/resources/games/on_ice_skater.rb +35 -0
- data/lib/ahl_scraper/resources/games/overtime.rb +48 -0
- data/lib/ahl_scraper/resources/games/penalty.rb +101 -0
- data/lib/ahl_scraper/resources/games/penalty_shot.rb +82 -0
- data/lib/ahl_scraper/resources/games/period.rb +31 -0
- data/lib/ahl_scraper/resources/games/referee.rb +23 -0
- data/lib/ahl_scraper/resources/games/shootout_attempt.rb +61 -0
- data/lib/ahl_scraper/resources/games/skater.rb +94 -0
- data/lib/ahl_scraper/resources/games/star.rb +47 -0
- data/lib/ahl_scraper/resources/games/team.rb +85 -0
- data/lib/ahl_scraper/resources/goalie_game_list_item.rb +69 -0
- data/lib/ahl_scraper/resources/player.rb +71 -0
- data/lib/ahl_scraper/resources/playoff_bracket.rb +21 -0
- data/lib/ahl_scraper/resources/playoff_brackets/game.rb +43 -0
- data/lib/ahl_scraper/resources/playoff_brackets/round.rb +31 -0
- data/lib/ahl_scraper/resources/playoff_brackets/series.rb +73 -0
- data/lib/ahl_scraper/resources/playoff_brackets/team.rb +39 -0
- data/lib/ahl_scraper/resources/roster_player.rb +71 -0
- data/lib/ahl_scraper/resources/season.rb +93 -0
- data/lib/ahl_scraper/resources/season_list_item.rb +30 -0
- data/lib/ahl_scraper/resources/seasons/team.rb +77 -0
- data/lib/ahl_scraper/resources/skater_game_list_item.rb +65 -0
- data/lib/ahl_scraper/resources/team_game_list_item.rb +64 -0
- data/lib/ahl_scraper/resources/team_list_item.rb +20 -0
- data/lib/ahl_scraper/roster_players.rb +11 -0
- data/lib/ahl_scraper/seasons.rb +31 -0
- data/lib/ahl_scraper/services/games/create_skaters_service.rb +72 -0
- data/lib/ahl_scraper/services/games/on_ice_statlines_service.rb +117 -0
- data/lib/ahl_scraper/services/games/penalty_shot_statlines_service.rb +38 -0
- data/lib/ahl_scraper/services/games/penalty_shots_service.rb +30 -0
- data/lib/ahl_scraper/services/games/penalty_statlines_service.rb +62 -0
- data/lib/ahl_scraper/services/games/scoring_statlines_service.rb +115 -0
- data/lib/ahl_scraper/services/games/shootout_statlines_service.rb +42 -0
- data/lib/ahl_scraper/services/games/team_on_ice_goals_service.rb +152 -0
- data/lib/ahl_scraper/services/games/time_splits_service.rb +70 -0
- data/lib/ahl_scraper/services/seasons/teams_service.rb +20 -0
- data/lib/ahl_scraper/team_games.rb +17 -0
- data/lib/ahl_scraper/teams.rb +11 -0
- data/lib/ahl_scraper/version.rb +5 -0
- metadata +138 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ahl_scraper/games/events"
|
4
|
+
|
5
|
+
require "ahl_scraper/services/games/create_skaters_service"
|
6
|
+
require "ahl_scraper/services/games/on_ice_statlines_service"
|
7
|
+
require "ahl_scraper/services/games/penalty_shots_service"
|
8
|
+
require "ahl_scraper/services/games/penalty_shot_statlines_service"
|
9
|
+
require "ahl_scraper/services/games/penalty_statlines_service"
|
10
|
+
require "ahl_scraper/services/games/scoring_statlines_service"
|
11
|
+
require "ahl_scraper/services/games/shootout_statlines_service"
|
12
|
+
require "ahl_scraper/services/games/team_on_ice_goals_service"
|
13
|
+
require "ahl_scraper/services/games/time_splits_service"
|
14
|
+
|
15
|
+
require "ahl_scraper/resources/games/coach"
|
16
|
+
require "ahl_scraper/resources/games/goal"
|
17
|
+
require "ahl_scraper/resources/games/goalie"
|
18
|
+
require "ahl_scraper/resources/games/info"
|
19
|
+
require "ahl_scraper/resources/games/on_ice_skater"
|
20
|
+
require "ahl_scraper/resources/games/overtime"
|
21
|
+
require "ahl_scraper/resources/games/penalty_shot"
|
22
|
+
require "ahl_scraper/resources/games/penalty"
|
23
|
+
require "ahl_scraper/resources/games/period"
|
24
|
+
require "ahl_scraper/resources/games/referee"
|
25
|
+
require "ahl_scraper/resources/games/shootout_attempt"
|
26
|
+
require "ahl_scraper/resources/games/skater"
|
27
|
+
require "ahl_scraper/resources/games/star"
|
28
|
+
require "ahl_scraper/resources/games/team"
|
29
|
+
|
30
|
+
require "ahl_scraper/resources/games/events/shot"
|
31
|
+
|
32
|
+
module AhlScraper
|
33
|
+
module Games
|
34
|
+
@season_games = {}
|
35
|
+
|
36
|
+
class << self
|
37
|
+
def retrieve(game_id, season_type = nil)
|
38
|
+
Game.new(game_id, season_type: season_type)
|
39
|
+
end
|
40
|
+
|
41
|
+
def list(season_id)
|
42
|
+
@season_games[season_id.to_s] ||= SeasonGameIdsFetcher.new(season_id).call&.map { |game_data| GameListItem.new(game_data) }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "date"
|
4
|
+
|
5
|
+
module AhlScraper
|
6
|
+
class BirthdateHelper
|
7
|
+
attr_reader :birthdate
|
8
|
+
|
9
|
+
def initialize(birthdate)
|
10
|
+
@birthdate = Date.parse(birthdate)
|
11
|
+
end
|
12
|
+
|
13
|
+
def draft_year
|
14
|
+
return (birthdate + (19 * 365)).year if (birthdate.month == 9 && birthdate.day > 15) || birthdate.month > 9
|
15
|
+
|
16
|
+
(birthdate + (18 * 365)).year
|
17
|
+
end
|
18
|
+
|
19
|
+
def current_age(round: 2)
|
20
|
+
((Time.now.utc.to_datetime - birthdate.to_datetime).to_i / BigDecimal("365")).round(round)
|
21
|
+
end
|
22
|
+
|
23
|
+
def age_on_date(date, round: 2)
|
24
|
+
((Date.parse(date).to_datetime - birthdate.to_datetime).to_i / BigDecimal("365")).round(round)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AhlScraper
|
4
|
+
class ElapsedTimeHelper
|
5
|
+
attr_reader :time
|
6
|
+
|
7
|
+
def initialize(time)
|
8
|
+
@time = time.to_i
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_minutes
|
12
|
+
"#{time / 60}:#{(time % 60).to_s.rjust(2, '0')}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_minutes_with_period
|
16
|
+
period_elapsed = time % 1200
|
17
|
+
|
18
|
+
["#{period_elapsed / 60}:#{period_elapsed % 60}", (time / 1200) + 1]
|
19
|
+
end
|
20
|
+
|
21
|
+
alias to_min to_minutes
|
22
|
+
alias to_min_with_per to_minutes_with_period
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AhlScraper
|
4
|
+
class IceTimeHelper
|
5
|
+
attr_reader :time
|
6
|
+
|
7
|
+
def initialize(time)
|
8
|
+
@time = time
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_seconds
|
12
|
+
ice_time = time.split(":")
|
13
|
+
ice_time[0].to_i * 60 + ice_time[1].to_i
|
14
|
+
end
|
15
|
+
|
16
|
+
alias to_sec to_seconds
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AhlScraper
|
4
|
+
class ParameterizeHelper
|
5
|
+
attr_reader :string, :separator, :preserve_case
|
6
|
+
|
7
|
+
def initialize(string, separator: "-", preserve_case: false)
|
8
|
+
@string = string
|
9
|
+
@separator = separator
|
10
|
+
@preserve_case = preserve_case
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
parameterized_string = string.dup.to_s
|
15
|
+
|
16
|
+
parameterized_string.gsub!(/[^a-zA-Z0-9\-_]+/, separator)
|
17
|
+
|
18
|
+
unless separator.nil? || separator.empty?
|
19
|
+
if separator == "-"
|
20
|
+
re_duplicate_separator = /-{2,}/
|
21
|
+
re_leading_trailing_separator = /^-|-$/
|
22
|
+
else
|
23
|
+
re_sep = Regexp.escape(separator)
|
24
|
+
re_duplicate_separator = /#{re_sep}{2,}/
|
25
|
+
re_leading_trailing_separator = /^#{re_sep}|#{re_sep}$/
|
26
|
+
end
|
27
|
+
parameterized_string.gsub!(re_duplicate_separator, separator)
|
28
|
+
parameterized_string.gsub!(re_leading_trailing_separator, "")
|
29
|
+
end
|
30
|
+
|
31
|
+
parameterized_string.downcase! unless preserve_case
|
32
|
+
parameterized_string
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AhlScraper
|
4
|
+
class PeriodTimeHelper
|
5
|
+
attr_reader :time, :period
|
6
|
+
|
7
|
+
def initialize(time, period = nil)
|
8
|
+
@time = time
|
9
|
+
@period = period.to_i
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_period_seconds
|
13
|
+
period_time = time.split(":")
|
14
|
+
period_time[0].to_i * 60 + period_time[1].to_i
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_time_elapsed
|
18
|
+
period_time = time.split(":")
|
19
|
+
period_time[0].to_i * 60 + period_time[1].to_i + ((period - 1) * 1200)
|
20
|
+
end
|
21
|
+
|
22
|
+
alias to_sec to_period_seconds
|
23
|
+
alias to_elapsed to_time_elapsed
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AhlScraper
|
4
|
+
class SeasonDatesHelper
|
5
|
+
DATE_EXCEPTIONS = {
|
6
|
+
68 => { start_date: "Mon, Feb 1", end_date: "Sat, Jun 8" },
|
7
|
+
}.freeze
|
8
|
+
|
9
|
+
SEASON_MONTH_KEY = {
|
10
|
+
regular: { start_month: "10", end_month: "4" },
|
11
|
+
playoffs: { start_month: "4", end_month: "6" },
|
12
|
+
}.freeze
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ahl_scraper/fetchers/player_games/data_fetcher"
|
4
|
+
|
5
|
+
module AhlScraper
|
6
|
+
module PlayerGames
|
7
|
+
@season_games = {}
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def list(player_id, season_id)
|
11
|
+
@season_games["#{player_id}-#{season_id}"] ||= DataFetcher.new(player_id, season_id).call&.map do |player_data|
|
12
|
+
player_data[:position] == "G" ? GoalieGameListItem.new(player_data) : SkaterGameListItem.new(player_data)
|
13
|
+
end
|
14
|
+
|
15
|
+
@season_games["#{player_id}-#{season_id}"]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ahl_scraper/resources/playoff_brackets/game"
|
4
|
+
require "ahl_scraper/resources/playoff_brackets/round"
|
5
|
+
require "ahl_scraper/resources/playoff_brackets/series"
|
6
|
+
require "ahl_scraper/resources/playoff_brackets/team"
|
7
|
+
|
8
|
+
module AhlScraper
|
9
|
+
module PlayoffBrackets
|
10
|
+
class << self
|
11
|
+
def retrieve(season_id)
|
12
|
+
bracket_data = PlayoffBracketDataFetcher.new(season_id).call
|
13
|
+
PlayoffBracket.new(bracket_data)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AhlScraper
|
4
|
+
class Resource
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
def initialize(raw_data, opts = {})
|
8
|
+
@raw_data = raw_data
|
9
|
+
@opts = opts
|
10
|
+
end
|
11
|
+
|
12
|
+
def values
|
13
|
+
@values ||= (self.class.instance_methods(false) - %i[to_json inspect each keys [] values]).map do |m|
|
14
|
+
[m, send(m)]
|
15
|
+
end.to_h.transform_keys(&:to_sym)
|
16
|
+
end
|
17
|
+
|
18
|
+
def inspect
|
19
|
+
"#<#{self.class.to_s.split('::').last}:0x#{object_id.to_s(16)} #{values}>"
|
20
|
+
end
|
21
|
+
|
22
|
+
def [](key)
|
23
|
+
values[key.to_sym]
|
24
|
+
end
|
25
|
+
|
26
|
+
def keys
|
27
|
+
values.keys
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_json(*_opts)
|
31
|
+
JSON.generate(values)
|
32
|
+
end
|
33
|
+
|
34
|
+
def each(&blk)
|
35
|
+
values.each(&blk)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,373 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AhlScraper
|
4
|
+
class Game < Resource # rubocop:disable Metrics/ClassLength
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
IRREGULAR_GAMES = {
|
8
|
+
"1022174" => { status: "result_void", start_time_in_seconds: 0, end_time_in_seconds: 1200 },
|
9
|
+
}.freeze
|
10
|
+
|
11
|
+
ATTRIBUTES = %i[
|
12
|
+
game_id
|
13
|
+
season_type
|
14
|
+
info
|
15
|
+
current_time
|
16
|
+
current_period
|
17
|
+
current_period_number
|
18
|
+
season_id
|
19
|
+
played
|
20
|
+
in_progress
|
21
|
+
referees
|
22
|
+
home_coaches
|
23
|
+
away_coaches
|
24
|
+
home_team
|
25
|
+
away_team
|
26
|
+
winning_team
|
27
|
+
three_stars
|
28
|
+
home_skaters
|
29
|
+
away_skaters
|
30
|
+
home_goalies
|
31
|
+
away_goalies
|
32
|
+
home_roster
|
33
|
+
away_roster
|
34
|
+
goals
|
35
|
+
penalties
|
36
|
+
penalty_shots
|
37
|
+
periods
|
38
|
+
overtimes
|
39
|
+
overtime
|
40
|
+
home_shootout_attempts
|
41
|
+
away_shootout_attempts
|
42
|
+
home_penalty_shots
|
43
|
+
away_penalty_shots
|
44
|
+
shootout
|
45
|
+
].freeze
|
46
|
+
|
47
|
+
attr_reader(*ATTRIBUTES)
|
48
|
+
|
49
|
+
def initialize(game_id, opts = {})
|
50
|
+
@game_id = game_id
|
51
|
+
@raw_data = GameDataFetcher.new(game_id).call
|
52
|
+
@raw_event_data = GameEventDataFetcher.new(game_id).call
|
53
|
+
@season_type = opts[:season_type] || SeasonTypeFetcher.new(@raw_data[:details][:seasonId]).call
|
54
|
+
end
|
55
|
+
|
56
|
+
def values
|
57
|
+
@values ||= ATTRIBUTES.index_with do |m|
|
58
|
+
send(m)
|
59
|
+
end.transform_keys(&:to_sym)
|
60
|
+
end
|
61
|
+
|
62
|
+
def status
|
63
|
+
@status ||= set_game_status
|
64
|
+
end
|
65
|
+
|
66
|
+
def info
|
67
|
+
@info ||= Games::Info.new(@raw_data[:details], { name: "#{away_team.abbreviation} @ #{home_team.abbreviation}" })
|
68
|
+
end
|
69
|
+
|
70
|
+
def current_time
|
71
|
+
@current_time ||= set_current_game_time
|
72
|
+
end
|
73
|
+
|
74
|
+
def current_period
|
75
|
+
@current_period ||= set_current_game_period
|
76
|
+
end
|
77
|
+
|
78
|
+
def current_period_number
|
79
|
+
@current_period_number ||= @raw_data[:periods].length
|
80
|
+
end
|
81
|
+
|
82
|
+
def season_id
|
83
|
+
@season_id ||= @raw_data[:details][:seasonId].to_i
|
84
|
+
end
|
85
|
+
|
86
|
+
def referees
|
87
|
+
@referees ||= Array((@raw_data[:referees] + @raw_data[:linesmen])).uniq { |referee| referee.values_at(:lastName, :firstName, :jerseyNumber) }
|
88
|
+
.map { |r| Games::Referee.new(r) }
|
89
|
+
end
|
90
|
+
|
91
|
+
def three_stars
|
92
|
+
@three_stars ||= Array(@raw_data[:mostValuablePlayers]).map.with_index { |t, i| Games::Star.new(t, { number: i + 1 }) }
|
93
|
+
end
|
94
|
+
|
95
|
+
def home_coaches
|
96
|
+
@home_coaches ||= Array(@raw_data[:homeTeam][:coaches]).uniq { |coach| coach.values_at(:lastName, :firstName) }
|
97
|
+
.map { |coach| Games::Coach.new(coach, { team_id: home_team.id }) }
|
98
|
+
end
|
99
|
+
|
100
|
+
def away_coaches
|
101
|
+
@away_coaches ||= Array(@raw_data[:visitingTeam][:coaches]).uniq { |coach| coach.values_at(:lastName, :firstName) }
|
102
|
+
.map { |coach| Games::Coach.new(coach, { team_id: away_team.id }) }
|
103
|
+
end
|
104
|
+
|
105
|
+
def home_team
|
106
|
+
@home_team ||= Games::Team.new(
|
107
|
+
@raw_data[:homeTeam],
|
108
|
+
{
|
109
|
+
home_team: true,
|
110
|
+
goals: raw_goals,
|
111
|
+
current_state: current_state,
|
112
|
+
game_properties: game_properties,
|
113
|
+
shots: raw_period_shots,
|
114
|
+
goal_totals: raw_period_goals,
|
115
|
+
winning_team_id: winning_team_id,
|
116
|
+
}
|
117
|
+
)
|
118
|
+
end
|
119
|
+
|
120
|
+
def away_team
|
121
|
+
@away_team ||= Games::Team.new(
|
122
|
+
@raw_data[:visitingTeam],
|
123
|
+
{
|
124
|
+
home_team: false,
|
125
|
+
goals: raw_goals,
|
126
|
+
current_state: current_state,
|
127
|
+
game_properties: game_properties,
|
128
|
+
shots: raw_period_shots,
|
129
|
+
goal_totals: raw_period_goals,
|
130
|
+
winning_team_id: winning_team_id,
|
131
|
+
}
|
132
|
+
)
|
133
|
+
end
|
134
|
+
|
135
|
+
def winning_team
|
136
|
+
@winning_team ||=
|
137
|
+
if status == "finished"
|
138
|
+
winning_team_id == home_team.id ? home_team : away_team
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def home_skaters
|
143
|
+
@home_skaters ||= Games::CreateSkatersService.new(
|
144
|
+
@raw_data[:homeTeam][:skaters],
|
145
|
+
raw_goals,
|
146
|
+
raw_penalties,
|
147
|
+
raw_home_shootout_attempts,
|
148
|
+
@raw_data[:penaltyShots][:homeTeam],
|
149
|
+
{ home_team: true, team_id: home_team.id, team_abbreviation: home_team.abbreviation, game_date: @raw_data[:details][:date] }
|
150
|
+
).call
|
151
|
+
end
|
152
|
+
|
153
|
+
def away_skaters
|
154
|
+
@away_skaters ||= Games::CreateSkatersService.new(
|
155
|
+
Array(@raw_data[:visitingTeam][:skaters]),
|
156
|
+
raw_goals,
|
157
|
+
raw_penalties,
|
158
|
+
raw_away_shootout_attempts,
|
159
|
+
@raw_data[:penaltyShots][:visitingTeam],
|
160
|
+
{ home_team: false, team_id: away_team.id, team_abbreviation: away_team.abbreviation, game_date: @raw_data[:details][:date] }
|
161
|
+
).call
|
162
|
+
end
|
163
|
+
|
164
|
+
def home_goalies
|
165
|
+
@home_goalies ||= Array(@raw_data[:homeTeam][:goalies]).map do |g|
|
166
|
+
Games::Goalie.new(
|
167
|
+
g,
|
168
|
+
{
|
169
|
+
team_id: home_team.id,
|
170
|
+
home_team: true,
|
171
|
+
shootout_data: @raw_data.dig(:shootoutDetails, :visitingTeamShots),
|
172
|
+
penalty_shot_data: @raw_data.dig(:penaltyShots, :visitingTeam),
|
173
|
+
game_date: @raw_data[:details][:date],
|
174
|
+
}
|
175
|
+
)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def away_goalies
|
180
|
+
@away_goalies ||= Array(@raw_data[:visitingTeam][:goalies]).map do |g|
|
181
|
+
Games::Goalie.new(
|
182
|
+
g,
|
183
|
+
{
|
184
|
+
team_id: away_team.id,
|
185
|
+
home_team: false,
|
186
|
+
shootout_data: @raw_data.dig(:shootoutDetails, :homeTeamShots),
|
187
|
+
penalty_shot_data: @raw_data.dig(:penaltyShots, :homeTeam),
|
188
|
+
game_date: @raw_data[:details][:date],
|
189
|
+
}
|
190
|
+
)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def home_roster
|
195
|
+
@home_roster ||= [*home_skaters, *home_goalies]
|
196
|
+
end
|
197
|
+
|
198
|
+
def away_roster
|
199
|
+
@away_roster ||= [*away_skaters, *away_goalies]
|
200
|
+
end
|
201
|
+
|
202
|
+
def goals
|
203
|
+
@goals ||= raw_goals.map.with_index { |g, i| Games::Goal.new(g, { number: i + 1 }) }
|
204
|
+
end
|
205
|
+
|
206
|
+
def penalties
|
207
|
+
@penalties ||= raw_penalties.map.with_index { |pn, i| Games::Penalty.new(pn, { number: i + 1 }) }
|
208
|
+
end
|
209
|
+
|
210
|
+
def penalty_shots
|
211
|
+
@penalty_shots ||= (home_penalty_shots || []) + (away_penalty_shots || [])
|
212
|
+
end
|
213
|
+
|
214
|
+
def home_penalty_shots
|
215
|
+
@home_penalty_shots ||= Games::PenaltyShotsService.new(@raw_data[:penaltyShots][:homeTeam]).call
|
216
|
+
end
|
217
|
+
|
218
|
+
def away_penalty_shots
|
219
|
+
@away_penalty_shots ||= Games::PenaltyShotsService.new(@raw_data[:penaltyShots][:visitingTeam]).call
|
220
|
+
end
|
221
|
+
|
222
|
+
def periods
|
223
|
+
@periods ||= Array(@raw_data[:periods][0..2]).map { |per| Games::Period.new(per) }
|
224
|
+
end
|
225
|
+
|
226
|
+
def overtimes
|
227
|
+
@overtimes ||= Array(@raw_data[:periods][3..-1]).map { |o| Games::Overtime.new(o, { regular_season: season_type == :regular }) }
|
228
|
+
end
|
229
|
+
|
230
|
+
def overtime?
|
231
|
+
@overtime ||= overtimes.length.positive?
|
232
|
+
end
|
233
|
+
|
234
|
+
def shootout_attempts
|
235
|
+
@shootout_attempts ||= [*home_shootout_attempts, *away_shootout_attempts]
|
236
|
+
end
|
237
|
+
|
238
|
+
def home_shootout_attempts
|
239
|
+
@home_shootout_attempts ||= raw_home_shootout_attempts&.map&.with_index do |att, i|
|
240
|
+
Games::ShootoutAttempt.new(att, { number: i + 1, opposing_team: find_opposing_team(att[:shooterTeam][:id].to_i) })
|
241
|
+
end || []
|
242
|
+
end
|
243
|
+
|
244
|
+
def away_shootout_attempts
|
245
|
+
@away_shootout_attempts ||= raw_away_shootout_attempts&.map&.with_index do |att, i|
|
246
|
+
Games::ShootoutAttempt.new(att, { number: i + 1, opposing_team: find_opposing_team(att[:shooterTeam][:id].to_i) })
|
247
|
+
end || []
|
248
|
+
end
|
249
|
+
|
250
|
+
def shootout?
|
251
|
+
@shootout ||= @raw_data[:hasShootout] == true
|
252
|
+
end
|
253
|
+
|
254
|
+
def played?
|
255
|
+
@played ||= status == "finished"
|
256
|
+
end
|
257
|
+
|
258
|
+
def in_progress?
|
259
|
+
@in_progress ||= status == "in_progress"
|
260
|
+
end
|
261
|
+
|
262
|
+
def ended_in
|
263
|
+
@ended_in ||=
|
264
|
+
if shootout?
|
265
|
+
"SO"
|
266
|
+
elsif overtime?
|
267
|
+
"OT"
|
268
|
+
else
|
269
|
+
"REG"
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
private
|
274
|
+
|
275
|
+
def raw_goals
|
276
|
+
@raw_goals ||= Array(@raw_data[:periods]).map { |a| a[:goals] }.flatten
|
277
|
+
end
|
278
|
+
|
279
|
+
def raw_penalties
|
280
|
+
@raw_penalties ||= Array(@raw_data[:periods]).map { |a| a[:penalties] }.flatten
|
281
|
+
end
|
282
|
+
|
283
|
+
def raw_period_shots
|
284
|
+
@raw_period_shots ||= Array(@raw_data[:periods]).map do |period|
|
285
|
+
{ home: period[:stats][:homeShots].to_i, away: period[:stats][:visitingShots].to_i }
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
def raw_period_goals
|
290
|
+
@raw_period_goals ||= Array(@raw_data[:periods]).map do |period|
|
291
|
+
{ home: period[:stats][:homeGoals].to_i, away: period[:stats][:visitingGoals].to_i }
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
def raw_home_shootout_attempts
|
296
|
+
@raw_home_shootout_attempts ||= @raw_data.dig(:shootoutDetails, :homeTeamShots)
|
297
|
+
end
|
298
|
+
|
299
|
+
def raw_away_shootout_attempts
|
300
|
+
@raw_away_shootout_attempts ||= @raw_data.dig(:shootoutDetails, :visitingTeamShots)
|
301
|
+
end
|
302
|
+
|
303
|
+
def find_opposing_team(team_id)
|
304
|
+
team_id == home_team.id ? away_team : home_team
|
305
|
+
end
|
306
|
+
|
307
|
+
def winning_team_id
|
308
|
+
@winning_team_id ||= status == "finished" ? set_winning_team_id : nil
|
309
|
+
end
|
310
|
+
|
311
|
+
def set_winning_team_id
|
312
|
+
if @raw_data[:homeTeam][:stats][:goals] > @raw_data[:visitingTeam][:stats][:goals]
|
313
|
+
@raw_data[:homeTeam][:info][:id]
|
314
|
+
elsif @raw_data[:homeTeam][:stats][:goals] < @raw_data[:visitingTeam][:stats][:goals]
|
315
|
+
@raw_data[:visitingTeam][:info][:id]
|
316
|
+
else
|
317
|
+
@raw_data[:shootoutDetails][:winningTeam][:id]
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
def current_state
|
322
|
+
@current_state ||= {
|
323
|
+
status: status,
|
324
|
+
period: current_period,
|
325
|
+
period_number: current_period_number,
|
326
|
+
time: current_time,
|
327
|
+
shootout: shootout?,
|
328
|
+
overtime: overtime?,
|
329
|
+
}
|
330
|
+
end
|
331
|
+
|
332
|
+
def game_properties
|
333
|
+
@game_properties ||= {
|
334
|
+
playoffs: @season_type == :playoffs,
|
335
|
+
periods: periods.length,
|
336
|
+
overtime_periods: overtimes.length,
|
337
|
+
game_start_time_in_seconds: IRREGULAR_GAMES.dig(game_id.to_s, :start_time_in_seconds),
|
338
|
+
game_end_time_in_seconds: IRREGULAR_GAMES.dig(game_id.to_s, :end_time_in_seconds),
|
339
|
+
}
|
340
|
+
end
|
341
|
+
|
342
|
+
def set_game_status
|
343
|
+
irregular_game_status = IRREGULAR_GAMES.dig(game_id.to_s, :status)
|
344
|
+
return irregular_game_status if irregular_game_status
|
345
|
+
|
346
|
+
# return "forfeited" if game is a forfeit, need to figure this out if it happens
|
347
|
+
|
348
|
+
return "finished" if @raw_data[:details][:final] == "1"
|
349
|
+
|
350
|
+
return "in_progress" if @raw_data[:details][:started] == "1"
|
351
|
+
|
352
|
+
"not_started"
|
353
|
+
end
|
354
|
+
|
355
|
+
def set_current_game_time
|
356
|
+
return if /Final/.match?(@raw_data[:details][:status])
|
357
|
+
|
358
|
+
game_time = @raw_data[:details][:status].match(/\d{1,2}:\d{2}/).to_s
|
359
|
+
return if game_time.empty?
|
360
|
+
|
361
|
+
game_time
|
362
|
+
end
|
363
|
+
|
364
|
+
def set_current_game_period
|
365
|
+
return if /Final/.match?(@raw_data[:details][:status])
|
366
|
+
|
367
|
+
period = @raw_data[:details][:status].match(/(1st|2nd|3rd|OT|[1-9]?[0-9]OT|SO)/).to_s
|
368
|
+
return if period.empty?
|
369
|
+
|
370
|
+
period
|
371
|
+
end
|
372
|
+
end
|
373
|
+
end
|