football-sources 0.0.1
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/CHANGELOG.md +4 -0
- data/Manifest.txt +36 -0
- data/README.md +28 -0
- data/Rakefile +31 -0
- data/lib/football-sources.rb +46 -0
- data/lib/football-sources/apis.rb +86 -0
- data/lib/football-sources/apis/config.rb +17 -0
- data/lib/football-sources/apis/convert.rb +239 -0
- data/lib/football-sources/apis/convert_cl.rb +267 -0
- data/lib/football-sources/apis/download.rb +11 -0
- data/lib/football-sources/apis/stat.rb +59 -0
- data/lib/football-sources/version.rb +19 -0
- data/lib/football-sources/worldfootball.rb +24 -0
- data/lib/football-sources/worldfootball/build.rb +245 -0
- data/lib/football-sources/worldfootball/config.rb +16 -0
- data/lib/football-sources/worldfootball/convert.rb +100 -0
- data/lib/football-sources/worldfootball/convert_reports.rb +107 -0
- data/lib/football-sources/worldfootball/download.rb +61 -0
- data/lib/football-sources/worldfootball/leagues.rb +200 -0
- data/lib/football-sources/worldfootball/leagues/asia.rb +53 -0
- data/lib/football-sources/worldfootball/leagues/europe--british_isles.rb +59 -0
- data/lib/football-sources/worldfootball/leagues/europe--central.rb +127 -0
- data/lib/football-sources/worldfootball/leagues/europe--eastern.rb +82 -0
- data/lib/football-sources/worldfootball/leagues/europe--northern.rb +57 -0
- data/lib/football-sources/worldfootball/leagues/europe--southern.rb +86 -0
- data/lib/football-sources/worldfootball/leagues/europe--western.rb +38 -0
- data/lib/football-sources/worldfootball/leagues/europe.rb +13 -0
- data/lib/football-sources/worldfootball/leagues/north_america.rb +44 -0
- data/lib/football-sources/worldfootball/leagues/pacific.rb +21 -0
- data/lib/football-sources/worldfootball/leagues/south_america.rb +11 -0
- data/lib/football-sources/worldfootball/mods.rb +72 -0
- data/lib/football-sources/worldfootball/tool.rb +100 -0
- data/lib/football-sources/worldfootball/vacuum.rb +66 -0
- data/lib/football/sources.rb +6 -0
- data/test/helper.rb +8 -0
- data/test/test_version.rb +16 -0
- metadata +147 -0
@@ -0,0 +1,267 @@
|
|
1
|
+
##########
|
2
|
+
## todo/fix:
|
3
|
+
## use a more generic name?
|
4
|
+
## might also works for euro or worldcup - check?
|
5
|
+
|
6
|
+
|
7
|
+
module Footballdata
|
8
|
+
|
9
|
+
|
10
|
+
STAGE_TO_STAGE = {
|
11
|
+
'PRELIMINARY_SEMI_FINALS' => 'Qualifying',
|
12
|
+
'PRELIMINARY_FINAL' => 'Qualifying',
|
13
|
+
'1ST_QUALIFYING_ROUND' => 'Qualifying',
|
14
|
+
'2ND_QUALIFYING_ROUND' => 'Qualifying',
|
15
|
+
'3RD_QUALIFYING_ROUND' => 'Qualifying',
|
16
|
+
'PLAY_OFF_ROUND' => 'Qualifying',
|
17
|
+
'ROUND_OF_16' => 'Knockout',
|
18
|
+
'QUARTER_FINALS' => 'Knockout',
|
19
|
+
'SEMI_FINALS' => 'Knockout',
|
20
|
+
'FINAL' => 'Knockout',
|
21
|
+
}
|
22
|
+
|
23
|
+
STAGE_TO_ROUND = {
|
24
|
+
'PRELIMINARY_SEMI_FINALS' => 'Preliminary Semifinals',
|
25
|
+
'PRELIMINARY_FINAL' => 'Preliminary Final',
|
26
|
+
'1ST_QUALIFYING_ROUND' => 'Qual. Round 1',
|
27
|
+
'2ND_QUALIFYING_ROUND' => 'Qual. Round 2',
|
28
|
+
'3RD_QUALIFYING_ROUND' => 'Qual. Round 3',
|
29
|
+
'PLAY_OFF_ROUND' => 'Playoff Round',
|
30
|
+
'ROUND_OF_16' => 'Round of 16',
|
31
|
+
'QUARTER_FINALS' => 'Quarterfinals',
|
32
|
+
'SEMI_FINALS' => 'Semifinals',
|
33
|
+
'FINAL' => 'Final',
|
34
|
+
}
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
|
39
|
+
def self.convert_cl( league:, season: )
|
40
|
+
season = Season( season ) ## cast (ensure) season class (NOT string, integer, etc.)
|
41
|
+
|
42
|
+
data = Webcache.read_json( Metal.competition_matches_url( LEAGUES[league.downcase], season.start_year ))
|
43
|
+
data_teams = Webcache.read_json( Metal.competition_teams_url( LEAGUES[league.downcase], season.start_year ))
|
44
|
+
|
45
|
+
|
46
|
+
## build a (reverse) team lookup by name
|
47
|
+
puts "#{data_teams['teams'].size} teams"
|
48
|
+
|
49
|
+
teams_by_name = data_teams['teams'].reduce( {} ) do |h,rec|
|
50
|
+
h[ rec['name'] ] = rec
|
51
|
+
h
|
52
|
+
end
|
53
|
+
|
54
|
+
pp teams_by_name.keys
|
55
|
+
|
56
|
+
|
57
|
+
|
58
|
+
mods = MODS[ league.downcase ] || {}
|
59
|
+
|
60
|
+
|
61
|
+
recs = []
|
62
|
+
|
63
|
+
teams = Hash.new( 0 )
|
64
|
+
stat = Stat.new
|
65
|
+
|
66
|
+
matches = data[ 'matches' ]
|
67
|
+
matches.each do |m|
|
68
|
+
stat.update( m )
|
69
|
+
|
70
|
+
team1 = m['homeTeam']['name']
|
71
|
+
team2 = m['awayTeam']['name']
|
72
|
+
|
73
|
+
|
74
|
+
score = m['score']
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
if m['stage'] == 'GROUP_STAGE'
|
79
|
+
stage = 'Group'
|
80
|
+
round = "Matchday #{m['matchday']}"
|
81
|
+
if m['group'] =~ /Group ([A-Z])/
|
82
|
+
group = $1
|
83
|
+
else
|
84
|
+
puts "!! ERROR - no group name found for group >#{m['group']}<"
|
85
|
+
exit 1
|
86
|
+
end
|
87
|
+
else
|
88
|
+
stage = STAGE_TO_STAGE[ m['stage'] ]
|
89
|
+
if stage.nil?
|
90
|
+
puts "!! ERROR - no stage mapping found for stage >#{m['stage']}<"
|
91
|
+
exit 1
|
92
|
+
end
|
93
|
+
round = STAGE_TO_ROUND[ m['stage'] ]
|
94
|
+
if round.nil?
|
95
|
+
puts "!! ERROR - no round mapping found for stage >#{m['stage']}<"
|
96
|
+
exit 1
|
97
|
+
end
|
98
|
+
group = ''
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
teams[ team1 ] += 1
|
103
|
+
teams[ team2 ] += 1
|
104
|
+
|
105
|
+
### mods - rename club names
|
106
|
+
unless mods.nil? || mods.empty?
|
107
|
+
team1 = mods[ team1 ] if mods[ team1 ]
|
108
|
+
team2 = mods[ team2 ] if mods[ team2 ]
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
## e.g. "utcDate": "2020-05-09T00:00:00Z",
|
113
|
+
date_str = m['utcDate']
|
114
|
+
date = DateTime.strptime( date_str, '%Y-%m-%dT%H:%M:%SZ' )
|
115
|
+
|
116
|
+
|
117
|
+
comments = ''
|
118
|
+
ft = ''
|
119
|
+
ht = ''
|
120
|
+
et = ''
|
121
|
+
pen = ''
|
122
|
+
|
123
|
+
case m['status']
|
124
|
+
when 'SCHEDULED', 'IN_PLAY'
|
125
|
+
ft = ''
|
126
|
+
ht = ''
|
127
|
+
et = ''
|
128
|
+
pen = ''
|
129
|
+
when 'AWARDED'
|
130
|
+
## todo/fix: assert duration == "REGULAR"
|
131
|
+
ft = "#{score['fullTime']['homeTeam']}-#{score['fullTime']['awayTeam']}"
|
132
|
+
ft << ' (*)'
|
133
|
+
ht = ''
|
134
|
+
comments = 'awarded'
|
135
|
+
when 'FINISHED'
|
136
|
+
## note: if extraTime present
|
137
|
+
## than fullTime is extraTime score!!
|
138
|
+
## AND fullTime - extraTime is fullTime score!!
|
139
|
+
## double check in other season too??
|
140
|
+
## - checked in cl 2018/19
|
141
|
+
|
142
|
+
if score['extraTime']['homeTeam'] && score['extraTime']['awayTeam']
|
143
|
+
et = "#{score['fullTime']['homeTeam']}-#{score['fullTime']['awayTeam']}"
|
144
|
+
ft = "#{score['fullTime']['homeTeam']-score['extraTime']['homeTeam']}-#{score['fullTime']['awayTeam']-score['extraTime']['awayTeam']}"
|
145
|
+
else
|
146
|
+
ft = "#{score['fullTime']['homeTeam']}-#{score['fullTime']['awayTeam']}"
|
147
|
+
end
|
148
|
+
|
149
|
+
ht = "#{score['halfTime']['homeTeam']}-#{score['halfTime']['awayTeam']}"
|
150
|
+
|
151
|
+
pen = if score['penalties']['homeTeam'] && score['penalties']['awayTeam']
|
152
|
+
"#{score['penalties']['homeTeam']}-#{score['penalties']['awayTeam']}"
|
153
|
+
else
|
154
|
+
''
|
155
|
+
end
|
156
|
+
else
|
157
|
+
puts "!! ERROR: unsupported match status >#{m['status']}< - sorry:"
|
158
|
+
pp m
|
159
|
+
exit 1
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
recs << [stage,
|
164
|
+
round,
|
165
|
+
group,
|
166
|
+
date.to_date.strftime( '%Y-%m-%d' ),
|
167
|
+
team1,
|
168
|
+
ft,
|
169
|
+
ht,
|
170
|
+
team2,
|
171
|
+
et,
|
172
|
+
pen,
|
173
|
+
comments
|
174
|
+
]
|
175
|
+
|
176
|
+
|
177
|
+
print '%2s' % m['matchday']
|
178
|
+
print ' - '
|
179
|
+
print '%-24s' % team1
|
180
|
+
print ' '
|
181
|
+
print ft
|
182
|
+
print ' '
|
183
|
+
print "(#{ht})" unless ht.empty?
|
184
|
+
print ' '
|
185
|
+
print '%-24s' % team2
|
186
|
+
print ' '
|
187
|
+
print comments
|
188
|
+
print ' | '
|
189
|
+
## print date.to_date ## strip time
|
190
|
+
print date.to_date.strftime( '%a %b %-d %Y' )
|
191
|
+
print ' -- '
|
192
|
+
print date
|
193
|
+
print "\n"
|
194
|
+
|
195
|
+
end # each match
|
196
|
+
|
197
|
+
|
198
|
+
## note: get season from first match
|
199
|
+
## assert - all other matches include the same season
|
200
|
+
## e.g.
|
201
|
+
# "season": {
|
202
|
+
# "id": 154,
|
203
|
+
# "startDate": "2018-08-03",
|
204
|
+
# "endDate": "2019-05-05",
|
205
|
+
# "currentMatchday": 46
|
206
|
+
# }
|
207
|
+
|
208
|
+
start_date = Date.strptime( matches[0]['season']['startDate'], '%Y-%m-%d' )
|
209
|
+
end_date = Date.strptime( matches[0]['season']['endDate'], '%Y-%m-%d' )
|
210
|
+
|
211
|
+
dates = "#{start_date.strftime('%b %-d')} - #{end_date.strftime('%b %-d')}"
|
212
|
+
|
213
|
+
buf = ''
|
214
|
+
buf << "#{season.key} (#{dates}) - "
|
215
|
+
buf << "#{teams.keys.size} clubs, "
|
216
|
+
buf << "#{stat[:all][:matches]} matches, "
|
217
|
+
buf << "#{stat[:all][:goals]} goals"
|
218
|
+
buf << "\n"
|
219
|
+
|
220
|
+
puts buf
|
221
|
+
|
222
|
+
|
223
|
+
|
224
|
+
# recs = recs.sort { |l,r| l[1] <=> r[1] }
|
225
|
+
## reformat date / beautify e.g. Sat Aug 7 1993
|
226
|
+
recs.each { |rec| rec[3] = Date.strptime( rec[3], '%Y-%m-%d' ).strftime( '%a %b %-d %Y' ) }
|
227
|
+
|
228
|
+
headers = [
|
229
|
+
'Stage',
|
230
|
+
'Round',
|
231
|
+
'Group',
|
232
|
+
'Date',
|
233
|
+
'Team 1',
|
234
|
+
'FT',
|
235
|
+
'HT',
|
236
|
+
'Team 2',
|
237
|
+
'ET',
|
238
|
+
'P',
|
239
|
+
'Comments'
|
240
|
+
]
|
241
|
+
|
242
|
+
## note: change season_key from 2019/20 to 2019-20 (for path/directory!!!!)
|
243
|
+
Cache::CsvMatchWriter.write( "#{config.convert.out_dir}/#{season.to_path}/#{league.downcase}.csv",
|
244
|
+
recs,
|
245
|
+
headers: headers )
|
246
|
+
|
247
|
+
|
248
|
+
teams.each do |name, count|
|
249
|
+
rec = teams_by_name[ name ]
|
250
|
+
print " #{count}x "
|
251
|
+
print name
|
252
|
+
if rec
|
253
|
+
print " | #{rec['shortName']} " if name != rec['shortName']
|
254
|
+
print " › #{rec['area']['name']}"
|
255
|
+
print " - #{rec['address']}"
|
256
|
+
else
|
257
|
+
print "!! ERROR - no team record found in teams.json for #{name}"
|
258
|
+
exit 1
|
259
|
+
end
|
260
|
+
print "\n"
|
261
|
+
end
|
262
|
+
|
263
|
+
pp stat
|
264
|
+
end # method convert_cl
|
265
|
+
end # module Footballdata
|
266
|
+
|
267
|
+
|
@@ -0,0 +1,11 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Footballdata
|
4
|
+
|
5
|
+
def self.schedule( league:, season: )
|
6
|
+
season = Season( season ) ## cast (ensure) season class (NOT string, integer, etc.)
|
7
|
+
|
8
|
+
Metal.competition( LEAGUES[ league.downcase ], season.start_year )
|
9
|
+
end
|
10
|
+
|
11
|
+
end # module Footballdata
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Footballdata
|
2
|
+
|
3
|
+
class Stat ## rename to match stat or something why? why not?
|
4
|
+
def initialize
|
5
|
+
@data = {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def [](key) @data[ key ]; end
|
9
|
+
|
10
|
+
def update( match )
|
11
|
+
## keep track of some statistics
|
12
|
+
stat = @data[:all] ||= { stage: Hash.new( 0 ),
|
13
|
+
duration: Hash.new( 0 ),
|
14
|
+
status: Hash.new( 0 ),
|
15
|
+
group: Hash.new( 0 ),
|
16
|
+
matchday: Hash.new( 0 ),
|
17
|
+
|
18
|
+
matches: 0,
|
19
|
+
goals: 0,
|
20
|
+
}
|
21
|
+
|
22
|
+
stat[:stage][ match['stage'] ] += 1
|
23
|
+
stat[:group][ match['group'] ] += 1
|
24
|
+
stat[:status][ match['status'] ] += 1
|
25
|
+
stat[:matchday][ match['matchday'] ] += 1
|
26
|
+
|
27
|
+
score = match['score']
|
28
|
+
|
29
|
+
stat[:duration][ score['duration'] ] += 1 ## track - assert always REGULAR
|
30
|
+
|
31
|
+
stat[:matches] += 1
|
32
|
+
stat[:goals] += score['fullTime']['homeTeam'].to_i if score['fullTime']['homeTeam']
|
33
|
+
stat[:goals] += score['fullTime']['awayTeam'].to_i if score['fullTime']['awayTeam']
|
34
|
+
|
35
|
+
|
36
|
+
stage_key = match['stage'].downcase.to_sym # e.g. :regular_season
|
37
|
+
stat = @data[ stage_key ] ||= { duration: Hash.new( 0 ),
|
38
|
+
status: Hash.new( 0 ),
|
39
|
+
group: Hash.new( 0 ),
|
40
|
+
matchday: Hash.new( 0 ),
|
41
|
+
|
42
|
+
matches: 0,
|
43
|
+
goals: 0,
|
44
|
+
}
|
45
|
+
stat[:group][ match['group'] ] += 1
|
46
|
+
stat[:status][ match['status'] ] += 1
|
47
|
+
stat[:matchday][ match['matchday'] ] += 1
|
48
|
+
|
49
|
+
stat[:duration][ score['duration'] ] += 1 ## track - assert always REGULAR
|
50
|
+
|
51
|
+
stat[:matches] += 1
|
52
|
+
stat[:goals] += score['fullTime']['homeTeam'].to_i if score['fullTime']['homeTeam']
|
53
|
+
stat[:goals] += score['fullTime']['awayTeam'].to_i if score['fullTime']['awayTeam']
|
54
|
+
end
|
55
|
+
end # class Stat
|
56
|
+
end # module Footballdata
|
57
|
+
|
58
|
+
|
59
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
|
2
|
+
module FootballSources
|
3
|
+
MAJOR = 0 ## todo: namespace inside version or something - why? why not??
|
4
|
+
MINOR = 0
|
5
|
+
PATCH = 1
|
6
|
+
VERSION = [MAJOR,MINOR,PATCH].join('.')
|
7
|
+
|
8
|
+
def self.version
|
9
|
+
VERSION
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.banner
|
13
|
+
"football-sources/#{VERSION} on Ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.root
|
17
|
+
File.expand_path( File.dirname(File.dirname(File.dirname(__FILE__))) )
|
18
|
+
end
|
19
|
+
end # module FootballSources
|
@@ -0,0 +1,24 @@
|
|
1
|
+
###########################
|
2
|
+
# note: split code in two parts
|
3
|
+
# metal - "bare" basics - no ref to sportdb
|
4
|
+
# and rest / convert with sportdb references / goodies
|
5
|
+
|
6
|
+
|
7
|
+
## our own code
|
8
|
+
require_relative 'worldfootball/leagues'
|
9
|
+
|
10
|
+
require_relative 'worldfootball/config'
|
11
|
+
|
12
|
+
require_relative 'worldfootball/download'
|
13
|
+
|
14
|
+
require_relative 'worldfootball/mods'
|
15
|
+
require_relative 'worldfootball/vacuum'
|
16
|
+
require_relative 'worldfootball/build'
|
17
|
+
require_relative 'worldfootball/convert'
|
18
|
+
require_relative 'worldfootball/convert_reports'
|
19
|
+
|
20
|
+
|
21
|
+
require_relative 'worldfootball/tool'
|
22
|
+
|
23
|
+
|
24
|
+
|
@@ -0,0 +1,245 @@
|
|
1
|
+
|
2
|
+
module Worldfootball
|
3
|
+
|
4
|
+
|
5
|
+
ROUND_TO_EN = {
|
6
|
+
'1. Runde' => 'Round 1',
|
7
|
+
'2. Runde' => 'Round 2',
|
8
|
+
'3. Runde' => 'Round 3',
|
9
|
+
'4. Runde' => 'Round 4',
|
10
|
+
'Achtelfinale' => 'Round of 16',
|
11
|
+
'Viertelfinale' => 'Quarterfinals',
|
12
|
+
'Halbfinale' => 'Semifinals',
|
13
|
+
'Finale' => 'Final',
|
14
|
+
}
|
15
|
+
|
16
|
+
|
17
|
+
## todo/check: english league cup/trophy has NO ET - also support - make more flexible!!!
|
18
|
+
|
19
|
+
## build "standard" match records from "raw" table rows
|
20
|
+
def self.build( rows, season:, league:, stage: '' ) ## rename to fixup or such - why? why not?
|
21
|
+
season = Season( season ) ## cast (ensure) season class (NOT string, integer, etc.)
|
22
|
+
|
23
|
+
raise ArgumentError, "league key as string expected" unless league.is_a?(String) ## note: do NOT pass in league struct! pass in key (string)
|
24
|
+
|
25
|
+
print " #{rows.size} rows - build #{league} #{season}"
|
26
|
+
print " - #{stage}" unless stage.empty?
|
27
|
+
print "\n"
|
28
|
+
|
29
|
+
|
30
|
+
## note: use only first part from key for lookup
|
31
|
+
## e.g. at.1 => at
|
32
|
+
## eng.1 => eng
|
33
|
+
## and so on
|
34
|
+
mods = MODS[ league.split('.')[0] ] || {}
|
35
|
+
|
36
|
+
score_errors = SCORE_ERRORS[ league ] || {}
|
37
|
+
|
38
|
+
|
39
|
+
i = 0
|
40
|
+
recs = []
|
41
|
+
rows.each do |row|
|
42
|
+
i += 1
|
43
|
+
|
44
|
+
|
45
|
+
if row[:round] =~ /Spieltag/
|
46
|
+
puts
|
47
|
+
print '[%03d] ' % (i+1)
|
48
|
+
print row[:round]
|
49
|
+
|
50
|
+
if m = row[:round].match( /([0-9]+)\. Spieltag/ )
|
51
|
+
## todo/check: always use a string even if number (as a string eg. '1' etc.)
|
52
|
+
round = m[1] ## note: keep as string (NOT number)
|
53
|
+
print " => #{round}"
|
54
|
+
else
|
55
|
+
puts "!! ERROR: cannot find matchday number"
|
56
|
+
exit 1
|
57
|
+
end
|
58
|
+
print "\n"
|
59
|
+
elsif row[:round] =~ /[1-9]\.[ ]Runde|
|
60
|
+
Achtelfinale|
|
61
|
+
Viertelfinale|
|
62
|
+
Halbfinale|
|
63
|
+
Finale
|
64
|
+
/x
|
65
|
+
puts
|
66
|
+
print '[%03d] ' % (i+1)
|
67
|
+
print row[:round]
|
68
|
+
|
69
|
+
|
70
|
+
## do NOT translate rounds (to english) - keep in german / deutsch (de)
|
71
|
+
if ['at.cup', 'at.1', ## at.1 - incl. europa league playoff
|
72
|
+
'de.cup'].include?( league )
|
73
|
+
round = row[:round]
|
74
|
+
else
|
75
|
+
round = ROUND_TO_EN[ row[:round] ]
|
76
|
+
if round.nil?
|
77
|
+
puts "!! ERROR: no mapping for round to english (en) found >#{row[:round]}<:"
|
78
|
+
pp row
|
79
|
+
exit 1
|
80
|
+
end
|
81
|
+
print " => #{round}"
|
82
|
+
end
|
83
|
+
print "\n"
|
84
|
+
else
|
85
|
+
puts "!! ERROR: unknown round >#{row[:round]}< for league >#{league}<:"
|
86
|
+
pp row
|
87
|
+
exit 1
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
date_str = row[:date]
|
92
|
+
time_str = row[:time]
|
93
|
+
team1_str = row[:team1]
|
94
|
+
team2_str = row[:team2]
|
95
|
+
score_str = row[:score]
|
96
|
+
|
97
|
+
## convert date from string e.g. 2019-25-10
|
98
|
+
date = Date.strptime( date_str, '%Y-%m-%d' )
|
99
|
+
|
100
|
+
|
101
|
+
### check for score_error; first (step 1) lookup by date
|
102
|
+
score_error = score_errors[ date.strftime('%Y-%m-%d') ]
|
103
|
+
if score_error
|
104
|
+
if team1_str == score_error[0] &&
|
105
|
+
team2_str == score_error[1]
|
106
|
+
## check if team names match too; if yes, apply fix/patch!!
|
107
|
+
if score_str != score_error[2][0]
|
108
|
+
puts "!! WARN - score fix changed? - expected #{score_error[2][0]}, got #{score_str} - fixing to #{score_error[2][1]}"
|
109
|
+
pp row
|
110
|
+
end
|
111
|
+
puts "FIX - applying score error fix - from #{score_error[2][0]} to => #{score_error[2][1]}"
|
112
|
+
score_str = score_error[2][1]
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
print '[%03d] ' % (i+1)
|
118
|
+
print "%-10s | " % date_str
|
119
|
+
print "%-5s | " % time_str
|
120
|
+
print "%-22s | " % team1_str
|
121
|
+
print "%-22s | " % team2_str
|
122
|
+
print score_str
|
123
|
+
print "\n"
|
124
|
+
|
125
|
+
|
126
|
+
## check for 0:3 Wert. - change Wert. to awd. (awarded)
|
127
|
+
score_str = score_str.sub( /Wert\./i, 'awd.' )
|
128
|
+
|
129
|
+
## clean team name (e.g. remove (old))
|
130
|
+
## and asciify (e.g. ’ to ' )
|
131
|
+
team1_str = norm_team( team1_str )
|
132
|
+
team2_str = norm_team( team2_str )
|
133
|
+
|
134
|
+
team1_str = mods[ team1_str ] if mods[ team1_str ]
|
135
|
+
team2_str = mods[ team2_str ] if mods[ team2_str ]
|
136
|
+
|
137
|
+
|
138
|
+
|
139
|
+
|
140
|
+
ht, ft, et, pen, comments = parse_score( score_str )
|
141
|
+
|
142
|
+
|
143
|
+
|
144
|
+
recs << [stage,
|
145
|
+
round,
|
146
|
+
date.strftime( '%Y-%m-%d' ),
|
147
|
+
time_str,
|
148
|
+
team1_str,
|
149
|
+
ft,
|
150
|
+
ht,
|
151
|
+
team2_str,
|
152
|
+
et, # extra: incl. extra time
|
153
|
+
pen, # extra: incl. penalties
|
154
|
+
comments]
|
155
|
+
end # each row
|
156
|
+
recs
|
157
|
+
end # build
|
158
|
+
|
159
|
+
|
160
|
+
|
161
|
+
def self.parse_score( score_str )
|
162
|
+
comments = String.new( '' ) ## check - rename to/use status or such - why? why not?
|
163
|
+
|
164
|
+
## split score
|
165
|
+
ft = ''
|
166
|
+
ht = ''
|
167
|
+
et = ''
|
168
|
+
pen = ''
|
169
|
+
if score_str == '---' ## in the future (no score yet) - was -:-
|
170
|
+
ft = ''
|
171
|
+
ht = ''
|
172
|
+
elsif score_str == 'n.gesp.' || ## cancelled (british) / canceled (us)
|
173
|
+
score_str == 'ausg.' || ## todo/check: change to some other status ????
|
174
|
+
score_str == 'annull.' ## todo/check: change to some other status (see ie 2012) ????
|
175
|
+
ft = '(*)'
|
176
|
+
ht = ''
|
177
|
+
comments = 'cancelled'
|
178
|
+
elsif score_str == 'abgebr.' ## abandoned -- waiting for replay?
|
179
|
+
ft = '(*)'
|
180
|
+
ht = ''
|
181
|
+
comments = 'abandoned'
|
182
|
+
elsif score_str == 'verl.' ## postponed
|
183
|
+
ft = ''
|
184
|
+
ht = ''
|
185
|
+
comments = 'postponed'
|
186
|
+
# 5-4 (0-0, 1-1, 2-2) i.E.
|
187
|
+
elsif score_str =~ /([0-9]+) [ ]*-[ ]* ([0-9]+)
|
188
|
+
[ ]*
|
189
|
+
\(([0-9]+) [ ]*-[ ]* ([0-9]+)
|
190
|
+
[ ]*,[ ]*
|
191
|
+
([0-9]+) [ ]*-[ ]* ([0-9]+)
|
192
|
+
[ ]*,[ ]*
|
193
|
+
([0-9]+) [ ]*-[ ]* ([0-9]+)\)
|
194
|
+
[ ]*
|
195
|
+
i\.E\.
|
196
|
+
/x
|
197
|
+
pen = "#{$1}-#{$2}"
|
198
|
+
ht = "#{$3}-#{$4}"
|
199
|
+
ft = "#{$5}-#{$6}"
|
200
|
+
et = "#{$7}-#{$8}"
|
201
|
+
# 2-1 (1-0, 1-1) n.V
|
202
|
+
elsif score_str =~ /([0-9]+) [ ]*-[ ]* ([0-9]+)
|
203
|
+
[ ]*
|
204
|
+
\(([0-9]+) [ ]*-[ ]* ([0-9]+)
|
205
|
+
[ ]*,[ ]*
|
206
|
+
([0-9]+) [ ]*-[ ]* ([0-9]+)
|
207
|
+
\)
|
208
|
+
[ ]*
|
209
|
+
n\.V\.
|
210
|
+
/x
|
211
|
+
et = "#{$1}-#{$2}"
|
212
|
+
ht = "#{$3}-#{$4}"
|
213
|
+
ft = "#{$5}-#{$6}"
|
214
|
+
elsif score_str =~ /([0-9]+)
|
215
|
+
[ ]*-[ ]*
|
216
|
+
([0-9]+)
|
217
|
+
[ ]*
|
218
|
+
\(([0-9]+)
|
219
|
+
[ ]*-[ ]*
|
220
|
+
([0-9]+)
|
221
|
+
\)
|
222
|
+
/x
|
223
|
+
ft = "#{$1}-#{$2}"
|
224
|
+
ht = "#{$3}-#{$4}"
|
225
|
+
elsif score_str =~ /([0-9]+)
|
226
|
+
[ ]*-[ ]*
|
227
|
+
([0-9]+)
|
228
|
+
[ ]*
|
229
|
+
([a-z.]+)
|
230
|
+
/x
|
231
|
+
ft = "#{$1}-#{$2} (*)"
|
232
|
+
ht = ''
|
233
|
+
comments = $3
|
234
|
+
elsif score_str =~ /^([0-9]+)-([0-9]+)$/
|
235
|
+
ft = "#{$1}-#{$2}" ## e.g. see luxemburg and others
|
236
|
+
ht = ''
|
237
|
+
else
|
238
|
+
puts "!! ERROR - unsupported score format >#{score_str}< - sorry; maybe add a score error fix/patch"
|
239
|
+
exit 1
|
240
|
+
end
|
241
|
+
|
242
|
+
[ht, ft, et, pen, comments]
|
243
|
+
end
|
244
|
+
|
245
|
+
end # module Worldfootball
|