mlb_terminal 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/README.md +76 -5
- data/bin/mlb +92 -1
- data/lib/mlb_terminal.rb +2 -0
- data/lib/mlb_terminal/game.rb +18 -8
- data/lib/mlb_terminal/globals.rb +57 -0
- data/lib/mlb_terminal/pitcher.rb +44 -0
- data/lib/mlb_terminal/version.rb +1 -1
- metadata +4 -2
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,18 +1,20 @@
|
|
1
|
-
|
1
|
+
nal
|
2
2
|
|
3
3
|
Access to MLB baseball scores in the terminal.
|
4
4
|
|
5
5
|
## Overview
|
6
6
|
|
7
|
-
Don't you just wish you could have a little terminal app to stream out real-time stats for a MLB baseball game? Look no further!
|
7
|
+
Don't you just wish you could have a little terminal app to stream out real-time stats for a MLB baseball game? Look no further! _Please note, the use of this data is subjected to the terms put forth by the MLB. More information can be found here: [http://gdx.mlb.com/components/copyright.txt](http://gdx.mlb.com/components/copyright.txt). You're okay if you're using this data for individual use!_
|
8
8
|
|
9
9
|
### Syntax
|
10
10
|
|
11
11
|
#### Commands
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
*
|
13
|
+
To find out more about a specific command, use `mlb [command] --help` to view the appropriate documentation.
|
14
|
+
|
15
|
+
* `help`: Display global or [command] help documentation.
|
16
|
+
* `games [options]`: Print out a list of scheduled games for the specified date
|
17
|
+
* `game [options] [game_number]`: Print out play-by-play events for a specific game. Use `--pitches` to output realtime pitch trajectory data.
|
16
18
|
|
17
19
|
#### Global options
|
18
20
|
|
@@ -22,6 +24,75 @@ Don't you just wish you could have a little terminal app to stream out real-time
|
|
22
24
|
|
23
25
|
* -t, --trace: Display backtrace when an error occurs
|
24
26
|
|
27
|
+
### Data Output Format
|
28
|
+
|
29
|
+
Each command outputs data in tab-separated format. When outputting data for a game in progress, the application will continue to pipe in data as it is made available.
|
30
|
+
|
31
|
+
#### `games` (Game listings)
|
32
|
+
|
33
|
+
1. Game index. A numbered value unique to the specified date that is referenced in the `game` command.
|
34
|
+
2. Opposing teams. A string containing: `<Away Team> (Wins - Losses) @ <Home Team> (Wins - Losses).
|
35
|
+
3. Starting time and status.
|
36
|
+
4. Current score.
|
37
|
+
|
38
|
+
#### `game` (Game events)
|
39
|
+
|
40
|
+
1. Event time.
|
41
|
+
2. Inning.
|
42
|
+
3. Event number.
|
43
|
+
4. Event description.
|
44
|
+
|
45
|
+
#### `game --pitches` (Pitch events)
|
46
|
+
|
47
|
+
1. Pitch time.
|
48
|
+
2. Inning.
|
49
|
+
3. Top/Bottom of inning.
|
50
|
+
4. Pitcher name.
|
51
|
+
5. Batter name.
|
52
|
+
6. Pitch type. (S-Strike, B-Ball, X-hit)
|
53
|
+
7. X (x). The horizontal location of the pitch as it crosses the home plate. Units: Old Gameday coordinate system
|
54
|
+
8. Y (y). The vertical location of the pitch as it crosses the home plate. Units: Old Gameday coordinate system
|
55
|
+
9. Start speed (start_speed). The initial speed of the pitch. Units: miles per hour
|
56
|
+
10. End speed (end_speed). The speed measured as it crosses the home plate. Units: miles per hour
|
57
|
+
11. Top of Strike Zone (sz_top). The distance from the ground to the top of the strike zone. Units: feet
|
58
|
+
12. Bottom of Strike Zone (sz_bot). The distance from the ground to the bottom of the strike zone. Units: feet
|
59
|
+
13. Horizontal movement (pfx_x). The horizontal movement of a pitch relative to a theoretical pitch thrown at the same speed with no spin-induced movement. Measured at 40 feet from the home plate. Units: inches
|
60
|
+
14. Vertical movement (pfx_z). The vertical movement of a pitch relative to a theoretical pitch thrown at the same speed with no spin-induced movement. Measured at 40 feet from the home plate. Units: inches
|
61
|
+
15. Horizontal pitch location at home plate (px). The horizontal location of the pitch as it crosses home plate from the perspective of the umpire. Units: feet
|
62
|
+
16. Vertical pitch location at home plate (pz). The height of the pitch as it crosses the front of home plate. Units: feet
|
63
|
+
17. Initial horizontal measurement for pitch (x0). Initial horizontal measurement of pitch as measured by PITCHf/x. Units: feet
|
64
|
+
18. Initial depth measurement for pitch (y0). Initial deptch measurement of pitch as measured by PITCHf/x. Note that this is fixed per stadium and typically located around 40-50 feet from home plate. Units: feet
|
65
|
+
19. Initial height measurement for pitch (z0). Initial height measurement of pitch as measured by PITCHf/x. Units: feet
|
66
|
+
20. Initial x velocity (vxo). Initial velocity in the horizontal direction at the initial point. Units: feet per second
|
67
|
+
21. Initial y velocity (vxo). Initial velocity in the depth-wise direction at the initial point. Units: feet per second
|
68
|
+
22. Initial z velocity (vxo). Initial velocity in the vertical direction at the initial point. Units: feet per second
|
69
|
+
23. Breaking point (break_y). The distance from the home plate in which the pitch achieved its greatest deviation from the straight line path between the release point and the front of home plate. Units: feet
|
70
|
+
24. Breaking angle (break_angle). The angle at which the pitch crossed the front of home plate as seen by the umpire. Units: degrees
|
71
|
+
25. Breaking length (break_length). The greatest distance between the pitch's trajectory and the straight path between release and home plate. Units: inches
|
72
|
+
26. Pitch type (pitch_type). Pitch type as classified by the PITCHf/x system.
|
73
|
+
* FA = Fastball
|
74
|
+
* FF = Four-seam fastball
|
75
|
+
* FT = Two-seam fastball
|
76
|
+
* FC = Fastball (cutter)
|
77
|
+
* FS / SI / SF = Fastball (sinker, split-fingered)
|
78
|
+
* SL = Slider
|
79
|
+
* CH = Changeup
|
80
|
+
* CB / CU = Curveball
|
81
|
+
* KC = Knuckle-curve
|
82
|
+
* KN = Knuckleball
|
83
|
+
* EP = Eephus
|
84
|
+
* UN / XX = Unidentified
|
85
|
+
* PO / FO = Pitch out
|
86
|
+
27. Pitch type confidence (type_confidence). A rating corresponding to the liklihood of the pitch type classification.
|
87
|
+
28. Pitch zone (zone).
|
88
|
+
29. Nasty factor (nasty). A auto-generated factor that describes the difficulty in hitting the pitch.
|
89
|
+
30. Spin direction (spin_dir).
|
90
|
+
31. Spin rate (spin_rate).
|
91
|
+
32. Comments (cc).
|
92
|
+
33. Unknown (mt).
|
93
|
+
|
94
|
+
For more information regarding PITCHf/x tracjectory data, please visit [http://fastballs.wordpress.com/category/pitchfx-glossary/](http://fastballs.wordpress.com/category/pitchfx-glossary/).
|
95
|
+
|
25
96
|
### Examples
|
26
97
|
|
27
98
|
> # List todays games
|
data/bin/mlb
CHANGED
@@ -10,7 +10,7 @@ program :description, 'Stream MLB games into the terminal'
|
|
10
10
|
|
11
11
|
command :games do |c|
|
12
12
|
c.syntax = 'mlb games [options] [date]'
|
13
|
-
c.summary = 'Print out a list of scheduled games for the specified date'
|
13
|
+
c.summary = 'Print out a list of scheduled games for the specified date.'
|
14
14
|
c.description = 'Print out a tab-seperated value list to STDOUT wih columns ' \
|
15
15
|
'for index, team names, game status, and current score.'
|
16
16
|
c.example 'description', 'mlb --date "2012-09-28" | grep Nationals'
|
@@ -30,6 +30,97 @@ command :games do |c|
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
+
command :pitchers do |c|
|
34
|
+
c.syntax = 'mlb pitchers [options] [game-number]'
|
35
|
+
c.summary = 'Print out a list of pitchers for the specified date and game index.'
|
36
|
+
c.description = 'Print out a tab-seperated value list to STDOUT wih columns ' \
|
37
|
+
'for team, pitcher id, and pitcher name. Note, this prints out ' \
|
38
|
+
'the full line-up on the team.'
|
39
|
+
c.example 'description', 'mlb pitchers 11 | grep "Edwin Jackson"'
|
40
|
+
c.option '--date STRING', String, 'List pitchers for specified date (Default: today)'
|
41
|
+
c.action do |args, options|
|
42
|
+
options.default :date => Time.now.to_date.to_s
|
43
|
+
|
44
|
+
# Validate input
|
45
|
+
if (Float(args.first) rescue nil).nil?
|
46
|
+
puts "Error: Game number must be a valid integer"
|
47
|
+
break
|
48
|
+
elsif (args.first.to_i < 0)
|
49
|
+
puts "Error: Game number must be greater than or equal to 0"
|
50
|
+
break
|
51
|
+
end
|
52
|
+
|
53
|
+
game_number = args.first.to_i
|
54
|
+
|
55
|
+
gameday_id = MLBTerminal::Game.list(Date.parse options.date)[game_number][:game_id]
|
56
|
+
|
57
|
+
MLBTerminal::Pitcher.list(gameday_id).each_pair do |pitcher_id, pitcher_info|
|
58
|
+
puts [
|
59
|
+
pitcher_info[:team],
|
60
|
+
pitcher_id,
|
61
|
+
pitcher_info[:name]].join("\t")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
command :pitcher do |c|
|
67
|
+
c.syntax = 'mlb pitcher [options] [game-number] [pitcher-id]'
|
68
|
+
c.summary = 'Print out a list of summary statistics for pitcher tendencies.'
|
69
|
+
c.description = 'Print out a tab-seperated value list to STDOUT wih columns ' \
|
70
|
+
'for pitcher name, pitcher team, date, away team, home team, ' \
|
71
|
+
'pitch count, average speed, pitch type, pitch count, average ' \
|
72
|
+
'movement, pfx, velocity, average initial x-position, and ' \
|
73
|
+
'average initial z-position.'
|
74
|
+
c.example 'description', 'mlb pitchers --date 2012-09-30 11 | grep "Ross Detwiler" ' \
|
75
|
+
'| cut -f 2 | xargs mlb pitcher --date 2012-09-30 11'
|
76
|
+
c.option '--date STRING', String, 'List pitchers for specified date (Default: today)'
|
77
|
+
c.action do |args, options|
|
78
|
+
game_number, pitcher_id = args
|
79
|
+
options.default :date => Time.now.to_date.to_s
|
80
|
+
|
81
|
+
# Validate input
|
82
|
+
if (Float(game_number) rescue nil).nil?
|
83
|
+
puts "Error: Game number must be a valid integer"
|
84
|
+
break
|
85
|
+
elsif (game_number.to_i < 0)
|
86
|
+
puts "Error: Game number must be greater than or equal to 0"
|
87
|
+
break
|
88
|
+
end
|
89
|
+
|
90
|
+
if (Float(pitcher_id) rescue nil).nil?
|
91
|
+
puts "Error: Pitcher ID must be a valid integer"
|
92
|
+
break
|
93
|
+
elsif (pitcher_id.to_i < 0)
|
94
|
+
puts "Error: Pitcher ID must be greater than or equal to 0"
|
95
|
+
break
|
96
|
+
end
|
97
|
+
|
98
|
+
game_number = game_number.to_i
|
99
|
+
games = MLBTerminal::Game.list(Date.parse options.date)
|
100
|
+
gameday_id = games[game_number][:game_id]
|
101
|
+
pitcher = MLBTerminal::Pitcher.new(gameday_id, pitcher_id)
|
102
|
+
|
103
|
+
pitcher.pitch_tendency_history.each do |game|
|
104
|
+
game_info = MLBTerminal::Game.parse_gameday_id(game[:gameday_id])
|
105
|
+
puts [
|
106
|
+
game[:pitcher_name],
|
107
|
+
game[:pitcher_team],
|
108
|
+
Date.new(game_info[:year].to_i, game_info[:month].to_i, game_info[:day].to_i),
|
109
|
+
MLBTerminal::TEAMS[game_info[:away_team].to_sym],
|
110
|
+
MLBTerminal::TEAMS[game_info[:home_team].to_sym],
|
111
|
+
game[:pitch_count],
|
112
|
+
game[:avg_speed],
|
113
|
+
game[:pitch_type],
|
114
|
+
game[:pitch_number],
|
115
|
+
game[:movement],
|
116
|
+
game[:pfx],
|
117
|
+
game[:vel],
|
118
|
+
game[:avg_x0],
|
119
|
+
game[:avg_z0]].join("\t")
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
33
124
|
command :game do |c|
|
34
125
|
c.syntax = 'mlb game [options] [game-number]'
|
35
126
|
c.summary = 'Print game events'
|
data/lib/mlb_terminal.rb
CHANGED
data/lib/mlb_terminal/game.rb
CHANGED
@@ -4,7 +4,6 @@ require 'open-uri'
|
|
4
4
|
require 'active_support/core_ext/integer/inflections'
|
5
5
|
|
6
6
|
module MLBTerminal
|
7
|
-
MLB_BASE_URL = 'http://gd2.mlb.com/components/game/mlb'
|
8
7
|
|
9
8
|
class Game
|
10
9
|
def self.list(date = Time.now.to_date)
|
@@ -31,9 +30,7 @@ module MLBTerminal
|
|
31
30
|
end
|
32
31
|
|
33
32
|
def initialize(gameday)
|
34
|
-
@
|
35
|
-
year, month, day, game_name = /([0-9]{4})_([0-9]{2})_([0-9]{2})_(.*)/.match(@gameday).to_a.slice(1,4)
|
36
|
-
@base_url = "#{Game.base_url_for_date(Date.new(year.to_i, month.to_i, day.to_i))}/gid_#{@gameday}"
|
33
|
+
@base_url = Game.parse_gameday_id_to_url gameday
|
37
34
|
end
|
38
35
|
|
39
36
|
def events(delay = 5, &block)
|
@@ -59,9 +56,8 @@ module MLBTerminal
|
|
59
56
|
|
60
57
|
last_atbat = doc.xpath("//game/inning/*/atbat/@num").map(&:value).map(&:to_i).max
|
61
58
|
|
62
|
-
sleep delay
|
63
|
-
|
64
59
|
if doc.xpath("//game").first["ind"] != "F"
|
60
|
+
sleep delay
|
65
61
|
doc = Nokogiri::HTML(open "#{@base_url}/inning/inning_all.xml")
|
66
62
|
end
|
67
63
|
end while game_status != "F"
|
@@ -125,9 +121,8 @@ module MLBTerminal
|
|
125
121
|
|
126
122
|
last_pitch = doc.xpath("//game/inning/*/*/pitch/@id").map(&:value).map(&:to_i).max
|
127
123
|
|
128
|
-
sleep delay
|
129
|
-
|
130
124
|
if doc.xpath("//game").first["ind"] != "F"
|
125
|
+
sleep delay
|
131
126
|
doc = Nokogiri::HTML(open "#{@base_url}/inning/inning_all.xml")
|
132
127
|
end
|
133
128
|
end while game_status != "F"
|
@@ -138,6 +133,21 @@ module MLBTerminal
|
|
138
133
|
"#{MLB_BASE_URL}/year_#{date.year}/month_#{"%02d" % date.month}/day_#{"%02d" % date.day}"
|
139
134
|
end
|
140
135
|
|
136
|
+
def self.parse_gameday_id_to_url(gameday)
|
137
|
+
game_info = Game.parse_gameday_id gameday
|
138
|
+
"#{Game.base_url_for_date(Date.new(game_info[:year].to_i, game_info[:month].to_i, game_info[:day].to_i))}/gid_" \
|
139
|
+
"#{game_info[:year]}_" \
|
140
|
+
"#{game_info[:month]}_" \
|
141
|
+
"#{game_info[:day]}_" \
|
142
|
+
"#{game_info[:away_team]}mlb_" \
|
143
|
+
"#{game_info[:home_team]}mlb_" \
|
144
|
+
"#{game_info[:game_number]}"
|
145
|
+
end
|
146
|
+
|
147
|
+
def self.parse_gameday_id(gameday)
|
148
|
+
Hash[[:year, :month, :day, :away_team, :home_team, :game_number].zip(/[gid_]*([0-9]{4})_([0-9]{2})_([0-9]{2})_([a-z]{3})mlb_([a-z]{3})mlb_([0-9])/.match(gameday).to_a.slice(1,6))]
|
149
|
+
end
|
150
|
+
|
141
151
|
private
|
142
152
|
|
143
153
|
def player_lookup
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module MLBTerminal
|
2
|
+
|
3
|
+
MLB_BASE_URL = 'http://gd2.mlb.com/components/game/mlb'
|
4
|
+
|
5
|
+
TEAMS = {
|
6
|
+
:ana => "Los Angeles Angels",
|
7
|
+
:ari => "Arizona Diamondbacks",
|
8
|
+
:atl => "Atlanta Braves",
|
9
|
+
:bal => "Baltimore Orioles",
|
10
|
+
:bos => "Boston Red Sox",
|
11
|
+
:cha => "Chicago White Sox",
|
12
|
+
:chn => "Chicago Cubs",
|
13
|
+
:cin => "Cincinnati Reds",
|
14
|
+
:cle => "Cleveland Indians",
|
15
|
+
:col => "Colorado Rockies",
|
16
|
+
:det => "Detroit Tigers",
|
17
|
+
:hou => "Houston Astros",
|
18
|
+
:kca => "Kansas City Royals",
|
19
|
+
:lan => "Los Angeles Dodgers",
|
20
|
+
:mia => "Miami Marlins",
|
21
|
+
:mil => "Milwaukee Brewers",
|
22
|
+
:min => "Minnesota Twins",
|
23
|
+
:nya => "New York Yankees",
|
24
|
+
:nyn => "New York Mets",
|
25
|
+
:oak => "Oakland Athletics",
|
26
|
+
:phi => "Philadelphia Phillies",
|
27
|
+
:pit => "Pittsburgh Pirates",
|
28
|
+
:sdn => "San Diego Padres",
|
29
|
+
:sea => "Seattle Mariners",
|
30
|
+
:sfn => "San Francisco Giants",
|
31
|
+
:sln => "Saint Louis Cardinals",
|
32
|
+
:tba => "Tampa Bay Rays",
|
33
|
+
:tex => "Texas Rangers",
|
34
|
+
:tor => "Toronto Blue Jays",
|
35
|
+
:was => "Washington Nationals"}
|
36
|
+
|
37
|
+
PITCH_TYPES = {
|
38
|
+
"FA" => "Fastball",
|
39
|
+
"FF" => "Four-seam Fastball",
|
40
|
+
"FT" => "Two-seam Fastball",
|
41
|
+
"FC" => "Fastball / Cutter",
|
42
|
+
"FS" => "Fastball / Sinker",
|
43
|
+
"SI" => "Sinker",
|
44
|
+
"SF" => "Split-Fingered Fastball",
|
45
|
+
"SL" => "Slider",
|
46
|
+
"CH" => "Changeup",
|
47
|
+
"CB" => "Curveball",
|
48
|
+
"CU" => "Curveball",
|
49
|
+
"KC" => "Kunckle-curve",
|
50
|
+
"KN" => "Kunckleball",
|
51
|
+
"EP" => "Eephus",
|
52
|
+
"UN" => "Unidentified",
|
53
|
+
"XX" => "Unidentified",
|
54
|
+
"PO" => "Pitch out",
|
55
|
+
"FO" => "Pitch out"}
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'open-uri'
|
3
|
+
|
4
|
+
module MLBTerminal
|
5
|
+
class Pitcher
|
6
|
+
|
7
|
+
def self.list(gameday)
|
8
|
+
base_url = MLBTerminal::Game.parse_gameday_id_to_url gameday
|
9
|
+
doc = Nokogiri::HTML(open( "#{base_url}/players.xml"))
|
10
|
+
Hash[doc.xpath("//game/team/player[@position='P']").map{|x| [x["id"], {:team => x.xpath("..").first["name"], :name => "#{x["first"]} #{x["last"]}"}]}]
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(gameday, pitcher_id)
|
14
|
+
@base_url = "#{MLBTerminal::Game.parse_gameday_id_to_url gameday}/premium/pitchers/#{pitcher_id}"
|
15
|
+
pitcher = Pitcher.list(gameday)[pitcher_id]
|
16
|
+
@team = pitcher[:team]
|
17
|
+
@name = pitcher[:name]
|
18
|
+
end
|
19
|
+
|
20
|
+
def pitch_tendency_history(&block)
|
21
|
+
doc = Nokogiri::HTML(open( "#{@base_url}/pitchtendencies_history.xml"))
|
22
|
+
|
23
|
+
Enumerator.new do |y|
|
24
|
+
doc.xpath("//pitchtendencies/games/game").each do |game|
|
25
|
+
game.xpath("types/type").each do |type|
|
26
|
+
y.yield({
|
27
|
+
:pitcher_name => @name,
|
28
|
+
:pitcher_team => @team,
|
29
|
+
:gameday_id => game["id"],
|
30
|
+
:pitch_count => game["num"],
|
31
|
+
:avg_speed => game["vel"],
|
32
|
+
:pitch_type => PITCH_TYPES[type["id"]],
|
33
|
+
:pitch_number => type["num"],
|
34
|
+
:movement => type["movement"],
|
35
|
+
:pfx => type["pfx"],
|
36
|
+
:vel => type["vel"],
|
37
|
+
:avg_x0 => type["avg_x0"],
|
38
|
+
:avg_z0 => type["avg_z0"] })
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end.each(&block)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/mlb_terminal/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mlb_terminal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-10-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: commander
|
@@ -77,6 +77,8 @@ files:
|
|
77
77
|
- bin/mlb
|
78
78
|
- lib/mlb_terminal.rb
|
79
79
|
- lib/mlb_terminal/game.rb
|
80
|
+
- lib/mlb_terminal/globals.rb
|
81
|
+
- lib/mlb_terminal/pitcher.rb
|
80
82
|
- lib/mlb_terminal/version.rb
|
81
83
|
- mlb_terminal.gemspec
|
82
84
|
homepage: https://github.com/slnovak/mlb_terminal
|