footballdata-api 0.2.0

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 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
@@ -0,0 +1,6 @@
1
+ ### 0.2.0
2
+
3
+ ### 0.0.1 / 2024-07-03
4
+
5
+ * Everything is new. First release.
6
+
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
+