Skip to content

Commit

Permalink
Fix ff_starters() for multi-week playoff ESPN leagues (#422)
Browse files Browse the repository at this point in the history
* code changes

* overhead changes

* Update test-ff_starters.R
  • Loading branch information
tonyelhabr authored Dec 8, 2023
1 parent 94a72b0 commit 88d3e51
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 14 deletions.
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Type: Package
Package: ffscrapr
Title: API Client for Fantasy Football League Platforms
Version: 1.4.8.14
Version: 1.4.8.15
Authors@R:
c(person(given = "Tan",
family = "Ho",
Expand Down
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ and keep NA data where a player is not in a slot. (v1.4.8.07)
- Bugfix ff_scoringhistory to handle new-format `load_rosters()` now that it returns
row per player-team-season (v1.4.8.13) (thanks @john-b-edwards!)
- Bugfix espn `ff_franchises()` to return coalesce of name/nickname (v1.4.8.14)
- Bugfix espn `ff_starters()` to return handle multi-week formats (v1.4.8.15) (#421)
(h/t @tonyelhabr 🤠)

# ffscrapr 1.4.8

Expand Down
63 changes: 50 additions & 13 deletions R/espn_starters.R
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,19 @@ ff_starters.espn_conn <- function(conn, weeks = 1:17, ...) {

checkmate::assert_numeric(weeks)

max_week <- .espn_week_checkmax(conn)
settings_url_query <- glue::glue(
"https://fantasy.espn.com/apis/v3/games/ffl/seasons/",
"{conn$season}/segments/0/leagues/{conn$league_id}",
"?scoringPeriodId=0&view=mSettings"
)

settings <- espn_getendpoint_raw(conn, settings_url_query)

week_matchup_periods_mapping <- .espn_week_matchup_periods_mapping(settings)
max_week <- .espn_week_checkmax(settings)

run_weeks <- weeks[weeks < max_week]
named_run_weeks <- week_matchup_periods_mapping[run_weeks]

if (length(run_weeks) == 0) {
warning(
Expand All @@ -38,7 +48,16 @@ ff_starters.espn_conn <- function(conn, weeks = 1:17, ...) {
return(NULL)
}

starters <- purrr::map_dfr(run_weeks, .espn_week_starter, conn) %>%
starters <- purrr::imap_dfr(
named_run_weeks,
function(.x, .y) {
.espn_week_starter(
matchup_period = .x,
nfl_week = .y,
conn = conn
)
}
) %>%
dplyr::mutate(
lineup_slot = .espn_lineupslot_map()[as.character(.data$lineup_id)] %>% unname(),
pos = .espn_pos_map()[as.character(.data$pos)] %>% unname(),
Expand Down Expand Up @@ -67,14 +86,7 @@ ff_starters.espn_conn <- function(conn, weeks = 1:17, ...) {
return(starters)
}

.espn_week_checkmax <- function(conn) {
url_query <- glue::glue(
"https://fantasy.espn.com/apis/v3/games/ffl/seasons/",
"{conn$season}/segments/0/leagues/{conn$league_id}",
"?scoringPeriodId=0&view=mSettings"
)

settings <- espn_getendpoint_raw(conn, url_query)
.espn_week_checkmax <- function(settings) {

current_week <- settings %>%
purrr::pluck("content", "status", "latestScoringPeriod")
Expand All @@ -87,19 +99,44 @@ ff_starters.espn_conn <- function(conn, weeks = 1:17, ...) {
return(max_week)
}

.espn_week_starter <- function(week, conn) {
.espn_week_matchup_periods_mapping <- function(settings) {

matchup_periods <- settings %>%
purrr::pluck("content", "settings", "scheduleSettings", "matchupPeriods")

## first, flatten out the values.
mapping <- matchup_periods %>%
purrr::map(
function(.x) {
unlist(.x)
}
)

## then, invert the mapping such that the NFL week is the name and the matchupPeriod
## (whic is always <= NFL week) is the value.
inverted_mapping <- list()
for (name in names(mapping)) {
values <- mapping[[name]]
for (value in values) {
inverted_mapping[[as.character(value)]] <- as.integer(name)
}
}
return(inverted_mapping)
}

.espn_week_starter <- function(matchup_period, nfl_week, conn) {
url_query <- glue::glue(
"https://fantasy.espn.com/apis/v3/games/ffl/seasons/",
"{conn$season}/segments/0/leagues/{conn$league_id}",
"?scoringPeriodId={week}&view=mMatchupScore&view=mBoxscore&view=mSettings&view=mRosterSettings"
"?scoringPeriodId={nfl_week}&view=mMatchupScore&view=mBoxscore&view=mSettings&view=mRosterSettings"
)

week_scores <- espn_getendpoint_raw(conn, url_query) %>%
purrr::pluck("content", "schedule") %>%
tibble::tibble() %>%
purrr::set_names("x") %>%
tidyr::hoist(1, "week" = "matchupPeriodId", "home", "away") %>%
dplyr::filter(.data$week == .env$week) %>%
dplyr::filter(.data$week == .env$matchup_period) %>%
tidyr::pivot_longer(c("home", "away"), names_to = NULL, values_to = "team") %>%
tidyr::hoist(
"team",
Expand Down
8 changes: 8 additions & 0 deletions tests/testthat/test-ff_starters.R
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,11 @@ test_that("ff_starters.espn finds the correct projected scores #397",{
n_projection_equal_actual <- sum(s$player_score == s$projected_score & s$player_score!=0)
expect_equal(n_projection_equal_actual, 0)
})

test_that("ff_starters.espn understands multi-week playoff formats #421",{
local_mock_api()
tony_conn <- espn_connect(season = 2022, league_id = 899513)
tony_starters <- ff_starters(tony_conn, weeks = 15:18)
expect_tibble(tony_starters, min.rows = 100)
})

0 comments on commit 88d3e51

Please sign in to comment.