football-sources 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/Manifest.txt +6 -15
  3. data/README.md +142 -1
  4. data/Rakefile +1 -1
  5. data/lib/football-sources.rb +26 -15
  6. data/lib/football-sources/apis.rb +1 -77
  7. data/lib/football-sources/apis/mods.rb +20 -0
  8. data/lib/football-sources/fbref.rb +4 -0
  9. data/lib/football-sources/fbref/build.rb +96 -0
  10. data/lib/football-sources/fbref/config.rb +16 -0
  11. data/lib/football-sources/fbref/convert.rb +95 -0
  12. data/lib/football-sources/version.rb +2 -2
  13. data/lib/football-sources/worldfootball.rb +1 -6
  14. data/lib/football-sources/worldfootball/jobs.rb +76 -0
  15. metadata +10 -19
  16. data/lib/football-sources/apis/download.rb +0 -11
  17. data/lib/football-sources/worldfootball/download.rb +0 -61
  18. data/lib/football-sources/worldfootball/leagues.rb +0 -200
  19. data/lib/football-sources/worldfootball/leagues/asia.rb +0 -53
  20. data/lib/football-sources/worldfootball/leagues/europe--british_isles.rb +0 -59
  21. data/lib/football-sources/worldfootball/leagues/europe--central.rb +0 -127
  22. data/lib/football-sources/worldfootball/leagues/europe--eastern.rb +0 -82
  23. data/lib/football-sources/worldfootball/leagues/europe--northern.rb +0 -57
  24. data/lib/football-sources/worldfootball/leagues/europe--southern.rb +0 -86
  25. data/lib/football-sources/worldfootball/leagues/europe--western.rb +0 -38
  26. data/lib/football-sources/worldfootball/leagues/europe.rb +0 -13
  27. data/lib/football-sources/worldfootball/leagues/north_america.rb +0 -44
  28. data/lib/football-sources/worldfootball/leagues/pacific.rb +0 -21
  29. data/lib/football-sources/worldfootball/leagues/south_america.rb +0 -11
  30. data/lib/football-sources/worldfootball/tool.rb +0 -100
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0d80d7220f2414773d0547c6aa69d15722d414bb
4
- data.tar.gz: eae20eaed5e9fd9efdb33602cc2f3125b1334797
3
+ metadata.gz: b068838936cfdba0eae277fe5f44c957f2281655
4
+ data.tar.gz: da3b4be77ac9661aaaa469580d38d37e68f3ae08
5
5
  SHA512:
6
- metadata.gz: cd4a9b5dbd4c86bd9ec20bebda0b56979bb6c5ce3d4fddf6fdfb947188b08f7dca68a931baf4bd199ff66f5518f326bc10bde273d43cd2c957c9e40c9f4b4cec
7
- data.tar.gz: d8be6c1a8246cd61f77aa4b63f0b382d9cde0da408c83e0e7626ad34ed9daf567b5735702f05dbbf9a0dd8035baea51f9ff83e67a0cb14dc02e261659781e121
6
+ metadata.gz: 9179c04e869df95a9b473aeabe1397f19c29108a1eac6e6d3fe149f2cb3b5f6967002d459e4ba013bfae26a22748724030805ebc591c333a389e53eb5d05576a
7
+ data.tar.gz: 31c7a7a673ea694996ddcf4ae550aa0904c2ba5391f5af3bfe09c9bf1f27f2af2ba0d8ddee0389da0b11a739b7bedb9e35055486a834a338072049d5a0f758e8
@@ -7,29 +7,20 @@ lib/football-sources/apis.rb
7
7
  lib/football-sources/apis/config.rb
8
8
  lib/football-sources/apis/convert.rb
9
9
  lib/football-sources/apis/convert_cl.rb
10
- lib/football-sources/apis/download.rb
10
+ lib/football-sources/apis/mods.rb
11
11
  lib/football-sources/apis/stat.rb
12
+ lib/football-sources/fbref.rb
13
+ lib/football-sources/fbref/build.rb
14
+ lib/football-sources/fbref/config.rb
15
+ lib/football-sources/fbref/convert.rb
12
16
  lib/football-sources/version.rb
13
17
  lib/football-sources/worldfootball.rb
14
18
  lib/football-sources/worldfootball/build.rb
15
19
  lib/football-sources/worldfootball/config.rb
16
20
  lib/football-sources/worldfootball/convert.rb
17
21
  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
22
+ lib/football-sources/worldfootball/jobs.rb
31
23
  lib/football-sources/worldfootball/mods.rb
32
- lib/football-sources/worldfootball/tool.rb
33
24
  lib/football-sources/worldfootball/vacuum.rb
34
25
  lib/football/sources.rb
35
26
  test/helper.rb
data/README.md CHANGED
@@ -8,10 +8,151 @@
8
8
  * forum :: [groups.google.com/group/opensport](https://groups.google.com/group/opensport)
9
9
 
10
10
 
11
+
11
12
  ## Usage
12
13
 
13
- TBD
14
14
 
15
+ ### Source #1 - `football-data.org` - ur src for machine readable football data
16
+
17
+ [Daniel Freitag](https://www.football-data.org/about)'s dev-friendly football API
18
+ offers a free to use plan
19
+ for 12 leagues (API key sign-up and use required).
20
+ See [`football-data.org` »](https://www.football-data.org)
21
+
22
+
23
+ **Step 0 - Setup Secrets**
24
+
25
+ Set the API key / token in the env(ironement).
26
+ Example:
27
+
28
+ ```
29
+ set FOOTBALLDATA=1234567890abcdef1234567890abcdef
30
+ ```
31
+
32
+
33
+ **Step 1 - Download Match Schedules**
34
+
35
+ Download the match schedules (in json) via api calls
36
+ to your (local) web cache (in `~/.cache`).
37
+ Note: The free trier has a 10 request/minute limit,
38
+ thus, sleep/wait 10 secs after every request
39
+ (should result in ~6 requests/minute).
40
+
41
+
42
+ ``` ruby
43
+ require 'football/sources'
44
+
45
+
46
+ # download up (ongoing) 2020 or 2020/21 seasons
47
+ Webget.config.sleep = 10
48
+
49
+ Footballdata.schedule( league: 'eng.1', season: '2020/21' )
50
+ Footballdata.schedule( league: 'eng.2', season: '2020/21' )
51
+
52
+ Footballdata.schedule( league: 'de.1', season: '2020/21' )
53
+ Footballdata.schedule( league: 'es.1', season: '2020/21' )
54
+
55
+ Footballdata.schedule( league: 'fr.1', season: '2020/21' )
56
+ Footballdata.schedule( league: 'it.1', season: '2020/21' )
57
+
58
+ Footballdata.schedule( league: 'nl.1', season: '2020/21' )
59
+ Footballdata.schedule( league: 'pt.1', season: '2020/21' )
60
+
61
+ Footballdata.schedule( league: 'cl', season: '2020/21' )
62
+
63
+ # note: Brasileirão - season is a calendar year (NOT an academic year)
64
+ Footballdata.schedule( league: 'br.1', season: '2020' )
65
+ ```
66
+
67
+ Note: You can find all downloaded match schedules
68
+ in your (local) web cache (in `~/.cache/api.football-data.org`) as pretty printed json documents.
69
+
70
+
71
+
72
+
73
+ **Step 2 - Convert (Cached) Match Schedules to Records**
74
+
75
+ Convert the (cached) match schedules
76
+ in JSON to the one-line, one-match & one-file, one-season
77
+ "standard" [Football.CSV format](https://github.com/footballcsv). Example:
78
+
79
+ ``` ruby
80
+ require 'football/sources'
81
+
82
+ ['eng.1', 'eng.2',
83
+ 'de.1',
84
+ 'es.1',
85
+ 'fr.1',
86
+ 'it.1',
87
+ 'nl.1',
88
+ 'pt.1',
89
+ 'cl',
90
+ ].each do |league|
91
+ Footballdata.convert( league: league, season: '2020/21' )
92
+ end
93
+
94
+ Footballdata.convert( league: 'br.1', season: '2020' )
95
+ ```
96
+
97
+ Note: By default all datasets get written into the `./o`
98
+ directory. Use `Footballdata.config.convert.out_dir`
99
+ to change the output directory.
100
+
101
+ The English Premier League (`eng.1`) results in `./o/2020-21/eng.1.csv`:
102
+
103
+ ```
104
+ Matchday,Date,Team 1,FT,HT,Team 2,Comments
105
+ 1,Sun Sep 13 2020,Manchester City FC,(*),,Aston Villa FC,postponed
106
+ 1,Sun Sep 13 2020,Burnley FC,(*),,Manchester United FC,postponed
107
+ 1,Sat Sep 12 2020,Fulham FC,0-3,0-1,Arsenal FC,
108
+ 1,Sat Sep 12 2020,Crystal Palace FC,1-0,1-0,Southampton FC,
109
+ 1,Sat Sep 12 2020,Liverpool FC,4-3,3-2,Leeds United FC,
110
+ 1,Sat Sep 12 2020,West Ham United FC,0-2,0-0,Newcastle United FC,
111
+ 1,Sun Sep 13 2020,West Bromwich Albion FC,0-3,0-0,Leicester City FC,
112
+ 1,Sun Sep 13 2020,Tottenham Hotspur FC,0-1,0-0,Everton FC,
113
+ 1,Mon Sep 14 2020,Sheffield United FC,0-2,0-2,Wolverhampton Wanderers FC,
114
+ 1,Mon Sep 14 2020,Brighton & Hove Albion FC,1-3,0-1,Chelsea FC,
115
+ 2,Sat Sep 19 2020,Everton FC,5-2,2-1,West Bromwich Albion FC,
116
+ 2,Sat Sep 19 2020,Leeds United FC,4-3,2-1,Fulham FC,
117
+ 2,Sat Sep 19 2020,Manchester United FC,1-3,0-1,Crystal Palace FC,
118
+ 2,Sat Sep 19 2020,Arsenal FC,2-1,1-1,West Ham United FC,
119
+ 2,Sun Sep 20 2020,Southampton FC,2-5,1-1,Tottenham Hotspur FC,
120
+ 2,Sun Sep 20 2020,Newcastle United FC,0-3,0-2,Brighton & Hove Albion FC,
121
+ 2,Sun Sep 20 2020,Chelsea FC,0-2,0-0,Liverpool FC,
122
+ 2,Sun Sep 20 2020,Leicester City FC,4-2,1-1,Burnley FC,
123
+ 2,Mon Sep 21 2020,Aston Villa FC,1-0,0-0,Sheffield United FC,
124
+ 2,Mon Sep 21 2020,Wolverhampton Wanderers FC,1-3,0-2,Manchester City FC,
125
+ ...
126
+ ```
127
+
128
+ Or the Brasileirão (`br.1`) in `./o/2020/br.1.csv`:
129
+
130
+ ```
131
+ Matchday,Date,Team 1,FT,HT,Team 2,Comments
132
+ 1,Sat Aug 8 2020,Fortaleza EC,0-2,0-2,CA Paranaense,
133
+ 1,Sat Aug 8 2020,Coritiba FBC,0-1,0-0,SC Internacional,
134
+ 1,Sun Aug 9 2020,SC Recife,3-2,3-1,Ceará SC,
135
+ 1,Sun Aug 9 2020,Santos FC,1-1,0-0,RB Bragantino,
136
+ 1,Sun Aug 9 2020,CR Flamengo,0-1,0-1,CA Mineiro,
137
+ 1,Sun Aug 9 2020,Goiás EC,(*),,São Paulo FC,postponed
138
+ 1,Sun Aug 9 2020,Grêmio FBPA,1-0,1-0,Fluminense FC,
139
+ 1,Sun Aug 9 2020,SE Palmeiras,(*),,CR Vasco da Gama,postponed
140
+ 2,Wed Aug 12 2020,CA Mineiro,3-2,0-2,SC Corinthians Paulista,
141
+ 2,Wed Aug 12 2020,CA Paranaense,2-1,1-1,Goiás EC,
142
+ 2,Wed Aug 12 2020,RB Bragantino,1-1,1-0,Botafogo FR,
143
+ 2,Wed Aug 12 2020,AC Goianiense,3-0,2-0,CR Flamengo,
144
+ 2,Wed Aug 12 2020,EC Bahia,1-0,1-0,Coritiba FBC,
145
+ 2,Thu Aug 13 2020,Fluminense FC,1-1,1-1,SE Palmeiras,
146
+ 2,Thu Aug 13 2020,Ceará SC,1-1,1-0,Grêmio FBPA,
147
+ 2,Thu Aug 13 2020,São Paulo FC,1-0,1-0,Fortaleza EC,
148
+ 2,Thu Aug 13 2020,SC Internacional,2-0,0-0,Santos FC,
149
+ 2,Thu Aug 13 2020,CR Vasco da Gama,2-0,2-0,SC Recife,
150
+ ...
151
+ ```
152
+
153
+
154
+
155
+ That's it for now. More sources upcoming.
15
156
 
16
157
  ## License
17
158
 
data/Rakefile CHANGED
@@ -18,7 +18,7 @@ Hoe.spec 'football-sources' do
18
18
  self.history_file = 'CHANGELOG.md'
19
19
 
20
20
  self.extra_deps = [
21
- ['webget-football', '>= 0.0.1'],
21
+ ['webget-football', '>= 0.1.1'],
22
22
  ['sportdb-catalogs', '>= 1.0.0'],
23
23
  ]
24
24
 
@@ -13,21 +13,32 @@ require 'sportdb/catalogs' ## note: incl. deps csvreader etc.
13
13
  module Cache
14
14
  class CsvMatchWriter
15
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
16
+ def self.csv_encode( values )
17
+ ## quote values that incl. a comma
18
+ values.map do |value|
19
+ if value.index(',')
20
+ puts "** rec with field with comma >#{value}< in:"
21
+ pp values
22
+ %Q{"#{value}"}
23
+ else
24
+ value
25
+ end
26
+ end.join( ',' )
27
+ end
28
+
29
+ def self.write( path, recs, headers: )
30
+ ## for convenience - make sure parent folders/directories exist
31
+ FileUtils.mkdir_p( File.dirname( path )) unless Dir.exist?( File.dirname( path ))
32
+
33
+ File.open( path, 'w:utf-8' ) do |f|
34
+ f.write( headers.join(',')) ## e.g. Date,Team 1,FT,HT,Team 2
35
+ f.write( "\n" )
36
+ recs.each do |values|
37
+ f.write( csv_encode( values ))
38
+ f.write( "\n" )
39
+ end
29
40
  end
30
-
41
+ end
31
42
  end # class CsvMatchWriter
32
43
  end # module Cache
33
44
 
@@ -40,7 +51,7 @@ require 'football-sources/version' # let version always go first
40
51
 
41
52
  require 'football-sources/apis'
42
53
  require 'football-sources/worldfootball'
43
-
54
+ require 'football-sources/fbref'
44
55
 
45
56
 
46
57
  puts FootballSources.banner # say hello
@@ -1,86 +1,10 @@
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
1
 
77
2
 
78
3
  ###########################
79
4
  ## our own code
80
5
  require_relative 'apis/config'
6
+ require_relative 'apis/mods'
81
7
  require_relative 'apis/stat'
82
- require_relative 'apis/download'
83
-
84
8
  require_relative 'apis/convert'
85
9
  require_relative 'apis/convert_cl'
86
10
 
@@ -0,0 +1,20 @@
1
+ module Footballdata
2
+
3
+ #########
4
+ ## Mods
5
+ # e.g.
6
+ # Cardiff City FC | Cardiff › Wales - Cardiff City Stadium, Leckwith Road Cardiff CF11 8AZ
7
+ # AS Monaco FC | Monaco › Monaco - Avenue des Castellans Monaco 98000
8
+
9
+
10
+ MODS = {
11
+ 'br.1' => {
12
+ 'América FC' => 'América MG', # in year 2018
13
+ },
14
+ 'pt.1' => {
15
+ 'Vitória SC' => 'Vitória Guimarães', ## avoid easy confusion with Vitória SC <=> Vitória FC
16
+ 'Vitória FC' => 'Vitória Setúbal',
17
+ },
18
+ }
19
+
20
+ end # module Footballdata
@@ -0,0 +1,4 @@
1
+
2
+ require_relative 'fbref/config'
3
+ require_relative 'fbref/build'
4
+ require_relative 'fbref/convert'
@@ -0,0 +1,96 @@
1
+
2
+ module Fbref
3
+
4
+ def self.build( rows, league:, season: )
5
+ season = Season( season ) ## cast (ensure) season class (NOT string, integer, etc.)
6
+
7
+ raise ArgumentError, "league key as string expected" unless league.is_a?(String) ## note: do NOT pass in league struct! pass in key (string)
8
+
9
+ print " #{rows.size} rows - build #{league} #{season}"
10
+ print "\n"
11
+
12
+
13
+ recs = []
14
+ rows.each do |row|
15
+
16
+ stage = row[:stage] || ''
17
+
18
+ ## todo/check: assert that only matchweek or round can be present NOT both!!
19
+ round = if row[:matchweek] && row[:matchweek].size > 0
20
+ row[:matchweek]
21
+ elsif row[:round] && row[:round].size > 0
22
+ row[:round]
23
+ else
24
+ ''
25
+ end
26
+
27
+ date_str = row[:date]
28
+ time_str = row[:time]
29
+ team1_str = row[:team1]
30
+ team2_str = row[:team2]
31
+ score_str = row[:score]
32
+
33
+ ## convert date from string e.g. 2019-25-10
34
+ date = Date.strptime( date_str, '%Y-%m-%d' )
35
+
36
+ comments = row[:comments]
37
+ ht, ft, et, pen, comments = parse_score( score_str, comments )
38
+
39
+
40
+ venue_str = row[:venue]
41
+ attendance_str = row[:attendance]
42
+
43
+
44
+ recs << [stage,
45
+ round,
46
+ date.strftime( '%Y-%m-%d' ),
47
+ time_str,
48
+ team1_str,
49
+ ft,
50
+ ht,
51
+ team2_str,
52
+ et, # extra: incl. extra time
53
+ pen, # extra: incl. penalties
54
+ venue_str,
55
+ attendance_str,
56
+ comments]
57
+ end
58
+
59
+ recs
60
+ end
61
+
62
+
63
+ def self.parse_score( score_str, comments )
64
+
65
+ ## split score
66
+ ft = ''
67
+ ht = ''
68
+ et = ''
69
+ pen = ''
70
+
71
+ if score_str.size > 0
72
+ ## note: replace unicode "fancy" dash with ascii-dash
73
+ # check other columns too - possible in teams?
74
+ score_str = score_str.gsub( /[–]/, '-' ).strip
75
+
76
+ if score_str =~ /^\(([0-9]+)\)
77
+ [ ]+ ([0-9]+) - ([0-9+]) [ ]+
78
+ \(([0-9]+)\)$/x
79
+ ft = '?'
80
+ et = "#{$2}-#{$3}"
81
+ pen = "#{$1}-#{$4}"
82
+ else ## assume "regular" score e.g. 0-0
83
+ ## check if notes include extra time otherwise assume regular time
84
+ if comments =~ /extra time/i
85
+ ft = '?'
86
+ et = score_str
87
+ else
88
+ ft = score_str
89
+ end
90
+ end
91
+ end
92
+
93
+ [ht, ft, et, pen, comments]
94
+ end
95
+
96
+ end # module Fbref