Skip to content

Commit

Permalink
Merge pull request #8 from mlb-rs/gameday
Browse files Browse the repository at this point in the history
Gameday is dialed up
  • Loading branch information
andschneider authored May 31, 2021
2 parents b416154 + 220588e commit 1716eaa
Show file tree
Hide file tree
Showing 38 changed files with 1,516 additions and 912 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Changelog

## [0.0.5] - 2021-05-30

- Pitches are displayed in the correct location in the strike zone!
- Dialed up the Gameday view, which added:
- play information for the inning
- team box score
- on deck and in the hole batters
- Changed the layout to a toggle-able three pane style.

## [0.0.4] - 2021-05-20

- Added pitch display (currently in the wrong locations relative to heatmap).
Expand Down
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
[package]
name = "mlbt"
version = "0.0.4"
version = "0.0.5"
authors = ["Andrew Schneider <[email protected]>"]
edition = "2018"

[workspace]
members = [".", "api"]

[dependencies]
mlb-api = {path = "api/", version = "0.0.3"}
mlb-api = {path = "api/", version = "0.0.4"}
chrono = "0.4"
tui = "0.14"
termion = "1.5"
Expand Down
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ A terminal user interface for the MLB stats API, written in Rust.
- [X] scoreboard and box score
- [ ] selectable date

- [ ] gameday
- [X] gameday

- [ ] standings

- [ ] player stats
- [ ] team stats
- [ ] stat search (store in sqlite or an embedded db?)
- [ ] stats
- [ ] player stats
- [ ] team stats
- [ ] stat search (store in sqlite or an embedded db?)

- [ ] CLI
- [ ] configuration: favorite team, colors, keymap
Expand Down
4 changes: 1 addition & 3 deletions api/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
[package]
name = "mlb-api"
version = "0.0.3"
version = "0.0.4"
authors = ["Andrew Schneider <[email protected]>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
chrono = "0.4"
derive_builder = "0.10"
Expand Down
111 changes: 111 additions & 0 deletions api/src/boxscore.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
use crate::live::Person;

use serde::{Deserialize, Serialize};
use std::collections::HashMap;

#[derive(Default, Debug, Serialize, Deserialize)]
pub struct Boxscore {
pub teams: Option<Teams>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Teams {
pub away: Team,
pub home: Team,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Team {
pub team: IdName,
#[serde(rename = "teamStats")]
pub team_stats: TeamStats,
pub players: HashMap<String, Player>,
pub batters: Vec<u64>,
pub pitchers: Vec<u64>,
bench: Vec<u64>,
bullpen: Vec<u64>,
#[serde(rename = "battingOrder")]
pub batting_order: Vec<u64>,
#[serde(rename = "seasonStats")]
pub season_stats: Option<TeamStats>,
}

#[derive(Default, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct IdName {
pub id: u16,
pub name: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Player {
pub person: Person,
pub position: Position,
pub stats: TeamStats,
#[serde(rename = "seasonStats")]
pub season_stats: TeamStats,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Position {
pub name: String,
pub abbreviation: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct TeamStats {
pub batting: Batting,
// pitching: TeamStatsPitching,
// fielding: Fielding,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Batting {
games_played: Option<u8>,
pub runs: Option<u8>,
doubles: Option<u8>,
triples: Option<u8>,
home_runs: Option<u8>,
pub strike_outs: Option<u8>,
pub base_on_balls: Option<u8>,
pub hits: Option<u8>,
hit_by_pitch: Option<u8>,
pub avg: Option<String>,
pub at_bats: Option<u8>,
obp: Option<String>,
slg: Option<String>,
ops: Option<String>,
ground_into_double_play: Option<u8>,
ground_into_triple_play: Option<u8>,
pub plate_appearances: Option<u8>,
total_bases: Option<u8>,
pub rbi: Option<u8>,
pub left_on_base: Option<u8>,
}

// #[derive(Debug, Serialize, Deserialize)]
// #[serde(rename_all = "camelCase")]
// pub struct TeamStatsPitching {
// runs: u8,
// doubles: u8,
// triples: u8,
// home_runs: u8,
// strike_outs: u8,
// base_on_balls: u8,
// intentional_walks: u8,
// hits: u8,
// hit_by_pitch: u8,
// at_bats: u8,
// obp: String,
// era: String,
// innings_pitched: String,
// save_opportunities: u8,
// earned_runs: u8,
// whip: String,
// batters_faced: u8,
// outs: u8,
// shutouts: u8,
// hit_batsmen: u8,
// rbi: u8,
// }
66 changes: 66 additions & 0 deletions api/src/client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use crate::live::LiveResponse;
use crate::schedule::ScheduleResponse;
use crate::{live, schedule};

use chrono::NaiveDate;
use derive_builder::Builder;
use reqwest::blocking::Client;
use serde::de::DeserializeOwned;

pub const BASE_URL: &str = "http://statsapi.mlb.com/api/";

/// MLB API object
#[derive(Builder, Debug, Clone)]
#[allow(clippy::upper_case_acronyms)]
pub struct MLBApi {
#[builder(default = "Client::new()")]
client: Client,
#[builder(setter(into), default = "String::from(BASE_URL)")]
base_url: String,
}

impl MLBApi {
pub fn get_todays_schedule(&self) -> ScheduleResponse {
let url = format!("{}v1/schedule?sportId=1", self.base_url);
self.get::<schedule::ScheduleResponse>(url)
}

pub fn get_schedule_date(&self, date: NaiveDate) -> ScheduleResponse {
let url = format!(
"{}v1/schedule?sportId=1&date={}",
self.base_url,
date.format("%Y-%m-%d").to_string()
);
self.get::<schedule::ScheduleResponse>(url)
}

pub fn get_live_data(&self, game_id: u64) -> LiveResponse {
if game_id == 0 {
return LiveResponse::default();
}
let url = format!(
"{}v1.1/game/{}/feed/live?language=en",
self.base_url, game_id
);
self.get::<live::LiveResponse>(url)
}

// TODO need better error handling, especially on parsing
fn get<T: Default + DeserializeOwned>(&self, url: String) -> T {
let response = self.client.get(url).send();
let response = match response {
Ok(r) => r,
Err(e) => {
panic!("network error {:?}", e);
}
};
let json = response.json::<T>().map(From::from);
match json {
Ok(j) => j,
Err(e) => {
eprintln!("parsing error {:?}", e);
T::default()
}
}
}
}
69 changes: 3 additions & 66 deletions api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,68 +1,5 @@
pub mod boxscore;
pub mod client;
pub mod live;
pub mod plays;
pub mod schedule;

use crate::live::LiveResponse;
use crate::schedule::ScheduleResponse;

use chrono::NaiveDate;
use derive_builder::Builder;
use reqwest::blocking::Client;
use serde::de::DeserializeOwned;

pub const BASE_URL: &str = "http://statsapi.mlb.com/api/";

/// MLB API object
#[derive(Builder, Debug, Clone)]
#[allow(clippy::upper_case_acronyms)]
pub struct MLBApi {
#[builder(default = "Client::new()")]
client: Client,
#[builder(setter(into), default = "String::from(BASE_URL)")]
base_url: String,
}

impl MLBApi {
pub fn get_todays_schedule(&self) -> ScheduleResponse {
let url = format!("{}v1/schedule?sportId=1", self.base_url);
self.get::<schedule::ScheduleResponse>(url)
}

pub fn get_schedule_date(&self, date: NaiveDate) -> ScheduleResponse {
let url = format!(
"{}v1/schedule?sportId=1&date={}",
self.base_url,
date.format("%Y-%m-%d").to_string()
);
self.get::<schedule::ScheduleResponse>(url)
}

pub fn get_live_data(&self, game_id: u64) -> LiveResponse {
if game_id == 0 {
return LiveResponse::default();
}
let url = format!(
"{}v1.1/game/{}/feed/live?language=en",
self.base_url, game_id
);
self.get::<live::LiveResponse>(url)
}

// TODO need better error handling, especially on parsing
fn get<T: Default + DeserializeOwned>(&self, url: String) -> T {
let response = self.client.get(url).send();
let response = match response {
Ok(r) => r,
Err(e) => {
panic!("network error {:?}", e);
}
};
let json = response.json::<T>().map(From::from);
match json {
Ok(j) => j,
Err(e) => {
eprintln!("parsing error {:?}", e);
T::default()
}
}
}
}
Loading

0 comments on commit 1716eaa

Please sign in to comment.