footballdata-api 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +6 -0
- data/Manifest.txt +15 -0
- data/README.md +165 -0
- data/Rakefile +33 -0
- data/bin/fbdat +200 -0
- data/lib/footballdata/convert.rb +332 -0
- data/lib/footballdata/download.rb +131 -0
- data/lib/footballdata/generator.rb +33 -0
- data/lib/footballdata/leagues.rb +59 -0
- data/lib/footballdata/mods.rb +22 -0
- data/lib/footballdata/prettyprint.rb +189 -0
- data/lib/footballdata/stat.rb +59 -0
- data/lib/footballdata/teams.rb +90 -0
- data/lib/footballdata/version.rb +20 -0
- data/lib/footballdata.rb +56 -0
- metadata +155 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 16f099d030a007993b7289956e920fd89baff6abc506feeca3dad792453efe76
|
4
|
+
data.tar.gz: 8f3d2df27a3dc12cc15fa2a8ee0dcd42a51ed793261a2ab2795020147596e7f6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cca1d63da2e1823a3c9cc2636953da2f691101c32b63f5004c5349338d9dd75099ac993786e038cf3e2ea8a41f3ac1ce7510cdf148f1f13a98d360203613cf99
|
7
|
+
data.tar.gz: 6030f680eb2e5dadd269ee78bd778c1b465914702e20fe98e55e0967346feb67a6b74d8a965dea73ce62b9c8f457ba1de811d02e26a603b90ff4d3a160b8ee99
|
data/CHANGELOG.md
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
CHANGELOG.md
|
2
|
+
Manifest.txt
|
3
|
+
README.md
|
4
|
+
Rakefile
|
5
|
+
bin/fbdat
|
6
|
+
lib/footballdata.rb
|
7
|
+
lib/footballdata/convert.rb
|
8
|
+
lib/footballdata/download.rb
|
9
|
+
lib/footballdata/generator.rb
|
10
|
+
lib/footballdata/leagues.rb
|
11
|
+
lib/footballdata/mods.rb
|
12
|
+
lib/footballdata/prettyprint.rb
|
13
|
+
lib/footballdata/stat.rb
|
14
|
+
lib/footballdata/teams.rb
|
15
|
+
lib/footballdata/version.rb
|
data/README.md
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
# footballdata-api - get football data via Daniel Freitag's football-data.org api v4
|
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/footballdata-api](https://rubygems.org/gems/footballdata-api)
|
7
|
+
* rdoc :: [rubydoc.info/gems/footballdata-api](http://rubydoc.info/gems/footballdata-api)
|
8
|
+
|
9
|
+
|
10
|
+
|
11
|
+
## Usage
|
12
|
+
|
13
|
+
|
14
|
+
[Daniel Freitag](https://www.football-data.org/about)'s dev-friendly football API
|
15
|
+
offers a free to use plan
|
16
|
+
for 12 leagues (API key sign-up and use required).
|
17
|
+
See [`football-data.org` »](https://www.football-data.org)
|
18
|
+
|
19
|
+
|
20
|
+
**Step 0 - Setup Secrets**
|
21
|
+
|
22
|
+
Set the API key / token in the env(ironement).
|
23
|
+
Example:
|
24
|
+
|
25
|
+
```
|
26
|
+
set FOOTBALLDATA=1234567890abcdef1234567890abcdef
|
27
|
+
```
|
28
|
+
|
29
|
+
|
30
|
+
**Step 1 - Download Match Schedules**
|
31
|
+
|
32
|
+
Download the match schedules (in json) via api calls
|
33
|
+
to your (local) web cache (in `~/.cache`).
|
34
|
+
Note: The free trier has a 10 request/minute limit,
|
35
|
+
thus, sleep/wait 10 secs after every request
|
36
|
+
(should result in ~6 requests/minute).
|
37
|
+
|
38
|
+
|
39
|
+
``` ruby
|
40
|
+
require 'footballdata'
|
41
|
+
|
42
|
+
|
43
|
+
# download up (ongoing) 2020 or 2020/21 seasons
|
44
|
+
Webget.config.sleep = 10
|
45
|
+
|
46
|
+
Footballdata.schedule( league: 'eng.1', season: '2020/21' )
|
47
|
+
Footballdata.schedule( league: 'eng.2', season: '2020/21' )
|
48
|
+
|
49
|
+
Footballdata.schedule( league: 'de.1', season: '2020/21' )
|
50
|
+
Footballdata.schedule( league: 'es.1', season: '2020/21' )
|
51
|
+
|
52
|
+
Footballdata.schedule( league: 'fr.1', season: '2020/21' )
|
53
|
+
Footballdata.schedule( league: 'it.1', season: '2020/21' )
|
54
|
+
|
55
|
+
Footballdata.schedule( league: 'nl.1', season: '2020/21' )
|
56
|
+
Footballdata.schedule( league: 'pt.1', season: '2020/21' )
|
57
|
+
|
58
|
+
Footballdata.schedule( league: 'cl', season: '2020/21' )
|
59
|
+
|
60
|
+
# note: Brasileirão - season is a calendar year (NOT an academic year)
|
61
|
+
Footballdata.schedule( league: 'br.1', season: '2020' )
|
62
|
+
```
|
63
|
+
|
64
|
+
Note: You can find all downloaded match schedules
|
65
|
+
in your (local) web cache (in `~/.cache/api.football-data.org`) as pretty printed json documents.
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
|
70
|
+
**Step 2 - Convert (Cached) Match Schedules to Records**
|
71
|
+
|
72
|
+
Convert the (cached) match schedules
|
73
|
+
in JSON to the one-line, one-match & one-file, one-season
|
74
|
+
"standard" [Football.CSV format](https://github.com/footballcsv). Example:
|
75
|
+
|
76
|
+
``` ruby
|
77
|
+
require 'footballdata'
|
78
|
+
|
79
|
+
['eng.1', 'eng.2',
|
80
|
+
'de.1',
|
81
|
+
'es.1',
|
82
|
+
'fr.1',
|
83
|
+
'it.1',
|
84
|
+
'nl.1',
|
85
|
+
'pt.1',
|
86
|
+
'cl',
|
87
|
+
].each do |league|
|
88
|
+
Footballdata.convert( league: league, season: '2020/21' )
|
89
|
+
end
|
90
|
+
|
91
|
+
Footballdata.convert( league: 'br.1', season: '2020' )
|
92
|
+
```
|
93
|
+
|
94
|
+
Note: By default all datasets get written into the `./o`
|
95
|
+
directory. Use `Footballdata.config.convert.out_dir`
|
96
|
+
to change the output directory.
|
97
|
+
|
98
|
+
The English Premier League (`eng.1`) results in `./o/2020-21/eng.1.csv`:
|
99
|
+
|
100
|
+
```
|
101
|
+
Matchday,Date,Team 1,FT,HT,Team 2,Comments
|
102
|
+
1,Sun Sep 13 2020,Manchester City FC,(*),,Aston Villa FC,postponed
|
103
|
+
1,Sun Sep 13 2020,Burnley FC,(*),,Manchester United FC,postponed
|
104
|
+
1,Sat Sep 12 2020,Fulham FC,0-3,0-1,Arsenal FC,
|
105
|
+
1,Sat Sep 12 2020,Crystal Palace FC,1-0,1-0,Southampton FC,
|
106
|
+
1,Sat Sep 12 2020,Liverpool FC,4-3,3-2,Leeds United FC,
|
107
|
+
1,Sat Sep 12 2020,West Ham United FC,0-2,0-0,Newcastle United FC,
|
108
|
+
1,Sun Sep 13 2020,West Bromwich Albion FC,0-3,0-0,Leicester City FC,
|
109
|
+
1,Sun Sep 13 2020,Tottenham Hotspur FC,0-1,0-0,Everton FC,
|
110
|
+
1,Mon Sep 14 2020,Sheffield United FC,0-2,0-2,Wolverhampton Wanderers FC,
|
111
|
+
1,Mon Sep 14 2020,Brighton & Hove Albion FC,1-3,0-1,Chelsea FC,
|
112
|
+
2,Sat Sep 19 2020,Everton FC,5-2,2-1,West Bromwich Albion FC,
|
113
|
+
2,Sat Sep 19 2020,Leeds United FC,4-3,2-1,Fulham FC,
|
114
|
+
2,Sat Sep 19 2020,Manchester United FC,1-3,0-1,Crystal Palace FC,
|
115
|
+
2,Sat Sep 19 2020,Arsenal FC,2-1,1-1,West Ham United FC,
|
116
|
+
2,Sun Sep 20 2020,Southampton FC,2-5,1-1,Tottenham Hotspur FC,
|
117
|
+
2,Sun Sep 20 2020,Newcastle United FC,0-3,0-2,Brighton & Hove Albion FC,
|
118
|
+
2,Sun Sep 20 2020,Chelsea FC,0-2,0-0,Liverpool FC,
|
119
|
+
2,Sun Sep 20 2020,Leicester City FC,4-2,1-1,Burnley FC,
|
120
|
+
2,Mon Sep 21 2020,Aston Villa FC,1-0,0-0,Sheffield United FC,
|
121
|
+
2,Mon Sep 21 2020,Wolverhampton Wanderers FC,1-3,0-2,Manchester City FC,
|
122
|
+
...
|
123
|
+
```
|
124
|
+
|
125
|
+
Or the Brasileirão (`br.1`) in `./o/2020/br.1.csv`:
|
126
|
+
|
127
|
+
```
|
128
|
+
Matchday,Date,Team 1,FT,HT,Team 2,Comments
|
129
|
+
1,Sat Aug 8 2020,Fortaleza EC,0-2,0-2,CA Paranaense,
|
130
|
+
1,Sat Aug 8 2020,Coritiba FBC,0-1,0-0,SC Internacional,
|
131
|
+
1,Sun Aug 9 2020,SC Recife,3-2,3-1,Ceará SC,
|
132
|
+
1,Sun Aug 9 2020,Santos FC,1-1,0-0,RB Bragantino,
|
133
|
+
1,Sun Aug 9 2020,CR Flamengo,0-1,0-1,CA Mineiro,
|
134
|
+
1,Sun Aug 9 2020,Goiás EC,(*),,São Paulo FC,postponed
|
135
|
+
1,Sun Aug 9 2020,Grêmio FBPA,1-0,1-0,Fluminense FC,
|
136
|
+
1,Sun Aug 9 2020,SE Palmeiras,(*),,CR Vasco da Gama,postponed
|
137
|
+
2,Wed Aug 12 2020,CA Mineiro,3-2,0-2,SC Corinthians Paulista,
|
138
|
+
2,Wed Aug 12 2020,CA Paranaense,2-1,1-1,Goiás EC,
|
139
|
+
2,Wed Aug 12 2020,RB Bragantino,1-1,1-0,Botafogo FR,
|
140
|
+
2,Wed Aug 12 2020,AC Goianiense,3-0,2-0,CR Flamengo,
|
141
|
+
2,Wed Aug 12 2020,EC Bahia,1-0,1-0,Coritiba FBC,
|
142
|
+
2,Thu Aug 13 2020,Fluminense FC,1-1,1-1,SE Palmeiras,
|
143
|
+
2,Thu Aug 13 2020,Ceará SC,1-1,1-0,Grêmio FBPA,
|
144
|
+
2,Thu Aug 13 2020,São Paulo FC,1-0,1-0,Fortaleza EC,
|
145
|
+
2,Thu Aug 13 2020,SC Internacional,2-0,0-0,Santos FC,
|
146
|
+
2,Thu Aug 13 2020,CR Vasco da Gama,2-0,2-0,SC Recife,
|
147
|
+
...
|
148
|
+
```
|
149
|
+
|
150
|
+
|
151
|
+
|
152
|
+
That's it for now.
|
153
|
+
|
154
|
+
|
155
|
+
|
156
|
+
## License
|
157
|
+
|
158
|
+
The `footballdata` scripts are dedicated to the public domain.
|
159
|
+
Use it as you please with no restrictions whatsoever.
|
160
|
+
|
161
|
+
|
162
|
+
## Questions? Comments?
|
163
|
+
|
164
|
+
Yes, you can. More than welcome.
|
165
|
+
See [Help & Support »](https://github.com/openfootball/help)
|
data/Rakefile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'hoe'
|
2
|
+
require './lib/footballdata/version.rb'
|
3
|
+
|
4
|
+
Hoe.spec 'footballdata-api' do
|
5
|
+
|
6
|
+
self.version = FootballdataApi::VERSION
|
7
|
+
|
8
|
+
self.summary = "footballdata-api - get football data via Daniel Freitag's football-data.org api v4"
|
9
|
+
self.description = summary
|
10
|
+
|
11
|
+
self.urls = { home: 'https://github.com/sportdb/sport.db' }
|
12
|
+
|
13
|
+
self.author = 'Gerald Bauer'
|
14
|
+
self.email = 'gerald.bauer@gmail.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
|
+
['tzinfo'],
|
22
|
+
['season-formats'],
|
23
|
+
['webget'],
|
24
|
+
['cocos'], ## later pull in with sportsdb-writers
|
25
|
+
]
|
26
|
+
|
27
|
+
self.licenses = ['Public Domain']
|
28
|
+
|
29
|
+
self.spec_extras = {
|
30
|
+
required_ruby_version: '>= 2.2.2'
|
31
|
+
}
|
32
|
+
|
33
|
+
end
|
data/bin/fbdat
ADDED
@@ -0,0 +1,200 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
## tip: to test run:
|
4
|
+
## ruby -I ./lib bin/fbdat
|
5
|
+
|
6
|
+
require 'footballdata'
|
7
|
+
|
8
|
+
|
9
|
+
load_env ## use dotenv (.env)
|
10
|
+
|
11
|
+
|
12
|
+
Webcache.root = if File.exist?( '/sports/cache' )
|
13
|
+
puts " setting web cache to >/sports/cache<"
|
14
|
+
'/sports/cache'
|
15
|
+
else
|
16
|
+
'./cache'
|
17
|
+
end
|
18
|
+
|
19
|
+
## note - free tier (tier one) plan - 10 requests/minute
|
20
|
+
## (one request every 6 seconds 6*10=60 secs)
|
21
|
+
## 10 API calls per minute max.
|
22
|
+
## note - default sleep (delay in secs) is 3 sec(s)
|
23
|
+
Webget.config.sleep = 10
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
require 'optparse'
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
module Footballdata
|
33
|
+
def self.main( args=ARGV )
|
34
|
+
|
35
|
+
opts = {}
|
36
|
+
parser = OptionParser.new do |parser|
|
37
|
+
parser.banner = "Usage: #{$PROGRAM_NAME} [options]"
|
38
|
+
|
39
|
+
parser.on( "--cache", "--cached", "--offline",
|
40
|
+
"use cached data in #{Webcache.root}" ) do |cached|
|
41
|
+
opts[:cached] = cached
|
42
|
+
end
|
43
|
+
end
|
44
|
+
parser.parse!( args )
|
45
|
+
|
46
|
+
puts "OPTS:"
|
47
|
+
p opts
|
48
|
+
puts "ARGV:"
|
49
|
+
p args
|
50
|
+
|
51
|
+
|
52
|
+
## try special args
|
53
|
+
|
54
|
+
if ['plan', 'plans',
|
55
|
+
'comp', 'comps'].include?(args[0])
|
56
|
+
|
57
|
+
if opts[:cached]
|
58
|
+
## do nothing
|
59
|
+
else
|
60
|
+
Metal.competitions( auth: true ) ## get free tier (TIER_ONE) with auth (token)
|
61
|
+
end
|
62
|
+
|
63
|
+
url = Metal.competitions_url
|
64
|
+
pp url
|
65
|
+
#=> "http://api.football-data.org/v4/competitions"
|
66
|
+
|
67
|
+
data = Webcache.read_json( url )
|
68
|
+
pp data
|
69
|
+
|
70
|
+
comps = data['competitions']
|
71
|
+
comps.each do |rec|
|
72
|
+
print "==> "
|
73
|
+
print "#{rec['area']['name']} (#{rec['area']['code']}) - "
|
74
|
+
print "#{rec['name']} (#{rec['code']}) -- "
|
75
|
+
print "#{rec['plan']} #{rec['type']}, "
|
76
|
+
print "#{rec['numberOfAvailableSeasons']} season(s)"
|
77
|
+
print "\n"
|
78
|
+
|
79
|
+
print " #{rec['currentSeason']['startDate']} - #{rec['currentSeason']['endDate']} "
|
80
|
+
print "@ #{rec['currentSeason']['currentMatchday']}"
|
81
|
+
print "\n"
|
82
|
+
end
|
83
|
+
|
84
|
+
puts " #{comps.size} competition(s)"
|
85
|
+
exit 0
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
###
|
90
|
+
# pretty print today's matches (tomorrow/yesterday/etc.)
|
91
|
+
|
92
|
+
|
93
|
+
##
|
94
|
+
## note - cannot use t for today (used for tomorrow)
|
95
|
+
## find a different shortcode - why? why not?
|
96
|
+
|
97
|
+
### note - today is default if no args passed in!!!
|
98
|
+
|
99
|
+
##
|
100
|
+
## todo - add more date offsets - t+2,t+3,t+4, etc.
|
101
|
+
|
102
|
+
date = if ['y', 'yesterday', 't-1', '-1'].include?( args[0] )
|
103
|
+
Date.today-1
|
104
|
+
elsif ['t', 'tomorrow', 't+1', '1', '+1'].include?( args[0] )
|
105
|
+
Date.today+1
|
106
|
+
elsif ['m', 'match', 'matches', 'today'].include?( args[0] || 'today' ) ## make default - why? why not?
|
107
|
+
Date.today
|
108
|
+
else
|
109
|
+
nil
|
110
|
+
end
|
111
|
+
|
112
|
+
if date
|
113
|
+
if opts[:cached]
|
114
|
+
## do nothing
|
115
|
+
else
|
116
|
+
Metal.todays_matches( date )
|
117
|
+
end
|
118
|
+
|
119
|
+
data = Webcache.read_json( Metal.todays_matches_url( date ) )
|
120
|
+
pp data
|
121
|
+
|
122
|
+
last_comp = nil
|
123
|
+
data['matches'].each do |rec|
|
124
|
+
## only print competition header if different from last match
|
125
|
+
comp = fmt_competition( rec )
|
126
|
+
puts comp if comp != last_comp
|
127
|
+
|
128
|
+
puts fmt_match( rec )
|
129
|
+
|
130
|
+
last_comp = comp
|
131
|
+
end
|
132
|
+
exit 0
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
|
137
|
+
###
|
138
|
+
# league and season - pretty print matches
|
139
|
+
#
|
140
|
+
## samples:
|
141
|
+
## national teams
|
142
|
+
## EC 2024 - euro
|
143
|
+
## EC 2021
|
144
|
+
## WC 2022 - world cup
|
145
|
+
## club cups intl
|
146
|
+
## CL 2023 - (uefa/european) champions league
|
147
|
+
## CLI 2204 - (south american) copa libertadores
|
148
|
+
## club leagues
|
149
|
+
## PL 2024 - england premiere league
|
150
|
+
|
151
|
+
|
152
|
+
league_code = args[0] || 'PL'
|
153
|
+
|
154
|
+
### convenience helpers - lets you use eng.1, euro, etc.
|
155
|
+
## check if mapping for league_code
|
156
|
+
if LEAGUES.has_key?( league_code.downcase )
|
157
|
+
league_code = LEAGUES[ league_code.downcase ]
|
158
|
+
else
|
159
|
+
## assume "native" code
|
160
|
+
## always upcase e.g. pl => PL etc.
|
161
|
+
league_code = league_code.upcase
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
season = Season( args[1] ||
|
166
|
+
(league_code == 'EC' ? '2024' : '2024/25'))
|
167
|
+
|
168
|
+
season_start_year = season.start_year ## use year - why? why not?
|
169
|
+
|
170
|
+
pp league_code, season_start_year
|
171
|
+
|
172
|
+
if opts[:cached]
|
173
|
+
## do nothing
|
174
|
+
else
|
175
|
+
## download dataset(s)
|
176
|
+
## try download
|
177
|
+
Metal.matches( league_code,
|
178
|
+
season_start_year )
|
179
|
+
end
|
180
|
+
|
181
|
+
url = Metal.competition_matches_url( league_code,
|
182
|
+
season_start_year )
|
183
|
+
pp url
|
184
|
+
#=> "http://api.football-data.org/v4/competitions/EC/matches?season=2024"
|
185
|
+
|
186
|
+
data = Webcache.read_json( url )
|
187
|
+
## pp data
|
188
|
+
|
189
|
+
pp_matches( data )
|
190
|
+
|
191
|
+
end # def self.main
|
192
|
+
end # module Footballdata
|
193
|
+
|
194
|
+
|
195
|
+
|
196
|
+
Footballdata.main( ARGV )
|
197
|
+
|
198
|
+
|
199
|
+
puts "bye"
|
200
|
+
|