football-sources 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +4 -0
  3. data/Manifest.txt +36 -0
  4. data/README.md +28 -0
  5. data/Rakefile +31 -0
  6. data/lib/football-sources.rb +46 -0
  7. data/lib/football-sources/apis.rb +86 -0
  8. data/lib/football-sources/apis/config.rb +17 -0
  9. data/lib/football-sources/apis/convert.rb +239 -0
  10. data/lib/football-sources/apis/convert_cl.rb +267 -0
  11. data/lib/football-sources/apis/download.rb +11 -0
  12. data/lib/football-sources/apis/stat.rb +59 -0
  13. data/lib/football-sources/version.rb +19 -0
  14. data/lib/football-sources/worldfootball.rb +24 -0
  15. data/lib/football-sources/worldfootball/build.rb +245 -0
  16. data/lib/football-sources/worldfootball/config.rb +16 -0
  17. data/lib/football-sources/worldfootball/convert.rb +100 -0
  18. data/lib/football-sources/worldfootball/convert_reports.rb +107 -0
  19. data/lib/football-sources/worldfootball/download.rb +61 -0
  20. data/lib/football-sources/worldfootball/leagues.rb +200 -0
  21. data/lib/football-sources/worldfootball/leagues/asia.rb +53 -0
  22. data/lib/football-sources/worldfootball/leagues/europe--british_isles.rb +59 -0
  23. data/lib/football-sources/worldfootball/leagues/europe--central.rb +127 -0
  24. data/lib/football-sources/worldfootball/leagues/europe--eastern.rb +82 -0
  25. data/lib/football-sources/worldfootball/leagues/europe--northern.rb +57 -0
  26. data/lib/football-sources/worldfootball/leagues/europe--southern.rb +86 -0
  27. data/lib/football-sources/worldfootball/leagues/europe--western.rb +38 -0
  28. data/lib/football-sources/worldfootball/leagues/europe.rb +13 -0
  29. data/lib/football-sources/worldfootball/leagues/north_america.rb +44 -0
  30. data/lib/football-sources/worldfootball/leagues/pacific.rb +21 -0
  31. data/lib/football-sources/worldfootball/leagues/south_america.rb +11 -0
  32. data/lib/football-sources/worldfootball/mods.rb +72 -0
  33. data/lib/football-sources/worldfootball/tool.rb +100 -0
  34. data/lib/football-sources/worldfootball/vacuum.rb +66 -0
  35. data/lib/football/sources.rb +6 -0
  36. data/test/helper.rb +8 -0
  37. data/test/test_version.rb +16 -0
  38. metadata +147 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0d80d7220f2414773d0547c6aa69d15722d414bb
4
+ data.tar.gz: eae20eaed5e9fd9efdb33602cc2f3125b1334797
5
+ SHA512:
6
+ metadata.gz: cd4a9b5dbd4c86bd9ec20bebda0b56979bb6c5ce3d4fddf6fdfb947188b08f7dca68a931baf4bd199ff66f5518f326bc10bde273d43cd2c957c9e40c9f4b4cec
7
+ data.tar.gz: d8be6c1a8246cd61f77aa4b63f0b382d9cde0da408c83e0e7626ad34ed9daf567b5735702f05dbbf9a0dd8035baea51f9ff83e67a0cb14dc02e261659781e121
@@ -0,0 +1,4 @@
1
+ ### 0.0.1 / 2020-11-09
2
+
3
+ * Everything is new. First release.
4
+
@@ -0,0 +1,36 @@
1
+ CHANGELOG.md
2
+ Manifest.txt
3
+ README.md
4
+ Rakefile
5
+ lib/football-sources.rb
6
+ lib/football-sources/apis.rb
7
+ lib/football-sources/apis/config.rb
8
+ lib/football-sources/apis/convert.rb
9
+ lib/football-sources/apis/convert_cl.rb
10
+ lib/football-sources/apis/download.rb
11
+ lib/football-sources/apis/stat.rb
12
+ lib/football-sources/version.rb
13
+ lib/football-sources/worldfootball.rb
14
+ lib/football-sources/worldfootball/build.rb
15
+ lib/football-sources/worldfootball/config.rb
16
+ lib/football-sources/worldfootball/convert.rb
17
+ lib/football-sources/worldfootball/convert_reports.rb
18
+ lib/football-sources/worldfootball/download.rb
19
+ lib/football-sources/worldfootball/leagues.rb
20
+ lib/football-sources/worldfootball/leagues/asia.rb
21
+ lib/football-sources/worldfootball/leagues/europe--british_isles.rb
22
+ lib/football-sources/worldfootball/leagues/europe--central.rb
23
+ lib/football-sources/worldfootball/leagues/europe--eastern.rb
24
+ lib/football-sources/worldfootball/leagues/europe--northern.rb
25
+ lib/football-sources/worldfootball/leagues/europe--southern.rb
26
+ lib/football-sources/worldfootball/leagues/europe--western.rb
27
+ lib/football-sources/worldfootball/leagues/europe.rb
28
+ lib/football-sources/worldfootball/leagues/north_america.rb
29
+ lib/football-sources/worldfootball/leagues/pacific.rb
30
+ lib/football-sources/worldfootball/leagues/south_america.rb
31
+ lib/football-sources/worldfootball/mods.rb
32
+ lib/football-sources/worldfootball/tool.rb
33
+ lib/football-sources/worldfootball/vacuum.rb
34
+ lib/football/sources.rb
35
+ test/helper.rb
36
+ test/test_version.rb
@@ -0,0 +1,28 @@
1
+ # football-sources - get football data via web pages or web api (json) calls
2
+
3
+
4
+ * home :: [github.com/sportdb/sport.db](https://github.com/sportdb/sport.db)
5
+ * bugs :: [github.com/sportdb/sport.db/issues](https://github.com/sportdb/sport.db/issues)
6
+ * gem :: [rubygems.org/gems/football-sources](https://rubygems.org/gems/football-sources)
7
+ * rdoc :: [rubydoc.info/gems/football-sources](http://rubydoc.info/gems/football-sources)
8
+ * forum :: [groups.google.com/group/opensport](https://groups.google.com/group/opensport)
9
+
10
+
11
+ ## Usage
12
+
13
+ TBD
14
+
15
+
16
+ ## License
17
+
18
+ ![](https://publicdomainworks.github.io/buttons/zero88x31.png)
19
+
20
+ The `football-sources` scripts are dedicated to the public domain.
21
+ Use it as you please with no restrictions whatsoever.
22
+
23
+
24
+ ## Questions? Comments?
25
+
26
+ Send them along to the
27
+ [Open Sports & Friends Forum/Mailing List](http://groups.google.com/group/opensport).
28
+ Thanks!
@@ -0,0 +1,31 @@
1
+ require 'hoe'
2
+ require './lib/football-sources/version.rb'
3
+
4
+ Hoe.spec 'football-sources' do
5
+
6
+ self.version = FootballSources::VERSION
7
+
8
+ self.summary = 'football-sources - get football data via web pages or web api (json) calls'
9
+ self.description = summary
10
+
11
+ self.urls = { home: 'https://github.com/sportdb/sport.db' }
12
+
13
+ self.author = 'Gerald Bauer'
14
+ self.email = 'opensport@googlegroups.com'
15
+
16
+ # switch extension to .markdown for gihub formatting
17
+ self.readme_file = 'README.md'
18
+ self.history_file = 'CHANGELOG.md'
19
+
20
+ self.extra_deps = [
21
+ ['webget-football', '>= 0.0.1'],
22
+ ['sportdb-catalogs', '>= 1.0.0'],
23
+ ]
24
+
25
+ self.licenses = ['Public Domain']
26
+
27
+ self.spec_extras = {
28
+ required_ruby_version: '>= 2.2.2'
29
+ }
30
+
31
+ end
@@ -0,0 +1,46 @@
1
+ require 'webget/football'
2
+
3
+
4
+ # require 'sportdb/formats' ## for Season etc.
5
+ require 'sportdb/catalogs' ## note: incl. deps csvreader etc.
6
+
7
+
8
+
9
+ #############
10
+ ## todo/fix: reuse a "original" CsvMatchWriter
11
+ ## how? why? why not?
12
+ ###############
13
+ module Cache
14
+ class CsvMatchWriter
15
+
16
+ def self.write( path, recs, headers: )
17
+
18
+ ## for convenience - make sure parent folders/directories exist
19
+ FileUtils.mkdir_p( File.dirname( path )) unless Dir.exist?( File.dirname( path ))
20
+
21
+ File.open( path, 'w:utf-8' ) do |f|
22
+ f.write headers.join(',') ## e.g. Date,Team 1,FT,HT,Team 2
23
+ f.write "\n"
24
+ recs.each do |rec|
25
+ f.write rec.join(',')
26
+ f.write "\n"
27
+ end
28
+ end
29
+ end
30
+
31
+ end # class CsvMatchWriter
32
+ end # module Cache
33
+
34
+
35
+
36
+
37
+ ###
38
+ # our own code
39
+ require 'football-sources/version' # let version always go first
40
+
41
+ require 'football-sources/apis'
42
+ require 'football-sources/worldfootball'
43
+
44
+
45
+
46
+ puts FootballSources.banner # say hello
@@ -0,0 +1,86 @@
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
+ module Footballdata
8
+
9
+ LEAGUES = {
10
+ 'eng.1' => 'PL', # incl. team(s) from wales
11
+ 'eng.2' => 'ELC',
12
+ # PL - Premier League , England 27 seasons | 2019-08-09 - 2020-07-25 / matchday 31
13
+ # ELC - Championship , England 3 seasons | 2019-08-02 - 2020-07-22 / matchday 38
14
+ #
15
+ # 2019 => 2019/20
16
+ # 2018 => 2018/19
17
+ # 2017 => xxx 2017-18 - requires subscription !!!
18
+
19
+ 'es.1' => 'PD',
20
+ # PD - Primera Division , Spain 27 seasons | 2019-08-16 - 2020-07-19 / matchday 31
21
+
22
+ 'pt.1' => 'PPL',
23
+ # PPL - Primeira Liga , Portugal 9 seasons | 2019-08-10 - 2020-07-26 / matchday 28
24
+
25
+ 'de.1' => 'BL1',
26
+ # BL1 - Bundesliga , Germany 24 seasons | 2019-08-16 - 2020-06-27 / matchday 34
27
+
28
+ 'nl.1' => 'DED',
29
+ # DED - Eredivisie , Netherlands 10 seasons | 2019-08-09 - 2020-03-08 / matchday 34
30
+
31
+ 'fr.1' => 'FL1', # incl. team(s) monaco
32
+ # FL1 - Ligue 1, France
33
+ # 9 seasons | 2019-08-09 - 2020-05-31 / matchday 38
34
+ #
35
+ # 2019 => 2019/20
36
+ # 2018 => 2018/19
37
+ # 2017 => xxx 2017-18 - requires subscription !!!
38
+
39
+ 'it.1' => 'SA',
40
+ # SA - Serie A , Italy 15 seasons | 2019-08-24 - 2020-08-02 / matchday 27
41
+
42
+ 'br.1' => 'BSA',
43
+ # BSA - Série A, Brazil
44
+ # 4 seasons | 2020-05-03 - 2020-12-06 / matchday 10
45
+ #
46
+ # 2020 => 2020
47
+ # 2019 => 2019
48
+ # 2018 => 2018
49
+ # 2017 => xxx 2017 - requires subscription !!!
50
+
51
+ ## todo/check: use champs and NOT cl - why? why not?
52
+ 'cl' => 'CL', ## note: cl is country code for chile!! - use champs - why? why not?
53
+ 'europe.cl' => 'CL', ## note: cl is country code for chile!! - use champs - why? why not?
54
+ # CL - UEFA Champions League , Europe 19 seasons | 2019-06-25 - 2020-05-30 / matchday 6
55
+ }
56
+
57
+
58
+ #########
59
+ ## Mods
60
+ # e.g.
61
+ # Cardiff City FC | Cardiff › Wales - Cardiff City Stadium, Leckwith Road Cardiff CF11 8AZ
62
+ # AS Monaco FC | Monaco › Monaco - Avenue des Castellans Monaco 98000
63
+
64
+
65
+ MODS = {
66
+ 'br.1' => {
67
+ 'América FC' => 'América MG', # in year 2018
68
+ },
69
+ 'pt.1' => {
70
+ 'Vitória SC' => 'Vitória Guimarães', ## avoid easy confusion with Vitória SC <=> Vitória FC
71
+ 'Vitória FC' => 'Vitória Setúbal',
72
+ },
73
+ }
74
+
75
+ end # module Footballdata
76
+
77
+
78
+ ###########################
79
+ ## our own code
80
+ require_relative 'apis/config'
81
+ require_relative 'apis/stat'
82
+ require_relative 'apis/download'
83
+
84
+ require_relative 'apis/convert'
85
+ require_relative 'apis/convert_cl'
86
+
@@ -0,0 +1,17 @@
1
+
2
+ module Footballdata
3
+
4
+ ### add some more config options / settings
5
+ class Configuration
6
+ #########
7
+ ## nested configuration classes - use - why? why not?
8
+ class Convert
9
+ def out_dir() @out_dir || './o'; end
10
+ def out_dir=(value) @out_dir = value; end
11
+ end
12
+
13
+ def convert() @convert ||= Convert.new; end
14
+ end # class Configuration
15
+
16
+
17
+ end # module Footballdata
@@ -0,0 +1,239 @@
1
+
2
+
3
+ module Footballdata
4
+
5
+
6
+ def self.convert( league:, season: )
7
+
8
+ ### note/fix: cl (champions league for now is a "special" case)
9
+ if league.downcase == 'cl'
10
+ convert_cl( league: league,
11
+ season: season )
12
+ return
13
+ end
14
+
15
+
16
+
17
+ season = Season( season ) ## cast (ensure) season class (NOT string, integer, etc.)
18
+
19
+ data = Webcache.read_json( Metal.competition_matches_url( LEAGUES[league.downcase], season.start_year ))
20
+ data_teams = Webcache.read_json( Metal.competition_teams_url( LEAGUES[league.downcase], season.start_year ))
21
+
22
+
23
+ ## build a (reverse) team lookup by name
24
+ puts "#{data_teams['teams'].size} teams"
25
+
26
+ teams_by_name = data_teams['teams'].reduce( {} ) do |h,rec|
27
+ h[ rec['name'] ] = rec
28
+ h
29
+ end
30
+
31
+ pp teams_by_name.keys
32
+
33
+
34
+
35
+ mods = MODS[ league.downcase ] || {}
36
+
37
+
38
+ recs = []
39
+
40
+ teams = Hash.new( 0 )
41
+
42
+ stat = Stat.new
43
+
44
+ matches = data[ 'matches']
45
+ matches.each do |m|
46
+ stat.update( m )
47
+
48
+ team1 = m['homeTeam']['name']
49
+ team2 = m['awayTeam']['name']
50
+
51
+ score = m['score']
52
+
53
+
54
+
55
+ if m['stage'] == 'REGULAR_SEASON'
56
+ teams[ team1 ] += 1
57
+ teams[ team2 ] += 1
58
+
59
+ ### mods - rename club names
60
+ unless mods.nil? || mods.empty?
61
+ team1 = mods[ team1 ] if mods[ team1 ]
62
+ team2 = mods[ team2 ] if mods[ team2 ]
63
+ end
64
+
65
+
66
+ ## e.g. "utcDate": "2020-05-09T00:00:00Z",
67
+ date_str = m['utcDate']
68
+ date = DateTime.strptime( date_str, '%Y-%m-%dT%H:%M:%SZ' )
69
+
70
+
71
+ comments = ''
72
+ ft = ''
73
+ ht = ''
74
+
75
+ case m['status']
76
+ when 'SCHEDULED', 'IN_PLAY'
77
+ ft = ''
78
+ ht = ''
79
+ when 'FINISHED'
80
+ ## todo/fix: assert duration == "REGULAR"
81
+ ft = "#{score['fullTime']['homeTeam']}-#{score['fullTime']['awayTeam']}"
82
+ ht = "#{score['halfTime']['homeTeam']}-#{score['halfTime']['awayTeam']}"
83
+ when 'AWARDED'
84
+ ## todo/fix: assert duration == "REGULAR"
85
+ ft = "#{score['fullTime']['homeTeam']}-#{score['fullTime']['awayTeam']}"
86
+ ft << ' (*)'
87
+ ht = ''
88
+ comments = 'awarded'
89
+ when 'CANCELLED'
90
+ ft = '(*)'
91
+ ht = ''
92
+ comments = 'canceled' ## us eng ? -> canceled, british eng. cancelled ?
93
+ when 'POSTPONED'
94
+ ft = '(*)'
95
+ ht = ''
96
+ comments = 'postponed'
97
+ else
98
+ puts "!! ERROR: unsupported match status >#{m['status']}< - sorry:"
99
+ pp m
100
+ exit 1
101
+ end
102
+
103
+
104
+ ## todo/fix: assert matchday is a number e.g. 1,2,3, etc.!!!
105
+ recs << [m['matchday'],
106
+ date.to_date.strftime( '%Y-%m-%d' ),
107
+ team1,
108
+ ft,
109
+ ht,
110
+ team2,
111
+ comments
112
+ ]
113
+
114
+
115
+ print '%2s' % m['matchday']
116
+ print ' - '
117
+ print '%-24s' % team1
118
+ print ' '
119
+ print ft
120
+ print ' '
121
+ print "(#{ht})" unless ht.empty?
122
+ print ' '
123
+ print '%-24s' % team2
124
+ print ' '
125
+ print comments
126
+ print ' | '
127
+ ## print date.to_date ## strip time
128
+ print date.to_date.strftime( '%a %b %-d %Y' )
129
+ print ' -- '
130
+ print date
131
+ print "\n"
132
+ else
133
+ puts "-- skipping #{m['stage']}"
134
+ end
135
+ end # each match
136
+
137
+
138
+
139
+ ## note: get season from first match
140
+ ## assert - all other matches include the same season
141
+ ## e.g.
142
+ # "season": {
143
+ # "id": 154,
144
+ # "startDate": "2018-08-03",
145
+ # "endDate": "2019-05-05",
146
+ # "currentMatchday": 46
147
+ # }
148
+
149
+ start_date = Date.strptime( matches[0]['season']['startDate'], '%Y-%m-%d' )
150
+ end_date = Date.strptime( matches[0]['season']['endDate'], '%Y-%m-%d' )
151
+
152
+ dates = "#{start_date.strftime('%b %-d')} - #{end_date.strftime('%b %-d')}"
153
+
154
+ buf = ''
155
+ buf << "#{season.key} (#{dates}) - "
156
+ buf << "#{teams.keys.size} clubs, "
157
+ buf << "#{stat[:regular_season][:matches]} matches, "
158
+ buf << "#{stat[:regular_season][:goals]} goals"
159
+ buf << "\n"
160
+
161
+ puts buf
162
+
163
+
164
+
165
+ ## note: warn if stage is greater one and not regular season!!
166
+ File.open( './errors.txt' , 'a:utf-8' ) do |f|
167
+ if stat[:all][:stage].keys != ['REGULAR_SEASON']
168
+ f.write "!! WARN - league: #{league}, season: #{season.key} includes non-regular stage(s):\n"
169
+ f.write " #{stat[:all][:stage].keys.inspect}\n"
170
+ end
171
+ end
172
+
173
+
174
+ File.open( './logs.txt', 'a:utf-8' ) do |f|
175
+ f.write "\n================================\n"
176
+ f.write "==== #{league} =============\n"
177
+ f.write buf
178
+ f.write " match status: #{stat[:regular_season][:status].inspect}\n"
179
+ f.write " match duration: #{stat[:regular_season][:duration].inspect}\n"
180
+
181
+ f.write "#{teams.keys.size} teams:\n"
182
+ teams.each do |name, count|
183
+ rec = teams_by_name[ name ]
184
+ f.write " #{count}x #{name}"
185
+ if rec
186
+ f.write " | #{rec['shortName']} " if name != rec['shortName']
187
+ f.write " › #{rec['area']['name']}"
188
+ f.write " - #{rec['address']}"
189
+ else
190
+ puts "!! ERROR - no team record found in teams.json for >#{name}<"
191
+ exit 1
192
+ end
193
+ f.write "\n"
194
+ end
195
+ end
196
+
197
+
198
+
199
+
200
+ # recs = recs.sort { |l,r| l[1] <=> r[1] }
201
+ ## reformat date / beautify e.g. Sat Aug 7 1993
202
+ recs.each { |rec| rec[1] = Date.strptime( rec[1], '%Y-%m-%d' ).strftime( '%a %b %-d %Y' ) }
203
+
204
+ headers = [
205
+ 'Matchday',
206
+ 'Date',
207
+ 'Team 1',
208
+ 'FT',
209
+ 'HT',
210
+ 'Team 2',
211
+ 'Comments'
212
+ ]
213
+
214
+ ## note: change season_key from 2019/20 to 2019-20 (for path/directory!!!!)
215
+ Cache::CsvMatchWriter.write( "#{config.convert.out_dir}/#{season.to_path}/#{league.downcase}.csv",
216
+ recs,
217
+ headers: headers )
218
+
219
+
220
+ teams.each do |name, count|
221
+ rec = teams_by_name[ name ]
222
+ print " #{count}x "
223
+ print name
224
+ if rec
225
+ print " | #{rec['shortName']} " if name != rec['shortName']
226
+ print " › #{rec['area']['name']}"
227
+ print " - #{rec['address']}"
228
+ else
229
+ puts "!! ERROR - no team record found in teams.json for #{name}"
230
+ exit 1
231
+ end
232
+ print "\n"
233
+ end
234
+
235
+ pp stat
236
+ end # method convert
237
+ end # module Footballdata
238
+
239
+