From 796acb41a877b7617bfb3992f9874d0f2b5f1852 Mon Sep 17 00:00:00 2001 From: Alex Bolduc Date: Wed, 1 Mar 2023 23:05:32 -0500 Subject: [PATCH 01/19] Show both boxscores, add hr count --- api/src/boxscore.rs | 2 +- src/boxscore.rs | 3 +++ src/draw.rs | 11 +++++++++-- src/main.rs | 2 +- src/schedule.rs | 7 +++---- src/ui/boxscore.rs | 2 +- src/ui/layout.rs | 3 ++- src/ui/schedule.rs | 2 +- 8 files changed, 21 insertions(+), 11 deletions(-) diff --git a/api/src/boxscore.rs b/api/src/boxscore.rs index 69498d0..d020dbe 100644 --- a/api/src/boxscore.rs +++ b/api/src/boxscore.rs @@ -66,7 +66,7 @@ pub struct Batting { pub runs: Option, doubles: Option, triples: Option, - home_runs: Option, + pub home_runs: Option, pub strike_outs: Option, pub base_on_balls: Option, pub hits: Option, diff --git a/src/boxscore.rs b/src/boxscore.rs index 7d77e92..8ced948 100644 --- a/src/boxscore.rs +++ b/src/boxscore.rs @@ -13,6 +13,7 @@ pub struct BatterBoxscore { rbis: u16, walks: u16, strike_outs: u16, + home_runs: u16, left_on: u16, batting_average: String, } @@ -29,6 +30,7 @@ impl BatterBoxscore { rbis: player.stats.batting.rbi.unwrap_or(0), walks: player.stats.batting.base_on_balls.unwrap_or(0), strike_outs: player.stats.batting.strike_outs.unwrap_or(0), + home_runs: player.stats.batting.home_runs.unwrap_or(0), left_on: player.stats.batting.left_on_base.unwrap_or(0), batting_average: player .season_stats @@ -53,6 +55,7 @@ impl BatterBoxscore { self.rbis.to_string(), self.walks.to_string(), self.strike_outs.to_string(), + self.home_runs.to_string(), self.left_on.to_string(), self.batting_average.to_string(), ] diff --git a/src/draw.rs b/src/draw.rs index 48d7b01..80ddbb8 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -5,7 +5,7 @@ use tui::text::{Span, Spans}; use tui::widgets::{Block, BorderType, Borders, Clear, Paragraph, Tabs}; use tui::{Frame, Terminal}; -use crate::app::{App, DebugState, MenuItem}; +use crate::app::{App, DebugState, MenuItem, HomeOrAway}; use crate::debug::DebugInfo; use crate::ui::at_bat::AtBatWidget; use crate::ui::boxscore::TeamBatterBoxscoreWidget; @@ -160,11 +160,18 @@ where ); f.render_stateful_widget( TeamBatterBoxscoreWidget { - active: app.boxscore_tab, + active: HomeOrAway::Away }, chunks[1], &mut app.live_game.boxscore, ); + f.render_stateful_widget( + TeamBatterBoxscoreWidget { + active: HomeOrAway::Home + }, + chunks[2], + &mut app.live_game.boxscore + ); } fn draw_date_picker(f: &mut Frame, rect: Rect, app: &mut App) diff --git a/src/main.rs b/src/main.rs index ed42b82..a60d70c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,7 +35,7 @@ use crossterm::{cursor, execute, terminal}; use lazy_static::lazy_static; use tui::{backend::CrosstermBackend, Terminal}; -const UPDATE_INTERVAL: u64 = 10; // seconds +const UPDATE_INTERVAL: u64 = 5; // seconds lazy_static! { static ref CLIENT: MLBApi = MLBApiBuilder::default().build().unwrap(); pub static ref REDRAW_REQUEST: (Sender<()>, Receiver<()>) = bounded(1); diff --git a/src/schedule.rs b/src/schedule.rs index 5d44597..4159aa2 100644 --- a/src/schedule.rs +++ b/src/schedule.rs @@ -2,8 +2,7 @@ use mlb_api::schedule::{Game, ScheduleResponse}; use crate::app::HomeOrAway; -use chrono::{DateTime, Datelike, NaiveDate, ParseError, Utc}; -use chrono_tz::America::Los_Angeles; +use chrono::{DateTime, Datelike, NaiveDate, ParseError, Utc, Local}; use core::option::Option::{None, Some}; use lazy_static::lazy_static; use tui::widgets::TableState; @@ -52,7 +51,7 @@ impl ScheduleState { self.date = match date.as_str() { "today" => { // TODO configurable timezone - let today = Utc::now().with_timezone(&Los_Angeles); + let today = Utc::now().with_timezone(&Local); NaiveDate::from_ymd(today.year(), today.month(), today.day()) } _ => NaiveDate::parse_from_str(date.as_str(), "%Y-%m-%d")?, @@ -139,7 +138,7 @@ impl ScheduleRow { // TODO let timezone be configurable let datetime = DateTime::parse_from_rfc3339(&game.game_date) .unwrap() - .with_timezone(&Los_Angeles); + .with_timezone(&Local); let start_time = datetime.format("%l:%M %P").to_string(); let game_status = match &game.status.detailed_state { diff --git a/src/ui/boxscore.rs b/src/ui/boxscore.rs index 4e0ee71..5a58c35 100644 --- a/src/ui/boxscore.rs +++ b/src/ui/boxscore.rs @@ -8,7 +8,7 @@ use tui::{ widgets::{Block, Borders, Cell, Row, StatefulWidget, Table, Widget}, }; -const HEADER: [&str; 9] = ["player", "ab", "r", "h", "rbi", "bb", "so", "lob", "avg"]; +const HEADER: [&str; 10] = ["player", "ab", "r", "h", "rbi", "bb", "so", "hr", "lob", "avg"]; pub struct TeamBatterBoxscoreWidget { pub active: HomeOrAway, diff --git a/src/ui/layout.rs b/src/ui/layout.rs index d8b10f5..d18c010 100644 --- a/src/ui/layout.rs +++ b/src/ui/layout.rs @@ -62,7 +62,8 @@ impl LayoutAreas { .constraints( [ Constraint::Length(4), // line score - Constraint::Percentage(100), // box score + Constraint::Percentage(50), // box score + Constraint::Percentage(50), // box score ] .as_ref(), ) diff --git a/src/ui/schedule.rs b/src/ui/schedule.rs index e4c41ef..bbd1bbf 100644 --- a/src/ui/schedule.rs +++ b/src/ui/schedule.rs @@ -9,7 +9,7 @@ use tui::{ widgets::{Block, BorderType, Borders, Cell, Row, StatefulWidget, Table}, }; -const HEADER: &[&str; 6] = &["away", "", "home", "", "time [PST]", "status"]; +const HEADER: &[&str; 6] = &["away", "", "home", "", "time [EST]", "status"]; pub struct ScheduleWidget {} From e3ae0d54d8076f0f7cb16a00bb3fbfb6c901aa00 Mon Sep 17 00:00:00 2001 From: Alex Bolduc Date: Wed, 1 Mar 2023 23:05:52 -0500 Subject: [PATCH 02/19] Add abilty to get stats on date in api --- api/src/client.rs | 22 + api/tests/client.rs | 43 + api/tests/responses/player-stats-date.json | 3519 ++++++++++++++++++++ api/tests/responses/team-stats-date.json | 1278 +++++++ 4 files changed, 4862 insertions(+) create mode 100644 api/tests/responses/player-stats-date.json create mode 100644 api/tests/responses/team-stats-date.json diff --git a/api/src/client.rs b/api/src/client.rs index 0ecb124..ab7bcd8 100644 --- a/api/src/client.rs +++ b/api/src/client.rs @@ -92,6 +92,17 @@ impl MLBApi { self.get(url) } + pub fn get_team_stats_on_date(&self, group: StatGroup, date: NaiveDate) -> StatResponse { + let url = format!( + "{}v1/teams/stats?sportId=1&stats=byDateRange&season={}&endDate={}&group={}", + self.base_url, + date.year(), + date.format("%Y-%m-%d"), + group + ); + self.get(url) + } + pub fn get_player_stats(&self, group: StatGroup) -> StatResponse { let local: DateTime = Local::now(); let url = format!( @@ -103,6 +114,17 @@ impl MLBApi { self.get(url) } + pub fn get_player_stats_on_date(&self, group: StatGroup, date: NaiveDate) -> StatResponse { + let url = format!( + "{}v1/stats?stats=byDateRange&season={}&endDate={}&group={}", + self.base_url, + date.year(), + date.format("%Y-%m-%d"), + group + ); + self.get(url) + } + // TODO need better error handling, especially on parsing fn get(&self, url: String) -> T { let response = self.client.get(url).send().unwrap_or_else(|err| { diff --git a/api/tests/client.rs b/api/tests/client.rs index da6c4d4..d3ea8e8 100644 --- a/api/tests/client.rs +++ b/api/tests/client.rs @@ -74,6 +74,27 @@ mod tests { } } + #[test] + fn test_team_stats_on_date() { + let client = MLBApiBuilder::default().build().unwrap(); + let date: NaiveDate = NaiveDate::from_ymd(2022, 07, 09); + for group in vec![StatGroup::Hitting, StatGroup::Pitching] { + let url = format!( + "v1/teams/stats?sportId=1&stats=byDateRange&season=2022&endDate=2022-07-09&group={}", + group + ); + + let _m = mock("GET", Matcher::Exact(url)) + .with_status(200) + .with_header("content-type", "application/json;charset=UTF-8") + .with_body_from_file("./tests/responses/team-stats-date.json") + .create(); + + let resp = client.get_team_stats_on_date(group, date); + println!("{:?}", resp); + } + } + #[test] fn test_player_stats() { let client = MLBApiBuilder::default().build().unwrap(); @@ -90,4 +111,26 @@ mod tests { println!("{:?}", resp); } } + + #[test] + fn test_player_stats_on_date() { + let client = MLBApiBuilder::default().build().unwrap(); + let date: NaiveDate = NaiveDate::from_ymd(2022, 07, 09); + for group in vec![StatGroup::Hitting, StatGroup::Pitching] { + let url = format!( + "v1/stats?sportId=1&stats=byDateRange&season=2022&endDate=2022-07-09&group={}", + group + ); + + let _m = mock("GET", Matcher::Exact(url)) + .with_status(200) + .with_header("content-type", "application/json;charset=UTF-8") + .with_body_from_file("./tests/responses/player-stats-date.json") + .create(); + + let resp = client.get_player_stats_on_date(group, date); + println!("{:?}", resp); + } + } + } diff --git a/api/tests/responses/player-stats-date.json b/api/tests/responses/player-stats-date.json new file mode 100644 index 0000000..fd35665 --- /dev/null +++ b/api/tests/responses/player-stats-date.json @@ -0,0 +1,3519 @@ +{ + "copyright": "Copyright 2023 MLB Advanced Media, L.P. Use of any content on this page acknowledges agreement to the terms posted here http://gdx.mlb.com/components/copyright.txt", + "stats": [ + { + "type": { + "displayName": "byDateRange" + }, + "group": { + "displayName": "hitting" + }, + "totalSplits": 146, + "exemptions": [], + "splits": [ + { + "season": "2022", + "stat": { + "gamesPlayed": 77, + "groundOuts": 85, + "airOuts": 73, + "runs": 50, + "doubles": 15, + "triples": 1, + "homeRuns": 4, + "strikeOuts": 25, + "baseOnBalls": 34, + "intentionalWalks": 1, + "hits": 100, + "hitByPitch": 2, + "avg": ".355", + "atBats": 282, + "obp": ".426", + "slg": ".457", + "ops": ".883", + "caughtStealing": 2, + "stolenBases": 2, + "stolenBasePercentage": ".500", + "groundIntoDoublePlay": 2, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1294, + "plateAppearances": 319, + "totalBases": 129, + "rbi": 29, + "leftOnBase": 83, + "sacBunts": 0, + "sacFlies": 1, + "babip": ".378", + "groundOutsToAirouts": "1.16", + "catchersInterference": 0, + "atBatsPerHomeRun": "70.50" + }, + "team": { + "id": 142, + "name": "Minnesota Twins", + "link": "/api/v1/teams/142" + }, + "player": { + "id": 650333, + "fullName": "Luis Arraez", + "link": "/api/v1/people/650333", + "firstName": "Luis", + "lastName": "Arraez" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 1, + "position": { + "code": "3", + "name": "First Base", + "type": "Infielder", + "abbreviation": "1B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 83, + "groundOuts": 60, + "airOuts": 75, + "runs": 61, + "doubles": 28, + "triples": 0, + "homeRuns": 19, + "strikeOuts": 74, + "baseOnBalls": 44, + "intentionalWalks": 1, + "hits": 107, + "hitByPitch": 2, + "avg": ".340", + "atBats": 315, + "obp": ".423", + "slg": ".610", + "ops": "1.033", + "caughtStealing": 0, + "stolenBases": 5, + "stolenBasePercentage": "1.000", + "groundIntoDoublePlay": 3, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1487, + "plateAppearances": 364, + "totalBases": 192, + "rbi": 65, + "leftOnBase": 105, + "sacBunts": 0, + "sacFlies": 1, + "babip": ".395", + "groundOutsToAirouts": "0.80", + "catchersInterference": 2, + "atBatsPerHomeRun": "16.58" + }, + "team": { + "id": 138, + "name": "St. Louis Cardinals", + "link": "/api/v1/teams/138" + }, + "player": { + "id": 502671, + "fullName": "Paul Goldschmidt", + "link": "/api/v1/people/502671", + "firstName": "Paul", + "lastName": "Goldschmidt" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 2, + "position": { + "code": "3", + "name": "First Base", + "type": "Infielder", + "abbreviation": "1B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 80, + "groundOuts": 81, + "airOuts": 74, + "runs": 59, + "doubles": 27, + "triples": 1, + "homeRuns": 19, + "strikeOuts": 63, + "baseOnBalls": 25, + "intentionalWalks": 5, + "hits": 106, + "hitByPitch": 5, + "avg": ".327", + "atBats": 324, + "obp": ".384", + "slg": ".593", + "ops": ".977", + "caughtStealing": 1, + "stolenBases": 2, + "stolenBasePercentage": ".667", + "groundIntoDoublePlay": 6, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1249, + "plateAppearances": 354, + "totalBases": 192, + "rbi": 51, + "leftOnBase": 121, + "sacBunts": 0, + "sacFlies": 0, + "babip": ".360", + "groundOutsToAirouts": "1.09", + "catchersInterference": 0, + "atBatsPerHomeRun": "17.05" + }, + "team": { + "id": 111, + "name": "Boston Red Sox", + "link": "/api/v1/teams/111" + }, + "player": { + "id": 646240, + "fullName": "Rafael Devers", + "link": "/api/v1/people/646240", + "firstName": "Rafael", + "lastName": "Devers" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 3, + "position": { + "code": "5", + "name": "Third Base", + "type": "Infielder", + "abbreviation": "3B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 64, + "groundOuts": 57, + "airOuts": 60, + "runs": 49, + "doubles": 21, + "triples": 1, + "homeRuns": 15, + "strikeOuts": 52, + "baseOnBalls": 26, + "intentionalWalks": 4, + "hits": 77, + "hitByPitch": 3, + "avg": ".318", + "atBats": 242, + "obp": ".385", + "slg": ".599", + "ops": ".984", + "caughtStealing": 2, + "stolenBases": 9, + "stolenBasePercentage": ".818", + "groundIntoDoublePlay": 9, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1035, + "plateAppearances": 275, + "totalBases": 145, + "rbi": 48, + "leftOnBase": 93, + "sacBunts": 0, + "sacFlies": 4, + "babip": ".346", + "groundOutsToAirouts": "0.95", + "catchersInterference": 0, + "atBatsPerHomeRun": "16.13" + }, + "team": { + "id": 143, + "name": "Philadelphia Phillies", + "link": "/api/v1/teams/143" + }, + "player": { + "id": 547180, + "fullName": "Bryce Harper", + "link": "/api/v1/people/547180", + "firstName": "Bryce", + "lastName": "Harper" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 4, + "position": { + "code": "10", + "name": "Designated Hitter", + "type": "Hitter", + "abbreviation": "DH" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 82, + "groundOuts": 79, + "airOuts": 84, + "runs": 34, + "doubles": 13, + "triples": 2, + "homeRuns": 3, + "strikeOuts": 49, + "baseOnBalls": 36, + "intentionalWalks": 0, + "hits": 97, + "hitByPitch": 1, + "avg": ".317", + "atBats": 306, + "obp": ".387", + "slg": ".402", + "ops": ".789", + "caughtStealing": 2, + "stolenBases": 2, + "stolenBasePercentage": ".500", + "groundIntoDoublePlay": 6, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1304, + "plateAppearances": 346, + "totalBases": 123, + "rbi": 34, + "leftOnBase": 120, + "sacBunts": 0, + "sacFlies": 3, + "babip": ".366", + "groundOutsToAirouts": "0.94", + "catchersInterference": 0, + "atBatsPerHomeRun": "102.00" + }, + "team": { + "id": 118, + "name": "Kansas City Royals", + "link": "/api/v1/teams/118" + }, + "player": { + "id": 643217, + "fullName": "Andrew Benintendi", + "link": "/api/v1/people/643217", + "firstName": "Andrew", + "lastName": "Benintendi" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 5, + "position": { + "code": "7", + "name": "Outfielder", + "type": "Outfielder", + "abbreviation": "LF" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 76, + "groundOuts": 63, + "airOuts": 79, + "runs": 38, + "doubles": 19, + "triples": 1, + "homeRuns": 4, + "strikeOuts": 37, + "baseOnBalls": 22, + "intentionalWalks": 0, + "hits": 82, + "hitByPitch": 4, + "avg": ".315", + "atBats": 260, + "obp": ".376", + "slg": ".442", + "ops": ".818", + "caughtStealing": 0, + "stolenBases": 2, + "stolenBasePercentage": "1.000", + "groundIntoDoublePlay": 3, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1042, + "plateAppearances": 287, + "totalBases": 115, + "rbi": 35, + "leftOnBase": 111, + "sacBunts": 0, + "sacFlies": 1, + "babip": ".355", + "groundOutsToAirouts": "0.80", + "catchersInterference": 0, + "atBatsPerHomeRun": "65.00" + }, + "team": { + "id": 121, + "name": "New York Mets", + "link": "/api/v1/teams/121" + }, + "player": { + "id": 643446, + "fullName": "Jeff McNeil", + "link": "/api/v1/people/643446", + "firstName": "Jeff", + "lastName": "McNeil" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 6, + "position": { + "code": "4", + "name": "Second Base", + "type": "Infielder", + "abbreviation": "2B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 74, + "groundOuts": 59, + "airOuts": 67, + "runs": 47, + "doubles": 27, + "triples": 0, + "homeRuns": 8, + "strikeOuts": 77, + "baseOnBalls": 30, + "intentionalWalks": 1, + "hits": 91, + "hitByPitch": 4, + "avg": ".313", + "atBats": 291, + "obp": ".381", + "slg": ".488", + "ops": ".869", + "caughtStealing": 0, + "stolenBases": 0, + "stolenBasePercentage": ".---", + "groundIntoDoublePlay": 10, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1348, + "plateAppearances": 328, + "totalBases": 142, + "rbi": 34, + "leftOnBase": 144, + "sacBunts": 0, + "sacFlies": 3, + "babip": ".397", + "groundOutsToAirouts": "0.88", + "catchersInterference": 0, + "atBatsPerHomeRun": "36.38" + }, + "team": { + "id": 111, + "name": "Boston Red Sox", + "link": "/api/v1/teams/111" + }, + "player": { + "id": 502110, + "fullName": "J.D. Martinez", + "link": "/api/v1/people/502110", + "firstName": "J.D.", + "lastName": "Martinez" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 7, + "position": { + "code": "10", + "name": "Designated Hitter", + "type": "Hitter", + "abbreviation": "DH" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 75, + "groundOuts": 60, + "airOuts": 75, + "runs": 51, + "doubles": 19, + "triples": 1, + "homeRuns": 14, + "strikeOuts": 61, + "baseOnBalls": 34, + "intentionalWalks": 6, + "hits": 88, + "hitByPitch": 1, + "avg": ".311", + "atBats": 283, + "obp": ".386", + "slg": ".534", + "ops": ".920", + "caughtStealing": 1, + "stolenBases": 7, + "stolenBasePercentage": ".875", + "groundIntoDoublePlay": 5, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1150, + "plateAppearances": 319, + "totalBases": 151, + "rbi": 50, + "leftOnBase": 118, + "sacBunts": 0, + "sacFlies": 1, + "babip": ".354", + "groundOutsToAirouts": "0.80", + "catchersInterference": 0, + "atBatsPerHomeRun": "20.21" + }, + "team": { + "id": 135, + "name": "San Diego Padres", + "link": "/api/v1/teams/135" + }, + "player": { + "id": 592518, + "fullName": "Manny Machado", + "link": "/api/v1/people/592518", + "firstName": "Manny", + "lastName": "Machado" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 8, + "position": { + "code": "5", + "name": "Third Base", + "type": "Infielder", + "abbreviation": "3B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 73, + "groundOuts": 76, + "airOuts": 77, + "runs": 32, + "doubles": 15, + "triples": 0, + "homeRuns": 10, + "strikeOuts": 46, + "baseOnBalls": 21, + "intentionalWalks": 2, + "hits": 89, + "hitByPitch": 14, + "avg": ".310", + "atBats": 287, + "obp": ".384", + "slg": ".467", + "ops": ".851", + "caughtStealing": 0, + "stolenBases": 0, + "stolenBasePercentage": ".---", + "groundIntoDoublePlay": 5, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1175, + "plateAppearances": 324, + "totalBases": 134, + "rbi": 45, + "leftOnBase": 99, + "sacBunts": 0, + "sacFlies": 1, + "babip": ".341", + "groundOutsToAirouts": "0.99", + "catchersInterference": 1, + "atBatsPerHomeRun": "28.70" + }, + "team": { + "id": 136, + "name": "Seattle Mariners", + "link": "/api/v1/teams/136" + }, + "player": { + "id": 664034, + "fullName": "Ty France", + "link": "/api/v1/people/664034", + "firstName": "Ty", + "lastName": "France" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 9, + "position": { + "code": "3", + "name": "First Base", + "type": "Infielder", + "abbreviation": "1B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 76, + "groundOuts": 69, + "airOuts": 75, + "runs": 40, + "doubles": 12, + "triples": 0, + "homeRuns": 10, + "strikeOuts": 25, + "baseOnBalls": 32, + "intentionalWalks": 1, + "hits": 75, + "hitByPitch": 4, + "avg": ".310", + "atBats": 242, + "obp": ".396", + "slg": ".483", + "ops": ".879", + "caughtStealing": 0, + "stolenBases": 0, + "stolenBasePercentage": ".---", + "groundIntoDoublePlay": 7, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1131, + "plateAppearances": 280, + "totalBases": 117, + "rbi": 33, + "leftOnBase": 91, + "sacBunts": 0, + "sacFlies": 2, + "babip": ".311", + "groundOutsToAirouts": "0.92", + "catchersInterference": 0, + "atBatsPerHomeRun": "24.20" + }, + "team": { + "id": 141, + "name": "Toronto Blue Jays", + "link": "/api/v1/teams/141" + }, + "player": { + "id": 672386, + "fullName": "Alejandro Kirk", + "link": "/api/v1/people/672386", + "firstName": "Alejandro", + "lastName": "Kirk" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 10, + "position": { + "code": "2", + "name": "Catcher", + "type": "Catcher", + "abbreviation": "C" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 81, + "groundOuts": 68, + "airOuts": 75, + "runs": 49, + "doubles": 21, + "triples": 0, + "homeRuns": 7, + "strikeOuts": 69, + "baseOnBalls": 34, + "intentionalWalks": 2, + "hits": 93, + "hitByPitch": 6, + "avg": ".309", + "atBats": 301, + "obp": ".386", + "slg": ".449", + "ops": ".835", + "caughtStealing": 0, + "stolenBases": 3, + "stolenBasePercentage": "1.000", + "groundIntoDoublePlay": 7, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1368, + "plateAppearances": 345, + "totalBases": 135, + "rbi": 35, + "leftOnBase": 145, + "sacBunts": 0, + "sacFlies": 4, + "babip": ".376", + "groundOutsToAirouts": "0.91", + "catchersInterference": 0, + "atBatsPerHomeRun": "43.00" + }, + "team": { + "id": 111, + "name": "Boston Red Sox", + "link": "/api/v1/teams/111" + }, + "player": { + "id": 593428, + "fullName": "Xander Bogaerts", + "link": "/api/v1/people/593428", + "firstName": "Xander", + "lastName": "Bogaerts" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 11, + "position": { + "code": "6", + "name": "Shortstop", + "type": "Infielder", + "abbreviation": "SS" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 86, + "groundOuts": 98, + "airOuts": 74, + "runs": 44, + "doubles": 19, + "triples": 2, + "homeRuns": 12, + "strikeOuts": 48, + "baseOnBalls": 39, + "intentionalWalks": 3, + "hits": 96, + "hitByPitch": 5, + "avg": ".308", + "atBats": 312, + "obp": ".389", + "slg": ".497", + "ops": ".886", + "caughtStealing": 1, + "stolenBases": 0, + "stolenBasePercentage": ".000", + "groundIntoDoublePlay": 15, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1314, + "plateAppearances": 362, + "totalBases": 155, + "rbi": 47, + "leftOnBase": 138, + "sacBunts": 0, + "sacFlies": 4, + "babip": ".328", + "groundOutsToAirouts": "1.32", + "catchersInterference": 2, + "atBatsPerHomeRun": "26.00" + }, + "team": { + "id": 120, + "name": "Washington Nationals", + "link": "/api/v1/teams/120" + }, + "player": { + "id": 605137, + "fullName": "Josh Bell", + "link": "/api/v1/people/605137", + "firstName": "Josh", + "lastName": "Bell" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 12, + "position": { + "code": "3", + "name": "First Base", + "type": "Infielder", + "abbreviation": "1B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 75, + "groundOuts": 69, + "airOuts": 62, + "runs": 57, + "doubles": 11, + "triples": 2, + "homeRuns": 26, + "strikeOuts": 57, + "baseOnBalls": 43, + "intentionalWalks": 4, + "hits": 82, + "hitByPitch": 3, + "avg": ".306", + "atBats": 268, + "obp": ".405", + "slg": ".653", + "ops": "1.058", + "caughtStealing": 1, + "stolenBases": 0, + "stolenBasePercentage": ".000", + "groundIntoDoublePlay": 7, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1252, + "plateAppearances": 316, + "totalBases": 175, + "rbi": 60, + "leftOnBase": 137, + "sacBunts": 0, + "sacFlies": 2, + "babip": ".299", + "groundOutsToAirouts": "1.11", + "catchersInterference": 0, + "atBatsPerHomeRun": "10.31" + }, + "team": { + "id": 117, + "name": "Houston Astros", + "link": "/api/v1/teams/117" + }, + "player": { + "id": 670541, + "fullName": "Yordan Alvarez", + "link": "/api/v1/people/670541", + "firstName": "Yordan", + "lastName": "Alvarez" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 13, + "position": { + "code": "10", + "name": "Designated Hitter", + "type": "Hitter", + "abbreviation": "DH" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 74, + "groundOuts": 66, + "airOuts": 52, + "runs": 27, + "doubles": 20, + "triples": 1, + "homeRuns": 7, + "strikeOuts": 73, + "baseOnBalls": 25, + "intentionalWalks": 0, + "hits": 81, + "hitByPitch": 6, + "avg": ".303", + "atBats": 267, + "obp": ".370", + "slg": ".464", + "ops": ".834", + "caughtStealing": 0, + "stolenBases": 0, + "stolenBasePercentage": ".---", + "groundIntoDoublePlay": 2, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1209, + "plateAppearances": 303, + "totalBases": 124, + "rbi": 40, + "leftOnBase": 74, + "sacBunts": 0, + "sacFlies": 5, + "babip": ".385", + "groundOutsToAirouts": "1.27", + "catchersInterference": 0, + "atBatsPerHomeRun": "38.14" + }, + "team": { + "id": 146, + "name": "Miami Marlins", + "link": "/api/v1/teams/146" + }, + "player": { + "id": 643265, + "fullName": "Garrett Cooper", + "link": "/api/v1/people/643265", + "firstName": "Garrett", + "lastName": "Cooper" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 14, + "position": { + "code": "3", + "name": "First Base", + "type": "Infielder", + "abbreviation": "1B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 72, + "groundOuts": 73, + "airOuts": 42, + "runs": 18, + "doubles": 7, + "triples": 0, + "homeRuns": 3, + "strikeOuts": 71, + "baseOnBalls": 15, + "intentionalWalks": 2, + "hits": 78, + "hitByPitch": 2, + "avg": ".300", + "atBats": 260, + "obp": ".338", + "slg": ".362", + "ops": ".700", + "caughtStealing": 0, + "stolenBases": 0, + "stolenBasePercentage": ".---", + "groundIntoDoublePlay": 5, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1045, + "plateAppearances": 281, + "totalBases": 94, + "rbi": 31, + "leftOnBase": 85, + "sacBunts": 0, + "sacFlies": 4, + "babip": ".395", + "groundOutsToAirouts": "1.74", + "catchersInterference": 0, + "atBatsPerHomeRun": "86.67" + }, + "team": { + "id": 116, + "name": "Detroit Tigers", + "link": "/api/v1/teams/116" + }, + "player": { + "id": 408234, + "fullName": "Miguel Cabrera", + "link": "/api/v1/people/408234", + "firstName": "Miguel", + "lastName": "Cabrera" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 15, + "position": { + "code": "10", + "name": "Designated Hitter", + "type": "Hitter", + "abbreviation": "DH" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 84, + "groundOuts": 80, + "airOuts": 86, + "runs": 45, + "doubles": 22, + "triples": 2, + "homeRuns": 11, + "strikeOuts": 74, + "baseOnBalls": 26, + "intentionalWalks": 1, + "hits": 101, + "hitByPitch": 2, + "avg": ".300", + "atBats": 337, + "obp": ".350", + "slg": ".475", + "ops": ".825", + "caughtStealing": 2, + "stolenBases": 16, + "stolenBasePercentage": ".889", + "groundIntoDoublePlay": 6, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1429, + "plateAppearances": 370, + "totalBases": 160, + "rbi": 59, + "leftOnBase": 146, + "sacBunts": 0, + "sacFlies": 4, + "babip": ".352", + "groundOutsToAirouts": "0.93", + "catchersInterference": 1, + "atBatsPerHomeRun": "30.64" + }, + "team": { + "id": 119, + "name": "Los Angeles Dodgers", + "link": "/api/v1/teams/119" + }, + "player": { + "id": 607208, + "fullName": "Trea Turner", + "link": "/api/v1/people/607208", + "firstName": "Trea", + "lastName": "Turner" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 16, + "position": { + "code": "6", + "name": "Shortstop", + "type": "Infielder", + "abbreviation": "SS" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 77, + "groundOuts": 64, + "airOuts": 79, + "runs": 34, + "doubles": 21, + "triples": 0, + "homeRuns": 5, + "strikeOuts": 53, + "baseOnBalls": 19, + "intentionalWalks": 1, + "hits": 83, + "hitByPitch": 5, + "avg": ".300", + "atBats": 277, + "obp": ".353", + "slg": ".430", + "ops": ".783", + "caughtStealing": 1, + "stolenBases": 3, + "stolenBasePercentage": ".750", + "groundIntoDoublePlay": 6, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1132, + "plateAppearances": 303, + "totalBases": 119, + "rbi": 35, + "leftOnBase": 105, + "sacBunts": 0, + "sacFlies": 2, + "babip": ".353", + "groundOutsToAirouts": "0.81", + "catchersInterference": 0, + "atBatsPerHomeRun": "55.40" + }, + "team": { + "id": 141, + "name": "Toronto Blue Jays", + "link": "/api/v1/teams/141" + }, + "player": { + "id": 666971, + "fullName": "Lourdes Gurriel Jr.", + "link": "/api/v1/people/666971", + "firstName": "Lourdes", + "lastName": "Gurriel" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 17, + "position": { + "code": "7", + "name": "Outfielder", + "type": "Outfielder", + "abbreviation": "LF" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 76, + "groundOuts": 62, + "airOuts": 61, + "runs": 41, + "doubles": 12, + "triples": 4, + "homeRuns": 3, + "strikeOuts": 50, + "baseOnBalls": 28, + "intentionalWalks": 0, + "hits": 73, + "hitByPitch": 0, + "avg": ".299", + "atBats": 244, + "obp": ".369", + "slg": ".418", + "ops": ".787", + "caughtStealing": 2, + "stolenBases": 5, + "stolenBasePercentage": ".714", + "groundIntoDoublePlay": 0, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1072, + "plateAppearances": 274, + "totalBases": 102, + "rbi": 19, + "leftOnBase": 105, + "sacBunts": 0, + "sacFlies": 2, + "babip": ".363", + "groundOutsToAirouts": "1.02", + "catchersInterference": 0, + "atBatsPerHomeRun": "81.33" + }, + "team": { + "id": 119, + "name": "Los Angeles Dodgers", + "link": "/api/v1/teams/119" + }, + "player": { + "id": 666158, + "fullName": "Gavin Lux", + "link": "/api/v1/people/666158", + "firstName": "Gavin", + "lastName": "Lux" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 18, + "position": { + "code": "4", + "name": "Second Base", + "type": "Infielder", + "abbreviation": "2B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 86, + "groundOuts": 51, + "airOuts": 84, + "runs": 52, + "doubles": 18, + "triples": 1, + "homeRuns": 14, + "strikeOuts": 96, + "baseOnBalls": 26, + "intentionalWalks": 0, + "hits": 98, + "hitByPitch": 3, + "avg": ".299", + "atBats": 328, + "obp": ".355", + "slg": ".488", + "ops": ".843", + "caughtStealing": 3, + "stolenBases": 14, + "stolenBasePercentage": ".824", + "groundIntoDoublePlay": 5, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1435, + "plateAppearances": 358, + "totalBases": 160, + "rbi": 50, + "leftOnBase": 103, + "sacBunts": 0, + "sacFlies": 1, + "babip": ".384", + "groundOutsToAirouts": "0.61", + "catchersInterference": 0, + "atBatsPerHomeRun": "23.43" + }, + "team": { + "id": 144, + "name": "Atlanta Braves", + "link": "/api/v1/teams/144" + }, + "player": { + "id": 621020, + "fullName": "Dansby Swanson", + "link": "/api/v1/people/621020", + "firstName": "Dansby", + "lastName": "Swanson" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 19, + "position": { + "code": "6", + "name": "Shortstop", + "type": "Infielder", + "abbreviation": "SS" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 70, + "groundOuts": 81, + "airOuts": 71, + "runs": 26, + "doubles": 18, + "triples": 0, + "homeRuns": 2, + "strikeOuts": 28, + "baseOnBalls": 11, + "intentionalWalks": 0, + "hits": 76, + "hitByPitch": 5, + "avg": ".297", + "atBats": 256, + "obp": ".338", + "slg": ".391", + "ops": ".729", + "caughtStealing": 3, + "stolenBases": 2, + "stolenBasePercentage": ".400", + "groundIntoDoublePlay": 8, + "groundIntoTriplePlay": 0, + "numberOfPitches": 972, + "plateAppearances": 272, + "totalBases": 100, + "rbi": 23, + "leftOnBase": 110, + "sacBunts": 0, + "sacFlies": 0, + "babip": ".327", + "groundOutsToAirouts": "1.14", + "catchersInterference": 0, + "atBatsPerHomeRun": "128.00" + }, + "team": { + "id": 115, + "name": "Colorado Rockies", + "link": "/api/v1/teams/115" + }, + "player": { + "id": 578428, + "fullName": "Jose Iglesias", + "link": "/api/v1/people/578428", + "firstName": "Jose", + "lastName": "Iglesias" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 20, + "position": { + "code": "6", + "name": "Shortstop", + "type": "Infielder", + "abbreviation": "SS" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 84, + "groundOuts": 78, + "airOuts": 93, + "runs": 53, + "doubles": 26, + "triples": 2, + "homeRuns": 10, + "strikeOuts": 65, + "baseOnBalls": 41, + "intentionalWalks": 5, + "hits": 98, + "hitByPitch": 3, + "avg": ".296", + "atBats": 331, + "obp": ".376", + "slg": ".477", + "ops": ".853", + "caughtStealing": 0, + "stolenBases": 7, + "stolenBasePercentage": "1.000", + "groundIntoDoublePlay": 4, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1470, + "plateAppearances": 378, + "totalBases": 158, + "rbi": 52, + "leftOnBase": 110, + "sacBunts": 0, + "sacFlies": 3, + "babip": ".340", + "groundOutsToAirouts": "0.84", + "catchersInterference": 0, + "atBatsPerHomeRun": "33.10" + }, + "team": { + "id": 119, + "name": "Los Angeles Dodgers", + "link": "/api/v1/teams/119" + }, + "player": { + "id": 518692, + "fullName": "Freddie Freeman", + "link": "/api/v1/people/518692", + "firstName": "Freddie", + "lastName": "Freeman" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 21, + "position": { + "code": "3", + "name": "First Base", + "type": "Infielder", + "abbreviation": "1B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 64, + "groundOuts": 67, + "airOuts": 65, + "runs": 31, + "doubles": 15, + "triples": 0, + "homeRuns": 8, + "strikeOuts": 46, + "baseOnBalls": 17, + "intentionalWalks": 0, + "hits": 73, + "hitByPitch": 4, + "avg": ".296", + "atBats": 247, + "obp": ".346", + "slg": ".453", + "ops": ".799", + "caughtStealing": 0, + "stolenBases": 0, + "stolenBasePercentage": ".---", + "groundIntoDoublePlay": 5, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1066, + "plateAppearances": 272, + "totalBases": 112, + "rbi": 38, + "leftOnBase": 87, + "sacBunts": 0, + "sacFlies": 4, + "babip": ".330", + "groundOutsToAirouts": "1.03", + "catchersInterference": 0, + "atBatsPerHomeRun": "30.88" + }, + "team": { + "id": 145, + "name": "Chicago White Sox", + "link": "/api/v1/teams/145" + }, + "player": { + "id": 683734, + "fullName": "Andrew Vaughn", + "link": "/api/v1/people/683734", + "firstName": "Andrew", + "lastName": "Vaughn" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 22, + "position": { + "code": "9", + "name": "Outfielder", + "type": "Outfielder", + "abbreviation": "RF" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 84, + "groundOuts": 64, + "airOuts": 77, + "runs": 49, + "doubles": 19, + "triples": 2, + "homeRuns": 20, + "strikeOuts": 91, + "baseOnBalls": 23, + "intentionalWalks": 2, + "hits": 96, + "hitByPitch": 6, + "avg": ".295", + "atBats": 325, + "obp": ".350", + "slg": ".551", + "ops": ".901", + "caughtStealing": 0, + "stolenBases": 0, + "stolenBasePercentage": ".---", + "groundIntoDoublePlay": 10, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1446, + "plateAppearances": 358, + "totalBases": 179, + "rbi": 66, + "leftOnBase": 153, + "sacBunts": 0, + "sacFlies": 3, + "babip": ".350", + "groundOutsToAirouts": "0.83", + "catchersInterference": 1, + "atBatsPerHomeRun": "16.25" + }, + "team": { + "id": 115, + "name": "Colorado Rockies", + "link": "/api/v1/teams/115" + }, + "player": { + "id": 543068, + "fullName": "C.J. Cron", + "link": "/api/v1/people/543068", + "firstName": "C.J.", + "lastName": "Cron" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 23, + "position": { + "code": "3", + "name": "First Base", + "type": "Infielder", + "abbreviation": "1B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 81, + "groundOuts": 88, + "airOuts": 77, + "runs": 47, + "doubles": 23, + "triples": 0, + "homeRuns": 10, + "strikeOuts": 56, + "baseOnBalls": 40, + "intentionalWalks": 0, + "hits": 92, + "hitByPitch": 3, + "avg": ".295", + "atBats": 312, + "obp": ".379", + "slg": ".465", + "ops": ".844", + "caughtStealing": 0, + "stolenBases": 0, + "stolenBasePercentage": ".---", + "groundIntoDoublePlay": 7, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1509, + "plateAppearances": 356, + "totalBases": 145, + "rbi": 40, + "leftOnBase": 133, + "sacBunts": 0, + "sacFlies": 1, + "babip": ".332", + "groundOutsToAirouts": "1.14", + "catchersInterference": 0, + "atBatsPerHomeRun": "31.20" + }, + "team": { + "id": 145, + "name": "Chicago White Sox", + "link": "/api/v1/teams/145" + }, + "player": { + "id": 547989, + "fullName": "Jose Abreu", + "link": "/api/v1/people/547989", + "firstName": "Jose", + "lastName": "Abreu" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 24, + "position": { + "code": "3", + "name": "First Base", + "type": "Infielder", + "abbreviation": "1B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 76, + "groundOuts": 82, + "airOuts": 68, + "runs": 36, + "doubles": 15, + "triples": 0, + "homeRuns": 3, + "strikeOuts": 32, + "baseOnBalls": 47, + "intentionalWalks": 0, + "hits": 75, + "hitByPitch": 3, + "avg": ".292", + "atBats": 257, + "obp": ".407", + "slg": ".385", + "ops": ".792", + "caughtStealing": 3, + "stolenBases": 1, + "stolenBasePercentage": ".250", + "groundIntoDoublePlay": 4, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1209, + "plateAppearances": 307, + "totalBases": 99, + "rbi": 18, + "leftOnBase": 98, + "sacBunts": 0, + "sacFlies": 0, + "babip": ".324", + "groundOutsToAirouts": "1.21", + "catchersInterference": 0, + "atBatsPerHomeRun": "85.67" + }, + "team": { + "id": 139, + "name": "Tampa Bay Rays", + "link": "/api/v1/teams/139" + }, + "player": { + "id": 650490, + "fullName": "Yandy Diaz", + "link": "/api/v1/people/650490", + "firstName": "Yandy", + "lastName": "Diaz" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 25, + "position": { + "code": "5", + "name": "Third Base", + "type": "Infielder", + "abbreviation": "3B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 68, + "groundOuts": 75, + "airOuts": 70, + "runs": 43, + "doubles": 11, + "triples": 0, + "homeRuns": 10, + "strikeOuts": 58, + "baseOnBalls": 11, + "intentionalWalks": 1, + "hits": 83, + "hitByPitch": 3, + "avg": ".291", + "atBats": 285, + "obp": ".323", + "slg": ".435", + "ops": ".758", + "caughtStealing": 2, + "stolenBases": 11, + "stolenBasePercentage": ".846", + "groundIntoDoublePlay": 4, + "groundIntoTriplePlay": 0, + "numberOfPitches": 994, + "plateAppearances": 300, + "totalBases": 124, + "rbi": 46, + "leftOnBase": 127, + "sacBunts": 0, + "sacFlies": 1, + "babip": ".335", + "groundOutsToAirouts": "1.07", + "catchersInterference": 0, + "atBatsPerHomeRun": "28.50" + }, + "team": { + "id": 145, + "name": "Chicago White Sox", + "link": "/api/v1/teams/145" + }, + "player": { + "id": 673357, + "fullName": "Luis Robert Jr.", + "link": "/api/v1/people/673357", + "firstName": "Luis", + "lastName": "Robert" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 26, + "position": { + "code": "8", + "name": "Outfielder", + "type": "Outfielder", + "abbreviation": "CF" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 83, + "groundOuts": 58, + "airOuts": 122, + "runs": 39, + "doubles": 20, + "triples": 1, + "homeRuns": 17, + "strikeOuts": 46, + "baseOnBalls": 30, + "intentionalWalks": 2, + "hits": 92, + "hitByPitch": 2, + "avg": ".291", + "atBats": 316, + "obp": ".354", + "slg": ".522", + "ops": ".876", + "caughtStealing": 3, + "stolenBases": 0, + "stolenBasePercentage": ".000", + "groundIntoDoublePlay": 10, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1324, + "plateAppearances": 350, + "totalBases": 165, + "rbi": 55, + "leftOnBase": 134, + "sacBunts": 0, + "sacFlies": 2, + "babip": ".294", + "groundOutsToAirouts": "0.48", + "catchersInterference": 0, + "atBatsPerHomeRun": "18.59" + }, + "team": { + "id": 138, + "name": "St. Louis Cardinals", + "link": "/api/v1/teams/138" + }, + "player": { + "id": 571448, + "fullName": "Nolan Arenado", + "link": "/api/v1/people/571448", + "firstName": "Nolan", + "lastName": "Arenado" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 27, + "position": { + "code": "5", + "name": "Third Base", + "type": "Infielder", + "abbreviation": "3B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 74, + "groundOuts": 94, + "airOuts": 61, + "runs": 50, + "doubles": 18, + "triples": 3, + "homeRuns": 9, + "strikeOuts": 57, + "baseOnBalls": 16, + "intentionalWalks": 0, + "hits": 87, + "hitByPitch": 7, + "avg": ".291", + "atBats": 299, + "obp": ".342", + "slg": ".462", + "ops": ".804", + "caughtStealing": 6, + "stolenBases": 10, + "stolenBasePercentage": ".625", + "groundIntoDoublePlay": 10, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1209, + "plateAppearances": 322, + "totalBases": 138, + "rbi": 40, + "leftOnBase": 126, + "sacBunts": 0, + "sacFlies": 0, + "babip": ".335", + "groundOutsToAirouts": "1.54", + "catchersInterference": 0, + "atBatsPerHomeRun": "33.22" + }, + "team": { + "id": 121, + "name": "New York Mets", + "link": "/api/v1/teams/121" + }, + "player": { + "id": 516782, + "fullName": "Starling Marte", + "link": "/api/v1/people/516782", + "firstName": "Starling", + "lastName": "Marte" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 28, + "position": { + "code": "9", + "name": "Outfielder", + "type": "Outfielder", + "abbreviation": "RF" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 79, + "groundOuts": 59, + "airOuts": 122, + "runs": 50, + "doubles": 29, + "triples": 4, + "homeRuns": 17, + "strikeOuts": 33, + "baseOnBalls": 38, + "intentionalWalks": 5, + "hits": 87, + "hitByPitch": 2, + "avg": ".291", + "atBats": 299, + "obp": ".372", + "slg": ".585", + "ops": ".957", + "caughtStealing": 3, + "stolenBases": 12, + "stolenBasePercentage": ".800", + "groundIntoDoublePlay": 4, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1414, + "plateAppearances": 341, + "totalBases": 175, + "rbi": 66, + "leftOnBase": 120, + "sacBunts": 0, + "sacFlies": 2, + "babip": ".279", + "groundOutsToAirouts": "0.48", + "catchersInterference": 0, + "atBatsPerHomeRun": "17.59" + }, + "team": { + "id": 114, + "name": "Cleveland Guardians", + "link": "/api/v1/teams/114" + }, + "player": { + "id": 608070, + "fullName": "Jose Ramirez", + "link": "/api/v1/people/608070", + "firstName": "Jose", + "lastName": "Ramirez" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 28, + "position": { + "code": "5", + "name": "Third Base", + "type": "Infielder", + "abbreviation": "3B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 64, + "groundOuts": 76, + "airOuts": 69, + "runs": 28, + "doubles": 14, + "triples": 1, + "homeRuns": 5, + "strikeOuts": 30, + "baseOnBalls": 31, + "intentionalWalks": 2, + "hits": 70, + "hitByPitch": 1, + "avg": ".288", + "atBats": 243, + "obp": ".370", + "slg": ".416", + "ops": ".786", + "caughtStealing": 1, + "stolenBases": 1, + "stolenBasePercentage": ".500", + "groundIntoDoublePlay": 1, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1006, + "plateAppearances": 277, + "totalBases": 101, + "rbi": 26, + "leftOnBase": 68, + "sacBunts": 1, + "sacFlies": 1, + "babip": ".311", + "groundOutsToAirouts": "1.10", + "catchersInterference": 0, + "atBatsPerHomeRun": "48.60" + }, + "team": { + "id": 117, + "name": "Houston Astros", + "link": "/api/v1/teams/117" + }, + "player": { + "id": 488726, + "fullName": "Michael Brantley", + "link": "/api/v1/people/488726", + "firstName": "Michael", + "lastName": "Brantley" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 30, + "position": { + "code": "10", + "name": "Designated Hitter", + "type": "Hitter", + "abbreviation": "DH" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 82, + "groundOuts": 72, + "airOuts": 64, + "runs": 66, + "doubles": 14, + "triples": 0, + "homeRuns": 30, + "strikeOuts": 92, + "baseOnBalls": 41, + "intentionalWalks": 6, + "hits": 89, + "hitByPitch": 0, + "avg": ".284", + "atBats": 313, + "obp": ".363", + "slg": ".617", + "ops": ".980", + "caughtStealing": 0, + "stolenBases": 7, + "stolenBasePercentage": "1.000", + "groundIntoDoublePlay": 11, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1496, + "plateAppearances": 360, + "totalBases": 193, + "rbi": 65, + "leftOnBase": 124, + "sacBunts": 0, + "sacFlies": 4, + "babip": ".303", + "groundOutsToAirouts": "1.13", + "catchersInterference": 2, + "atBatsPerHomeRun": "10.43" + }, + "team": { + "id": 147, + "name": "New York Yankees", + "link": "/api/v1/teams/147" + }, + "player": { + "id": 592450, + "fullName": "Aaron Judge", + "link": "/api/v1/people/592450", + "firstName": "Aaron", + "lastName": "Judge" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 31, + "position": { + "code": "8", + "name": "Outfielder", + "type": "Outfielder", + "abbreviation": "CF" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 63, + "groundOuts": 61, + "airOuts": 55, + "runs": 37, + "doubles": 13, + "triples": 0, + "homeRuns": 10, + "strikeOuts": 61, + "baseOnBalls": 27, + "intentionalWalks": 0, + "hits": 69, + "hitByPitch": 1, + "avg": ".283", + "atBats": 244, + "obp": ".354", + "slg": ".459", + "ops": ".813", + "caughtStealing": 0, + "stolenBases": 0, + "stolenBasePercentage": ".---", + "groundIntoDoublePlay": 10, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1133, + "plateAppearances": 274, + "totalBases": 112, + "rbi": 31, + "leftOnBase": 109, + "sacBunts": 0, + "sacFlies": 2, + "babip": ".337", + "groundOutsToAirouts": "1.11", + "catchersInterference": 0, + "atBatsPerHomeRun": "24.40" + }, + "team": { + "id": 142, + "name": "Minnesota Twins", + "link": "/api/v1/teams/142" + }, + "player": { + "id": 621043, + "fullName": "Carlos Correa", + "link": "/api/v1/people/621043", + "firstName": "Carlos", + "lastName": "Correa" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 32, + "position": { + "code": "6", + "name": "Shortstop", + "type": "Infielder", + "abbreviation": "SS" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 77, + "groundOuts": 61, + "airOuts": 85, + "runs": 32, + "doubles": 15, + "triples": 1, + "homeRuns": 8, + "strikeOuts": 68, + "baseOnBalls": 26, + "intentionalWalks": 1, + "hits": 83, + "hitByPitch": 8, + "avg": ".281", + "atBats": 295, + "obp": ".353", + "slg": ".420", + "ops": ".773", + "caughtStealing": 0, + "stolenBases": 0, + "stolenBasePercentage": ".---", + "groundIntoDoublePlay": 3, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1342, + "plateAppearances": 331, + "totalBases": 124, + "rbi": 34, + "leftOnBase": 110, + "sacBunts": 0, + "sacFlies": 2, + "babip": ".339", + "groundOutsToAirouts": "0.72", + "catchersInterference": 0, + "atBatsPerHomeRun": "36.88" + }, + "team": { + "id": 110, + "name": "Baltimore Orioles", + "link": "/api/v1/teams/110" + }, + "player": { + "id": 641820, + "fullName": "Trey Mancini", + "link": "/api/v1/people/641820", + "firstName": "Trey", + "lastName": "Mancini" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 33, + "position": { + "code": "10", + "name": "Designated Hitter", + "type": "Hitter", + "abbreviation": "DH" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 77, + "groundOuts": 74, + "airOuts": 59, + "runs": 36, + "doubles": 11, + "triples": 1, + "homeRuns": 12, + "strikeOuts": 74, + "baseOnBalls": 23, + "intentionalWalks": 1, + "hits": 81, + "hitByPitch": 0, + "avg": ".281", + "atBats": 288, + "obp": ".334", + "slg": ".451", + "ops": ".785", + "caughtStealing": 2, + "stolenBases": 1, + "stolenBasePercentage": ".333", + "groundIntoDoublePlay": 5, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1181, + "plateAppearances": 311, + "totalBases": 130, + "rbi": 37, + "leftOnBase": 116, + "sacBunts": 0, + "sacFlies": 0, + "babip": ".342", + "groundOutsToAirouts": "1.25", + "catchersInterference": 0, + "atBatsPerHomeRun": "24.00" + }, + "team": { + "id": 140, + "name": "Texas Rangers", + "link": "/api/v1/teams/140" + }, + "player": { + "id": 663993, + "fullName": "Nathaniel Lowe", + "link": "/api/v1/people/663993", + "firstName": "Nathaniel", + "lastName": "Lowe" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 34, + "position": { + "code": "3", + "name": "First Base", + "type": "Infielder", + "abbreviation": "1B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 68, + "groundOuts": 68, + "airOuts": 74, + "runs": 44, + "doubles": 16, + "triples": 0, + "homeRuns": 17, + "strikeOuts": 47, + "baseOnBalls": 33, + "intentionalWalks": 0, + "hits": 73, + "hitByPitch": 5, + "avg": ".280", + "atBats": 261, + "obp": ".370", + "slg": ".536", + "ops": ".906", + "caughtStealing": 1, + "stolenBases": 6, + "stolenBasePercentage": ".857", + "groundIntoDoublePlay": 7, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1160, + "plateAppearances": 300, + "totalBases": 140, + "rbi": 32, + "leftOnBase": 66, + "sacBunts": 0, + "sacFlies": 1, + "babip": ".283", + "groundOutsToAirouts": "0.92", + "catchersInterference": 0, + "atBatsPerHomeRun": "15.35" + }, + "team": { + "id": 117, + "name": "Houston Astros", + "link": "/api/v1/teams/117" + }, + "player": { + "id": 514888, + "fullName": "Jose Altuve", + "link": "/api/v1/people/514888", + "firstName": "Jose", + "lastName": "Altuve" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 35, + "position": { + "code": "4", + "name": "Second Base", + "type": "Infielder", + "abbreviation": "2B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 76, + "groundOuts": 102, + "airOuts": 74, + "runs": 46, + "doubles": 12, + "triples": 5, + "homeRuns": 4, + "strikeOuts": 48, + "baseOnBalls": 17, + "intentionalWalks": 0, + "hits": 86, + "hitByPitch": 2, + "avg": ".279", + "atBats": 308, + "obp": ".319", + "slg": ".390", + "ops": ".709", + "caughtStealing": 3, + "stolenBases": 9, + "stolenBasePercentage": ".750", + "groundIntoDoublePlay": 9, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1178, + "plateAppearances": 329, + "totalBases": 120, + "rbi": 25, + "leftOnBase": 119, + "sacBunts": 0, + "sacFlies": 2, + "babip": ".318", + "groundOutsToAirouts": "1.38", + "catchersInterference": 0, + "atBatsPerHomeRun": "77.00" + }, + "team": { + "id": 114, + "name": "Cleveland Guardians", + "link": "/api/v1/teams/114" + }, + "player": { + "id": 642708, + "fullName": "Amed Rosario", + "link": "/api/v1/people/642708", + "firstName": "Amed", + "lastName": "Rosario" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 36, + "position": { + "code": "6", + "name": "Shortstop", + "type": "Infielder", + "abbreviation": "SS" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 70, + "groundOuts": 74, + "airOuts": 83, + "runs": 34, + "doubles": 11, + "triples": 3, + "homeRuns": 1, + "strikeOuts": 23, + "baseOnBalls": 30, + "intentionalWalks": 1, + "hits": 68, + "hitByPitch": 4, + "avg": ".279", + "atBats": 244, + "obp": ".363", + "slg": ".361", + "ops": ".724", + "caughtStealing": 2, + "stolenBases": 5, + "stolenBasePercentage": ".714", + "groundIntoDoublePlay": 4, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1161, + "plateAppearances": 282, + "totalBases": 88, + "rbi": 23, + "leftOnBase": 108, + "sacBunts": 1, + "sacFlies": 3, + "babip": ".300", + "groundOutsToAirouts": "0.89", + "catchersInterference": 0, + "atBatsPerHomeRun": "244.00" + }, + "team": { + "id": 114, + "name": "Cleveland Guardians", + "link": "/api/v1/teams/114" + }, + "player": { + "id": 680757, + "fullName": "Steven Kwan", + "link": "/api/v1/people/680757", + "firstName": "Steven", + "lastName": "Kwan" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 37, + "position": { + "code": "7", + "name": "Outfielder", + "type": "Outfielder", + "abbreviation": "LF" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 84, + "groundOuts": 67, + "airOuts": 77, + "runs": 49, + "doubles": 21, + "triples": 1, + "homeRuns": 22, + "strikeOuts": 94, + "baseOnBalls": 28, + "intentionalWalks": 1, + "hits": 91, + "hitByPitch": 7, + "avg": ".278", + "atBats": 327, + "obp": ".346", + "slg": ".550", + "ops": ".896", + "caughtStealing": 0, + "stolenBases": 2, + "stolenBasePercentage": "1.000", + "groundIntoDoublePlay": 6, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1350, + "plateAppearances": 364, + "totalBases": 180, + "rbi": 53, + "leftOnBase": 156, + "sacBunts": 0, + "sacFlies": 2, + "babip": ".324", + "groundOutsToAirouts": "0.87", + "catchersInterference": 0, + "atBatsPerHomeRun": "14.86" + }, + "team": { + "id": 144, + "name": "Atlanta Braves", + "link": "/api/v1/teams/144" + }, + "player": { + "id": 663586, + "fullName": "Austin Riley", + "link": "/api/v1/people/663586", + "firstName": "Austin", + "lastName": "Riley" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 38, + "position": { + "code": "5", + "name": "Third Base", + "type": "Infielder", + "abbreviation": "3B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 75, + "groundOuts": 67, + "airOuts": 69, + "runs": 52, + "doubles": 17, + "triples": 2, + "homeRuns": 18, + "strikeOuts": 70, + "baseOnBalls": 21, + "intentionalWalks": 0, + "hits": 79, + "hitByPitch": 4, + "avg": ".278", + "atBats": 284, + "obp": ".335", + "slg": ".542", + "ops": ".877", + "caughtStealing": 2, + "stolenBases": 2, + "stolenBasePercentage": ".500", + "groundIntoDoublePlay": 6, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1245, + "plateAppearances": 310, + "totalBases": 154, + "rbi": 50, + "leftOnBase": 91, + "sacBunts": 0, + "sacFlies": 1, + "babip": ".310", + "groundOutsToAirouts": "0.97", + "catchersInterference": 0, + "atBatsPerHomeRun": "15.78" + }, + "team": { + "id": 113, + "name": "Cincinnati Reds", + "link": "/api/v1/teams/113" + }, + "player": { + "id": 592273, + "fullName": "Brandon Drury", + "link": "/api/v1/people/592273", + "firstName": "Brandon", + "lastName": "Drury" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 39, + "position": { + "code": "5", + "name": "Third Base", + "type": "Infielder", + "abbreviation": "3B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 83, + "groundOuts": 79, + "airOuts": 64, + "runs": 38, + "doubles": 22, + "triples": 2, + "homeRuns": 8, + "strikeOuts": 71, + "baseOnBalls": 41, + "intentionalWalks": 3, + "hits": 81, + "hitByPitch": 5, + "avg": ".277", + "atBats": 292, + "obp": ".372", + "slg": ".449", + "ops": ".821", + "caughtStealing": 3, + "stolenBases": 6, + "stolenBasePercentage": ".667", + "groundIntoDoublePlay": 8, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1369, + "plateAppearances": 341, + "totalBases": 131, + "rbi": 40, + "leftOnBase": 140, + "sacBunts": 0, + "sacFlies": 3, + "babip": ".338", + "groundOutsToAirouts": "1.23", + "catchersInterference": 0, + "atBatsPerHomeRun": "36.50" + }, + "team": { + "id": 112, + "name": "Chicago Cubs", + "link": "/api/v1/teams/112" + }, + "player": { + "id": 664023, + "fullName": "Ian Happ", + "link": "/api/v1/people/664023", + "firstName": "Ian", + "lastName": "Happ" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 40, + "position": { + "code": "7", + "name": "Outfielder", + "type": "Outfielder", + "abbreviation": "LF" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 73, + "groundOuts": 59, + "airOuts": 72, + "runs": 36, + "doubles": 19, + "triples": 0, + "homeRuns": 14, + "strikeOuts": 78, + "baseOnBalls": 16, + "intentionalWalks": 1, + "hits": 79, + "hitByPitch": 1, + "avg": ".277", + "atBats": 285, + "obp": ".315", + "slg": ".491", + "ops": ".806", + "caughtStealing": 1, + "stolenBases": 4, + "stolenBasePercentage": ".800", + "groundIntoDoublePlay": 9, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1161, + "plateAppearances": 305, + "totalBases": 140, + "rbi": 43, + "leftOnBase": 112, + "sacBunts": 0, + "sacFlies": 3, + "babip": ".332", + "groundOutsToAirouts": "0.82", + "catchersInterference": 0, + "atBatsPerHomeRun": "20.36" + }, + "team": { + "id": 110, + "name": "Baltimore Orioles", + "link": "/api/v1/teams/110" + }, + "player": { + "id": 663624, + "fullName": "Ryan Mountcastle", + "link": "/api/v1/people/663624", + "firstName": "Ryan", + "lastName": "Mountcastle" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 41, + "position": { + "code": "3", + "name": "First Base", + "type": "Infielder", + "abbreviation": "1B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 67, + "groundOuts": 60, + "airOuts": 87, + "runs": 58, + "doubles": 15, + "triples": 0, + "homeRuns": 20, + "strikeOuts": 52, + "baseOnBalls": 29, + "intentionalWalks": 0, + "hits": 75, + "hitByPitch": 3, + "avg": ".276", + "atBats": 272, + "obp": ".350", + "slg": ".551", + "ops": ".901", + "caughtStealing": 1, + "stolenBases": 6, + "stolenBasePercentage": ".857", + "groundIntoDoublePlay": 3, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1187, + "plateAppearances": 306, + "totalBases": 150, + "rbi": 46, + "leftOnBase": 107, + "sacBunts": 0, + "sacFlies": 2, + "babip": ".272", + "groundOutsToAirouts": "0.69", + "catchersInterference": 0, + "atBatsPerHomeRun": "13.60" + }, + "team": { + "id": 119, + "name": "Los Angeles Dodgers", + "link": "/api/v1/teams/119" + }, + "player": { + "id": 605141, + "fullName": "Mookie Betts", + "link": "/api/v1/people/605141", + "firstName": "Mookie", + "lastName": "Betts" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 42, + "position": { + "code": "9", + "name": "Outfielder", + "type": "Outfielder", + "abbreviation": "RF" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 85, + "groundOuts": 71, + "airOuts": 67, + "runs": 50, + "doubles": 17, + "triples": 2, + "homeRuns": 15, + "strikeOuts": 96, + "baseOnBalls": 25, + "intentionalWalks": 1, + "hits": 88, + "hitByPitch": 5, + "avg": ".274", + "atBats": 321, + "obp": ".335", + "slg": ".480", + "ops": ".815", + "caughtStealing": 4, + "stolenBases": 21, + "stolenBasePercentage": ".840", + "groundIntoDoublePlay": 6, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1319, + "plateAppearances": 352, + "totalBases": 154, + "rbi": 43, + "leftOnBase": 129, + "sacBunts": 0, + "sacFlies": 1, + "babip": ".346", + "groundOutsToAirouts": "1.06", + "catchersInterference": 0, + "atBatsPerHomeRun": "21.40" + }, + "team": { + "id": 136, + "name": "Seattle Mariners", + "link": "/api/v1/teams/136" + }, + "player": { + "id": 677594, + "fullName": "Julio Rodriguez", + "link": "/api/v1/people/677594", + "firstName": "Julio", + "lastName": "Rodriguez" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 43, + "position": { + "code": "8", + "name": "Outfielder", + "type": "Outfielder", + "abbreviation": "CF" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 84, + "groundOuts": 69, + "airOuts": 93, + "runs": 47, + "doubles": 13, + "triples": 0, + "homeRuns": 23, + "strikeOuts": 71, + "baseOnBalls": 33, + "intentionalWalks": 6, + "hits": 85, + "hitByPitch": 7, + "avg": ".273", + "atBats": 311, + "obp": ".349", + "slg": ".537", + "ops": ".886", + "caughtStealing": 1, + "stolenBases": 2, + "stolenBasePercentage": ".667", + "groundIntoDoublePlay": 7, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1352, + "plateAppearances": 358, + "totalBases": 167, + "rbi": 70, + "leftOnBase": 139, + "sacBunts": 0, + "sacFlies": 7, + "babip": ".277", + "groundOutsToAirouts": "0.74", + "catchersInterference": 0, + "atBatsPerHomeRun": "13.52" + }, + "team": { + "id": 121, + "name": "New York Mets", + "link": "/api/v1/teams/121" + }, + "player": { + "id": 624413, + "fullName": "Pete Alonso", + "link": "/api/v1/people/624413", + "firstName": "Pete", + "lastName": "Alonso" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 44, + "position": { + "code": "3", + "name": "First Base", + "type": "Infielder", + "abbreviation": "1B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 77, + "groundOuts": 85, + "airOuts": 76, + "runs": 49, + "doubles": 15, + "triples": 5, + "homeRuns": 8, + "strikeOuts": 57, + "baseOnBalls": 31, + "intentionalWalks": 0, + "hits": 80, + "hitByPitch": 9, + "avg": ".273", + "atBats": 293, + "obp": ".357", + "slg": ".440", + "ops": ".797", + "caughtStealing": 2, + "stolenBases": 0, + "stolenBasePercentage": ".000", + "groundIntoDoublePlay": 4, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1393, + "plateAppearances": 338, + "totalBases": 129, + "rbi": 32, + "leftOnBase": 82, + "sacBunts": 2, + "sacFlies": 3, + "babip": ".312", + "groundOutsToAirouts": "1.12", + "catchersInterference": 0, + "atBatsPerHomeRun": "36.62" + }, + "team": { + "id": 121, + "name": "New York Mets", + "link": "/api/v1/teams/121" + }, + "player": { + "id": 607043, + "fullName": "Brandon Nimmo", + "link": "/api/v1/people/607043", + "firstName": "Brandon", + "lastName": "Nimmo" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 45, + "position": { + "code": "8", + "name": "Outfielder", + "type": "Outfielder", + "abbreviation": "CF" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 76, + "groundOuts": 104, + "airOuts": 53, + "runs": 28, + "doubles": 14, + "triples": 0, + "homeRuns": 6, + "strikeOuts": 52, + "baseOnBalls": 24, + "intentionalWalks": 5, + "hits": 78, + "hitByPitch": 0, + "avg": ".273", + "atBats": 286, + "obp": ".328", + "slg": ".385", + "ops": ".713", + "caughtStealing": 0, + "stolenBases": 0, + "stolenBasePercentage": ".---", + "groundIntoDoublePlay": 8, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1180, + "plateAppearances": 311, + "totalBases": 110, + "rbi": 33, + "leftOnBase": 119, + "sacBunts": 0, + "sacFlies": 1, + "babip": ".314", + "groundOutsToAirouts": "1.96", + "catchersInterference": 0, + "atBatsPerHomeRun": "47.67" + }, + "team": { + "id": 135, + "name": "San Diego Padres", + "link": "/api/v1/teams/135" + }, + "player": { + "id": 543333, + "fullName": "Eric Hosmer", + "link": "/api/v1/people/543333", + "firstName": "Eric", + "lastName": "Hosmer" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 46, + "position": { + "code": "3", + "name": "First Base", + "type": "Infielder", + "abbreviation": "1B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 70, + "groundOuts": 62, + "airOuts": 62, + "runs": 39, + "doubles": 7, + "triples": 0, + "homeRuns": 6, + "strikeOuts": 51, + "baseOnBalls": 26, + "intentionalWalks": 0, + "hits": 65, + "hitByPitch": 10, + "avg": ".272", + "atBats": 239, + "obp": ".366", + "slg": ".377", + "ops": ".743", + "caughtStealing": 1, + "stolenBases": 1, + "stolenBasePercentage": ".500", + "groundIntoDoublePlay": 1, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1172, + "plateAppearances": 276, + "totalBases": 90, + "rbi": 30, + "leftOnBase": 112, + "sacBunts": 0, + "sacFlies": 1, + "babip": ".322", + "groundOutsToAirouts": "1.00", + "catchersInterference": 0, + "atBatsPerHomeRun": "39.83" + }, + "team": { + "id": 121, + "name": "New York Mets", + "link": "/api/v1/teams/121" + }, + "player": { + "id": 592192, + "fullName": "Mark Canha", + "link": "/api/v1/people/592192", + "firstName": "Mark", + "lastName": "Canha" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 47, + "position": { + "code": "7", + "name": "Outfielder", + "type": "Outfielder", + "abbreviation": "LF" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 77, + "groundOuts": 26, + "airOuts": 81, + "runs": 54, + "doubles": 17, + "triples": 2, + "homeRuns": 24, + "strikeOuts": 94, + "baseOnBalls": 39, + "intentionalWalks": 6, + "hits": 75, + "hitByPitch": 5, + "avg": ".272", + "atBats": 276, + "obp": ".372", + "slg": ".609", + "ops": ".981", + "caughtStealing": 0, + "stolenBases": 1, + "stolenBasePercentage": "1.000", + "groundIntoDoublePlay": 3, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1347, + "plateAppearances": 320, + "totalBases": 168, + "rbi": 51, + "leftOnBase": 103, + "sacBunts": 0, + "sacFlies": 0, + "babip": ".323", + "groundOutsToAirouts": "0.32", + "catchersInterference": 0, + "atBatsPerHomeRun": "11.50" + }, + "team": { + "id": 108, + "name": "Los Angeles Angels", + "link": "/api/v1/teams/108" + }, + "player": { + "id": 545361, + "fullName": "Mike Trout", + "link": "/api/v1/people/545361", + "firstName": "Mike", + "lastName": "Trout" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 48, + "position": { + "code": "8", + "name": "Outfielder", + "type": "Outfielder", + "abbreviation": "CF" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 85, + "groundOuts": 79, + "airOuts": 91, + "runs": 31, + "doubles": 21, + "triples": 0, + "homeRuns": 6, + "strikeOuts": 53, + "baseOnBalls": 24, + "intentionalWalks": 1, + "hits": 82, + "hitByPitch": 1, + "avg": ".272", + "atBats": 302, + "obp": ".324", + "slg": ".401", + "ops": ".725", + "caughtStealing": 2, + "stolenBases": 5, + "stolenBasePercentage": ".714", + "groundIntoDoublePlay": 9, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1260, + "plateAppearances": 330, + "totalBases": 121, + "rbi": 37, + "leftOnBase": 152, + "sacBunts": 0, + "sacFlies": 3, + "babip": ".309", + "groundOutsToAirouts": "0.87", + "catchersInterference": 0, + "atBatsPerHomeRun": "50.33" + }, + "team": { + "id": 141, + "name": "Toronto Blue Jays", + "link": "/api/v1/teams/141" + }, + "player": { + "id": 669289, + "fullName": "Santiago Espinal", + "link": "/api/v1/people/669289", + "firstName": "Santiago", + "lastName": "Espinal" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 49, + "position": { + "code": "4", + "name": "Second Base", + "type": "Infielder", + "abbreviation": "2B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 80, + "groundOuts": 80, + "airOuts": 79, + "runs": 40, + "doubles": 12, + "triples": 2, + "homeRuns": 6, + "strikeOuts": 66, + "baseOnBalls": 16, + "intentionalWalks": 0, + "hits": 81, + "hitByPitch": 2, + "avg": ".271", + "atBats": 299, + "obp": ".306", + "slg": ".385", + "ops": ".691", + "caughtStealing": 2, + "stolenBases": 1, + "stolenBasePercentage": ".333", + "groundIntoDoublePlay": 9, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1245, + "plateAppearances": 324, + "totalBases": 115, + "rbi": 33, + "leftOnBase": 106, + "sacBunts": 0, + "sacFlies": 7, + "babip": ".321", + "groundOutsToAirouts": "1.01", + "catchersInterference": 0, + "atBatsPerHomeRun": "49.83" + }, + "team": { + "id": 143, + "name": "Philadelphia Phillies", + "link": "/api/v1/teams/143" + }, + "player": { + "id": 664761, + "fullName": "Alec Bohm", + "link": "/api/v1/people/664761", + "firstName": "Alec", + "lastName": "Bohm" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 50, + "position": { + "code": "5", + "name": "Third Base", + "type": "Infielder", + "abbreviation": "3B" + } + } + ], + "splitsTiedWithOffset": [], + "splitsTiedWithLimit": [] + } + ] +} diff --git a/api/tests/responses/team-stats-date.json b/api/tests/responses/team-stats-date.json new file mode 100644 index 0000000..5466aa0 --- /dev/null +++ b/api/tests/responses/team-stats-date.json @@ -0,0 +1,1278 @@ +{ + "stats": [ + { + "type": { + "displayName": "byDateRange" + }, + "group": { + "displayName": "hitting" + }, + "totalSplits": 30, + "exemptions": [], + "splits": [ + { + "stat": { + "gamesPlayed": 85, + "groundOuts": 747, + "airOuts": 788, + "runs": 399, + "doubles": 195, + "triples": 6, + "homeRuns": 82, + "strikeOuts": 684, + "baseOnBalls": 256, + "intentionalWalks": 14, + "hits": 767, + "hitByPitch": 36, + "avg": ".260", + "atBats": 2949, + "obp": ".324", + "slg": ".414", + "ops": ".738", + "caughtStealing": 10, + "stolenBases": 31, + "stolenBasePercentage": ".756", + "groundIntoDoublePlay": 57, + "numberOfPitches": 12565, + "plateAppearances": 3278, + "totalBases": 1220, + "rbi": 382, + "leftOnBase": 620, + "sacBunts": 6, + "sacFlies": 31, + "babip": ".309", + "groundOutsToAirouts": "0.95", + "atBatsPerHomeRun": "35.96" + }, + "team": { + "id": 111, + "name": "Boston Red Sox", + "link": "/api/v1/teams/111" + }, + "numTeams": 1, + "rank": 1 + }, + { + "stat": { + "gamesPlayed": 85, + "groundOuts": 801, + "airOuts": 722, + "runs": 378, + "doubles": 142, + "triples": 18, + "homeRuns": 80, + "strikeOuts": 665, + "baseOnBalls": 252, + "intentionalWalks": 3, + "hits": 753, + "hitByPitch": 30, + "avg": ".258", + "atBats": 2916, + "obp": ".322", + "slg": ".402", + "ops": ".724", + "caughtStealing": 13, + "stolenBases": 19, + "stolenBasePercentage": ".594", + "groundIntoDoublePlay": 75, + "numberOfPitches": 12479, + "plateAppearances": 3224, + "totalBases": 1171, + "rbi": 358, + "leftOnBase": 602, + "sacBunts": 6, + "sacFlies": 19, + "babip": ".307", + "groundOutsToAirouts": "1.11", + "atBatsPerHomeRun": "36.45" + }, + "team": { + "id": 115, + "name": "Colorado Rockies", + "link": "/api/v1/teams/115" + }, + "numTeams": 1, + "rank": 2 + }, + { + "stat": { + "gamesPlayed": 86, + "groundOuts": 754, + "airOuts": 777, + "runs": 392, + "doubles": 166, + "triples": 4, + "homeRuns": 109, + "strikeOuts": 671, + "baseOnBalls": 262, + "intentionalWalks": 8, + "hits": 753, + "hitByPitch": 36, + "avg": ".257", + "atBats": 2930, + "obp": ".324", + "slg": ".428", + "ops": ".752", + "caughtStealing": 15, + "stolenBases": 32, + "stolenBasePercentage": ".681", + "groundIntoDoublePlay": 65, + "numberOfPitches": 12492, + "plateAppearances": 3256, + "totalBases": 1254, + "rbi": 380, + "leftOnBase": 595, + "sacBunts": 7, + "sacFlies": 18, + "babip": ".297", + "groundOutsToAirouts": "0.97", + "atBatsPerHomeRun": "26.88" + }, + "team": { + "id": 141, + "name": "Toronto Blue Jays", + "link": "/api/v1/teams/141" + }, + "numTeams": 1, + "rank": 3 + }, + { + "stat": { + "gamesPlayed": 85, + "groundOuts": 769, + "airOuts": 770, + "runs": 409, + "doubles": 135, + "triples": 16, + "homeRuns": 85, + "strikeOuts": 639, + "baseOnBalls": 255, + "intentionalWalks": 8, + "hits": 735, + "hitByPitch": 59, + "avg": ".256", + "atBats": 2874, + "obp": ".326", + "slg": ".403", + "ops": ".729", + "caughtStealing": 15, + "stolenBases": 30, + "stolenBasePercentage": ".667", + "groundIntoDoublePlay": 55, + "numberOfPitches": 12497, + "plateAppearances": 3227, + "totalBases": 1157, + "rbi": 391, + "leftOnBase": 589, + "sacBunts": 10, + "sacFlies": 29, + "babip": ".298", + "groundOutsToAirouts": "1.00", + "atBatsPerHomeRun": "33.81" + }, + "team": { + "id": 121, + "name": "New York Mets", + "link": "/api/v1/teams/121" + }, + "numTeams": 1, + "rank": 4 + }, + { + "stat": { + "gamesPlayed": 83, + "groundOuts": 781, + "airOuts": 748, + "runs": 356, + "doubles": 147, + "triples": 6, + "homeRuns": 67, + "strikeOuts": 654, + "baseOnBalls": 201, + "intentionalWalks": 6, + "hits": 740, + "hitByPitch": 40, + "avg": ".256", + "atBats": 2894, + "obp": ".311", + "slg": ".380", + "ops": ".691", + "caughtStealing": 4, + "stolenBases": 35, + "stolenBasePercentage": ".897", + "groundIntoDoublePlay": 60, + "numberOfPitches": 12056, + "plateAppearances": 3164, + "totalBases": 1100, + "rbi": 336, + "leftOnBase": 581, + "sacBunts": 11, + "sacFlies": 18, + "babip": ".307", + "groundOutsToAirouts": "1.04", + "atBatsPerHomeRun": "43.19" + }, + "team": { + "id": 145, + "name": "Chicago White Sox", + "link": "/api/v1/teams/145" + }, + "numTeams": 1, + "rank": 5 + }, + { + "stat": { + "gamesPlayed": 87, + "groundOuts": 716, + "airOuts": 796, + "runs": 398, + "doubles": 154, + "triples": 9, + "homeRuns": 109, + "strikeOuts": 713, + "baseOnBalls": 285, + "intentionalWalks": 2, + "hits": 745, + "hitByPitch": 28, + "avg": ".253", + "atBats": 2940, + "obp": ".323", + "slg": ".423", + "ops": ".746", + "caughtStealing": 10, + "stolenBases": 14, + "stolenBasePercentage": ".583", + "groundIntoDoublePlay": 65, + "numberOfPitches": 12876, + "plateAppearances": 3284, + "totalBases": 1244, + "rbi": 385, + "leftOnBase": 592, + "sacBunts": 6, + "sacFlies": 24, + "babip": ".297", + "groundOutsToAirouts": "0.90", + "atBatsPerHomeRun": "26.97" + }, + "team": { + "id": 142, + "name": "Minnesota Twins", + "link": "/api/v1/teams/142" + }, + "numTeams": 1, + "rank": 6 + }, + { + "stat": { + "gamesPlayed": 84, + "groundOuts": 626, + "airOuts": 816, + "runs": 418, + "doubles": 158, + "triples": 15, + "homeRuns": 108, + "strikeOuts": 708, + "baseOnBalls": 317, + "intentionalWalks": 12, + "hits": 715, + "hitByPitch": 21, + "avg": ".252", + "atBats": 2838, + "obp": ".329", + "slg": ".432", + "ops": ".761", + "caughtStealing": 8, + "stolenBases": 57, + "stolenBasePercentage": ".877", + "groundIntoDoublePlay": 48, + "numberOfPitches": 12879, + "plateAppearances": 3204, + "totalBases": 1227, + "rbi": 395, + "leftOnBase": 587, + "sacBunts": 1, + "sacFlies": 26, + "babip": ".296", + "groundOutsToAirouts": "0.77", + "atBatsPerHomeRun": "26.28" + }, + "team": { + "id": 119, + "name": "Los Angeles Dodgers", + "link": "/api/v1/teams/119" + }, + "numTeams": 1, + "rank": 7 + }, + { + "stat": { + "gamesPlayed": 86, + "groundOuts": 676, + "airOuts": 746, + "runs": 412, + "doubles": 163, + "triples": 6, + "homeRuns": 132, + "strikeOuts": 792, + "baseOnBalls": 253, + "intentionalWalks": 5, + "hits": 733, + "hitByPitch": 37, + "avg": ".251", + "atBats": 2926, + "obp": ".316", + "slg": ".446", + "ops": ".762", + "caughtStealing": 16, + "stolenBases": 47, + "stolenBasePercentage": ".746", + "groundIntoDoublePlay": 52, + "numberOfPitches": 12685, + "plateAppearances": 3237, + "totalBases": 1304, + "rbi": 393, + "leftOnBase": 559, + "sacBunts": 0, + "sacFlies": 21, + "babip": ".297", + "groundOutsToAirouts": "0.91", + "atBatsPerHomeRun": "22.17" + }, + "team": { + "id": 144, + "name": "Atlanta Braves", + "link": "/api/v1/teams/144" + }, + "numTeams": 1, + "rank": 8 + }, + { + "stat": { + "gamesPlayed": 87, + "groundOuts": 856, + "airOuts": 734, + "runs": 338, + "doubles": 148, + "triples": 10, + "homeRuns": 67, + "strikeOuts": 625, + "baseOnBalls": 269, + "intentionalWalks": 6, + "hits": 728, + "hitByPitch": 29, + "avg": ".250", + "atBats": 2914, + "obp": ".318", + "slg": ".376", + "ops": ".694", + "caughtStealing": 13, + "stolenBases": 32, + "stolenBasePercentage": ".711", + "groundIntoDoublePlay": 86, + "numberOfPitches": 12282, + "plateAppearances": 3245, + "totalBases": 1097, + "rbi": 323, + "leftOnBase": 597, + "sacBunts": 11, + "sacFlies": 18, + "babip": ".295", + "groundOutsToAirouts": "1.17", + "atBatsPerHomeRun": "43.49" + }, + "team": { + "id": 120, + "name": "Washington Nationals", + "link": "/api/v1/teams/120" + }, + "numTeams": 1, + "rank": 9 + }, + { + "stat": { + "gamesPlayed": 87, + "groundOuts": 718, + "airOuts": 859, + "runs": 390, + "doubles": 145, + "triples": 14, + "homeRuns": 90, + "strikeOuts": 680, + "baseOnBalls": 267, + "intentionalWalks": 6, + "hits": 738, + "hitByPitch": 38, + "avg": ".249", + "atBats": 2966, + "obp": ".316", + "slg": ".398", + "ops": ".714", + "caughtStealing": 15, + "stolenBases": 59, + "stolenBasePercentage": ".797", + "groundIntoDoublePlay": 60, + "numberOfPitches": 12930, + "plateAppearances": 3302, + "totalBases": 1181, + "rbi": 372, + "leftOnBase": 609, + "sacBunts": 3, + "sacFlies": 26, + "babip": ".292", + "groundOutsToAirouts": "0.84", + "atBatsPerHomeRun": "32.96" + }, + "team": { + "id": 138, + "name": "St. Louis Cardinals", + "link": "/api/v1/teams/138" + }, + "numTeams": 1, + "rank": 10 + }, + { + "stat": { + "gamesPlayed": 82, + "groundOuts": 745, + "airOuts": 817, + "runs": 357, + "doubles": 152, + "triples": 16, + "homeRuns": 66, + "strikeOuts": 573, + "baseOnBalls": 241, + "intentionalWalks": 9, + "hits": 688, + "hitByPitch": 31, + "avg": ".247", + "atBats": 2784, + "obp": ".311", + "slg": ".384", + "ops": ".695", + "caughtStealing": 14, + "stolenBases": 51, + "stolenBasePercentage": ".785", + "groundIntoDoublePlay": 57, + "numberOfPitches": 12066, + "plateAppearances": 3095, + "totalBases": 1070, + "rbi": 339, + "leftOnBase": 556, + "sacBunts": 8, + "sacFlies": 31, + "babip": ".286", + "groundOutsToAirouts": "0.91", + "atBatsPerHomeRun": "42.18" + }, + "team": { + "id": 114, + "name": "Cleveland Guardians", + "link": "/api/v1/teams/114" + }, + "numTeams": 1, + "rank": 11 + }, + { + "stat": { + "gamesPlayed": 85, + "groundOuts": 721, + "airOuts": 766, + "runs": 406, + "doubles": 135, + "triples": 14, + "homeRuns": 111, + "strikeOuts": 714, + "baseOnBalls": 276, + "intentionalWalks": 8, + "hits": 710, + "hitByPitch": 25, + "avg": ".246", + "atBats": 2882, + "obp": ".315", + "slg": ".418", + "ops": ".733", + "caughtStealing": 11, + "stolenBases": 52, + "stolenBasePercentage": ".825", + "groundIntoDoublePlay": 64, + "numberOfPitches": 12752, + "plateAppearances": 3212, + "totalBases": 1206, + "rbi": 387, + "leftOnBase": 557, + "sacBunts": 4, + "sacFlies": 25, + "babip": ".288", + "groundOutsToAirouts": "0.94", + "atBatsPerHomeRun": "25.96" + }, + "team": { + "id": 143, + "name": "Philadelphia Phillies", + "link": "/api/v1/teams/143" + }, + "numTeams": 1, + "rank": 12 + }, + { + "stat": { + "gamesPlayed": 85, + "groundOuts": 760, + "airOuts": 698, + "runs": 367, + "doubles": 146, + "triples": 18, + "homeRuns": 84, + "strikeOuts": 751, + "baseOnBalls": 288, + "intentionalWalks": 10, + "hits": 710, + "hitByPitch": 43, + "avg": ".246", + "atBats": 2891, + "obp": ".321", + "slg": ".396", + "ops": ".717", + "caughtStealing": 19, + "stolenBases": 56, + "stolenBasePercentage": ".747", + "groundIntoDoublePlay": 71, + "numberOfPitches": 12729, + "plateAppearances": 3251, + "totalBases": 1144, + "rbi": 343, + "leftOnBase": 612, + "sacBunts": 7, + "sacFlies": 21, + "babip": ".301", + "groundOutsToAirouts": "1.09", + "atBatsPerHomeRun": "34.42" + }, + "team": { + "id": 112, + "name": "Chicago Cubs", + "link": "/api/v1/teams/112" + }, + "numTeams": 1, + "rank": 13 + }, + { + "stat": { + "gamesPlayed": 85, + "groundOuts": 695, + "airOuts": 768, + "runs": 444, + "doubles": 119, + "triples": 6, + "homeRuns": 144, + "strikeOuts": 707, + "baseOnBalls": 330, + "intentionalWalks": 17, + "hits": 689, + "hitByPitch": 32, + "avg": ".244", + "atBats": 2826, + "obp": ".327", + "slg": ".443", + "ops": ".770", + "caughtStealing": 14, + "stolenBases": 58, + "stolenBasePercentage": ".806", + "groundIntoDoublePlay": 63, + "numberOfPitches": 12841, + "plateAppearances": 3224, + "totalBases": 1252, + "rbi": 421, + "leftOnBase": 552, + "sacBunts": 7, + "sacFlies": 26, + "babip": ".272", + "groundOutsToAirouts": "0.90", + "atBatsPerHomeRun": "19.62" + }, + "team": { + "id": 147, + "name": "New York Yankees", + "link": "/api/v1/teams/147" + }, + "numTeams": 1, + "rank": 14 + }, + { + "stat": { + "gamesPlayed": 83, + "groundOuts": 755, + "airOuts": 663, + "runs": 357, + "doubles": 131, + "triples": 12, + "homeRuns": 90, + "strikeOuts": 724, + "baseOnBalls": 237, + "intentionalWalks": 3, + "hits": 678, + "hitByPitch": 35, + "avg": ".243", + "atBats": 2795, + "obp": ".307", + "slg": ".395", + "ops": ".702", + "caughtStealing": 13, + "stolenBases": 68, + "stolenBasePercentage": ".840", + "groundIntoDoublePlay": 59, + "numberOfPitches": 12106, + "plateAppearances": 3097, + "totalBases": 1103, + "rbi": 339, + "leftOnBase": 541, + "sacBunts": 2, + "sacFlies": 23, + "babip": ".293", + "groundOutsToAirouts": "1.14", + "atBatsPerHomeRun": "31.06" + }, + "team": { + "id": 146, + "name": "Miami Marlins", + "link": "/api/v1/teams/146" + }, + "numTeams": 1, + "rank": 15 + }, + { + "stat": { + "gamesPlayed": 84, + "groundOuts": 704, + "airOuts": 802, + "runs": 378, + "doubles": 139, + "triples": 8, + "homeRuns": 123, + "strikeOuts": 627, + "baseOnBalls": 303, + "intentionalWalks": 7, + "hits": 675, + "hitByPitch": 31, + "avg": ".242", + "atBats": 2785, + "obp": ".322", + "slg": ".431", + "ops": ".753", + "caughtStealing": 13, + "stolenBases": 40, + "stolenBasePercentage": ".755", + "groundIntoDoublePlay": 55, + "numberOfPitches": 12012, + "plateAppearances": 3143, + "totalBases": 1199, + "rbi": 370, + "leftOnBase": 567, + "sacBunts": 5, + "sacFlies": 18, + "babip": ".269", + "groundOutsToAirouts": "0.88", + "atBatsPerHomeRun": "22.64" + }, + "team": { + "id": 117, + "name": "Houston Astros", + "link": "/api/v1/teams/117" + }, + "numTeams": 1, + "rank": 16 + }, + { + "stat": { + "gamesPlayed": 83, + "groundOuts": 720, + "airOuts": 797, + "runs": 323, + "doubles": 128, + "triples": 20, + "homeRuns": 71, + "strikeOuts": 636, + "baseOnBalls": 256, + "intentionalWalks": 4, + "hits": 674, + "hitByPitch": 21, + "avg": ".241", + "atBats": 2800, + "obp": ".307", + "slg": ".377", + "ops": ".684", + "caughtStealing": 15, + "stolenBases": 48, + "stolenBasePercentage": ".762", + "groundIntoDoublePlay": 60, + "numberOfPitches": 11768, + "plateAppearances": 3104, + "totalBases": 1055, + "rbi": 309, + "leftOnBase": 571, + "sacBunts": 8, + "sacFlies": 19, + "babip": ".286", + "groundOutsToAirouts": "0.90", + "atBatsPerHomeRun": "39.44" + }, + "team": { + "id": 118, + "name": "Kansas City Royals", + "link": "/api/v1/teams/118" + }, + "numTeams": 1, + "rank": 17 + }, + { + "stat": { + "gamesPlayed": 82, + "groundOuts": 646, + "airOuts": 794, + "runs": 367, + "doubles": 102, + "triples": 9, + "homeRuns": 109, + "strikeOuts": 704, + "baseOnBalls": 228, + "intentionalWalks": 6, + "hits": 669, + "hitByPitch": 19, + "avg": ".240", + "atBats": 2788, + "obp": ".300", + "slg": ".400", + "ops": ".700", + "caughtStealing": 20, + "stolenBases": 66, + "stolenBasePercentage": ".767", + "groundIntoDoublePlay": 37, + "numberOfPitches": 11697, + "plateAppearances": 3060, + "totalBases": 1116, + "rbi": 347, + "leftOnBase": 512, + "sacBunts": 4, + "sacFlies": 21, + "babip": ".281", + "groundOutsToAirouts": "0.81", + "atBatsPerHomeRun": "25.58" + }, + "team": { + "id": 140, + "name": "Texas Rangers", + "link": "/api/v1/teams/140" + }, + "numTeams": 1, + "rank": 18 + }, + { + "stat": { + "gamesPlayed": 86, + "groundOuts": 753, + "airOuts": 783, + "runs": 378, + "doubles": 151, + "triples": 13, + "homeRuns": 70, + "strikeOuts": 716, + "baseOnBalls": 300, + "intentionalWalks": 15, + "hits": 698, + "hitByPitch": 35, + "avg": ".240", + "atBats": 2914, + "obp": ".315", + "slg": ".372", + "ops": ".687", + "caughtStealing": 15, + "stolenBases": 26, + "stolenBasePercentage": ".634", + "groundIntoDoublePlay": 52, + "numberOfPitches": 12835, + "plateAppearances": 3288, + "totalBases": 1085, + "rbi": 365, + "leftOnBase": 620, + "sacBunts": 8, + "sacFlies": 28, + "babip": ".291", + "groundOutsToAirouts": "0.96", + "atBatsPerHomeRun": "41.63" + }, + "team": { + "id": 135, + "name": "San Diego Padres", + "link": "/api/v1/teams/135" + }, + "numTeams": 1, + "rank": 19 + }, + { + "stat": { + "gamesPlayed": 85, + "groundOuts": 679, + "airOuts": 737, + "runs": 357, + "doubles": 133, + "triples": 8, + "homeRuns": 77, + "strikeOuts": 746, + "baseOnBalls": 238, + "intentionalWalks": 2, + "hits": 666, + "hitByPitch": 52, + "avg": ".238", + "atBats": 2801, + "obp": ".307", + "slg": ".373", + "ops": ".680", + "caughtStealing": 16, + "stolenBases": 41, + "stolenBasePercentage": ".719", + "groundIntoDoublePlay": 71, + "numberOfPitches": 12188, + "plateAppearances": 3124, + "totalBases": 1046, + "rbi": 341, + "leftOnBase": 511, + "sacBunts": 7, + "sacFlies": 20, + "babip": ".295", + "groundOutsToAirouts": "0.92", + "atBatsPerHomeRun": "36.38" + }, + "team": { + "id": 113, + "name": "Cincinnati Reds", + "link": "/api/v1/teams/113" + }, + "numTeams": 1, + "rank": 20 + }, + { + "stat": { + "gamesPlayed": 84, + "groundOuts": 729, + "airOuts": 711, + "runs": 345, + "doubles": 142, + "triples": 11, + "homeRuns": 77, + "strikeOuts": 734, + "baseOnBalls": 254, + "intentionalWalks": 8, + "hits": 668, + "hitByPitch": 23, + "avg": ".237", + "atBats": 2822, + "obp": ".303", + "slg": ".377", + "ops": ".680", + "caughtStealing": 23, + "stolenBases": 58, + "stolenBasePercentage": ".716", + "groundIntoDoublePlay": 47, + "numberOfPitches": 12133, + "plateAppearances": 3119, + "totalBases": 1063, + "rbi": 328, + "leftOnBase": 547, + "sacBunts": 3, + "sacFlies": 17, + "babip": ".291", + "groundOutsToAirouts": "1.03", + "atBatsPerHomeRun": "36.65" + }, + "team": { + "id": 139, + "name": "Tampa Bay Rays", + "link": "/api/v1/teams/139" + }, + "numTeams": 1, + "rank": 21 + }, + { + "stat": { + "gamesPlayed": 86, + "groundOuts": 714, + "airOuts": 738, + "runs": 390, + "doubles": 130, + "triples": 11, + "homeRuns": 118, + "strikeOuts": 757, + "baseOnBalls": 297, + "intentionalWalks": 7, + "hits": 677, + "hitByPitch": 44, + "avg": ".236", + "atBats": 2865, + "obp": ".316", + "slg": ".413", + "ops": ".729", + "caughtStealing": 16, + "stolenBases": 54, + "stolenBasePercentage": ".771", + "groundIntoDoublePlay": 66, + "numberOfPitches": 13165, + "plateAppearances": 3227, + "totalBases": 1183, + "rbi": 380, + "leftOnBase": 564, + "sacBunts": 2, + "sacFlies": 19, + "babip": ".278", + "groundOutsToAirouts": "0.97", + "atBatsPerHomeRun": "24.28" + }, + "team": { + "id": 158, + "name": "Milwaukee Brewers", + "link": "/api/v1/teams/158" + }, + "numTeams": 1, + "rank": 22 + }, + { + "stat": { + "gamesPlayed": 86, + "groundOuts": 675, + "airOuts": 805, + "runs": 348, + "doubles": 138, + "triples": 11, + "homeRuns": 91, + "strikeOuts": 737, + "baseOnBalls": 310, + "intentionalWalks": 8, + "hits": 672, + "hitByPitch": 47, + "avg": ".234", + "atBats": 2866, + "obp": ".317", + "slg": ".386", + "ops": ".703", + "caughtStealing": 17, + "stolenBases": 47, + "stolenBasePercentage": ".734", + "groundIntoDoublePlay": 54, + "numberOfPitches": 12662, + "plateAppearances": 3249, + "totalBases": 1105, + "rbi": 333, + "leftOnBase": 625, + "sacBunts": 3, + "sacFlies": 20, + "babip": ".282", + "groundOutsToAirouts": "0.84", + "atBatsPerHomeRun": "31.50" + }, + "team": { + "id": 136, + "name": "Seattle Mariners", + "link": "/api/v1/teams/136" + }, + "numTeams": 1, + "rank": 23 + }, + { + "stat": { + "gamesPlayed": 83, + "groundOuts": 673, + "airOuts": 746, + "runs": 384, + "doubles": 131, + "triples": 7, + "homeRuns": 96, + "strikeOuts": 727, + "baseOnBalls": 311, + "intentionalWalks": 9, + "hits": 641, + "hitByPitch": 47, + "avg": ".233", + "atBats": 2753, + "obp": ".318", + "slg": ".390", + "ops": ".708", + "caughtStealing": 10, + "stolenBases": 38, + "stolenBasePercentage": ".792", + "groundIntoDoublePlay": 59, + "numberOfPitches": 12604, + "plateAppearances": 3145, + "totalBases": 1074, + "rbi": 369, + "leftOnBase": 562, + "sacBunts": 1, + "sacFlies": 33, + "babip": ".278", + "groundOutsToAirouts": "0.90", + "atBatsPerHomeRun": "28.68" + }, + "team": { + "id": 137, + "name": "San Francisco Giants", + "link": "/api/v1/teams/137" + }, + "numTeams": 1, + "rank": 24 + }, + { + "stat": { + "gamesPlayed": 86, + "groundOuts": 656, + "airOuts": 727, + "runs": 342, + "doubles": 119, + "triples": 13, + "homeRuns": 101, + "strikeOuts": 831, + "baseOnBalls": 263, + "intentionalWalks": 15, + "hits": 663, + "hitByPitch": 27, + "avg": ".232", + "atBats": 2852, + "obp": ".302", + "slg": ".390", + "ops": ".692", + "caughtStealing": 18, + "stolenBases": 48, + "stolenBasePercentage": ".727", + "groundIntoDoublePlay": 54, + "numberOfPitches": 12428, + "plateAppearances": 3167, + "totalBases": 1111, + "rbi": 331, + "leftOnBase": 549, + "sacBunts": 13, + "sacFlies": 12, + "babip": ".291", + "groundOutsToAirouts": "0.90", + "atBatsPerHomeRun": "28.24" + }, + "team": { + "id": 108, + "name": "Los Angeles Angels", + "link": "/api/v1/teams/108" + }, + "numTeams": 1, + "rank": 25 + }, + { + "stat": { + "gamesPlayed": 84, + "groundOuts": 716, + "airOuts": 716, + "runs": 268, + "doubles": 109, + "triples": 16, + "homeRuns": 51, + "strikeOuts": 707, + "baseOnBalls": 204, + "intentionalWalks": 3, + "hits": 633, + "hitByPitch": 26, + "avg": ".230", + "atBats": 2747, + "obp": ".288", + "slg": ".337", + "ops": ".625", + "caughtStealing": 12, + "stolenBases": 22, + "stolenBasePercentage": ".647", + "groundIntoDoublePlay": 60, + "numberOfPitches": 11526, + "plateAppearances": 3002, + "totalBases": 927, + "rbi": 258, + "leftOnBase": 524, + "sacBunts": 5, + "sacFlies": 20, + "babip": ".290", + "groundOutsToAirouts": "1.00", + "atBatsPerHomeRun": "53.86" + }, + "team": { + "id": 116, + "name": "Detroit Tigers", + "link": "/api/v1/teams/116" + }, + "numTeams": 1, + "rank": 26 + }, + { + "stat": { + "gamesPlayed": 86, + "groundOuts": 645, + "airOuts": 840, + "runs": 351, + "doubles": 154, + "triples": 11, + "homeRuns": 87, + "strikeOuts": 775, + "baseOnBalls": 240, + "intentionalWalks": 6, + "hits": 668, + "hitByPitch": 50, + "avg": ".230", + "atBats": 2900, + "obp": ".298", + "slg": ".381", + "ops": ".679", + "caughtStealing": 14, + "stolenBases": 52, + "stolenBasePercentage": ".788", + "groundIntoDoublePlay": 53, + "numberOfPitches": 12440, + "plateAppearances": 3222, + "totalBases": 1105, + "rbi": 333, + "leftOnBase": 588, + "sacBunts": 7, + "sacFlies": 21, + "babip": ".282", + "groundOutsToAirouts": "0.77", + "atBatsPerHomeRun": "33.33" + }, + "team": { + "id": 110, + "name": "Baltimore Orioles", + "link": "/api/v1/teams/110" + }, + "numTeams": 1, + "rank": 27 + }, + { + "stat": { + "gamesPlayed": 85, + "groundOuts": 737, + "airOuts": 741, + "runs": 365, + "doubles": 129, + "triples": 13, + "homeRuns": 99, + "strikeOuts": 732, + "baseOnBalls": 298, + "intentionalWalks": 11, + "hits": 624, + "hitByPitch": 29, + "avg": ".223", + "atBats": 2797, + "obp": ".302", + "slg": ".385", + "ops": ".687", + "caughtStealing": 13, + "stolenBases": 35, + "stolenBasePercentage": ".729", + "groundIntoDoublePlay": 45, + "numberOfPitches": 12407, + "plateAppearances": 3161, + "totalBases": 1076, + "rbi": 341, + "leftOnBase": 551, + "sacBunts": 15, + "sacFlies": 22, + "babip": ".264", + "groundOutsToAirouts": "0.99", + "atBatsPerHomeRun": "28.25" + }, + "team": { + "id": 109, + "name": "Arizona Diamondbacks", + "link": "/api/v1/teams/109" + }, + "numTeams": 1, + "rank": 28 + }, + { + "stat": { + "gamesPlayed": 85, + "groundOuts": 705, + "airOuts": 701, + "runs": 308, + "doubles": 113, + "triples": 14, + "homeRuns": 91, + "strikeOuts": 785, + "baseOnBalls": 251, + "intentionalWalks": 6, + "hits": 607, + "hitByPitch": 23, + "avg": ".219", + "atBats": 2771, + "obp": ".288", + "slg": ".368", + "ops": ".656", + "caughtStealing": 18, + "stolenBases": 35, + "stolenBasePercentage": ".660", + "groundIntoDoublePlay": 51, + "numberOfPitches": 12272, + "plateAppearances": 3072, + "totalBases": 1021, + "rbi": 288, + "leftOnBase": 518, + "sacBunts": 8, + "sacFlies": 19, + "babip": ".270", + "groundOutsToAirouts": "1.01", + "atBatsPerHomeRun": "30.45" + }, + "team": { + "id": 134, + "name": "Pittsburgh Pirates", + "link": "/api/v1/teams/134" + }, + "numTeams": 1, + "rank": 29 + }, + { + "stat": { + "gamesPlayed": 86, + "groundOuts": 771, + "airOuts": 748, + "runs": 272, + "doubles": 130, + "triples": 7, + "homeRuns": 61, + "strikeOuts": 714, + "baseOnBalls": 215, + "intentionalWalks": 4, + "hits": 583, + "hitByPitch": 32, + "avg": ".209", + "atBats": 2789, + "obp": ".272", + "slg": ".326", + "ops": ".598", + "caughtStealing": 14, + "stolenBases": 51, + "stolenBasePercentage": ".785", + "groundIntoDoublePlay": 60, + "numberOfPitches": 11688, + "plateAppearances": 3064, + "totalBases": 910, + "rbi": 250, + "leftOnBase": 495, + "sacBunts": 10, + "sacFlies": 17, + "babip": ".257", + "groundOutsToAirouts": "1.03", + "atBatsPerHomeRun": "45.72" + }, + "team": { + "id": 133, + "name": "Oakland Athletics", + "link": "/api/v1/teams/133" + }, + "numTeams": 1, + "rank": 30 + } + ], + "splitsTiedWithOffset": [], + "splitsTiedWithLimit": [] + } + ] +} From 246d2d879e32caada7abcbeb2ae5da5c42fe50d9 Mon Sep 17 00:00:00 2001 From: Alex Bolduc Date: Thu, 2 Mar 2023 15:26:34 -0500 Subject: [PATCH 03/19] Get stats for schedule date --- api/src/stats.rs | 30 +++++++++++++----------------- src/debug.rs | 15 +++++++++++++-- src/main.rs | 4 ++-- src/ui/boxscore.rs | 2 +- 4 files changed, 29 insertions(+), 22 deletions(-) diff --git a/api/src/stats.rs b/api/src/stats.rs index 299c14d..eca8a2a 100644 --- a/api/src/stats.rs +++ b/api/src/stats.rs @@ -25,7 +25,6 @@ pub struct DisplayName { #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Split { - season: String, pub stat: StatSplit, pub team: IdNameLink, pub player: Option, @@ -53,30 +52,19 @@ pub enum StatSplit { #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct PitchingStat { - pub wins: u16, - pub losses: u16, - pub era: String, pub games_played: u16, pub games_started: u16, - pub complete_games: u16, - pub shutouts: u16, - pub saves: u16, - pub save_opportunities: u16, ground_outs: u16, air_outs: u16, - pub innings_pitched: String, - pub hits: u16, pub runs: u16, - pub earned_runs: u16, doubles: i64, triples: i64, pub home_runs: u16, - pub hit_batsmen: u16, - pub base_on_balls: u16, pub strike_outs: u16, + pub base_on_balls: u16, intentional_walks: u16, + pub hits: u16, hit_by_pitch: u16, - pub whip: String, pub avg: String, at_bats: u16, obp: String, @@ -87,16 +75,26 @@ pub struct PitchingStat { stolen_base_percentage: String, ground_into_double_play: u16, number_of_pitches: u16, + pub era: String, + pub innings_pitched: String, + pub wins: u16, + pub losses: u16, + pub saves: u16, + pub save_opportunities: u16, holds: u16, blown_saves: u16, + pub earned_runs: u16, + pub whip: String, batters_faced: u16, outs: u16, games_pitched: u16, + pub complete_games: u16, + pub shutouts: u16, strikes: u32, strike_percentage: String, + pub hit_batsmen: u16, balks: u16, wild_pitches: u16, - pickoffs: u16, total_bases: u16, ground_outs_to_airouts: String, win_percentage: String, @@ -108,7 +106,6 @@ pub struct PitchingStat { hits_per9_inn: String, runs_scored_per9: String, home_runs_per9: String, - catchers_interference: u16, sac_bunts: u16, sac_flies: u16, } @@ -146,6 +143,5 @@ pub struct HittingStat { pub sac_flies: u16, pub babip: String, pub ground_outs_to_airouts: String, - pub catchers_interference: u16, pub at_bats_per_home_run: String, } diff --git a/src/debug.rs b/src/debug.rs index 48b5209..ad191cc 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -1,5 +1,7 @@ use crate::app::{App, GamedayPanels}; use std::fmt; +use chrono::NaiveDate; +use mlb_api::client::StatGroup; use tui::backend::Backend; use tui::Frame; @@ -9,18 +11,23 @@ pub struct DebugInfo { pub terminal_width: u16, pub terminal_height: u16, pub gameday_active_views: GamedayPanels, + pub date: NaiveDate, + pub stat_type: StatGroup, } impl fmt::Display for DebugInfo { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, - "game id: {}\ngameday: {}\nterminal height: {} width: {}\n{:?}", + "game id: {}\ngameday: {}\nterminal height: {} width: {}\ndate: {}\nstat group: {}\n{:?}", self.game_id, self.gameday_url, self.terminal_height, self.terminal_width, - self.gameday_active_views + self.date, + self.stat_type, + self.gameday_active_views, + ) } } @@ -33,6 +40,8 @@ impl DebugInfo { terminal_width: 0, terminal_height: 0, gameday_active_views: GamedayPanels::default(), + date: NaiveDate::from_ymd(2022, 07, 09), + stat_type: StatGroup::Pitching } } // TODO add more info @@ -47,5 +56,7 @@ impl DebugInfo { self.terminal_width = f.size().width; self.terminal_height = f.size().height; self.gameday_active_views = app.gameday; + self.date = app.schedule.date; + self.stat_type = app.stats.stat_type.group.clone(); } } diff --git a/src/main.rs b/src/main.rs index a60d70c..3d83f81 100644 --- a/src/main.rs +++ b/src/main.rs @@ -111,8 +111,8 @@ fn main() -> Result<(), Box> { // pitching/hitting is changed Ok(MenuItem::Stats) => { let response = match app.stats.stat_type.team_player { - TeamOrPlayer::Team => CLIENT.get_team_stats(app.stats.stat_type.group.clone()), - TeamOrPlayer::Player => CLIENT.get_player_stats(app.stats.stat_type.group.clone()), + TeamOrPlayer::Team => CLIENT.get_team_stats_on_date(app.stats.stat_type.group.clone(), app.schedule.date), + TeamOrPlayer::Player => CLIENT.get_player_stats_on_date(app.stats.stat_type.group.clone(), app.schedule.date), }; app.stats.update(&response); } diff --git a/src/ui/boxscore.rs b/src/ui/boxscore.rs index 5a58c35..89c4c17 100644 --- a/src/ui/boxscore.rs +++ b/src/ui/boxscore.rs @@ -21,7 +21,7 @@ impl StatefulWidget for TeamBatterBoxscoreWidget { let width = 4; let mut widths = vec![Constraint::Length(width); HEADER.len()]; // the first width needs to be wider to display the player name - widths[0] = Constraint::Length(15); + widths[0] = Constraint::Length(20); // the last width needs to be wider to display batting average widths[HEADER.len() - 1] = Constraint::Length(5); From 3a6d7056a5e15e2966bc45868a9ecf8440cae094 Mon Sep 17 00:00:00 2001 From: Alex Bolduc Date: Thu, 2 Mar 2023 16:09:15 -0500 Subject: [PATCH 04/19] Change date from stats screen --- src/draw.rs | 24 ++++++++++++++++++------ src/event.rs | 18 ++++++++++++++++-- src/main.rs | 6 ++++++ 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/draw.rs b/src/draw.rs index 80ddbb8..49d2037 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -42,17 +42,18 @@ where match app.active_tab { MenuItem::Scoreboard => draw_scoreboard(f, main_layout.main, app), MenuItem::DatePicker => { - draw_scoreboard(f, main_layout.main, app); + match app.previous_tab { + MenuItem::Scoreboard => draw_scoreboard(f, main_layout.main, app), + MenuItem::Stats => draw_stats(f, main_layout.main, app), + _ => () + } + draw_date_picker(f, main_layout.main, app); } MenuItem::Gameday => draw_gameday(f, main_layout.main, app), MenuItem::Stats => draw_stats(f, main_layout.main, app), MenuItem::Standings => { - f.render_stateful_widget( - StandingsWidget {}, - main_layout.main, - &mut app.standings, - ); + draw_standings(f, main_layout.main, app); } MenuItem::Help => draw_help(f, f.size()), } @@ -265,6 +266,17 @@ where ); } +fn draw_standings(f: &mut Frame, rect: Rect, app: &mut App) +where + B: Backend, +{ + f.render_stateful_widget( + StandingsWidget {}, + rect, + &mut app.standings, + ); +} + fn draw_help(f: &mut Frame, rect: Rect) where B: Backend, diff --git a/src/event.rs b/src/event.rs index ea14920..25dbc49 100644 --- a/src/event.rs +++ b/src/event.rs @@ -37,6 +37,13 @@ pub fn handle_key_bindings( let _ = selective_update.try_send(MenuItem::Standings); } + (_, Char(':')) => { + match app.active_tab { + MenuItem::Scoreboard | MenuItem::Stats => app.update_tab(MenuItem::DatePicker), + _ => () + } + } + (MenuItem::Scoreboard, Char('j')) => { app.schedule.next(); let _ = selective_update.try_send(MenuItem::Scoreboard); @@ -45,17 +52,24 @@ pub fn handle_key_bindings( app.schedule.previous(); let _ = selective_update.try_send(MenuItem::Scoreboard); } - (MenuItem::Scoreboard, Char(':')) => app.update_tab(MenuItem::DatePicker), (MenuItem::DatePicker, KeyCode::Enter) => { let date: String = app.date_input.text.drain(..).collect(); if app.schedule.set_date_from_input(date).is_ok() { app.date_input.is_valid = true; - app.update_tab(MenuItem::Scoreboard); let _ = selective_update.try_send(MenuItem::DatePicker); } else { app.date_input.is_valid = false; } + + match app.previous_tab { + MenuItem::Scoreboard => app.update_tab(MenuItem::Scoreboard), + MenuItem::Stats => { + app.update_tab(MenuItem::Stats); + let _ = selective_update.try_send(MenuItem::Stats); + }, + _ => () + } } (MenuItem::DatePicker, KeyCode::Esc) => { app.date_input.text.clear(); diff --git a/src/main.rs b/src/main.rs index 3d83f81..9ac78dc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -102,6 +102,12 @@ fn main() -> Result<(), Box> { app.schedule.update(&CLIENT.get_schedule_date(date)); let game_id = app.schedule.get_selected_game(); app.update_live_data(&CLIENT.get_live_data(game_id)); + + let response = match app.stats.stat_type.team_player { + TeamOrPlayer::Team => CLIENT.get_team_stats_on_date(app.stats.stat_type.group.clone(), app.schedule.date), + TeamOrPlayer::Player => CLIENT.get_player_stats_on_date(app.stats.stat_type.group.clone(), app.schedule.date), + }; + app.stats.update(&response); } // update standings only when tab is switched to Ok(MenuItem::Standings) => { From b4ec80949bcf21801b8adad2ebe679aa068567af Mon Sep 17 00:00:00 2001 From: Alex Bolduc Date: Sun, 25 Feb 2024 23:11:04 -0500 Subject: [PATCH 05/19] Merge branch 'main' of github-axbolduc.com:axbolduc/mlbt --- api/src/boxscore.rs | 2 +- api/src/client.rs | 43 +- api/src/stats.rs | 30 +- api/tests/client.rs | 48 +- api/tests/responses/player-stats-date.json | 3519 ++++++++++++++++++++ api/tests/responses/team-stats-date.json | 1278 +++++++ src/components/boxscore.rs | 3 + src/components/debug.rs | 17 +- src/components/schedule.rs | 2 +- src/draw.rs | 31 +- src/event.rs | 17 +- src/ui/boxscore.rs | 4 +- src/ui/layout.rs | 3 +- src/ui/schedule.rs | 2 +- 14 files changed, 4952 insertions(+), 47 deletions(-) create mode 100644 api/tests/responses/player-stats-date.json create mode 100644 api/tests/responses/team-stats-date.json diff --git a/api/src/boxscore.rs b/api/src/boxscore.rs index c80e47b..5e2659b 100644 --- a/api/src/boxscore.rs +++ b/api/src/boxscore.rs @@ -64,7 +64,7 @@ pub struct Batting { pub runs: Option, doubles: Option, triples: Option, - home_runs: Option, + pub home_runs: Option, pub strike_outs: Option, pub base_on_balls: Option, pub hits: Option, diff --git a/api/src/client.rs b/api/src/client.rs index dac62ca..3857555 100644 --- a/api/src/client.rs +++ b/api/src/client.rs @@ -92,7 +92,18 @@ impl MLBApi { self.get(url).await } - pub async fn get_player_stats(&self, group: StatGroup) -> StatResponse { + pub fn get_team_stats_on_date(&self, group: StatGroup, date: NaiveDate) -> StatResponse { + let url = format!( + "{}v1/teams/stats?sportId=1&stats=byDateRange&season={}&endDate={}&group={}", + self.base_url, + date.year(), + date.format("%Y-%m-%d"), + group + ); + self.get(url) + } + + pub fn get_player_stats(&self, group: StatGroup) -> StatResponse { let local: DateTime = Local::now(); let url = format!( "{}v1/stats?stats=season&season={}&group={}", @@ -103,16 +114,26 @@ impl MLBApi { self.get(url).await } - async fn get(&self, url: String) -> T { - let response = self.client.get(url).send().await.expect("network error"); - response - .json::() - .await - .map(From::from) - .unwrap_or_else(|err| { - eprintln!("parsing error {:?}", err); - T::default() - }) + pub fn get_player_stats_on_date(&self, group: StatGroup, date: NaiveDate) -> StatResponse { + let url = format!( + "{}v1/stats?stats=byDateRange&season={}&endDate={}&group={}", + self.base_url, + date.year(), + date.format("%Y-%m-%d"), + group + ); + self.get(url) + } + + // TODO need better error handling, especially on parsing + fn get(&self, url: String) -> T { + let response = self.client.get(url).send().unwrap_or_else(|err| { + panic!("network error {:?}", err); + }); + response.json::().map(From::from).unwrap_or_else(|err| { + eprintln!("parsing error {:?}", err); + T::default() + }) } } diff --git a/api/src/stats.rs b/api/src/stats.rs index 299c14d..eca8a2a 100644 --- a/api/src/stats.rs +++ b/api/src/stats.rs @@ -25,7 +25,6 @@ pub struct DisplayName { #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Split { - season: String, pub stat: StatSplit, pub team: IdNameLink, pub player: Option, @@ -53,30 +52,19 @@ pub enum StatSplit { #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct PitchingStat { - pub wins: u16, - pub losses: u16, - pub era: String, pub games_played: u16, pub games_started: u16, - pub complete_games: u16, - pub shutouts: u16, - pub saves: u16, - pub save_opportunities: u16, ground_outs: u16, air_outs: u16, - pub innings_pitched: String, - pub hits: u16, pub runs: u16, - pub earned_runs: u16, doubles: i64, triples: i64, pub home_runs: u16, - pub hit_batsmen: u16, - pub base_on_balls: u16, pub strike_outs: u16, + pub base_on_balls: u16, intentional_walks: u16, + pub hits: u16, hit_by_pitch: u16, - pub whip: String, pub avg: String, at_bats: u16, obp: String, @@ -87,16 +75,26 @@ pub struct PitchingStat { stolen_base_percentage: String, ground_into_double_play: u16, number_of_pitches: u16, + pub era: String, + pub innings_pitched: String, + pub wins: u16, + pub losses: u16, + pub saves: u16, + pub save_opportunities: u16, holds: u16, blown_saves: u16, + pub earned_runs: u16, + pub whip: String, batters_faced: u16, outs: u16, games_pitched: u16, + pub complete_games: u16, + pub shutouts: u16, strikes: u32, strike_percentage: String, + pub hit_batsmen: u16, balks: u16, wild_pitches: u16, - pickoffs: u16, total_bases: u16, ground_outs_to_airouts: String, win_percentage: String, @@ -108,7 +106,6 @@ pub struct PitchingStat { hits_per9_inn: String, runs_scored_per9: String, home_runs_per9: String, - catchers_interference: u16, sac_bunts: u16, sac_flies: u16, } @@ -146,6 +143,5 @@ pub struct HittingStat { pub sac_flies: u16, pub babip: String, pub ground_outs_to_airouts: String, - pub catchers_interference: u16, pub at_bats_per_home_run: String, } diff --git a/api/tests/client.rs b/api/tests/client.rs index 751a4b6..80e84ae 100644 --- a/api/tests/client.rs +++ b/api/tests/client.rs @@ -83,10 +83,30 @@ mod tests { } } - #[tokio::test] - async fn test_player_stats() { - let mut server = mockito::Server::new(); + #[test] + fn test_team_stats_on_date() { + let client = MLBApiBuilder::default().build().unwrap(); + let date: NaiveDate = NaiveDate::from_ymd(2022, 07, 09); + for group in vec![StatGroup::Hitting, StatGroup::Pitching] { + let url = format!( + "v1/teams/stats?sportId=1&stats=byDateRange&season=2022&endDate=2022-07-09&group={}", + group + ); + + let _m = mock("GET", Matcher::Exact(url)) + .with_status(200) + .with_header("content-type", "application/json;charset=UTF-8") + .with_body_from_file("./tests/responses/team-stats-date.json") + .create(); + + let resp = client.get_team_stats_on_date(group, date); + println!("{:?}", resp); + } + } + #[test] + fn test_player_stats() { + let client = MLBApiBuilder::default().build().unwrap(); for group in vec![StatGroup::Hitting, StatGroup::Pitching] { let url = format!("v1/stats?stats=season&season=2021&group={}", group); @@ -101,4 +121,26 @@ mod tests { println!("{:?}", resp); } } + + #[test] + fn test_player_stats_on_date() { + let client = MLBApiBuilder::default().build().unwrap(); + let date: NaiveDate = NaiveDate::from_ymd(2022, 07, 09); + for group in vec![StatGroup::Hitting, StatGroup::Pitching] { + let url = format!( + "v1/stats?sportId=1&stats=byDateRange&season=2022&endDate=2022-07-09&group={}", + group + ); + + let _m = mock("GET", Matcher::Exact(url)) + .with_status(200) + .with_header("content-type", "application/json;charset=UTF-8") + .with_body_from_file("./tests/responses/player-stats-date.json") + .create(); + + let resp = client.get_player_stats_on_date(group, date); + println!("{:?}", resp); + } + } + } diff --git a/api/tests/responses/player-stats-date.json b/api/tests/responses/player-stats-date.json new file mode 100644 index 0000000..fd35665 --- /dev/null +++ b/api/tests/responses/player-stats-date.json @@ -0,0 +1,3519 @@ +{ + "copyright": "Copyright 2023 MLB Advanced Media, L.P. Use of any content on this page acknowledges agreement to the terms posted here http://gdx.mlb.com/components/copyright.txt", + "stats": [ + { + "type": { + "displayName": "byDateRange" + }, + "group": { + "displayName": "hitting" + }, + "totalSplits": 146, + "exemptions": [], + "splits": [ + { + "season": "2022", + "stat": { + "gamesPlayed": 77, + "groundOuts": 85, + "airOuts": 73, + "runs": 50, + "doubles": 15, + "triples": 1, + "homeRuns": 4, + "strikeOuts": 25, + "baseOnBalls": 34, + "intentionalWalks": 1, + "hits": 100, + "hitByPitch": 2, + "avg": ".355", + "atBats": 282, + "obp": ".426", + "slg": ".457", + "ops": ".883", + "caughtStealing": 2, + "stolenBases": 2, + "stolenBasePercentage": ".500", + "groundIntoDoublePlay": 2, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1294, + "plateAppearances": 319, + "totalBases": 129, + "rbi": 29, + "leftOnBase": 83, + "sacBunts": 0, + "sacFlies": 1, + "babip": ".378", + "groundOutsToAirouts": "1.16", + "catchersInterference": 0, + "atBatsPerHomeRun": "70.50" + }, + "team": { + "id": 142, + "name": "Minnesota Twins", + "link": "/api/v1/teams/142" + }, + "player": { + "id": 650333, + "fullName": "Luis Arraez", + "link": "/api/v1/people/650333", + "firstName": "Luis", + "lastName": "Arraez" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 1, + "position": { + "code": "3", + "name": "First Base", + "type": "Infielder", + "abbreviation": "1B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 83, + "groundOuts": 60, + "airOuts": 75, + "runs": 61, + "doubles": 28, + "triples": 0, + "homeRuns": 19, + "strikeOuts": 74, + "baseOnBalls": 44, + "intentionalWalks": 1, + "hits": 107, + "hitByPitch": 2, + "avg": ".340", + "atBats": 315, + "obp": ".423", + "slg": ".610", + "ops": "1.033", + "caughtStealing": 0, + "stolenBases": 5, + "stolenBasePercentage": "1.000", + "groundIntoDoublePlay": 3, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1487, + "plateAppearances": 364, + "totalBases": 192, + "rbi": 65, + "leftOnBase": 105, + "sacBunts": 0, + "sacFlies": 1, + "babip": ".395", + "groundOutsToAirouts": "0.80", + "catchersInterference": 2, + "atBatsPerHomeRun": "16.58" + }, + "team": { + "id": 138, + "name": "St. Louis Cardinals", + "link": "/api/v1/teams/138" + }, + "player": { + "id": 502671, + "fullName": "Paul Goldschmidt", + "link": "/api/v1/people/502671", + "firstName": "Paul", + "lastName": "Goldschmidt" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 2, + "position": { + "code": "3", + "name": "First Base", + "type": "Infielder", + "abbreviation": "1B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 80, + "groundOuts": 81, + "airOuts": 74, + "runs": 59, + "doubles": 27, + "triples": 1, + "homeRuns": 19, + "strikeOuts": 63, + "baseOnBalls": 25, + "intentionalWalks": 5, + "hits": 106, + "hitByPitch": 5, + "avg": ".327", + "atBats": 324, + "obp": ".384", + "slg": ".593", + "ops": ".977", + "caughtStealing": 1, + "stolenBases": 2, + "stolenBasePercentage": ".667", + "groundIntoDoublePlay": 6, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1249, + "plateAppearances": 354, + "totalBases": 192, + "rbi": 51, + "leftOnBase": 121, + "sacBunts": 0, + "sacFlies": 0, + "babip": ".360", + "groundOutsToAirouts": "1.09", + "catchersInterference": 0, + "atBatsPerHomeRun": "17.05" + }, + "team": { + "id": 111, + "name": "Boston Red Sox", + "link": "/api/v1/teams/111" + }, + "player": { + "id": 646240, + "fullName": "Rafael Devers", + "link": "/api/v1/people/646240", + "firstName": "Rafael", + "lastName": "Devers" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 3, + "position": { + "code": "5", + "name": "Third Base", + "type": "Infielder", + "abbreviation": "3B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 64, + "groundOuts": 57, + "airOuts": 60, + "runs": 49, + "doubles": 21, + "triples": 1, + "homeRuns": 15, + "strikeOuts": 52, + "baseOnBalls": 26, + "intentionalWalks": 4, + "hits": 77, + "hitByPitch": 3, + "avg": ".318", + "atBats": 242, + "obp": ".385", + "slg": ".599", + "ops": ".984", + "caughtStealing": 2, + "stolenBases": 9, + "stolenBasePercentage": ".818", + "groundIntoDoublePlay": 9, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1035, + "plateAppearances": 275, + "totalBases": 145, + "rbi": 48, + "leftOnBase": 93, + "sacBunts": 0, + "sacFlies": 4, + "babip": ".346", + "groundOutsToAirouts": "0.95", + "catchersInterference": 0, + "atBatsPerHomeRun": "16.13" + }, + "team": { + "id": 143, + "name": "Philadelphia Phillies", + "link": "/api/v1/teams/143" + }, + "player": { + "id": 547180, + "fullName": "Bryce Harper", + "link": "/api/v1/people/547180", + "firstName": "Bryce", + "lastName": "Harper" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 4, + "position": { + "code": "10", + "name": "Designated Hitter", + "type": "Hitter", + "abbreviation": "DH" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 82, + "groundOuts": 79, + "airOuts": 84, + "runs": 34, + "doubles": 13, + "triples": 2, + "homeRuns": 3, + "strikeOuts": 49, + "baseOnBalls": 36, + "intentionalWalks": 0, + "hits": 97, + "hitByPitch": 1, + "avg": ".317", + "atBats": 306, + "obp": ".387", + "slg": ".402", + "ops": ".789", + "caughtStealing": 2, + "stolenBases": 2, + "stolenBasePercentage": ".500", + "groundIntoDoublePlay": 6, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1304, + "plateAppearances": 346, + "totalBases": 123, + "rbi": 34, + "leftOnBase": 120, + "sacBunts": 0, + "sacFlies": 3, + "babip": ".366", + "groundOutsToAirouts": "0.94", + "catchersInterference": 0, + "atBatsPerHomeRun": "102.00" + }, + "team": { + "id": 118, + "name": "Kansas City Royals", + "link": "/api/v1/teams/118" + }, + "player": { + "id": 643217, + "fullName": "Andrew Benintendi", + "link": "/api/v1/people/643217", + "firstName": "Andrew", + "lastName": "Benintendi" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 5, + "position": { + "code": "7", + "name": "Outfielder", + "type": "Outfielder", + "abbreviation": "LF" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 76, + "groundOuts": 63, + "airOuts": 79, + "runs": 38, + "doubles": 19, + "triples": 1, + "homeRuns": 4, + "strikeOuts": 37, + "baseOnBalls": 22, + "intentionalWalks": 0, + "hits": 82, + "hitByPitch": 4, + "avg": ".315", + "atBats": 260, + "obp": ".376", + "slg": ".442", + "ops": ".818", + "caughtStealing": 0, + "stolenBases": 2, + "stolenBasePercentage": "1.000", + "groundIntoDoublePlay": 3, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1042, + "plateAppearances": 287, + "totalBases": 115, + "rbi": 35, + "leftOnBase": 111, + "sacBunts": 0, + "sacFlies": 1, + "babip": ".355", + "groundOutsToAirouts": "0.80", + "catchersInterference": 0, + "atBatsPerHomeRun": "65.00" + }, + "team": { + "id": 121, + "name": "New York Mets", + "link": "/api/v1/teams/121" + }, + "player": { + "id": 643446, + "fullName": "Jeff McNeil", + "link": "/api/v1/people/643446", + "firstName": "Jeff", + "lastName": "McNeil" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 6, + "position": { + "code": "4", + "name": "Second Base", + "type": "Infielder", + "abbreviation": "2B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 74, + "groundOuts": 59, + "airOuts": 67, + "runs": 47, + "doubles": 27, + "triples": 0, + "homeRuns": 8, + "strikeOuts": 77, + "baseOnBalls": 30, + "intentionalWalks": 1, + "hits": 91, + "hitByPitch": 4, + "avg": ".313", + "atBats": 291, + "obp": ".381", + "slg": ".488", + "ops": ".869", + "caughtStealing": 0, + "stolenBases": 0, + "stolenBasePercentage": ".---", + "groundIntoDoublePlay": 10, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1348, + "plateAppearances": 328, + "totalBases": 142, + "rbi": 34, + "leftOnBase": 144, + "sacBunts": 0, + "sacFlies": 3, + "babip": ".397", + "groundOutsToAirouts": "0.88", + "catchersInterference": 0, + "atBatsPerHomeRun": "36.38" + }, + "team": { + "id": 111, + "name": "Boston Red Sox", + "link": "/api/v1/teams/111" + }, + "player": { + "id": 502110, + "fullName": "J.D. Martinez", + "link": "/api/v1/people/502110", + "firstName": "J.D.", + "lastName": "Martinez" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 7, + "position": { + "code": "10", + "name": "Designated Hitter", + "type": "Hitter", + "abbreviation": "DH" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 75, + "groundOuts": 60, + "airOuts": 75, + "runs": 51, + "doubles": 19, + "triples": 1, + "homeRuns": 14, + "strikeOuts": 61, + "baseOnBalls": 34, + "intentionalWalks": 6, + "hits": 88, + "hitByPitch": 1, + "avg": ".311", + "atBats": 283, + "obp": ".386", + "slg": ".534", + "ops": ".920", + "caughtStealing": 1, + "stolenBases": 7, + "stolenBasePercentage": ".875", + "groundIntoDoublePlay": 5, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1150, + "plateAppearances": 319, + "totalBases": 151, + "rbi": 50, + "leftOnBase": 118, + "sacBunts": 0, + "sacFlies": 1, + "babip": ".354", + "groundOutsToAirouts": "0.80", + "catchersInterference": 0, + "atBatsPerHomeRun": "20.21" + }, + "team": { + "id": 135, + "name": "San Diego Padres", + "link": "/api/v1/teams/135" + }, + "player": { + "id": 592518, + "fullName": "Manny Machado", + "link": "/api/v1/people/592518", + "firstName": "Manny", + "lastName": "Machado" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 8, + "position": { + "code": "5", + "name": "Third Base", + "type": "Infielder", + "abbreviation": "3B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 73, + "groundOuts": 76, + "airOuts": 77, + "runs": 32, + "doubles": 15, + "triples": 0, + "homeRuns": 10, + "strikeOuts": 46, + "baseOnBalls": 21, + "intentionalWalks": 2, + "hits": 89, + "hitByPitch": 14, + "avg": ".310", + "atBats": 287, + "obp": ".384", + "slg": ".467", + "ops": ".851", + "caughtStealing": 0, + "stolenBases": 0, + "stolenBasePercentage": ".---", + "groundIntoDoublePlay": 5, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1175, + "plateAppearances": 324, + "totalBases": 134, + "rbi": 45, + "leftOnBase": 99, + "sacBunts": 0, + "sacFlies": 1, + "babip": ".341", + "groundOutsToAirouts": "0.99", + "catchersInterference": 1, + "atBatsPerHomeRun": "28.70" + }, + "team": { + "id": 136, + "name": "Seattle Mariners", + "link": "/api/v1/teams/136" + }, + "player": { + "id": 664034, + "fullName": "Ty France", + "link": "/api/v1/people/664034", + "firstName": "Ty", + "lastName": "France" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 9, + "position": { + "code": "3", + "name": "First Base", + "type": "Infielder", + "abbreviation": "1B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 76, + "groundOuts": 69, + "airOuts": 75, + "runs": 40, + "doubles": 12, + "triples": 0, + "homeRuns": 10, + "strikeOuts": 25, + "baseOnBalls": 32, + "intentionalWalks": 1, + "hits": 75, + "hitByPitch": 4, + "avg": ".310", + "atBats": 242, + "obp": ".396", + "slg": ".483", + "ops": ".879", + "caughtStealing": 0, + "stolenBases": 0, + "stolenBasePercentage": ".---", + "groundIntoDoublePlay": 7, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1131, + "plateAppearances": 280, + "totalBases": 117, + "rbi": 33, + "leftOnBase": 91, + "sacBunts": 0, + "sacFlies": 2, + "babip": ".311", + "groundOutsToAirouts": "0.92", + "catchersInterference": 0, + "atBatsPerHomeRun": "24.20" + }, + "team": { + "id": 141, + "name": "Toronto Blue Jays", + "link": "/api/v1/teams/141" + }, + "player": { + "id": 672386, + "fullName": "Alejandro Kirk", + "link": "/api/v1/people/672386", + "firstName": "Alejandro", + "lastName": "Kirk" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 10, + "position": { + "code": "2", + "name": "Catcher", + "type": "Catcher", + "abbreviation": "C" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 81, + "groundOuts": 68, + "airOuts": 75, + "runs": 49, + "doubles": 21, + "triples": 0, + "homeRuns": 7, + "strikeOuts": 69, + "baseOnBalls": 34, + "intentionalWalks": 2, + "hits": 93, + "hitByPitch": 6, + "avg": ".309", + "atBats": 301, + "obp": ".386", + "slg": ".449", + "ops": ".835", + "caughtStealing": 0, + "stolenBases": 3, + "stolenBasePercentage": "1.000", + "groundIntoDoublePlay": 7, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1368, + "plateAppearances": 345, + "totalBases": 135, + "rbi": 35, + "leftOnBase": 145, + "sacBunts": 0, + "sacFlies": 4, + "babip": ".376", + "groundOutsToAirouts": "0.91", + "catchersInterference": 0, + "atBatsPerHomeRun": "43.00" + }, + "team": { + "id": 111, + "name": "Boston Red Sox", + "link": "/api/v1/teams/111" + }, + "player": { + "id": 593428, + "fullName": "Xander Bogaerts", + "link": "/api/v1/people/593428", + "firstName": "Xander", + "lastName": "Bogaerts" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 11, + "position": { + "code": "6", + "name": "Shortstop", + "type": "Infielder", + "abbreviation": "SS" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 86, + "groundOuts": 98, + "airOuts": 74, + "runs": 44, + "doubles": 19, + "triples": 2, + "homeRuns": 12, + "strikeOuts": 48, + "baseOnBalls": 39, + "intentionalWalks": 3, + "hits": 96, + "hitByPitch": 5, + "avg": ".308", + "atBats": 312, + "obp": ".389", + "slg": ".497", + "ops": ".886", + "caughtStealing": 1, + "stolenBases": 0, + "stolenBasePercentage": ".000", + "groundIntoDoublePlay": 15, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1314, + "plateAppearances": 362, + "totalBases": 155, + "rbi": 47, + "leftOnBase": 138, + "sacBunts": 0, + "sacFlies": 4, + "babip": ".328", + "groundOutsToAirouts": "1.32", + "catchersInterference": 2, + "atBatsPerHomeRun": "26.00" + }, + "team": { + "id": 120, + "name": "Washington Nationals", + "link": "/api/v1/teams/120" + }, + "player": { + "id": 605137, + "fullName": "Josh Bell", + "link": "/api/v1/people/605137", + "firstName": "Josh", + "lastName": "Bell" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 12, + "position": { + "code": "3", + "name": "First Base", + "type": "Infielder", + "abbreviation": "1B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 75, + "groundOuts": 69, + "airOuts": 62, + "runs": 57, + "doubles": 11, + "triples": 2, + "homeRuns": 26, + "strikeOuts": 57, + "baseOnBalls": 43, + "intentionalWalks": 4, + "hits": 82, + "hitByPitch": 3, + "avg": ".306", + "atBats": 268, + "obp": ".405", + "slg": ".653", + "ops": "1.058", + "caughtStealing": 1, + "stolenBases": 0, + "stolenBasePercentage": ".000", + "groundIntoDoublePlay": 7, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1252, + "plateAppearances": 316, + "totalBases": 175, + "rbi": 60, + "leftOnBase": 137, + "sacBunts": 0, + "sacFlies": 2, + "babip": ".299", + "groundOutsToAirouts": "1.11", + "catchersInterference": 0, + "atBatsPerHomeRun": "10.31" + }, + "team": { + "id": 117, + "name": "Houston Astros", + "link": "/api/v1/teams/117" + }, + "player": { + "id": 670541, + "fullName": "Yordan Alvarez", + "link": "/api/v1/people/670541", + "firstName": "Yordan", + "lastName": "Alvarez" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 13, + "position": { + "code": "10", + "name": "Designated Hitter", + "type": "Hitter", + "abbreviation": "DH" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 74, + "groundOuts": 66, + "airOuts": 52, + "runs": 27, + "doubles": 20, + "triples": 1, + "homeRuns": 7, + "strikeOuts": 73, + "baseOnBalls": 25, + "intentionalWalks": 0, + "hits": 81, + "hitByPitch": 6, + "avg": ".303", + "atBats": 267, + "obp": ".370", + "slg": ".464", + "ops": ".834", + "caughtStealing": 0, + "stolenBases": 0, + "stolenBasePercentage": ".---", + "groundIntoDoublePlay": 2, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1209, + "plateAppearances": 303, + "totalBases": 124, + "rbi": 40, + "leftOnBase": 74, + "sacBunts": 0, + "sacFlies": 5, + "babip": ".385", + "groundOutsToAirouts": "1.27", + "catchersInterference": 0, + "atBatsPerHomeRun": "38.14" + }, + "team": { + "id": 146, + "name": "Miami Marlins", + "link": "/api/v1/teams/146" + }, + "player": { + "id": 643265, + "fullName": "Garrett Cooper", + "link": "/api/v1/people/643265", + "firstName": "Garrett", + "lastName": "Cooper" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 14, + "position": { + "code": "3", + "name": "First Base", + "type": "Infielder", + "abbreviation": "1B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 72, + "groundOuts": 73, + "airOuts": 42, + "runs": 18, + "doubles": 7, + "triples": 0, + "homeRuns": 3, + "strikeOuts": 71, + "baseOnBalls": 15, + "intentionalWalks": 2, + "hits": 78, + "hitByPitch": 2, + "avg": ".300", + "atBats": 260, + "obp": ".338", + "slg": ".362", + "ops": ".700", + "caughtStealing": 0, + "stolenBases": 0, + "stolenBasePercentage": ".---", + "groundIntoDoublePlay": 5, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1045, + "plateAppearances": 281, + "totalBases": 94, + "rbi": 31, + "leftOnBase": 85, + "sacBunts": 0, + "sacFlies": 4, + "babip": ".395", + "groundOutsToAirouts": "1.74", + "catchersInterference": 0, + "atBatsPerHomeRun": "86.67" + }, + "team": { + "id": 116, + "name": "Detroit Tigers", + "link": "/api/v1/teams/116" + }, + "player": { + "id": 408234, + "fullName": "Miguel Cabrera", + "link": "/api/v1/people/408234", + "firstName": "Miguel", + "lastName": "Cabrera" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 15, + "position": { + "code": "10", + "name": "Designated Hitter", + "type": "Hitter", + "abbreviation": "DH" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 84, + "groundOuts": 80, + "airOuts": 86, + "runs": 45, + "doubles": 22, + "triples": 2, + "homeRuns": 11, + "strikeOuts": 74, + "baseOnBalls": 26, + "intentionalWalks": 1, + "hits": 101, + "hitByPitch": 2, + "avg": ".300", + "atBats": 337, + "obp": ".350", + "slg": ".475", + "ops": ".825", + "caughtStealing": 2, + "stolenBases": 16, + "stolenBasePercentage": ".889", + "groundIntoDoublePlay": 6, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1429, + "plateAppearances": 370, + "totalBases": 160, + "rbi": 59, + "leftOnBase": 146, + "sacBunts": 0, + "sacFlies": 4, + "babip": ".352", + "groundOutsToAirouts": "0.93", + "catchersInterference": 1, + "atBatsPerHomeRun": "30.64" + }, + "team": { + "id": 119, + "name": "Los Angeles Dodgers", + "link": "/api/v1/teams/119" + }, + "player": { + "id": 607208, + "fullName": "Trea Turner", + "link": "/api/v1/people/607208", + "firstName": "Trea", + "lastName": "Turner" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 16, + "position": { + "code": "6", + "name": "Shortstop", + "type": "Infielder", + "abbreviation": "SS" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 77, + "groundOuts": 64, + "airOuts": 79, + "runs": 34, + "doubles": 21, + "triples": 0, + "homeRuns": 5, + "strikeOuts": 53, + "baseOnBalls": 19, + "intentionalWalks": 1, + "hits": 83, + "hitByPitch": 5, + "avg": ".300", + "atBats": 277, + "obp": ".353", + "slg": ".430", + "ops": ".783", + "caughtStealing": 1, + "stolenBases": 3, + "stolenBasePercentage": ".750", + "groundIntoDoublePlay": 6, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1132, + "plateAppearances": 303, + "totalBases": 119, + "rbi": 35, + "leftOnBase": 105, + "sacBunts": 0, + "sacFlies": 2, + "babip": ".353", + "groundOutsToAirouts": "0.81", + "catchersInterference": 0, + "atBatsPerHomeRun": "55.40" + }, + "team": { + "id": 141, + "name": "Toronto Blue Jays", + "link": "/api/v1/teams/141" + }, + "player": { + "id": 666971, + "fullName": "Lourdes Gurriel Jr.", + "link": "/api/v1/people/666971", + "firstName": "Lourdes", + "lastName": "Gurriel" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 17, + "position": { + "code": "7", + "name": "Outfielder", + "type": "Outfielder", + "abbreviation": "LF" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 76, + "groundOuts": 62, + "airOuts": 61, + "runs": 41, + "doubles": 12, + "triples": 4, + "homeRuns": 3, + "strikeOuts": 50, + "baseOnBalls": 28, + "intentionalWalks": 0, + "hits": 73, + "hitByPitch": 0, + "avg": ".299", + "atBats": 244, + "obp": ".369", + "slg": ".418", + "ops": ".787", + "caughtStealing": 2, + "stolenBases": 5, + "stolenBasePercentage": ".714", + "groundIntoDoublePlay": 0, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1072, + "plateAppearances": 274, + "totalBases": 102, + "rbi": 19, + "leftOnBase": 105, + "sacBunts": 0, + "sacFlies": 2, + "babip": ".363", + "groundOutsToAirouts": "1.02", + "catchersInterference": 0, + "atBatsPerHomeRun": "81.33" + }, + "team": { + "id": 119, + "name": "Los Angeles Dodgers", + "link": "/api/v1/teams/119" + }, + "player": { + "id": 666158, + "fullName": "Gavin Lux", + "link": "/api/v1/people/666158", + "firstName": "Gavin", + "lastName": "Lux" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 18, + "position": { + "code": "4", + "name": "Second Base", + "type": "Infielder", + "abbreviation": "2B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 86, + "groundOuts": 51, + "airOuts": 84, + "runs": 52, + "doubles": 18, + "triples": 1, + "homeRuns": 14, + "strikeOuts": 96, + "baseOnBalls": 26, + "intentionalWalks": 0, + "hits": 98, + "hitByPitch": 3, + "avg": ".299", + "atBats": 328, + "obp": ".355", + "slg": ".488", + "ops": ".843", + "caughtStealing": 3, + "stolenBases": 14, + "stolenBasePercentage": ".824", + "groundIntoDoublePlay": 5, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1435, + "plateAppearances": 358, + "totalBases": 160, + "rbi": 50, + "leftOnBase": 103, + "sacBunts": 0, + "sacFlies": 1, + "babip": ".384", + "groundOutsToAirouts": "0.61", + "catchersInterference": 0, + "atBatsPerHomeRun": "23.43" + }, + "team": { + "id": 144, + "name": "Atlanta Braves", + "link": "/api/v1/teams/144" + }, + "player": { + "id": 621020, + "fullName": "Dansby Swanson", + "link": "/api/v1/people/621020", + "firstName": "Dansby", + "lastName": "Swanson" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 19, + "position": { + "code": "6", + "name": "Shortstop", + "type": "Infielder", + "abbreviation": "SS" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 70, + "groundOuts": 81, + "airOuts": 71, + "runs": 26, + "doubles": 18, + "triples": 0, + "homeRuns": 2, + "strikeOuts": 28, + "baseOnBalls": 11, + "intentionalWalks": 0, + "hits": 76, + "hitByPitch": 5, + "avg": ".297", + "atBats": 256, + "obp": ".338", + "slg": ".391", + "ops": ".729", + "caughtStealing": 3, + "stolenBases": 2, + "stolenBasePercentage": ".400", + "groundIntoDoublePlay": 8, + "groundIntoTriplePlay": 0, + "numberOfPitches": 972, + "plateAppearances": 272, + "totalBases": 100, + "rbi": 23, + "leftOnBase": 110, + "sacBunts": 0, + "sacFlies": 0, + "babip": ".327", + "groundOutsToAirouts": "1.14", + "catchersInterference": 0, + "atBatsPerHomeRun": "128.00" + }, + "team": { + "id": 115, + "name": "Colorado Rockies", + "link": "/api/v1/teams/115" + }, + "player": { + "id": 578428, + "fullName": "Jose Iglesias", + "link": "/api/v1/people/578428", + "firstName": "Jose", + "lastName": "Iglesias" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 20, + "position": { + "code": "6", + "name": "Shortstop", + "type": "Infielder", + "abbreviation": "SS" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 84, + "groundOuts": 78, + "airOuts": 93, + "runs": 53, + "doubles": 26, + "triples": 2, + "homeRuns": 10, + "strikeOuts": 65, + "baseOnBalls": 41, + "intentionalWalks": 5, + "hits": 98, + "hitByPitch": 3, + "avg": ".296", + "atBats": 331, + "obp": ".376", + "slg": ".477", + "ops": ".853", + "caughtStealing": 0, + "stolenBases": 7, + "stolenBasePercentage": "1.000", + "groundIntoDoublePlay": 4, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1470, + "plateAppearances": 378, + "totalBases": 158, + "rbi": 52, + "leftOnBase": 110, + "sacBunts": 0, + "sacFlies": 3, + "babip": ".340", + "groundOutsToAirouts": "0.84", + "catchersInterference": 0, + "atBatsPerHomeRun": "33.10" + }, + "team": { + "id": 119, + "name": "Los Angeles Dodgers", + "link": "/api/v1/teams/119" + }, + "player": { + "id": 518692, + "fullName": "Freddie Freeman", + "link": "/api/v1/people/518692", + "firstName": "Freddie", + "lastName": "Freeman" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 21, + "position": { + "code": "3", + "name": "First Base", + "type": "Infielder", + "abbreviation": "1B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 64, + "groundOuts": 67, + "airOuts": 65, + "runs": 31, + "doubles": 15, + "triples": 0, + "homeRuns": 8, + "strikeOuts": 46, + "baseOnBalls": 17, + "intentionalWalks": 0, + "hits": 73, + "hitByPitch": 4, + "avg": ".296", + "atBats": 247, + "obp": ".346", + "slg": ".453", + "ops": ".799", + "caughtStealing": 0, + "stolenBases": 0, + "stolenBasePercentage": ".---", + "groundIntoDoublePlay": 5, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1066, + "plateAppearances": 272, + "totalBases": 112, + "rbi": 38, + "leftOnBase": 87, + "sacBunts": 0, + "sacFlies": 4, + "babip": ".330", + "groundOutsToAirouts": "1.03", + "catchersInterference": 0, + "atBatsPerHomeRun": "30.88" + }, + "team": { + "id": 145, + "name": "Chicago White Sox", + "link": "/api/v1/teams/145" + }, + "player": { + "id": 683734, + "fullName": "Andrew Vaughn", + "link": "/api/v1/people/683734", + "firstName": "Andrew", + "lastName": "Vaughn" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 22, + "position": { + "code": "9", + "name": "Outfielder", + "type": "Outfielder", + "abbreviation": "RF" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 84, + "groundOuts": 64, + "airOuts": 77, + "runs": 49, + "doubles": 19, + "triples": 2, + "homeRuns": 20, + "strikeOuts": 91, + "baseOnBalls": 23, + "intentionalWalks": 2, + "hits": 96, + "hitByPitch": 6, + "avg": ".295", + "atBats": 325, + "obp": ".350", + "slg": ".551", + "ops": ".901", + "caughtStealing": 0, + "stolenBases": 0, + "stolenBasePercentage": ".---", + "groundIntoDoublePlay": 10, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1446, + "plateAppearances": 358, + "totalBases": 179, + "rbi": 66, + "leftOnBase": 153, + "sacBunts": 0, + "sacFlies": 3, + "babip": ".350", + "groundOutsToAirouts": "0.83", + "catchersInterference": 1, + "atBatsPerHomeRun": "16.25" + }, + "team": { + "id": 115, + "name": "Colorado Rockies", + "link": "/api/v1/teams/115" + }, + "player": { + "id": 543068, + "fullName": "C.J. Cron", + "link": "/api/v1/people/543068", + "firstName": "C.J.", + "lastName": "Cron" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 23, + "position": { + "code": "3", + "name": "First Base", + "type": "Infielder", + "abbreviation": "1B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 81, + "groundOuts": 88, + "airOuts": 77, + "runs": 47, + "doubles": 23, + "triples": 0, + "homeRuns": 10, + "strikeOuts": 56, + "baseOnBalls": 40, + "intentionalWalks": 0, + "hits": 92, + "hitByPitch": 3, + "avg": ".295", + "atBats": 312, + "obp": ".379", + "slg": ".465", + "ops": ".844", + "caughtStealing": 0, + "stolenBases": 0, + "stolenBasePercentage": ".---", + "groundIntoDoublePlay": 7, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1509, + "plateAppearances": 356, + "totalBases": 145, + "rbi": 40, + "leftOnBase": 133, + "sacBunts": 0, + "sacFlies": 1, + "babip": ".332", + "groundOutsToAirouts": "1.14", + "catchersInterference": 0, + "atBatsPerHomeRun": "31.20" + }, + "team": { + "id": 145, + "name": "Chicago White Sox", + "link": "/api/v1/teams/145" + }, + "player": { + "id": 547989, + "fullName": "Jose Abreu", + "link": "/api/v1/people/547989", + "firstName": "Jose", + "lastName": "Abreu" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 24, + "position": { + "code": "3", + "name": "First Base", + "type": "Infielder", + "abbreviation": "1B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 76, + "groundOuts": 82, + "airOuts": 68, + "runs": 36, + "doubles": 15, + "triples": 0, + "homeRuns": 3, + "strikeOuts": 32, + "baseOnBalls": 47, + "intentionalWalks": 0, + "hits": 75, + "hitByPitch": 3, + "avg": ".292", + "atBats": 257, + "obp": ".407", + "slg": ".385", + "ops": ".792", + "caughtStealing": 3, + "stolenBases": 1, + "stolenBasePercentage": ".250", + "groundIntoDoublePlay": 4, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1209, + "plateAppearances": 307, + "totalBases": 99, + "rbi": 18, + "leftOnBase": 98, + "sacBunts": 0, + "sacFlies": 0, + "babip": ".324", + "groundOutsToAirouts": "1.21", + "catchersInterference": 0, + "atBatsPerHomeRun": "85.67" + }, + "team": { + "id": 139, + "name": "Tampa Bay Rays", + "link": "/api/v1/teams/139" + }, + "player": { + "id": 650490, + "fullName": "Yandy Diaz", + "link": "/api/v1/people/650490", + "firstName": "Yandy", + "lastName": "Diaz" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 25, + "position": { + "code": "5", + "name": "Third Base", + "type": "Infielder", + "abbreviation": "3B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 68, + "groundOuts": 75, + "airOuts": 70, + "runs": 43, + "doubles": 11, + "triples": 0, + "homeRuns": 10, + "strikeOuts": 58, + "baseOnBalls": 11, + "intentionalWalks": 1, + "hits": 83, + "hitByPitch": 3, + "avg": ".291", + "atBats": 285, + "obp": ".323", + "slg": ".435", + "ops": ".758", + "caughtStealing": 2, + "stolenBases": 11, + "stolenBasePercentage": ".846", + "groundIntoDoublePlay": 4, + "groundIntoTriplePlay": 0, + "numberOfPitches": 994, + "plateAppearances": 300, + "totalBases": 124, + "rbi": 46, + "leftOnBase": 127, + "sacBunts": 0, + "sacFlies": 1, + "babip": ".335", + "groundOutsToAirouts": "1.07", + "catchersInterference": 0, + "atBatsPerHomeRun": "28.50" + }, + "team": { + "id": 145, + "name": "Chicago White Sox", + "link": "/api/v1/teams/145" + }, + "player": { + "id": 673357, + "fullName": "Luis Robert Jr.", + "link": "/api/v1/people/673357", + "firstName": "Luis", + "lastName": "Robert" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 26, + "position": { + "code": "8", + "name": "Outfielder", + "type": "Outfielder", + "abbreviation": "CF" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 83, + "groundOuts": 58, + "airOuts": 122, + "runs": 39, + "doubles": 20, + "triples": 1, + "homeRuns": 17, + "strikeOuts": 46, + "baseOnBalls": 30, + "intentionalWalks": 2, + "hits": 92, + "hitByPitch": 2, + "avg": ".291", + "atBats": 316, + "obp": ".354", + "slg": ".522", + "ops": ".876", + "caughtStealing": 3, + "stolenBases": 0, + "stolenBasePercentage": ".000", + "groundIntoDoublePlay": 10, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1324, + "plateAppearances": 350, + "totalBases": 165, + "rbi": 55, + "leftOnBase": 134, + "sacBunts": 0, + "sacFlies": 2, + "babip": ".294", + "groundOutsToAirouts": "0.48", + "catchersInterference": 0, + "atBatsPerHomeRun": "18.59" + }, + "team": { + "id": 138, + "name": "St. Louis Cardinals", + "link": "/api/v1/teams/138" + }, + "player": { + "id": 571448, + "fullName": "Nolan Arenado", + "link": "/api/v1/people/571448", + "firstName": "Nolan", + "lastName": "Arenado" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 27, + "position": { + "code": "5", + "name": "Third Base", + "type": "Infielder", + "abbreviation": "3B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 74, + "groundOuts": 94, + "airOuts": 61, + "runs": 50, + "doubles": 18, + "triples": 3, + "homeRuns": 9, + "strikeOuts": 57, + "baseOnBalls": 16, + "intentionalWalks": 0, + "hits": 87, + "hitByPitch": 7, + "avg": ".291", + "atBats": 299, + "obp": ".342", + "slg": ".462", + "ops": ".804", + "caughtStealing": 6, + "stolenBases": 10, + "stolenBasePercentage": ".625", + "groundIntoDoublePlay": 10, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1209, + "plateAppearances": 322, + "totalBases": 138, + "rbi": 40, + "leftOnBase": 126, + "sacBunts": 0, + "sacFlies": 0, + "babip": ".335", + "groundOutsToAirouts": "1.54", + "catchersInterference": 0, + "atBatsPerHomeRun": "33.22" + }, + "team": { + "id": 121, + "name": "New York Mets", + "link": "/api/v1/teams/121" + }, + "player": { + "id": 516782, + "fullName": "Starling Marte", + "link": "/api/v1/people/516782", + "firstName": "Starling", + "lastName": "Marte" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 28, + "position": { + "code": "9", + "name": "Outfielder", + "type": "Outfielder", + "abbreviation": "RF" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 79, + "groundOuts": 59, + "airOuts": 122, + "runs": 50, + "doubles": 29, + "triples": 4, + "homeRuns": 17, + "strikeOuts": 33, + "baseOnBalls": 38, + "intentionalWalks": 5, + "hits": 87, + "hitByPitch": 2, + "avg": ".291", + "atBats": 299, + "obp": ".372", + "slg": ".585", + "ops": ".957", + "caughtStealing": 3, + "stolenBases": 12, + "stolenBasePercentage": ".800", + "groundIntoDoublePlay": 4, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1414, + "plateAppearances": 341, + "totalBases": 175, + "rbi": 66, + "leftOnBase": 120, + "sacBunts": 0, + "sacFlies": 2, + "babip": ".279", + "groundOutsToAirouts": "0.48", + "catchersInterference": 0, + "atBatsPerHomeRun": "17.59" + }, + "team": { + "id": 114, + "name": "Cleveland Guardians", + "link": "/api/v1/teams/114" + }, + "player": { + "id": 608070, + "fullName": "Jose Ramirez", + "link": "/api/v1/people/608070", + "firstName": "Jose", + "lastName": "Ramirez" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 28, + "position": { + "code": "5", + "name": "Third Base", + "type": "Infielder", + "abbreviation": "3B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 64, + "groundOuts": 76, + "airOuts": 69, + "runs": 28, + "doubles": 14, + "triples": 1, + "homeRuns": 5, + "strikeOuts": 30, + "baseOnBalls": 31, + "intentionalWalks": 2, + "hits": 70, + "hitByPitch": 1, + "avg": ".288", + "atBats": 243, + "obp": ".370", + "slg": ".416", + "ops": ".786", + "caughtStealing": 1, + "stolenBases": 1, + "stolenBasePercentage": ".500", + "groundIntoDoublePlay": 1, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1006, + "plateAppearances": 277, + "totalBases": 101, + "rbi": 26, + "leftOnBase": 68, + "sacBunts": 1, + "sacFlies": 1, + "babip": ".311", + "groundOutsToAirouts": "1.10", + "catchersInterference": 0, + "atBatsPerHomeRun": "48.60" + }, + "team": { + "id": 117, + "name": "Houston Astros", + "link": "/api/v1/teams/117" + }, + "player": { + "id": 488726, + "fullName": "Michael Brantley", + "link": "/api/v1/people/488726", + "firstName": "Michael", + "lastName": "Brantley" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 30, + "position": { + "code": "10", + "name": "Designated Hitter", + "type": "Hitter", + "abbreviation": "DH" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 82, + "groundOuts": 72, + "airOuts": 64, + "runs": 66, + "doubles": 14, + "triples": 0, + "homeRuns": 30, + "strikeOuts": 92, + "baseOnBalls": 41, + "intentionalWalks": 6, + "hits": 89, + "hitByPitch": 0, + "avg": ".284", + "atBats": 313, + "obp": ".363", + "slg": ".617", + "ops": ".980", + "caughtStealing": 0, + "stolenBases": 7, + "stolenBasePercentage": "1.000", + "groundIntoDoublePlay": 11, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1496, + "plateAppearances": 360, + "totalBases": 193, + "rbi": 65, + "leftOnBase": 124, + "sacBunts": 0, + "sacFlies": 4, + "babip": ".303", + "groundOutsToAirouts": "1.13", + "catchersInterference": 2, + "atBatsPerHomeRun": "10.43" + }, + "team": { + "id": 147, + "name": "New York Yankees", + "link": "/api/v1/teams/147" + }, + "player": { + "id": 592450, + "fullName": "Aaron Judge", + "link": "/api/v1/people/592450", + "firstName": "Aaron", + "lastName": "Judge" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 31, + "position": { + "code": "8", + "name": "Outfielder", + "type": "Outfielder", + "abbreviation": "CF" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 63, + "groundOuts": 61, + "airOuts": 55, + "runs": 37, + "doubles": 13, + "triples": 0, + "homeRuns": 10, + "strikeOuts": 61, + "baseOnBalls": 27, + "intentionalWalks": 0, + "hits": 69, + "hitByPitch": 1, + "avg": ".283", + "atBats": 244, + "obp": ".354", + "slg": ".459", + "ops": ".813", + "caughtStealing": 0, + "stolenBases": 0, + "stolenBasePercentage": ".---", + "groundIntoDoublePlay": 10, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1133, + "plateAppearances": 274, + "totalBases": 112, + "rbi": 31, + "leftOnBase": 109, + "sacBunts": 0, + "sacFlies": 2, + "babip": ".337", + "groundOutsToAirouts": "1.11", + "catchersInterference": 0, + "atBatsPerHomeRun": "24.40" + }, + "team": { + "id": 142, + "name": "Minnesota Twins", + "link": "/api/v1/teams/142" + }, + "player": { + "id": 621043, + "fullName": "Carlos Correa", + "link": "/api/v1/people/621043", + "firstName": "Carlos", + "lastName": "Correa" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 32, + "position": { + "code": "6", + "name": "Shortstop", + "type": "Infielder", + "abbreviation": "SS" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 77, + "groundOuts": 61, + "airOuts": 85, + "runs": 32, + "doubles": 15, + "triples": 1, + "homeRuns": 8, + "strikeOuts": 68, + "baseOnBalls": 26, + "intentionalWalks": 1, + "hits": 83, + "hitByPitch": 8, + "avg": ".281", + "atBats": 295, + "obp": ".353", + "slg": ".420", + "ops": ".773", + "caughtStealing": 0, + "stolenBases": 0, + "stolenBasePercentage": ".---", + "groundIntoDoublePlay": 3, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1342, + "plateAppearances": 331, + "totalBases": 124, + "rbi": 34, + "leftOnBase": 110, + "sacBunts": 0, + "sacFlies": 2, + "babip": ".339", + "groundOutsToAirouts": "0.72", + "catchersInterference": 0, + "atBatsPerHomeRun": "36.88" + }, + "team": { + "id": 110, + "name": "Baltimore Orioles", + "link": "/api/v1/teams/110" + }, + "player": { + "id": 641820, + "fullName": "Trey Mancini", + "link": "/api/v1/people/641820", + "firstName": "Trey", + "lastName": "Mancini" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 33, + "position": { + "code": "10", + "name": "Designated Hitter", + "type": "Hitter", + "abbreviation": "DH" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 77, + "groundOuts": 74, + "airOuts": 59, + "runs": 36, + "doubles": 11, + "triples": 1, + "homeRuns": 12, + "strikeOuts": 74, + "baseOnBalls": 23, + "intentionalWalks": 1, + "hits": 81, + "hitByPitch": 0, + "avg": ".281", + "atBats": 288, + "obp": ".334", + "slg": ".451", + "ops": ".785", + "caughtStealing": 2, + "stolenBases": 1, + "stolenBasePercentage": ".333", + "groundIntoDoublePlay": 5, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1181, + "plateAppearances": 311, + "totalBases": 130, + "rbi": 37, + "leftOnBase": 116, + "sacBunts": 0, + "sacFlies": 0, + "babip": ".342", + "groundOutsToAirouts": "1.25", + "catchersInterference": 0, + "atBatsPerHomeRun": "24.00" + }, + "team": { + "id": 140, + "name": "Texas Rangers", + "link": "/api/v1/teams/140" + }, + "player": { + "id": 663993, + "fullName": "Nathaniel Lowe", + "link": "/api/v1/people/663993", + "firstName": "Nathaniel", + "lastName": "Lowe" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 34, + "position": { + "code": "3", + "name": "First Base", + "type": "Infielder", + "abbreviation": "1B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 68, + "groundOuts": 68, + "airOuts": 74, + "runs": 44, + "doubles": 16, + "triples": 0, + "homeRuns": 17, + "strikeOuts": 47, + "baseOnBalls": 33, + "intentionalWalks": 0, + "hits": 73, + "hitByPitch": 5, + "avg": ".280", + "atBats": 261, + "obp": ".370", + "slg": ".536", + "ops": ".906", + "caughtStealing": 1, + "stolenBases": 6, + "stolenBasePercentage": ".857", + "groundIntoDoublePlay": 7, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1160, + "plateAppearances": 300, + "totalBases": 140, + "rbi": 32, + "leftOnBase": 66, + "sacBunts": 0, + "sacFlies": 1, + "babip": ".283", + "groundOutsToAirouts": "0.92", + "catchersInterference": 0, + "atBatsPerHomeRun": "15.35" + }, + "team": { + "id": 117, + "name": "Houston Astros", + "link": "/api/v1/teams/117" + }, + "player": { + "id": 514888, + "fullName": "Jose Altuve", + "link": "/api/v1/people/514888", + "firstName": "Jose", + "lastName": "Altuve" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 35, + "position": { + "code": "4", + "name": "Second Base", + "type": "Infielder", + "abbreviation": "2B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 76, + "groundOuts": 102, + "airOuts": 74, + "runs": 46, + "doubles": 12, + "triples": 5, + "homeRuns": 4, + "strikeOuts": 48, + "baseOnBalls": 17, + "intentionalWalks": 0, + "hits": 86, + "hitByPitch": 2, + "avg": ".279", + "atBats": 308, + "obp": ".319", + "slg": ".390", + "ops": ".709", + "caughtStealing": 3, + "stolenBases": 9, + "stolenBasePercentage": ".750", + "groundIntoDoublePlay": 9, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1178, + "plateAppearances": 329, + "totalBases": 120, + "rbi": 25, + "leftOnBase": 119, + "sacBunts": 0, + "sacFlies": 2, + "babip": ".318", + "groundOutsToAirouts": "1.38", + "catchersInterference": 0, + "atBatsPerHomeRun": "77.00" + }, + "team": { + "id": 114, + "name": "Cleveland Guardians", + "link": "/api/v1/teams/114" + }, + "player": { + "id": 642708, + "fullName": "Amed Rosario", + "link": "/api/v1/people/642708", + "firstName": "Amed", + "lastName": "Rosario" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 36, + "position": { + "code": "6", + "name": "Shortstop", + "type": "Infielder", + "abbreviation": "SS" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 70, + "groundOuts": 74, + "airOuts": 83, + "runs": 34, + "doubles": 11, + "triples": 3, + "homeRuns": 1, + "strikeOuts": 23, + "baseOnBalls": 30, + "intentionalWalks": 1, + "hits": 68, + "hitByPitch": 4, + "avg": ".279", + "atBats": 244, + "obp": ".363", + "slg": ".361", + "ops": ".724", + "caughtStealing": 2, + "stolenBases": 5, + "stolenBasePercentage": ".714", + "groundIntoDoublePlay": 4, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1161, + "plateAppearances": 282, + "totalBases": 88, + "rbi": 23, + "leftOnBase": 108, + "sacBunts": 1, + "sacFlies": 3, + "babip": ".300", + "groundOutsToAirouts": "0.89", + "catchersInterference": 0, + "atBatsPerHomeRun": "244.00" + }, + "team": { + "id": 114, + "name": "Cleveland Guardians", + "link": "/api/v1/teams/114" + }, + "player": { + "id": 680757, + "fullName": "Steven Kwan", + "link": "/api/v1/people/680757", + "firstName": "Steven", + "lastName": "Kwan" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 37, + "position": { + "code": "7", + "name": "Outfielder", + "type": "Outfielder", + "abbreviation": "LF" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 84, + "groundOuts": 67, + "airOuts": 77, + "runs": 49, + "doubles": 21, + "triples": 1, + "homeRuns": 22, + "strikeOuts": 94, + "baseOnBalls": 28, + "intentionalWalks": 1, + "hits": 91, + "hitByPitch": 7, + "avg": ".278", + "atBats": 327, + "obp": ".346", + "slg": ".550", + "ops": ".896", + "caughtStealing": 0, + "stolenBases": 2, + "stolenBasePercentage": "1.000", + "groundIntoDoublePlay": 6, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1350, + "plateAppearances": 364, + "totalBases": 180, + "rbi": 53, + "leftOnBase": 156, + "sacBunts": 0, + "sacFlies": 2, + "babip": ".324", + "groundOutsToAirouts": "0.87", + "catchersInterference": 0, + "atBatsPerHomeRun": "14.86" + }, + "team": { + "id": 144, + "name": "Atlanta Braves", + "link": "/api/v1/teams/144" + }, + "player": { + "id": 663586, + "fullName": "Austin Riley", + "link": "/api/v1/people/663586", + "firstName": "Austin", + "lastName": "Riley" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 38, + "position": { + "code": "5", + "name": "Third Base", + "type": "Infielder", + "abbreviation": "3B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 75, + "groundOuts": 67, + "airOuts": 69, + "runs": 52, + "doubles": 17, + "triples": 2, + "homeRuns": 18, + "strikeOuts": 70, + "baseOnBalls": 21, + "intentionalWalks": 0, + "hits": 79, + "hitByPitch": 4, + "avg": ".278", + "atBats": 284, + "obp": ".335", + "slg": ".542", + "ops": ".877", + "caughtStealing": 2, + "stolenBases": 2, + "stolenBasePercentage": ".500", + "groundIntoDoublePlay": 6, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1245, + "plateAppearances": 310, + "totalBases": 154, + "rbi": 50, + "leftOnBase": 91, + "sacBunts": 0, + "sacFlies": 1, + "babip": ".310", + "groundOutsToAirouts": "0.97", + "catchersInterference": 0, + "atBatsPerHomeRun": "15.78" + }, + "team": { + "id": 113, + "name": "Cincinnati Reds", + "link": "/api/v1/teams/113" + }, + "player": { + "id": 592273, + "fullName": "Brandon Drury", + "link": "/api/v1/people/592273", + "firstName": "Brandon", + "lastName": "Drury" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 39, + "position": { + "code": "5", + "name": "Third Base", + "type": "Infielder", + "abbreviation": "3B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 83, + "groundOuts": 79, + "airOuts": 64, + "runs": 38, + "doubles": 22, + "triples": 2, + "homeRuns": 8, + "strikeOuts": 71, + "baseOnBalls": 41, + "intentionalWalks": 3, + "hits": 81, + "hitByPitch": 5, + "avg": ".277", + "atBats": 292, + "obp": ".372", + "slg": ".449", + "ops": ".821", + "caughtStealing": 3, + "stolenBases": 6, + "stolenBasePercentage": ".667", + "groundIntoDoublePlay": 8, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1369, + "plateAppearances": 341, + "totalBases": 131, + "rbi": 40, + "leftOnBase": 140, + "sacBunts": 0, + "sacFlies": 3, + "babip": ".338", + "groundOutsToAirouts": "1.23", + "catchersInterference": 0, + "atBatsPerHomeRun": "36.50" + }, + "team": { + "id": 112, + "name": "Chicago Cubs", + "link": "/api/v1/teams/112" + }, + "player": { + "id": 664023, + "fullName": "Ian Happ", + "link": "/api/v1/people/664023", + "firstName": "Ian", + "lastName": "Happ" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 40, + "position": { + "code": "7", + "name": "Outfielder", + "type": "Outfielder", + "abbreviation": "LF" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 73, + "groundOuts": 59, + "airOuts": 72, + "runs": 36, + "doubles": 19, + "triples": 0, + "homeRuns": 14, + "strikeOuts": 78, + "baseOnBalls": 16, + "intentionalWalks": 1, + "hits": 79, + "hitByPitch": 1, + "avg": ".277", + "atBats": 285, + "obp": ".315", + "slg": ".491", + "ops": ".806", + "caughtStealing": 1, + "stolenBases": 4, + "stolenBasePercentage": ".800", + "groundIntoDoublePlay": 9, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1161, + "plateAppearances": 305, + "totalBases": 140, + "rbi": 43, + "leftOnBase": 112, + "sacBunts": 0, + "sacFlies": 3, + "babip": ".332", + "groundOutsToAirouts": "0.82", + "catchersInterference": 0, + "atBatsPerHomeRun": "20.36" + }, + "team": { + "id": 110, + "name": "Baltimore Orioles", + "link": "/api/v1/teams/110" + }, + "player": { + "id": 663624, + "fullName": "Ryan Mountcastle", + "link": "/api/v1/people/663624", + "firstName": "Ryan", + "lastName": "Mountcastle" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 41, + "position": { + "code": "3", + "name": "First Base", + "type": "Infielder", + "abbreviation": "1B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 67, + "groundOuts": 60, + "airOuts": 87, + "runs": 58, + "doubles": 15, + "triples": 0, + "homeRuns": 20, + "strikeOuts": 52, + "baseOnBalls": 29, + "intentionalWalks": 0, + "hits": 75, + "hitByPitch": 3, + "avg": ".276", + "atBats": 272, + "obp": ".350", + "slg": ".551", + "ops": ".901", + "caughtStealing": 1, + "stolenBases": 6, + "stolenBasePercentage": ".857", + "groundIntoDoublePlay": 3, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1187, + "plateAppearances": 306, + "totalBases": 150, + "rbi": 46, + "leftOnBase": 107, + "sacBunts": 0, + "sacFlies": 2, + "babip": ".272", + "groundOutsToAirouts": "0.69", + "catchersInterference": 0, + "atBatsPerHomeRun": "13.60" + }, + "team": { + "id": 119, + "name": "Los Angeles Dodgers", + "link": "/api/v1/teams/119" + }, + "player": { + "id": 605141, + "fullName": "Mookie Betts", + "link": "/api/v1/people/605141", + "firstName": "Mookie", + "lastName": "Betts" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 42, + "position": { + "code": "9", + "name": "Outfielder", + "type": "Outfielder", + "abbreviation": "RF" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 85, + "groundOuts": 71, + "airOuts": 67, + "runs": 50, + "doubles": 17, + "triples": 2, + "homeRuns": 15, + "strikeOuts": 96, + "baseOnBalls": 25, + "intentionalWalks": 1, + "hits": 88, + "hitByPitch": 5, + "avg": ".274", + "atBats": 321, + "obp": ".335", + "slg": ".480", + "ops": ".815", + "caughtStealing": 4, + "stolenBases": 21, + "stolenBasePercentage": ".840", + "groundIntoDoublePlay": 6, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1319, + "plateAppearances": 352, + "totalBases": 154, + "rbi": 43, + "leftOnBase": 129, + "sacBunts": 0, + "sacFlies": 1, + "babip": ".346", + "groundOutsToAirouts": "1.06", + "catchersInterference": 0, + "atBatsPerHomeRun": "21.40" + }, + "team": { + "id": 136, + "name": "Seattle Mariners", + "link": "/api/v1/teams/136" + }, + "player": { + "id": 677594, + "fullName": "Julio Rodriguez", + "link": "/api/v1/people/677594", + "firstName": "Julio", + "lastName": "Rodriguez" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 43, + "position": { + "code": "8", + "name": "Outfielder", + "type": "Outfielder", + "abbreviation": "CF" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 84, + "groundOuts": 69, + "airOuts": 93, + "runs": 47, + "doubles": 13, + "triples": 0, + "homeRuns": 23, + "strikeOuts": 71, + "baseOnBalls": 33, + "intentionalWalks": 6, + "hits": 85, + "hitByPitch": 7, + "avg": ".273", + "atBats": 311, + "obp": ".349", + "slg": ".537", + "ops": ".886", + "caughtStealing": 1, + "stolenBases": 2, + "stolenBasePercentage": ".667", + "groundIntoDoublePlay": 7, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1352, + "plateAppearances": 358, + "totalBases": 167, + "rbi": 70, + "leftOnBase": 139, + "sacBunts": 0, + "sacFlies": 7, + "babip": ".277", + "groundOutsToAirouts": "0.74", + "catchersInterference": 0, + "atBatsPerHomeRun": "13.52" + }, + "team": { + "id": 121, + "name": "New York Mets", + "link": "/api/v1/teams/121" + }, + "player": { + "id": 624413, + "fullName": "Pete Alonso", + "link": "/api/v1/people/624413", + "firstName": "Pete", + "lastName": "Alonso" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 44, + "position": { + "code": "3", + "name": "First Base", + "type": "Infielder", + "abbreviation": "1B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 77, + "groundOuts": 85, + "airOuts": 76, + "runs": 49, + "doubles": 15, + "triples": 5, + "homeRuns": 8, + "strikeOuts": 57, + "baseOnBalls": 31, + "intentionalWalks": 0, + "hits": 80, + "hitByPitch": 9, + "avg": ".273", + "atBats": 293, + "obp": ".357", + "slg": ".440", + "ops": ".797", + "caughtStealing": 2, + "stolenBases": 0, + "stolenBasePercentage": ".000", + "groundIntoDoublePlay": 4, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1393, + "plateAppearances": 338, + "totalBases": 129, + "rbi": 32, + "leftOnBase": 82, + "sacBunts": 2, + "sacFlies": 3, + "babip": ".312", + "groundOutsToAirouts": "1.12", + "catchersInterference": 0, + "atBatsPerHomeRun": "36.62" + }, + "team": { + "id": 121, + "name": "New York Mets", + "link": "/api/v1/teams/121" + }, + "player": { + "id": 607043, + "fullName": "Brandon Nimmo", + "link": "/api/v1/people/607043", + "firstName": "Brandon", + "lastName": "Nimmo" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 45, + "position": { + "code": "8", + "name": "Outfielder", + "type": "Outfielder", + "abbreviation": "CF" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 76, + "groundOuts": 104, + "airOuts": 53, + "runs": 28, + "doubles": 14, + "triples": 0, + "homeRuns": 6, + "strikeOuts": 52, + "baseOnBalls": 24, + "intentionalWalks": 5, + "hits": 78, + "hitByPitch": 0, + "avg": ".273", + "atBats": 286, + "obp": ".328", + "slg": ".385", + "ops": ".713", + "caughtStealing": 0, + "stolenBases": 0, + "stolenBasePercentage": ".---", + "groundIntoDoublePlay": 8, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1180, + "plateAppearances": 311, + "totalBases": 110, + "rbi": 33, + "leftOnBase": 119, + "sacBunts": 0, + "sacFlies": 1, + "babip": ".314", + "groundOutsToAirouts": "1.96", + "catchersInterference": 0, + "atBatsPerHomeRun": "47.67" + }, + "team": { + "id": 135, + "name": "San Diego Padres", + "link": "/api/v1/teams/135" + }, + "player": { + "id": 543333, + "fullName": "Eric Hosmer", + "link": "/api/v1/people/543333", + "firstName": "Eric", + "lastName": "Hosmer" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 46, + "position": { + "code": "3", + "name": "First Base", + "type": "Infielder", + "abbreviation": "1B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 70, + "groundOuts": 62, + "airOuts": 62, + "runs": 39, + "doubles": 7, + "triples": 0, + "homeRuns": 6, + "strikeOuts": 51, + "baseOnBalls": 26, + "intentionalWalks": 0, + "hits": 65, + "hitByPitch": 10, + "avg": ".272", + "atBats": 239, + "obp": ".366", + "slg": ".377", + "ops": ".743", + "caughtStealing": 1, + "stolenBases": 1, + "stolenBasePercentage": ".500", + "groundIntoDoublePlay": 1, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1172, + "plateAppearances": 276, + "totalBases": 90, + "rbi": 30, + "leftOnBase": 112, + "sacBunts": 0, + "sacFlies": 1, + "babip": ".322", + "groundOutsToAirouts": "1.00", + "catchersInterference": 0, + "atBatsPerHomeRun": "39.83" + }, + "team": { + "id": 121, + "name": "New York Mets", + "link": "/api/v1/teams/121" + }, + "player": { + "id": 592192, + "fullName": "Mark Canha", + "link": "/api/v1/people/592192", + "firstName": "Mark", + "lastName": "Canha" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 47, + "position": { + "code": "7", + "name": "Outfielder", + "type": "Outfielder", + "abbreviation": "LF" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 77, + "groundOuts": 26, + "airOuts": 81, + "runs": 54, + "doubles": 17, + "triples": 2, + "homeRuns": 24, + "strikeOuts": 94, + "baseOnBalls": 39, + "intentionalWalks": 6, + "hits": 75, + "hitByPitch": 5, + "avg": ".272", + "atBats": 276, + "obp": ".372", + "slg": ".609", + "ops": ".981", + "caughtStealing": 0, + "stolenBases": 1, + "stolenBasePercentage": "1.000", + "groundIntoDoublePlay": 3, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1347, + "plateAppearances": 320, + "totalBases": 168, + "rbi": 51, + "leftOnBase": 103, + "sacBunts": 0, + "sacFlies": 0, + "babip": ".323", + "groundOutsToAirouts": "0.32", + "catchersInterference": 0, + "atBatsPerHomeRun": "11.50" + }, + "team": { + "id": 108, + "name": "Los Angeles Angels", + "link": "/api/v1/teams/108" + }, + "player": { + "id": 545361, + "fullName": "Mike Trout", + "link": "/api/v1/people/545361", + "firstName": "Mike", + "lastName": "Trout" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 48, + "position": { + "code": "8", + "name": "Outfielder", + "type": "Outfielder", + "abbreviation": "CF" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 85, + "groundOuts": 79, + "airOuts": 91, + "runs": 31, + "doubles": 21, + "triples": 0, + "homeRuns": 6, + "strikeOuts": 53, + "baseOnBalls": 24, + "intentionalWalks": 1, + "hits": 82, + "hitByPitch": 1, + "avg": ".272", + "atBats": 302, + "obp": ".324", + "slg": ".401", + "ops": ".725", + "caughtStealing": 2, + "stolenBases": 5, + "stolenBasePercentage": ".714", + "groundIntoDoublePlay": 9, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1260, + "plateAppearances": 330, + "totalBases": 121, + "rbi": 37, + "leftOnBase": 152, + "sacBunts": 0, + "sacFlies": 3, + "babip": ".309", + "groundOutsToAirouts": "0.87", + "catchersInterference": 0, + "atBatsPerHomeRun": "50.33" + }, + "team": { + "id": 141, + "name": "Toronto Blue Jays", + "link": "/api/v1/teams/141" + }, + "player": { + "id": 669289, + "fullName": "Santiago Espinal", + "link": "/api/v1/people/669289", + "firstName": "Santiago", + "lastName": "Espinal" + }, + "league": { + "id": 103, + "name": "American League", + "link": "/api/v1/league/103", + "abbreviation": "AL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 49, + "position": { + "code": "4", + "name": "Second Base", + "type": "Infielder", + "abbreviation": "2B" + } + }, + { + "season": "2022", + "stat": { + "gamesPlayed": 80, + "groundOuts": 80, + "airOuts": 79, + "runs": 40, + "doubles": 12, + "triples": 2, + "homeRuns": 6, + "strikeOuts": 66, + "baseOnBalls": 16, + "intentionalWalks": 0, + "hits": 81, + "hitByPitch": 2, + "avg": ".271", + "atBats": 299, + "obp": ".306", + "slg": ".385", + "ops": ".691", + "caughtStealing": 2, + "stolenBases": 1, + "stolenBasePercentage": ".333", + "groundIntoDoublePlay": 9, + "groundIntoTriplePlay": 0, + "numberOfPitches": 1245, + "plateAppearances": 324, + "totalBases": 115, + "rbi": 33, + "leftOnBase": 106, + "sacBunts": 0, + "sacFlies": 7, + "babip": ".321", + "groundOutsToAirouts": "1.01", + "catchersInterference": 0, + "atBatsPerHomeRun": "49.83" + }, + "team": { + "id": 143, + "name": "Philadelphia Phillies", + "link": "/api/v1/teams/143" + }, + "player": { + "id": 664761, + "fullName": "Alec Bohm", + "link": "/api/v1/people/664761", + "firstName": "Alec", + "lastName": "Bohm" + }, + "league": { + "id": 104, + "name": "National League", + "link": "/api/v1/league/104", + "abbreviation": "NL" + }, + "sport": { + "id": 1, + "link": "/api/v1/sports/1", + "name": "Major League Baseball", + "abbreviation": "MLB" + }, + "numTeams": 1, + "rank": 50, + "position": { + "code": "5", + "name": "Third Base", + "type": "Infielder", + "abbreviation": "3B" + } + } + ], + "splitsTiedWithOffset": [], + "splitsTiedWithLimit": [] + } + ] +} diff --git a/api/tests/responses/team-stats-date.json b/api/tests/responses/team-stats-date.json new file mode 100644 index 0000000..5466aa0 --- /dev/null +++ b/api/tests/responses/team-stats-date.json @@ -0,0 +1,1278 @@ +{ + "stats": [ + { + "type": { + "displayName": "byDateRange" + }, + "group": { + "displayName": "hitting" + }, + "totalSplits": 30, + "exemptions": [], + "splits": [ + { + "stat": { + "gamesPlayed": 85, + "groundOuts": 747, + "airOuts": 788, + "runs": 399, + "doubles": 195, + "triples": 6, + "homeRuns": 82, + "strikeOuts": 684, + "baseOnBalls": 256, + "intentionalWalks": 14, + "hits": 767, + "hitByPitch": 36, + "avg": ".260", + "atBats": 2949, + "obp": ".324", + "slg": ".414", + "ops": ".738", + "caughtStealing": 10, + "stolenBases": 31, + "stolenBasePercentage": ".756", + "groundIntoDoublePlay": 57, + "numberOfPitches": 12565, + "plateAppearances": 3278, + "totalBases": 1220, + "rbi": 382, + "leftOnBase": 620, + "sacBunts": 6, + "sacFlies": 31, + "babip": ".309", + "groundOutsToAirouts": "0.95", + "atBatsPerHomeRun": "35.96" + }, + "team": { + "id": 111, + "name": "Boston Red Sox", + "link": "/api/v1/teams/111" + }, + "numTeams": 1, + "rank": 1 + }, + { + "stat": { + "gamesPlayed": 85, + "groundOuts": 801, + "airOuts": 722, + "runs": 378, + "doubles": 142, + "triples": 18, + "homeRuns": 80, + "strikeOuts": 665, + "baseOnBalls": 252, + "intentionalWalks": 3, + "hits": 753, + "hitByPitch": 30, + "avg": ".258", + "atBats": 2916, + "obp": ".322", + "slg": ".402", + "ops": ".724", + "caughtStealing": 13, + "stolenBases": 19, + "stolenBasePercentage": ".594", + "groundIntoDoublePlay": 75, + "numberOfPitches": 12479, + "plateAppearances": 3224, + "totalBases": 1171, + "rbi": 358, + "leftOnBase": 602, + "sacBunts": 6, + "sacFlies": 19, + "babip": ".307", + "groundOutsToAirouts": "1.11", + "atBatsPerHomeRun": "36.45" + }, + "team": { + "id": 115, + "name": "Colorado Rockies", + "link": "/api/v1/teams/115" + }, + "numTeams": 1, + "rank": 2 + }, + { + "stat": { + "gamesPlayed": 86, + "groundOuts": 754, + "airOuts": 777, + "runs": 392, + "doubles": 166, + "triples": 4, + "homeRuns": 109, + "strikeOuts": 671, + "baseOnBalls": 262, + "intentionalWalks": 8, + "hits": 753, + "hitByPitch": 36, + "avg": ".257", + "atBats": 2930, + "obp": ".324", + "slg": ".428", + "ops": ".752", + "caughtStealing": 15, + "stolenBases": 32, + "stolenBasePercentage": ".681", + "groundIntoDoublePlay": 65, + "numberOfPitches": 12492, + "plateAppearances": 3256, + "totalBases": 1254, + "rbi": 380, + "leftOnBase": 595, + "sacBunts": 7, + "sacFlies": 18, + "babip": ".297", + "groundOutsToAirouts": "0.97", + "atBatsPerHomeRun": "26.88" + }, + "team": { + "id": 141, + "name": "Toronto Blue Jays", + "link": "/api/v1/teams/141" + }, + "numTeams": 1, + "rank": 3 + }, + { + "stat": { + "gamesPlayed": 85, + "groundOuts": 769, + "airOuts": 770, + "runs": 409, + "doubles": 135, + "triples": 16, + "homeRuns": 85, + "strikeOuts": 639, + "baseOnBalls": 255, + "intentionalWalks": 8, + "hits": 735, + "hitByPitch": 59, + "avg": ".256", + "atBats": 2874, + "obp": ".326", + "slg": ".403", + "ops": ".729", + "caughtStealing": 15, + "stolenBases": 30, + "stolenBasePercentage": ".667", + "groundIntoDoublePlay": 55, + "numberOfPitches": 12497, + "plateAppearances": 3227, + "totalBases": 1157, + "rbi": 391, + "leftOnBase": 589, + "sacBunts": 10, + "sacFlies": 29, + "babip": ".298", + "groundOutsToAirouts": "1.00", + "atBatsPerHomeRun": "33.81" + }, + "team": { + "id": 121, + "name": "New York Mets", + "link": "/api/v1/teams/121" + }, + "numTeams": 1, + "rank": 4 + }, + { + "stat": { + "gamesPlayed": 83, + "groundOuts": 781, + "airOuts": 748, + "runs": 356, + "doubles": 147, + "triples": 6, + "homeRuns": 67, + "strikeOuts": 654, + "baseOnBalls": 201, + "intentionalWalks": 6, + "hits": 740, + "hitByPitch": 40, + "avg": ".256", + "atBats": 2894, + "obp": ".311", + "slg": ".380", + "ops": ".691", + "caughtStealing": 4, + "stolenBases": 35, + "stolenBasePercentage": ".897", + "groundIntoDoublePlay": 60, + "numberOfPitches": 12056, + "plateAppearances": 3164, + "totalBases": 1100, + "rbi": 336, + "leftOnBase": 581, + "sacBunts": 11, + "sacFlies": 18, + "babip": ".307", + "groundOutsToAirouts": "1.04", + "atBatsPerHomeRun": "43.19" + }, + "team": { + "id": 145, + "name": "Chicago White Sox", + "link": "/api/v1/teams/145" + }, + "numTeams": 1, + "rank": 5 + }, + { + "stat": { + "gamesPlayed": 87, + "groundOuts": 716, + "airOuts": 796, + "runs": 398, + "doubles": 154, + "triples": 9, + "homeRuns": 109, + "strikeOuts": 713, + "baseOnBalls": 285, + "intentionalWalks": 2, + "hits": 745, + "hitByPitch": 28, + "avg": ".253", + "atBats": 2940, + "obp": ".323", + "slg": ".423", + "ops": ".746", + "caughtStealing": 10, + "stolenBases": 14, + "stolenBasePercentage": ".583", + "groundIntoDoublePlay": 65, + "numberOfPitches": 12876, + "plateAppearances": 3284, + "totalBases": 1244, + "rbi": 385, + "leftOnBase": 592, + "sacBunts": 6, + "sacFlies": 24, + "babip": ".297", + "groundOutsToAirouts": "0.90", + "atBatsPerHomeRun": "26.97" + }, + "team": { + "id": 142, + "name": "Minnesota Twins", + "link": "/api/v1/teams/142" + }, + "numTeams": 1, + "rank": 6 + }, + { + "stat": { + "gamesPlayed": 84, + "groundOuts": 626, + "airOuts": 816, + "runs": 418, + "doubles": 158, + "triples": 15, + "homeRuns": 108, + "strikeOuts": 708, + "baseOnBalls": 317, + "intentionalWalks": 12, + "hits": 715, + "hitByPitch": 21, + "avg": ".252", + "atBats": 2838, + "obp": ".329", + "slg": ".432", + "ops": ".761", + "caughtStealing": 8, + "stolenBases": 57, + "stolenBasePercentage": ".877", + "groundIntoDoublePlay": 48, + "numberOfPitches": 12879, + "plateAppearances": 3204, + "totalBases": 1227, + "rbi": 395, + "leftOnBase": 587, + "sacBunts": 1, + "sacFlies": 26, + "babip": ".296", + "groundOutsToAirouts": "0.77", + "atBatsPerHomeRun": "26.28" + }, + "team": { + "id": 119, + "name": "Los Angeles Dodgers", + "link": "/api/v1/teams/119" + }, + "numTeams": 1, + "rank": 7 + }, + { + "stat": { + "gamesPlayed": 86, + "groundOuts": 676, + "airOuts": 746, + "runs": 412, + "doubles": 163, + "triples": 6, + "homeRuns": 132, + "strikeOuts": 792, + "baseOnBalls": 253, + "intentionalWalks": 5, + "hits": 733, + "hitByPitch": 37, + "avg": ".251", + "atBats": 2926, + "obp": ".316", + "slg": ".446", + "ops": ".762", + "caughtStealing": 16, + "stolenBases": 47, + "stolenBasePercentage": ".746", + "groundIntoDoublePlay": 52, + "numberOfPitches": 12685, + "plateAppearances": 3237, + "totalBases": 1304, + "rbi": 393, + "leftOnBase": 559, + "sacBunts": 0, + "sacFlies": 21, + "babip": ".297", + "groundOutsToAirouts": "0.91", + "atBatsPerHomeRun": "22.17" + }, + "team": { + "id": 144, + "name": "Atlanta Braves", + "link": "/api/v1/teams/144" + }, + "numTeams": 1, + "rank": 8 + }, + { + "stat": { + "gamesPlayed": 87, + "groundOuts": 856, + "airOuts": 734, + "runs": 338, + "doubles": 148, + "triples": 10, + "homeRuns": 67, + "strikeOuts": 625, + "baseOnBalls": 269, + "intentionalWalks": 6, + "hits": 728, + "hitByPitch": 29, + "avg": ".250", + "atBats": 2914, + "obp": ".318", + "slg": ".376", + "ops": ".694", + "caughtStealing": 13, + "stolenBases": 32, + "stolenBasePercentage": ".711", + "groundIntoDoublePlay": 86, + "numberOfPitches": 12282, + "plateAppearances": 3245, + "totalBases": 1097, + "rbi": 323, + "leftOnBase": 597, + "sacBunts": 11, + "sacFlies": 18, + "babip": ".295", + "groundOutsToAirouts": "1.17", + "atBatsPerHomeRun": "43.49" + }, + "team": { + "id": 120, + "name": "Washington Nationals", + "link": "/api/v1/teams/120" + }, + "numTeams": 1, + "rank": 9 + }, + { + "stat": { + "gamesPlayed": 87, + "groundOuts": 718, + "airOuts": 859, + "runs": 390, + "doubles": 145, + "triples": 14, + "homeRuns": 90, + "strikeOuts": 680, + "baseOnBalls": 267, + "intentionalWalks": 6, + "hits": 738, + "hitByPitch": 38, + "avg": ".249", + "atBats": 2966, + "obp": ".316", + "slg": ".398", + "ops": ".714", + "caughtStealing": 15, + "stolenBases": 59, + "stolenBasePercentage": ".797", + "groundIntoDoublePlay": 60, + "numberOfPitches": 12930, + "plateAppearances": 3302, + "totalBases": 1181, + "rbi": 372, + "leftOnBase": 609, + "sacBunts": 3, + "sacFlies": 26, + "babip": ".292", + "groundOutsToAirouts": "0.84", + "atBatsPerHomeRun": "32.96" + }, + "team": { + "id": 138, + "name": "St. Louis Cardinals", + "link": "/api/v1/teams/138" + }, + "numTeams": 1, + "rank": 10 + }, + { + "stat": { + "gamesPlayed": 82, + "groundOuts": 745, + "airOuts": 817, + "runs": 357, + "doubles": 152, + "triples": 16, + "homeRuns": 66, + "strikeOuts": 573, + "baseOnBalls": 241, + "intentionalWalks": 9, + "hits": 688, + "hitByPitch": 31, + "avg": ".247", + "atBats": 2784, + "obp": ".311", + "slg": ".384", + "ops": ".695", + "caughtStealing": 14, + "stolenBases": 51, + "stolenBasePercentage": ".785", + "groundIntoDoublePlay": 57, + "numberOfPitches": 12066, + "plateAppearances": 3095, + "totalBases": 1070, + "rbi": 339, + "leftOnBase": 556, + "sacBunts": 8, + "sacFlies": 31, + "babip": ".286", + "groundOutsToAirouts": "0.91", + "atBatsPerHomeRun": "42.18" + }, + "team": { + "id": 114, + "name": "Cleveland Guardians", + "link": "/api/v1/teams/114" + }, + "numTeams": 1, + "rank": 11 + }, + { + "stat": { + "gamesPlayed": 85, + "groundOuts": 721, + "airOuts": 766, + "runs": 406, + "doubles": 135, + "triples": 14, + "homeRuns": 111, + "strikeOuts": 714, + "baseOnBalls": 276, + "intentionalWalks": 8, + "hits": 710, + "hitByPitch": 25, + "avg": ".246", + "atBats": 2882, + "obp": ".315", + "slg": ".418", + "ops": ".733", + "caughtStealing": 11, + "stolenBases": 52, + "stolenBasePercentage": ".825", + "groundIntoDoublePlay": 64, + "numberOfPitches": 12752, + "plateAppearances": 3212, + "totalBases": 1206, + "rbi": 387, + "leftOnBase": 557, + "sacBunts": 4, + "sacFlies": 25, + "babip": ".288", + "groundOutsToAirouts": "0.94", + "atBatsPerHomeRun": "25.96" + }, + "team": { + "id": 143, + "name": "Philadelphia Phillies", + "link": "/api/v1/teams/143" + }, + "numTeams": 1, + "rank": 12 + }, + { + "stat": { + "gamesPlayed": 85, + "groundOuts": 760, + "airOuts": 698, + "runs": 367, + "doubles": 146, + "triples": 18, + "homeRuns": 84, + "strikeOuts": 751, + "baseOnBalls": 288, + "intentionalWalks": 10, + "hits": 710, + "hitByPitch": 43, + "avg": ".246", + "atBats": 2891, + "obp": ".321", + "slg": ".396", + "ops": ".717", + "caughtStealing": 19, + "stolenBases": 56, + "stolenBasePercentage": ".747", + "groundIntoDoublePlay": 71, + "numberOfPitches": 12729, + "plateAppearances": 3251, + "totalBases": 1144, + "rbi": 343, + "leftOnBase": 612, + "sacBunts": 7, + "sacFlies": 21, + "babip": ".301", + "groundOutsToAirouts": "1.09", + "atBatsPerHomeRun": "34.42" + }, + "team": { + "id": 112, + "name": "Chicago Cubs", + "link": "/api/v1/teams/112" + }, + "numTeams": 1, + "rank": 13 + }, + { + "stat": { + "gamesPlayed": 85, + "groundOuts": 695, + "airOuts": 768, + "runs": 444, + "doubles": 119, + "triples": 6, + "homeRuns": 144, + "strikeOuts": 707, + "baseOnBalls": 330, + "intentionalWalks": 17, + "hits": 689, + "hitByPitch": 32, + "avg": ".244", + "atBats": 2826, + "obp": ".327", + "slg": ".443", + "ops": ".770", + "caughtStealing": 14, + "stolenBases": 58, + "stolenBasePercentage": ".806", + "groundIntoDoublePlay": 63, + "numberOfPitches": 12841, + "plateAppearances": 3224, + "totalBases": 1252, + "rbi": 421, + "leftOnBase": 552, + "sacBunts": 7, + "sacFlies": 26, + "babip": ".272", + "groundOutsToAirouts": "0.90", + "atBatsPerHomeRun": "19.62" + }, + "team": { + "id": 147, + "name": "New York Yankees", + "link": "/api/v1/teams/147" + }, + "numTeams": 1, + "rank": 14 + }, + { + "stat": { + "gamesPlayed": 83, + "groundOuts": 755, + "airOuts": 663, + "runs": 357, + "doubles": 131, + "triples": 12, + "homeRuns": 90, + "strikeOuts": 724, + "baseOnBalls": 237, + "intentionalWalks": 3, + "hits": 678, + "hitByPitch": 35, + "avg": ".243", + "atBats": 2795, + "obp": ".307", + "slg": ".395", + "ops": ".702", + "caughtStealing": 13, + "stolenBases": 68, + "stolenBasePercentage": ".840", + "groundIntoDoublePlay": 59, + "numberOfPitches": 12106, + "plateAppearances": 3097, + "totalBases": 1103, + "rbi": 339, + "leftOnBase": 541, + "sacBunts": 2, + "sacFlies": 23, + "babip": ".293", + "groundOutsToAirouts": "1.14", + "atBatsPerHomeRun": "31.06" + }, + "team": { + "id": 146, + "name": "Miami Marlins", + "link": "/api/v1/teams/146" + }, + "numTeams": 1, + "rank": 15 + }, + { + "stat": { + "gamesPlayed": 84, + "groundOuts": 704, + "airOuts": 802, + "runs": 378, + "doubles": 139, + "triples": 8, + "homeRuns": 123, + "strikeOuts": 627, + "baseOnBalls": 303, + "intentionalWalks": 7, + "hits": 675, + "hitByPitch": 31, + "avg": ".242", + "atBats": 2785, + "obp": ".322", + "slg": ".431", + "ops": ".753", + "caughtStealing": 13, + "stolenBases": 40, + "stolenBasePercentage": ".755", + "groundIntoDoublePlay": 55, + "numberOfPitches": 12012, + "plateAppearances": 3143, + "totalBases": 1199, + "rbi": 370, + "leftOnBase": 567, + "sacBunts": 5, + "sacFlies": 18, + "babip": ".269", + "groundOutsToAirouts": "0.88", + "atBatsPerHomeRun": "22.64" + }, + "team": { + "id": 117, + "name": "Houston Astros", + "link": "/api/v1/teams/117" + }, + "numTeams": 1, + "rank": 16 + }, + { + "stat": { + "gamesPlayed": 83, + "groundOuts": 720, + "airOuts": 797, + "runs": 323, + "doubles": 128, + "triples": 20, + "homeRuns": 71, + "strikeOuts": 636, + "baseOnBalls": 256, + "intentionalWalks": 4, + "hits": 674, + "hitByPitch": 21, + "avg": ".241", + "atBats": 2800, + "obp": ".307", + "slg": ".377", + "ops": ".684", + "caughtStealing": 15, + "stolenBases": 48, + "stolenBasePercentage": ".762", + "groundIntoDoublePlay": 60, + "numberOfPitches": 11768, + "plateAppearances": 3104, + "totalBases": 1055, + "rbi": 309, + "leftOnBase": 571, + "sacBunts": 8, + "sacFlies": 19, + "babip": ".286", + "groundOutsToAirouts": "0.90", + "atBatsPerHomeRun": "39.44" + }, + "team": { + "id": 118, + "name": "Kansas City Royals", + "link": "/api/v1/teams/118" + }, + "numTeams": 1, + "rank": 17 + }, + { + "stat": { + "gamesPlayed": 82, + "groundOuts": 646, + "airOuts": 794, + "runs": 367, + "doubles": 102, + "triples": 9, + "homeRuns": 109, + "strikeOuts": 704, + "baseOnBalls": 228, + "intentionalWalks": 6, + "hits": 669, + "hitByPitch": 19, + "avg": ".240", + "atBats": 2788, + "obp": ".300", + "slg": ".400", + "ops": ".700", + "caughtStealing": 20, + "stolenBases": 66, + "stolenBasePercentage": ".767", + "groundIntoDoublePlay": 37, + "numberOfPitches": 11697, + "plateAppearances": 3060, + "totalBases": 1116, + "rbi": 347, + "leftOnBase": 512, + "sacBunts": 4, + "sacFlies": 21, + "babip": ".281", + "groundOutsToAirouts": "0.81", + "atBatsPerHomeRun": "25.58" + }, + "team": { + "id": 140, + "name": "Texas Rangers", + "link": "/api/v1/teams/140" + }, + "numTeams": 1, + "rank": 18 + }, + { + "stat": { + "gamesPlayed": 86, + "groundOuts": 753, + "airOuts": 783, + "runs": 378, + "doubles": 151, + "triples": 13, + "homeRuns": 70, + "strikeOuts": 716, + "baseOnBalls": 300, + "intentionalWalks": 15, + "hits": 698, + "hitByPitch": 35, + "avg": ".240", + "atBats": 2914, + "obp": ".315", + "slg": ".372", + "ops": ".687", + "caughtStealing": 15, + "stolenBases": 26, + "stolenBasePercentage": ".634", + "groundIntoDoublePlay": 52, + "numberOfPitches": 12835, + "plateAppearances": 3288, + "totalBases": 1085, + "rbi": 365, + "leftOnBase": 620, + "sacBunts": 8, + "sacFlies": 28, + "babip": ".291", + "groundOutsToAirouts": "0.96", + "atBatsPerHomeRun": "41.63" + }, + "team": { + "id": 135, + "name": "San Diego Padres", + "link": "/api/v1/teams/135" + }, + "numTeams": 1, + "rank": 19 + }, + { + "stat": { + "gamesPlayed": 85, + "groundOuts": 679, + "airOuts": 737, + "runs": 357, + "doubles": 133, + "triples": 8, + "homeRuns": 77, + "strikeOuts": 746, + "baseOnBalls": 238, + "intentionalWalks": 2, + "hits": 666, + "hitByPitch": 52, + "avg": ".238", + "atBats": 2801, + "obp": ".307", + "slg": ".373", + "ops": ".680", + "caughtStealing": 16, + "stolenBases": 41, + "stolenBasePercentage": ".719", + "groundIntoDoublePlay": 71, + "numberOfPitches": 12188, + "plateAppearances": 3124, + "totalBases": 1046, + "rbi": 341, + "leftOnBase": 511, + "sacBunts": 7, + "sacFlies": 20, + "babip": ".295", + "groundOutsToAirouts": "0.92", + "atBatsPerHomeRun": "36.38" + }, + "team": { + "id": 113, + "name": "Cincinnati Reds", + "link": "/api/v1/teams/113" + }, + "numTeams": 1, + "rank": 20 + }, + { + "stat": { + "gamesPlayed": 84, + "groundOuts": 729, + "airOuts": 711, + "runs": 345, + "doubles": 142, + "triples": 11, + "homeRuns": 77, + "strikeOuts": 734, + "baseOnBalls": 254, + "intentionalWalks": 8, + "hits": 668, + "hitByPitch": 23, + "avg": ".237", + "atBats": 2822, + "obp": ".303", + "slg": ".377", + "ops": ".680", + "caughtStealing": 23, + "stolenBases": 58, + "stolenBasePercentage": ".716", + "groundIntoDoublePlay": 47, + "numberOfPitches": 12133, + "plateAppearances": 3119, + "totalBases": 1063, + "rbi": 328, + "leftOnBase": 547, + "sacBunts": 3, + "sacFlies": 17, + "babip": ".291", + "groundOutsToAirouts": "1.03", + "atBatsPerHomeRun": "36.65" + }, + "team": { + "id": 139, + "name": "Tampa Bay Rays", + "link": "/api/v1/teams/139" + }, + "numTeams": 1, + "rank": 21 + }, + { + "stat": { + "gamesPlayed": 86, + "groundOuts": 714, + "airOuts": 738, + "runs": 390, + "doubles": 130, + "triples": 11, + "homeRuns": 118, + "strikeOuts": 757, + "baseOnBalls": 297, + "intentionalWalks": 7, + "hits": 677, + "hitByPitch": 44, + "avg": ".236", + "atBats": 2865, + "obp": ".316", + "slg": ".413", + "ops": ".729", + "caughtStealing": 16, + "stolenBases": 54, + "stolenBasePercentage": ".771", + "groundIntoDoublePlay": 66, + "numberOfPitches": 13165, + "plateAppearances": 3227, + "totalBases": 1183, + "rbi": 380, + "leftOnBase": 564, + "sacBunts": 2, + "sacFlies": 19, + "babip": ".278", + "groundOutsToAirouts": "0.97", + "atBatsPerHomeRun": "24.28" + }, + "team": { + "id": 158, + "name": "Milwaukee Brewers", + "link": "/api/v1/teams/158" + }, + "numTeams": 1, + "rank": 22 + }, + { + "stat": { + "gamesPlayed": 86, + "groundOuts": 675, + "airOuts": 805, + "runs": 348, + "doubles": 138, + "triples": 11, + "homeRuns": 91, + "strikeOuts": 737, + "baseOnBalls": 310, + "intentionalWalks": 8, + "hits": 672, + "hitByPitch": 47, + "avg": ".234", + "atBats": 2866, + "obp": ".317", + "slg": ".386", + "ops": ".703", + "caughtStealing": 17, + "stolenBases": 47, + "stolenBasePercentage": ".734", + "groundIntoDoublePlay": 54, + "numberOfPitches": 12662, + "plateAppearances": 3249, + "totalBases": 1105, + "rbi": 333, + "leftOnBase": 625, + "sacBunts": 3, + "sacFlies": 20, + "babip": ".282", + "groundOutsToAirouts": "0.84", + "atBatsPerHomeRun": "31.50" + }, + "team": { + "id": 136, + "name": "Seattle Mariners", + "link": "/api/v1/teams/136" + }, + "numTeams": 1, + "rank": 23 + }, + { + "stat": { + "gamesPlayed": 83, + "groundOuts": 673, + "airOuts": 746, + "runs": 384, + "doubles": 131, + "triples": 7, + "homeRuns": 96, + "strikeOuts": 727, + "baseOnBalls": 311, + "intentionalWalks": 9, + "hits": 641, + "hitByPitch": 47, + "avg": ".233", + "atBats": 2753, + "obp": ".318", + "slg": ".390", + "ops": ".708", + "caughtStealing": 10, + "stolenBases": 38, + "stolenBasePercentage": ".792", + "groundIntoDoublePlay": 59, + "numberOfPitches": 12604, + "plateAppearances": 3145, + "totalBases": 1074, + "rbi": 369, + "leftOnBase": 562, + "sacBunts": 1, + "sacFlies": 33, + "babip": ".278", + "groundOutsToAirouts": "0.90", + "atBatsPerHomeRun": "28.68" + }, + "team": { + "id": 137, + "name": "San Francisco Giants", + "link": "/api/v1/teams/137" + }, + "numTeams": 1, + "rank": 24 + }, + { + "stat": { + "gamesPlayed": 86, + "groundOuts": 656, + "airOuts": 727, + "runs": 342, + "doubles": 119, + "triples": 13, + "homeRuns": 101, + "strikeOuts": 831, + "baseOnBalls": 263, + "intentionalWalks": 15, + "hits": 663, + "hitByPitch": 27, + "avg": ".232", + "atBats": 2852, + "obp": ".302", + "slg": ".390", + "ops": ".692", + "caughtStealing": 18, + "stolenBases": 48, + "stolenBasePercentage": ".727", + "groundIntoDoublePlay": 54, + "numberOfPitches": 12428, + "plateAppearances": 3167, + "totalBases": 1111, + "rbi": 331, + "leftOnBase": 549, + "sacBunts": 13, + "sacFlies": 12, + "babip": ".291", + "groundOutsToAirouts": "0.90", + "atBatsPerHomeRun": "28.24" + }, + "team": { + "id": 108, + "name": "Los Angeles Angels", + "link": "/api/v1/teams/108" + }, + "numTeams": 1, + "rank": 25 + }, + { + "stat": { + "gamesPlayed": 84, + "groundOuts": 716, + "airOuts": 716, + "runs": 268, + "doubles": 109, + "triples": 16, + "homeRuns": 51, + "strikeOuts": 707, + "baseOnBalls": 204, + "intentionalWalks": 3, + "hits": 633, + "hitByPitch": 26, + "avg": ".230", + "atBats": 2747, + "obp": ".288", + "slg": ".337", + "ops": ".625", + "caughtStealing": 12, + "stolenBases": 22, + "stolenBasePercentage": ".647", + "groundIntoDoublePlay": 60, + "numberOfPitches": 11526, + "plateAppearances": 3002, + "totalBases": 927, + "rbi": 258, + "leftOnBase": 524, + "sacBunts": 5, + "sacFlies": 20, + "babip": ".290", + "groundOutsToAirouts": "1.00", + "atBatsPerHomeRun": "53.86" + }, + "team": { + "id": 116, + "name": "Detroit Tigers", + "link": "/api/v1/teams/116" + }, + "numTeams": 1, + "rank": 26 + }, + { + "stat": { + "gamesPlayed": 86, + "groundOuts": 645, + "airOuts": 840, + "runs": 351, + "doubles": 154, + "triples": 11, + "homeRuns": 87, + "strikeOuts": 775, + "baseOnBalls": 240, + "intentionalWalks": 6, + "hits": 668, + "hitByPitch": 50, + "avg": ".230", + "atBats": 2900, + "obp": ".298", + "slg": ".381", + "ops": ".679", + "caughtStealing": 14, + "stolenBases": 52, + "stolenBasePercentage": ".788", + "groundIntoDoublePlay": 53, + "numberOfPitches": 12440, + "plateAppearances": 3222, + "totalBases": 1105, + "rbi": 333, + "leftOnBase": 588, + "sacBunts": 7, + "sacFlies": 21, + "babip": ".282", + "groundOutsToAirouts": "0.77", + "atBatsPerHomeRun": "33.33" + }, + "team": { + "id": 110, + "name": "Baltimore Orioles", + "link": "/api/v1/teams/110" + }, + "numTeams": 1, + "rank": 27 + }, + { + "stat": { + "gamesPlayed": 85, + "groundOuts": 737, + "airOuts": 741, + "runs": 365, + "doubles": 129, + "triples": 13, + "homeRuns": 99, + "strikeOuts": 732, + "baseOnBalls": 298, + "intentionalWalks": 11, + "hits": 624, + "hitByPitch": 29, + "avg": ".223", + "atBats": 2797, + "obp": ".302", + "slg": ".385", + "ops": ".687", + "caughtStealing": 13, + "stolenBases": 35, + "stolenBasePercentage": ".729", + "groundIntoDoublePlay": 45, + "numberOfPitches": 12407, + "plateAppearances": 3161, + "totalBases": 1076, + "rbi": 341, + "leftOnBase": 551, + "sacBunts": 15, + "sacFlies": 22, + "babip": ".264", + "groundOutsToAirouts": "0.99", + "atBatsPerHomeRun": "28.25" + }, + "team": { + "id": 109, + "name": "Arizona Diamondbacks", + "link": "/api/v1/teams/109" + }, + "numTeams": 1, + "rank": 28 + }, + { + "stat": { + "gamesPlayed": 85, + "groundOuts": 705, + "airOuts": 701, + "runs": 308, + "doubles": 113, + "triples": 14, + "homeRuns": 91, + "strikeOuts": 785, + "baseOnBalls": 251, + "intentionalWalks": 6, + "hits": 607, + "hitByPitch": 23, + "avg": ".219", + "atBats": 2771, + "obp": ".288", + "slg": ".368", + "ops": ".656", + "caughtStealing": 18, + "stolenBases": 35, + "stolenBasePercentage": ".660", + "groundIntoDoublePlay": 51, + "numberOfPitches": 12272, + "plateAppearances": 3072, + "totalBases": 1021, + "rbi": 288, + "leftOnBase": 518, + "sacBunts": 8, + "sacFlies": 19, + "babip": ".270", + "groundOutsToAirouts": "1.01", + "atBatsPerHomeRun": "30.45" + }, + "team": { + "id": 134, + "name": "Pittsburgh Pirates", + "link": "/api/v1/teams/134" + }, + "numTeams": 1, + "rank": 29 + }, + { + "stat": { + "gamesPlayed": 86, + "groundOuts": 771, + "airOuts": 748, + "runs": 272, + "doubles": 130, + "triples": 7, + "homeRuns": 61, + "strikeOuts": 714, + "baseOnBalls": 215, + "intentionalWalks": 4, + "hits": 583, + "hitByPitch": 32, + "avg": ".209", + "atBats": 2789, + "obp": ".272", + "slg": ".326", + "ops": ".598", + "caughtStealing": 14, + "stolenBases": 51, + "stolenBasePercentage": ".785", + "groundIntoDoublePlay": 60, + "numberOfPitches": 11688, + "plateAppearances": 3064, + "totalBases": 910, + "rbi": 250, + "leftOnBase": 495, + "sacBunts": 10, + "sacFlies": 17, + "babip": ".257", + "groundOutsToAirouts": "1.03", + "atBatsPerHomeRun": "45.72" + }, + "team": { + "id": 133, + "name": "Oakland Athletics", + "link": "/api/v1/teams/133" + }, + "numTeams": 1, + "rank": 30 + } + ], + "splitsTiedWithOffset": [], + "splitsTiedWithLimit": [] + } + ] +} diff --git a/src/components/boxscore.rs b/src/components/boxscore.rs index 3849480..888b7fa 100644 --- a/src/components/boxscore.rs +++ b/src/components/boxscore.rs @@ -13,6 +13,7 @@ pub struct BatterBoxscore { rbis: u16, walks: u16, strike_outs: u16, + home_runs: u16, left_on: u16, batting_average: String, } @@ -29,6 +30,7 @@ impl BatterBoxscore { rbis: player.stats.batting.rbi.unwrap_or(0), walks: player.stats.batting.base_on_balls.unwrap_or(0), strike_outs: player.stats.batting.strike_outs.unwrap_or(0), + home_runs: player.stats.batting.home_runs.unwrap_or(0), left_on: player.stats.batting.left_on_base.unwrap_or(0), batting_average: player .season_stats @@ -53,6 +55,7 @@ impl BatterBoxscore { self.rbis.to_string(), self.walks.to_string(), self.strike_outs.to_string(), + self.home_runs.to_string(), self.left_on.to_string(), self.batting_average.to_string(), ] diff --git a/src/components/debug.rs b/src/components/debug.rs index d6a00c4..ecde722 100644 --- a/src/components/debug.rs +++ b/src/components/debug.rs @@ -1,5 +1,7 @@ use crate::app::{App, GamedayPanels}; use std::fmt; +use chrono::NaiveDate; +use mlb_api::client::StatGroup; use tui::backend::Backend; use tui::Frame; @@ -9,18 +11,23 @@ pub struct DebugInfo { pub terminal_width: u16, pub terminal_height: u16, pub gameday_active_views: GamedayPanels, + pub date: NaiveDate, + pub stat_type: StatGroup, } impl fmt::Display for DebugInfo { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, - "game id: {}\ngameday: {}\nterminal height: {} width: {}\n{:?}", + "game id: {}\ngameday: {}\nterminal height: {} width: {}\ndate: {}\nstat group: {}\n{:?}", self.game_id, self.gameday_url, self.terminal_height, self.terminal_width, - self.gameday_active_views + self.date, + self.stat_type, + self.gameday_active_views, + ) } } @@ -33,6 +40,8 @@ impl DebugInfo { terminal_width: 0, terminal_height: 0, gameday_active_views: GamedayPanels::default(), + date: NaiveDate::from_ymd(2022, 07, 09), + stat_type: StatGroup::Pitching } } // TODO add more info @@ -46,6 +55,8 @@ impl DebugInfo { self.gameday_url = format!("https://www.mlb.com/gameday/{}", self.game_id); self.terminal_width = f.size().width; self.terminal_height = f.size().height; - self.gameday_active_views = app.state.gameday; + self.gameday_active_views = app.gameday; + self.date = app.schedule.date; + self.stat_type = app.stats.stat_type.group.clone(); } } diff --git a/src/components/schedule.rs b/src/components/schedule.rs index e326f3d..c9c8843 100644 --- a/src/components/schedule.rs +++ b/src/components/schedule.rs @@ -155,7 +155,7 @@ impl ScheduleRow { // TODO let timezone be configurable let datetime = DateTime::parse_from_rfc3339(&game.game_date) .unwrap() - .with_timezone(&Los_Angeles); + .with_timezone(&Local); let start_time = datetime.format("%l:%M %P").to_string(); let game_status = match &game.status.detailed_state { diff --git a/src/draw.rs b/src/draw.rs index 6f699e6..a834b6e 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -42,17 +42,18 @@ where match app.state.active_tab { MenuItem::Scoreboard => draw_scoreboard(f, main_layout.main, app), MenuItem::DatePicker => { - draw_scoreboard(f, main_layout.main, app); + match app.previous_tab { + MenuItem::Scoreboard => draw_scoreboard(f, main_layout.main, app), + MenuItem::Stats => draw_stats(f, main_layout.main, app), + _ => () + } + draw_date_picker(f, main_layout.main, app); } MenuItem::Gameday => draw_gameday(f, main_layout.main, app), MenuItem::Stats => draw_stats(f, main_layout.main, app), MenuItem::Standings => { - f.render_stateful_widget( - StandingsWidget {}, - main_layout.main, - &mut app.state.standings, - ); + draw_standings(f, main_layout.main, app); } MenuItem::Help => draw_help(f, f.size()), } @@ -165,6 +166,13 @@ where chunks[1], &mut app.state.live_game.boxscore, ); + f.render_stateful_widget( + TeamBatterBoxscoreWidget { + active: HomeOrAway::Home + }, + chunks[2], + &mut app.live_game.boxscore + ); } fn draw_date_picker(f: &mut Frame, rect: Rect, app: &mut App) @@ -258,6 +266,17 @@ where ); } +fn draw_standings(f: &mut Frame, rect: Rect, app: &mut App) +where + B: Backend, +{ + f.render_stateful_widget( + StandingsWidget {}, + rect, + &mut app.standings, + ); +} + fn draw_help(f: &mut Frame, rect: Rect) where B: Backend, diff --git a/src/event.rs b/src/event.rs index 3859425..0f4f372 100644 --- a/src/event.rs +++ b/src/event.rs @@ -36,6 +36,13 @@ pub fn handle_key_bindings( let _ = selective_update.try_send(MenuItem::Standings); } + (_, Char(':')) => { + match app.active_tab { + MenuItem::Scoreboard | MenuItem::Stats => app.update_tab(MenuItem::DatePicker), + _ => () + } + } + (MenuItem::Scoreboard, Char('j')) => { app.state.schedule.next(); let _ = selective_update.try_send(MenuItem::Scoreboard); @@ -44,7 +51,6 @@ pub fn handle_key_bindings( app.state.schedule.previous(); let _ = selective_update.try_send(MenuItem::Scoreboard); } - (MenuItem::Scoreboard, Char(':')) => app.update_tab(MenuItem::DatePicker), (MenuItem::DatePicker, KeyCode::Enter) => { let date: String = app.state.date_input.text.drain(..).collect(); @@ -55,6 +61,15 @@ pub fn handle_key_bindings( } else { app.state.date_input.is_valid = false; } + + match app.previous_tab { + MenuItem::Scoreboard => app.update_tab(MenuItem::Scoreboard), + MenuItem::Stats => { + app.update_tab(MenuItem::Stats); + let _ = selective_update.try_send(MenuItem::Stats); + }, + _ => () + } } (MenuItem::DatePicker, KeyCode::Right) => { let date = app.state.schedule.set_date_with_arrows(true); diff --git a/src/ui/boxscore.rs b/src/ui/boxscore.rs index 382df49..0b710a9 100644 --- a/src/ui/boxscore.rs +++ b/src/ui/boxscore.rs @@ -8,7 +8,7 @@ use tui::{ widgets::{Block, Borders, Cell, Row, StatefulWidget, Table, Widget}, }; -const HEADER: [&str; 9] = ["player", "ab", "r", "h", "rbi", "bb", "so", "lob", "avg"]; +const HEADER: [&str; 10] = ["player", "ab", "r", "h", "rbi", "bb", "so", "hr", "lob", "avg"]; pub struct TeamBatterBoxscoreWidget { pub active: HomeOrAway, @@ -21,7 +21,7 @@ impl StatefulWidget for TeamBatterBoxscoreWidget { let width = 4; let mut widths = vec![Constraint::Length(width); HEADER.len()]; // the first width needs to be wider to display the player name - widths[0] = Constraint::Length(15); + widths[0] = Constraint::Length(20); // the last width needs to be wider to display batting average widths[HEADER.len() - 1] = Constraint::Length(5); diff --git a/src/ui/layout.rs b/src/ui/layout.rs index d5b1ccd..b2a8cbd 100644 --- a/src/ui/layout.rs +++ b/src/ui/layout.rs @@ -63,7 +63,8 @@ impl LayoutAreas { .constraints( [ Constraint::Length(4), // line score - Constraint::Percentage(100), // box score + Constraint::Percentage(50), // box score + Constraint::Percentage(50), // box score ] .as_ref(), ) diff --git a/src/ui/schedule.rs b/src/ui/schedule.rs index 216abbf..4d2a12c 100644 --- a/src/ui/schedule.rs +++ b/src/ui/schedule.rs @@ -9,7 +9,7 @@ use tui::{ widgets::{Block, BorderType, Borders, Cell, Row, StatefulWidget, Table}, }; -const HEADER: &[&str; 6] = &["away", "", "home", "", "time [PST]", "status"]; +const HEADER: &[&str; 6] = &["away", "", "home", "", "time [EST]", "status"]; pub struct ScheduleWidget {} From b341c85721eee2c47c7cdf8fd5439c75876da8ca Mon Sep 17 00:00:00 2001 From: Alex Bolduc Date: Sun, 25 Feb 2024 23:23:15 -0500 Subject: [PATCH 06/19] chore: fix errors from bad merge --- api/src/client.rs | 29 +++++++++++++++-------------- src/components/debug.rs | 8 ++++---- src/components/schedule.rs | 2 +- src/draw.rs | 14 +++++++++----- src/event.rs | 4 ++-- 5 files changed, 31 insertions(+), 26 deletions(-) diff --git a/api/src/client.rs b/api/src/client.rs index 3857555..b107104 100644 --- a/api/src/client.rs +++ b/api/src/client.rs @@ -92,7 +92,7 @@ impl MLBApi { self.get(url).await } - pub fn get_team_stats_on_date(&self, group: StatGroup, date: NaiveDate) -> StatResponse { + pub async fn get_team_stats_on_date(&self, group: StatGroup, date: NaiveDate) -> StatResponse { let url = format!( "{}v1/teams/stats?sportId=1&stats=byDateRange&season={}&endDate={}&group={}", self.base_url, @@ -100,10 +100,10 @@ impl MLBApi { date.format("%Y-%m-%d"), group ); - self.get(url) + self.get(url).await } - pub fn get_player_stats(&self, group: StatGroup) -> StatResponse { + pub async fn get_player_stats(&self, group: StatGroup) -> StatResponse { let local: DateTime = Local::now(); let url = format!( "{}v1/stats?stats=season&season={}&group={}", @@ -114,7 +114,7 @@ impl MLBApi { self.get(url).await } - pub fn get_player_stats_on_date(&self, group: StatGroup, date: NaiveDate) -> StatResponse { + pub async fn get_player_stats_on_date(&self, group: StatGroup, date: NaiveDate) -> StatResponse { let url = format!( "{}v1/stats?stats=byDateRange&season={}&endDate={}&group={}", self.base_url, @@ -122,18 +122,19 @@ impl MLBApi { date.format("%Y-%m-%d"), group ); - self.get(url) + self.get(url).await } - // TODO need better error handling, especially on parsing - fn get(&self, url: String) -> T { - let response = self.client.get(url).send().unwrap_or_else(|err| { - panic!("network error {:?}", err); - }); - response.json::().map(From::from).unwrap_or_else(|err| { - eprintln!("parsing error {:?}", err); - T::default() - }) + async fn get(&self, url: String) -> T { + let response = self.client.get(url).send().await.expect("network error"); + response + .json::() + .await + .map(From::from) + .unwrap_or_else(|err| { + eprintln!("parsing error {:?}", err); + T::default() + }) } } diff --git a/src/components/debug.rs b/src/components/debug.rs index ecde722..0ef44e6 100644 --- a/src/components/debug.rs +++ b/src/components/debug.rs @@ -40,7 +40,7 @@ impl DebugInfo { terminal_width: 0, terminal_height: 0, gameday_active_views: GamedayPanels::default(), - date: NaiveDate::from_ymd(2022, 07, 09), + date: NaiveDate::from_ymd_opt(2022, 07, 09).unwrap(), stat_type: StatGroup::Pitching } } @@ -55,8 +55,8 @@ impl DebugInfo { self.gameday_url = format!("https://www.mlb.com/gameday/{}", self.game_id); self.terminal_width = f.size().width; self.terminal_height = f.size().height; - self.gameday_active_views = app.gameday; - self.date = app.schedule.date; - self.stat_type = app.stats.stat_type.group.clone(); + self.gameday_active_views = app.state.gameday; + self.date = app.state.schedule.date; + self.stat_type = app.state.stats.stat_type.group.clone(); } } diff --git a/src/components/schedule.rs b/src/components/schedule.rs index c9c8843..0f9fb11 100644 --- a/src/components/schedule.rs +++ b/src/components/schedule.rs @@ -155,7 +155,7 @@ impl ScheduleRow { // TODO let timezone be configurable let datetime = DateTime::parse_from_rfc3339(&game.game_date) .unwrap() - .with_timezone(&Local); + .with_timezone(&TIMEZONE); let start_time = datetime.format("%l:%M %P").to_string(); let game_status = match &game.status.detailed_state { diff --git a/src/draw.rs b/src/draw.rs index a834b6e..b74bf1c 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -5,7 +5,7 @@ use tui::text::{Line, Span}; use tui::widgets::{Block, BorderType, Borders, Clear, Paragraph, Tabs}; use tui::{Frame, Terminal}; -use crate::app::{App, DebugState, MenuItem}; +use crate::app::{App, DebugState, MenuItem, HomeOrAway}; use crate::components::debug::DebugInfo; use crate::ui::at_bat::AtBatWidget; use crate::ui::boxscore::TeamBatterBoxscoreWidget; @@ -42,7 +42,7 @@ where match app.state.active_tab { MenuItem::Scoreboard => draw_scoreboard(f, main_layout.main, app), MenuItem::DatePicker => { - match app.previous_tab { + match app.state.previous_tab { MenuItem::Scoreboard => draw_scoreboard(f, main_layout.main, app), MenuItem::Stats => draw_stats(f, main_layout.main, app), _ => () @@ -159,19 +159,23 @@ where chunks[0], &mut app.state.live_game.linescore, ); + + // Away Team Box Score f.render_stateful_widget( TeamBatterBoxscoreWidget { - active: app.state.boxscore_tab, + active: HomeOrAway::Away }, chunks[1], &mut app.state.live_game.boxscore, ); + + // Home Team Box Score f.render_stateful_widget( TeamBatterBoxscoreWidget { active: HomeOrAway::Home }, chunks[2], - &mut app.live_game.boxscore + &mut app.state.live_game.boxscore ); } @@ -273,7 +277,7 @@ where f.render_stateful_widget( StandingsWidget {}, rect, - &mut app.standings, + &mut app.state.standings, ); } diff --git a/src/event.rs b/src/event.rs index 0f4f372..83e1637 100644 --- a/src/event.rs +++ b/src/event.rs @@ -37,7 +37,7 @@ pub fn handle_key_bindings( } (_, Char(':')) => { - match app.active_tab { + match app.state.active_tab { MenuItem::Scoreboard | MenuItem::Stats => app.update_tab(MenuItem::DatePicker), _ => () } @@ -62,7 +62,7 @@ pub fn handle_key_bindings( app.state.date_input.is_valid = false; } - match app.previous_tab { + match app.state.previous_tab { MenuItem::Scoreboard => app.update_tab(MenuItem::Scoreboard), MenuItem::Stats => { app.update_tab(MenuItem::Stats); From 0ccc4f4d66632834da1e368ef47074f2e6239358 Mon Sep 17 00:00:00 2001 From: Alex Bolduc Date: Sun, 25 Feb 2024 23:30:37 -0500 Subject: [PATCH 07/19] chore: fix get stats for selected date --- api/tests/client.rs | 50 +++++++++++++++++++++++---------------------- src/event.rs | 13 ++---------- src/main.rs | 4 ++-- 3 files changed, 30 insertions(+), 37 deletions(-) diff --git a/api/tests/client.rs b/api/tests/client.rs index 80e84ae..8f0e244 100644 --- a/api/tests/client.rs +++ b/api/tests/client.rs @@ -83,30 +83,32 @@ mod tests { } } - #[test] - fn test_team_stats_on_date() { - let client = MLBApiBuilder::default().build().unwrap(); - let date: NaiveDate = NaiveDate::from_ymd(2022, 07, 09); + #[tokio::test] + async fn test_team_stats_on_date() { + let mut server = mockito::Server::new(); + + let date: NaiveDate = NaiveDate::from_ymd_opt(2022, 07, 09).unwrap(); for group in vec![StatGroup::Hitting, StatGroup::Pitching] { let url = format!( "v1/teams/stats?sportId=1&stats=byDateRange&season=2022&endDate=2022-07-09&group={}", group ); - let _m = mock("GET", Matcher::Exact(url)) - .with_status(200) - .with_header("content-type", "application/json;charset=UTF-8") - .with_body_from_file("./tests/responses/team-stats-date.json") - .create(); + let _m = server + .mock("GET", Matcher::Exact(url)) + .with_status(200) + .with_header("content-type", "application/json;charset=UTF-8") + .with_body_from_file("./tests/responses/team-stats-date.json") + .create(); - let resp = client.get_team_stats_on_date(group, date); + let resp = CLIENT.get_team_stats_on_date(group, date).await; println!("{:?}", resp); } } - #[test] - fn test_player_stats() { - let client = MLBApiBuilder::default().build().unwrap(); + #[tokio::test] + async fn test_player_stats() { + let mut server = mockito::Server::new(); for group in vec![StatGroup::Hitting, StatGroup::Pitching] { let url = format!("v1/stats?stats=season&season=2021&group={}", group); @@ -122,25 +124,25 @@ mod tests { } } - #[test] - fn test_player_stats_on_date() { - let client = MLBApiBuilder::default().build().unwrap(); - let date: NaiveDate = NaiveDate::from_ymd(2022, 07, 09); + #[tokio::test] + async fn test_player_stats_on_date() { + let mut server = mockito::Server::new(); + let date: NaiveDate = NaiveDate::from_ymd_opt(2022, 07, 09).unwrap(); for group in vec![StatGroup::Hitting, StatGroup::Pitching] { let url = format!( "v1/stats?sportId=1&stats=byDateRange&season=2022&endDate=2022-07-09&group={}", group ); - let _m = mock("GET", Matcher::Exact(url)) - .with_status(200) - .with_header("content-type", "application/json;charset=UTF-8") - .with_body_from_file("./tests/responses/player-stats-date.json") - .create(); + let _m = server + .mock("GET", Matcher::Exact(url)) + .with_status(200) + .with_header("content-type", "application/json;charset=UTF-8") + .with_body_from_file("./tests/responses/player-stats-date.json") + .create(); - let resp = client.get_player_stats_on_date(group, date); + let resp = CLIENT.get_player_stats_on_date(group, date).await; println!("{:?}", resp); } } - } diff --git a/src/event.rs b/src/event.rs index 83e1637..3914322 100644 --- a/src/event.rs +++ b/src/event.rs @@ -56,20 +56,11 @@ pub fn handle_key_bindings( let date: String = app.state.date_input.text.drain(..).collect(); if app.state.schedule.set_date_from_input(date).is_ok() { app.state.date_input.is_valid = true; - app.update_tab(MenuItem::Scoreboard); - let _ = selective_update.try_send(MenuItem::DatePicker); + app.update_tab(app.state.previous_tab); + let _ = selective_update.try_send(app.state.active_tab); } else { app.state.date_input.is_valid = false; } - - match app.state.previous_tab { - MenuItem::Scoreboard => app.update_tab(MenuItem::Scoreboard), - MenuItem::Stats => { - app.update_tab(MenuItem::Stats); - let _ = selective_update.try_send(MenuItem::Stats); - }, - _ => () - } } (MenuItem::DatePicker, KeyCode::Right) => { let date = app.state.schedule.set_date_with_arrows(true); diff --git a/src/main.rs b/src/main.rs index cb8322c..2be5215 100644 --- a/src/main.rs +++ b/src/main.rs @@ -140,8 +140,8 @@ async fn network_thread(app: Arc>) { // pitching/hitting is changed Ok(MenuItem::Stats) => { let response = match app.state.stats.stat_type.team_player { - TeamOrPlayer::Team => app.client.get_team_stats(app.state.stats.stat_type.group.clone()).await, - TeamOrPlayer::Player => app.client.get_player_stats(app.state.stats.stat_type.group.clone()).await, + TeamOrPlayer::Team => app.client.get_team_stats_on_date(app.state.stats.stat_type.group.clone(), app.state.schedule.date).await, + TeamOrPlayer::Player => app.client.get_player_stats_on_date(app.state.stats.stat_type.group.clone(), app.state.schedule.date).await, }; app.state.stats.update(&response); } From f8b6e2422c4207a5ae1cb9cc7dcebc949097f233 Mon Sep 17 00:00:00 2001 From: Alex Bolduc Date: Sun, 25 Feb 2024 23:35:12 -0500 Subject: [PATCH 08/19] fix: get standings for selected date --- api/src/client.rs | 12 ++++++++++++ src/main.rs | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/api/src/client.rs b/api/src/client.rs index b107104..05d981a 100644 --- a/api/src/client.rs +++ b/api/src/client.rs @@ -81,6 +81,18 @@ impl MLBApi { self.get(url).await } + pub async fn get_standings_on_date(&self, date: T) -> StandingsResponse { + let url = format!( + "{}v1/standings?sportId=1&season={}&date={}-{}-{}&leagueId=103,104", + self.base_url, + date.year(), + date.year(), + date.month(), + date.day(), + ); + self.get(url).await + } + pub async fn get_team_stats(&self, group: StatGroup) -> StatResponse { let local: DateTime = Local::now(); let url = format!( diff --git a/src/main.rs b/src/main.rs index 2be5215..7db578a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -133,7 +133,7 @@ async fn network_thread(app: Arc>) { } // update standings only when tab is switched to Ok(MenuItem::Standings) => { - let standings = app.client.get_standings().await; + let standings = app.client.get_standings_on_date(app.state.schedule.date).await; app.state.standings.update(&standings); } // update stats only when tab is switched to, team/player is changed, or From 6009c309dfeceaa0a484c903fdae202a2dba51a4 Mon Sep 17 00:00:00 2001 From: Alex Bolduc Date: Sun, 25 Feb 2024 23:39:52 -0500 Subject: [PATCH 09/19] chore: fix bad merge --- src/draw.rs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/draw.rs b/src/draw.rs index 9a7f69a..3d13459 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -177,13 +177,6 @@ where chunks[2], &mut app.state.live_game.boxscore ); - f.render_stateful_widget( - TeamBatterBoxscoreWidget { - active: HomeOrAway::Home - }, - chunks[2], - &mut app.live_game.boxscore - ); } fn draw_date_picker(f: &mut Frame, rect: Rect, app: &mut App) @@ -288,16 +281,6 @@ where ); } -fn draw_standings(f: &mut Frame, rect: Rect, app: &mut App) -where - B: Backend, -{ - f.render_stateful_widget( - StandingsWidget {}, - rect, - &mut app.standings, - ); -} fn draw_help(f: &mut Frame, rect: Rect) where From 2bf5e52f3ba93147930cc5d58ba276b0693941a7 Mon Sep 17 00:00:00 2001 From: Alex Bolduc Date: Sun, 25 Feb 2024 23:44:07 -0500 Subject: [PATCH 10/19] chore: allow date picker on standings page --- src/draw.rs | 5 ++--- src/event.rs | 2 +- src/ui/schedule.rs | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/draw.rs b/src/draw.rs index 3d13459..a741c13 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -45,6 +45,7 @@ where match app.state.previous_tab { MenuItem::Scoreboard => draw_scoreboard(f, main_layout.main, app), MenuItem::Stats => draw_stats(f, main_layout.main, app), + MenuItem::Standings => draw_standings(f, main_layout.main, app), _ => () } @@ -52,9 +53,7 @@ where } MenuItem::Gameday => draw_gameday(f, main_layout.main, app), MenuItem::Stats => draw_stats(f, main_layout.main, app), - MenuItem::Standings => { - draw_standings(f, main_layout.main, app); - } + MenuItem::Standings => draw_standings(f, main_layout.main, app), MenuItem::Help => draw_help(f, f.size()), } if app.state.debug_state == DebugState::On { diff --git a/src/event.rs b/src/event.rs index 3914322..46041ad 100644 --- a/src/event.rs +++ b/src/event.rs @@ -38,7 +38,7 @@ pub fn handle_key_bindings( (_, Char(':')) => { match app.state.active_tab { - MenuItem::Scoreboard | MenuItem::Stats => app.update_tab(MenuItem::DatePicker), + MenuItem::Scoreboard | MenuItem::Stats | MenuItem::Standings => app.update_tab(MenuItem::DatePicker), _ => () } } diff --git a/src/ui/schedule.rs b/src/ui/schedule.rs index 4d2a12c..216abbf 100644 --- a/src/ui/schedule.rs +++ b/src/ui/schedule.rs @@ -9,7 +9,7 @@ use tui::{ widgets::{Block, BorderType, Borders, Cell, Row, StatefulWidget, Table}, }; -const HEADER: &[&str; 6] = &["away", "", "home", "", "time [EST]", "status"]; +const HEADER: &[&str; 6] = &["away", "", "home", "", "time [PST]", "status"]; pub struct ScheduleWidget {} From 3d47ea6cd572a5d894b3286d6ca4b29dddc1c37c Mon Sep 17 00:00:00 2001 From: Alex Bolduc Date: Sun, 25 Feb 2024 23:46:48 -0500 Subject: [PATCH 11/19] chore: update help with new keybinds --- src/ui/help.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/help.rs b/src/ui/help.rs index 2ab0b78..f98fb5c 100644 --- a/src/ui/help.rs +++ b/src/ui/help.rs @@ -18,13 +18,12 @@ const DOCS: &[&[&str; 2]; DOCS_LEN] = &[ &["Move down", "j"], &["Move up", "k"], &["Select date", ":"], - &["Switch boxscore team", "h/a"], &["Gameday", "2"], &["Toggle game info", "i"], &["Toggle pitches", "p"], &["Toggle boxscore", "b"], - &["Switch boxscore team", "h/a"], &["Stats", "3"], + &["Select date", ":"], &["Switch hitting/pitching", "h/p"], &["Switch team/player", "t/l"], &["Move down", "j"], @@ -32,6 +31,7 @@ const DOCS: &[&[&str; 2]; DOCS_LEN] = &[ &["Toggle stat", "Enter"], &["Toggle stat selection", "o"], &["Standings", "4"], + &["Select date", ":"], &["Move down", "j"], &["Move up", "k"], &["View team info", "Enter"], From 7d9395ee7fc05a7fa23685ca245bbc7399f1a6f1 Mon Sep 17 00:00:00 2001 From: Alex Bolduc Date: Sun, 25 Feb 2024 23:49:02 -0500 Subject: [PATCH 12/19] chore: revert formatting change --- api/src/client.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/api/src/client.rs b/api/src/client.rs index c2a9d16..9ce1999 100644 --- a/api/src/client.rs +++ b/api/src/client.rs @@ -138,15 +138,15 @@ impl MLBApi { } async fn get(&self, url: String) -> T { - let response = self.client.get(url).send().await.expect("network error"); - response - .json::() - .await - .map(From::from) - .unwrap_or_else(|err| { - eprintln!("parsing error {:?}", err); - T::default() - }) + let response = self.client.get(url).send().await.expect("network error"); + response + .json::() + .await + .map(From::from) + .unwrap_or_else(|err| { + eprintln!("parsing error {:?}", err); + T::default() + }) } } From 9074575890a546bf93e4be230b49c1ab57532fa9 Mon Sep 17 00:00:00 2001 From: Alex Bolduc Date: Mon, 26 Feb 2024 08:19:35 -0500 Subject: [PATCH 13/19] chore: cargo fmt --- api/src/client.rs | 10 +++++++--- api/tests/client.rs | 21 ++++++++++----------- src/components/debug.rs | 4 ++-- src/draw.rs | 17 ++++++----------- src/event.rs | 10 +++++----- src/ui/boxscore.rs | 4 +++- src/ui/layout.rs | 2 +- 7 files changed, 34 insertions(+), 34 deletions(-) diff --git a/api/src/client.rs b/api/src/client.rs index 9ce1999..3880555 100644 --- a/api/src/client.rs +++ b/api/src/client.rs @@ -126,7 +126,11 @@ impl MLBApi { self.get(url).await } - pub async fn get_player_stats_on_date(&self, group: StatGroup, date: NaiveDate) -> StatResponse { + pub async fn get_player_stats_on_date( + &self, + group: StatGroup, + date: NaiveDate, + ) -> StatResponse { let url = format!( "{}v1/stats?stats=byDateRange&season={}&endDate={}&group={}", self.base_url, @@ -144,8 +148,8 @@ impl MLBApi { .await .map(From::from) .unwrap_or_else(|err| { - eprintln!("parsing error {:?}", err); - T::default() + eprintln!("parsing error {:?}", err); + T::default() }) } } diff --git a/api/tests/client.rs b/api/tests/client.rs index 963f068..bb99edc 100644 --- a/api/tests/client.rs +++ b/api/tests/client.rs @@ -95,11 +95,11 @@ mod tests { ); let _m = server - .mock("GET", Matcher::Exact(url)) - .with_status(200) - .with_header("content-type", "application/json;charset=UTF-8") - .with_body_from_file("./tests/responses/team-stats-date.json") - .create(); + .mock("GET", Matcher::Exact(url)) + .with_status(200) + .with_header("content-type", "application/json;charset=UTF-8") + .with_body_from_file("./tests/responses/team-stats-date.json") + .create(); let resp = CLIENT.get_team_stats_on_date(group, date).await; println!("{:?}", resp); @@ -135,11 +135,11 @@ mod tests { ); let _m = server - .mock("GET", Matcher::Exact(url)) - .with_status(200) - .with_header("content-type", "application/json;charset=UTF-8") - .with_body_from_file("./tests/responses/player-stats-date.json") - .create(); + .mock("GET", Matcher::Exact(url)) + .with_status(200) + .with_header("content-type", "application/json;charset=UTF-8") + .with_body_from_file("./tests/responses/player-stats-date.json") + .create(); let resp = CLIENT.get_player_stats_on_date(group, date).await; println!("{:?}", resp); @@ -166,5 +166,4 @@ mod tests { println!("{:?}", resp); } } - } diff --git a/src/components/debug.rs b/src/components/debug.rs index 0ef44e6..9f28844 100644 --- a/src/components/debug.rs +++ b/src/components/debug.rs @@ -1,7 +1,7 @@ use crate::app::{App, GamedayPanels}; -use std::fmt; use chrono::NaiveDate; use mlb_api::client::StatGroup; +use std::fmt; use tui::backend::Backend; use tui::Frame; @@ -41,7 +41,7 @@ impl DebugInfo { terminal_height: 0, gameday_active_views: GamedayPanels::default(), date: NaiveDate::from_ymd_opt(2022, 07, 09).unwrap(), - stat_type: StatGroup::Pitching + stat_type: StatGroup::Pitching, } } // TODO add more info diff --git a/src/draw.rs b/src/draw.rs index a741c13..47a9e9b 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -5,7 +5,7 @@ use tui::text::{Line, Span}; use tui::widgets::{Block, BorderType, Borders, Clear, Paragraph, Tabs}; use tui::{Frame, Terminal}; -use crate::app::{App, DebugState, MenuItem, HomeOrAway}; +use crate::app::{App, DebugState, HomeOrAway, MenuItem}; use crate::components::debug::DebugInfo; use crate::ui::at_bat::AtBatWidget; use crate::ui::boxscore::TeamBatterBoxscoreWidget; @@ -46,7 +46,7 @@ where MenuItem::Scoreboard => draw_scoreboard(f, main_layout.main, app), MenuItem::Stats => draw_stats(f, main_layout.main, app), MenuItem::Standings => draw_standings(f, main_layout.main, app), - _ => () + _ => (), } draw_date_picker(f, main_layout.main, app); @@ -162,7 +162,7 @@ where // Away Team Box Score f.render_stateful_widget( TeamBatterBoxscoreWidget { - active: HomeOrAway::Away + active: HomeOrAway::Away, }, chunks[1], &mut app.state.live_game.boxscore, @@ -171,10 +171,10 @@ where // Home Team Box Score f.render_stateful_widget( TeamBatterBoxscoreWidget { - active: HomeOrAway::Home + active: HomeOrAway::Home, }, chunks[2], - &mut app.state.live_game.boxscore + &mut app.state.live_game.boxscore, ); } @@ -273,14 +273,9 @@ fn draw_standings(f: &mut Frame, rect: Rect, app: &mut App) where B: Backend, { - f.render_stateful_widget( - StandingsWidget {}, - rect, - &mut app.state.standings, - ); + f.render_stateful_widget(StandingsWidget {}, rect, &mut app.state.standings); } - fn draw_help(f: &mut Frame, rect: Rect) where B: Backend, diff --git a/src/event.rs b/src/event.rs index 46041ad..954a19d 100644 --- a/src/event.rs +++ b/src/event.rs @@ -36,12 +36,12 @@ pub fn handle_key_bindings( let _ = selective_update.try_send(MenuItem::Standings); } - (_, Char(':')) => { - match app.state.active_tab { - MenuItem::Scoreboard | MenuItem::Stats | MenuItem::Standings => app.update_tab(MenuItem::DatePicker), - _ => () + (_, Char(':')) => match app.state.active_tab { + MenuItem::Scoreboard | MenuItem::Stats | MenuItem::Standings => { + app.update_tab(MenuItem::DatePicker) } - } + _ => (), + }, (MenuItem::Scoreboard, Char('j')) => { app.state.schedule.next(); diff --git a/src/ui/boxscore.rs b/src/ui/boxscore.rs index 0b710a9..eaaf4e7 100644 --- a/src/ui/boxscore.rs +++ b/src/ui/boxscore.rs @@ -8,7 +8,9 @@ use tui::{ widgets::{Block, Borders, Cell, Row, StatefulWidget, Table, Widget}, }; -const HEADER: [&str; 10] = ["player", "ab", "r", "h", "rbi", "bb", "so", "hr", "lob", "avg"]; +const HEADER: [&str; 10] = [ + "player", "ab", "r", "h", "rbi", "bb", "so", "hr", "lob", "avg", +]; pub struct TeamBatterBoxscoreWidget { pub active: HomeOrAway, diff --git a/src/ui/layout.rs b/src/ui/layout.rs index b2a8cbd..70aabab 100644 --- a/src/ui/layout.rs +++ b/src/ui/layout.rs @@ -62,7 +62,7 @@ impl LayoutAreas { .vertical_margin(1) .constraints( [ - Constraint::Length(4), // line score + Constraint::Length(4), // line score Constraint::Percentage(50), // box score Constraint::Percentage(50), // box score ] From 00345aa4113c5d362b309cbc1978a23d45b4423e Mon Sep 17 00:00:00 2001 From: Alex Bolduc Date: Mon, 26 Feb 2024 08:25:21 -0500 Subject: [PATCH 14/19] fix: clippy errors and warnings --- api/tests/client.rs | 25 ++----------------------- src/components/debug.rs | 4 ++-- 2 files changed, 4 insertions(+), 25 deletions(-) diff --git a/api/tests/client.rs b/api/tests/client.rs index bb99edc..ceeb85e 100644 --- a/api/tests/client.rs +++ b/api/tests/client.rs @@ -87,7 +87,7 @@ mod tests { async fn test_team_stats_on_date() { let mut server = mockito::Server::new(); - let date: NaiveDate = NaiveDate::from_ymd_opt(2022, 07, 09).unwrap(); + let date: NaiveDate = NaiveDate::from_ymd_opt(2022,7, 9).unwrap(); for group in vec![StatGroup::Hitting, StatGroup::Pitching] { let url = format!( "v1/teams/stats?sportId=1&stats=byDateRange&season=2022&endDate=2022-07-09&group={}", @@ -127,7 +127,7 @@ mod tests { #[tokio::test] async fn test_player_stats_on_date() { let mut server = mockito::Server::new(); - let date: NaiveDate = NaiveDate::from_ymd_opt(2022, 07, 09).unwrap(); + let date: NaiveDate = NaiveDate::from_ymd_opt(2022, 7, 9).unwrap(); for group in vec![StatGroup::Hitting, StatGroup::Pitching] { let url = format!( "v1/stats?sportId=1&stats=byDateRange&season=2022&endDate=2022-07-09&group={}", @@ -145,25 +145,4 @@ mod tests { println!("{:?}", resp); } } - - #[test] - fn test_player_stats_on_date() { - let client = MLBApiBuilder::default().build().unwrap(); - let date: NaiveDate = NaiveDate::from_ymd(2022, 07, 09); - for group in vec![StatGroup::Hitting, StatGroup::Pitching] { - let url = format!( - "v1/stats?sportId=1&stats=byDateRange&season=2022&endDate=2022-07-09&group={}", - group - ); - - let _m = mock("GET", Matcher::Exact(url)) - .with_status(200) - .with_header("content-type", "application/json;charset=UTF-8") - .with_body_from_file("./tests/responses/player-stats-date.json") - .create(); - - let resp = client.get_player_stats_on_date(group, date); - println!("{:?}", resp); - } - } } diff --git a/src/components/debug.rs b/src/components/debug.rs index 9f28844..54b0532 100644 --- a/src/components/debug.rs +++ b/src/components/debug.rs @@ -1,5 +1,5 @@ use crate::app::{App, GamedayPanels}; -use chrono::NaiveDate; +use chrono::{NaiveDate, Utc}; use mlb_api::client::StatGroup; use std::fmt; use tui::backend::Backend; @@ -40,7 +40,7 @@ impl DebugInfo { terminal_width: 0, terminal_height: 0, gameday_active_views: GamedayPanels::default(), - date: NaiveDate::from_ymd_opt(2022, 07, 09).unwrap(), + date: Utc::now().date_naive(), stat_type: StatGroup::Pitching, } } From 239f95d132f776911b159ff9038625d643a8dee2 Mon Sep 17 00:00:00 2001 From: Alex Bolduc Date: Mon, 26 Feb 2024 08:27:49 -0500 Subject: [PATCH 15/19] chore: cargo version updates --- Cargo.lock | 2 +- Cargo.toml | 2 +- api/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 72b39e4..4f7ed9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -897,7 +897,7 @@ dependencies = [ [[package]] name = "mlb-api" -version = "0.0.9" +version = "0.0.10" dependencies = [ "chrono", "derive_builder", diff --git a/Cargo.toml b/Cargo.toml index 471968e..b9ea95f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ crossterm = "0.26.1" crossbeam-channel = "0.5.8" directories = "5.0.1" indexmap = "2.0.0" -mlb-api = { path = "api", version = "0.0.9" } +mlb-api = { path = "api", version = "0.0.10" } once_cell = "1.18.0" serde = { version = "1.0.164", features = ["derive"] } serde_json = "1.0.99" diff --git a/api/Cargo.toml b/api/Cargo.toml index a835466..1ffac52 100644 --- a/api/Cargo.toml +++ b/api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mlb-api" -version = "0.0.9" +version = "0.0.10" authors = ["Andrew Schneider "] edition = "2021" From 28d43bc435a6ea8b6699604c2d4ef55e5216e006 Mon Sep 17 00:00:00 2001 From: Alex Bolduc Date: Mon, 26 Feb 2024 08:35:58 -0500 Subject: [PATCH 16/19] chore: update README --- README.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 725718a..e27abf0 100644 --- a/README.md +++ b/README.md @@ -120,11 +120,6 @@ With the date picker active, input a date in the form of `YYYY-MM-DD`, or use the `left`/`right` arrow keys, and press `Enter`. This will display the schedule for that day. To view games for the current day, input `today`. -To switch the team displayed in the box score: - -- `h`: home team -- `a`: away team - ### Gameday Press `2` to activate this tab. @@ -136,11 +131,6 @@ toggled on and off using: - `p`: pitches pane - `b`: box score pane -To switch the team displayed in the box score: - -- `h`: home team -- `a`: away team - ### Stats Press `3` to activate this tab. @@ -152,6 +142,11 @@ or `player` using: - `h`: hitting - `t`: team - `l`: player +- `:`: activate date picker + +With the date picker active, input a date in the form of `YYYY-MM-DD`, or use +the `left`/`right` arrow keys, and press `Enter`. This will display the selected stats +for the season up to that day. To view stats for the up to the current day, input `today`. Within each stat group (pitching or hitting) you can toggle the display of individual stat columns by selecting the stat with `Enter`. This selection pane @@ -171,8 +166,14 @@ Press `4` to activate this tab. - `j`: move down - `k`: move up +- `:`: activate date picker - `Enter`: display a teams roster TODO +With the date picker active, input a date in the form of `YYYY-MM-DD`, or use +the `left`/`right` arrow keys, and press `Enter`. This will display the standings +up to that day. To view the standingsup to the current day, input `today`. + + ### Help - `?`: display help box From 524de79f2fa5fc6e465cebea0d0bf88271a8e6b1 Mon Sep 17 00:00:00 2001 From: Alex Bolduc Date: Mon, 26 Feb 2024 08:36:22 -0500 Subject: [PATCH 17/19] chore: use default() for default debug values --- api/src/client.rs | 6 ++++++ src/components/debug.rs | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/api/src/client.rs b/api/src/client.rs index 3880555..313536d 100644 --- a/api/src/client.rs +++ b/api/src/client.rs @@ -37,6 +37,12 @@ pub enum StatGroup { // Streak, } +impl Default for StatGroup { + fn default() -> Self { + StatGroup::Pitching + } +} + /// Display the StatGroup in all lowercase. impl fmt::Display for StatGroup { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/components/debug.rs b/src/components/debug.rs index 54b0532..beef411 100644 --- a/src/components/debug.rs +++ b/src/components/debug.rs @@ -1,5 +1,5 @@ use crate::app::{App, GamedayPanels}; -use chrono::{NaiveDate, Utc}; +use chrono::NaiveDate; use mlb_api::client::StatGroup; use std::fmt; use tui::backend::Backend; @@ -40,8 +40,8 @@ impl DebugInfo { terminal_width: 0, terminal_height: 0, gameday_active_views: GamedayPanels::default(), - date: Utc::now().date_naive(), - stat_type: StatGroup::Pitching, + date: NaiveDate::default(), + stat_type: StatGroup::default(), } } // TODO add more info From 96ff74ddfd7a6ff55be5f12648811b84e1cd1b30 Mon Sep 17 00:00:00 2001 From: Alex Bolduc Date: Mon, 26 Feb 2024 08:37:02 -0500 Subject: [PATCH 18/19] chore: cargo fmt --- api/src/client.rs | 6 +++--- api/tests/client.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/src/client.rs b/api/src/client.rs index 313536d..03878de 100644 --- a/api/src/client.rs +++ b/api/src/client.rs @@ -38,9 +38,9 @@ pub enum StatGroup { } impl Default for StatGroup { - fn default() -> Self { - StatGroup::Pitching - } + fn default() -> Self { + StatGroup::Pitching + } } /// Display the StatGroup in all lowercase. diff --git a/api/tests/client.rs b/api/tests/client.rs index ceeb85e..ccbc4f8 100644 --- a/api/tests/client.rs +++ b/api/tests/client.rs @@ -87,7 +87,7 @@ mod tests { async fn test_team_stats_on_date() { let mut server = mockito::Server::new(); - let date: NaiveDate = NaiveDate::from_ymd_opt(2022,7, 9).unwrap(); + let date: NaiveDate = NaiveDate::from_ymd_opt(2022, 7, 9).unwrap(); for group in vec![StatGroup::Hitting, StatGroup::Pitching] { let url = format!( "v1/teams/stats?sportId=1&stats=byDateRange&season=2022&endDate=2022-07-09&group={}", From 6c70aeb56d1925cb74ace157bfafc09a840a5436 Mon Sep 17 00:00:00 2001 From: Alex Bolduc Date: Mon, 26 Feb 2024 08:38:55 -0500 Subject: [PATCH 19/19] chore: fix warnings and fmt --- api/src/client.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/api/src/client.rs b/api/src/client.rs index 03878de..3000400 100644 --- a/api/src/client.rs +++ b/api/src/client.rs @@ -25,10 +25,11 @@ pub struct MLBApi { /// The available stat groups. These are taken from the "meta" endpoint: /// https://statsapi.mlb.com/api/v1/statGroups /// I only need to use Hitting and Pitching for now. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub enum StatGroup { - Hitting, + #[default] Pitching, + Hitting, // Fielding, // Catching, // Running, @@ -37,12 +38,6 @@ pub enum StatGroup { // Streak, } -impl Default for StatGroup { - fn default() -> Self { - StatGroup::Pitching - } -} - /// Display the StatGroup in all lowercase. impl fmt::Display for StatGroup { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {