Skip to content

Commit

Permalink
Merge pull request #296 from dynastyprocess/dev
Browse files Browse the repository at this point in the history
release 1.4.3
  • Loading branch information
tanho63 authored Jun 12, 2021
2 parents 8bc235e + c128a79 commit 4e7bda8
Show file tree
Hide file tree
Showing 208 changed files with 531 additions and 21,862 deletions.
1 change: 0 additions & 1 deletion .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,4 @@
^README\.Rmd$
^cran-comments\.md$
^CRAN-RELEASE$

^data-raw$
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,5 @@ vignettes/*.pdf
# R Environment Variables
.Renviron
inst/doc

docs/
4 changes: 2 additions & 2 deletions 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.2
Version: 1.4.3
Authors@R:
c(person(given = "Tan",
family = "Ho",
Expand All @@ -26,7 +26,7 @@ URL: https://ffscrapr.dynastyprocess.com,
https://docs.sleeper.app,
https://www.fleaflicker.com/api-docs/index.html,
https://www.espn.com/fantasy/,
https://www.nflfastr.com/reference/load_player_stats.html
https://nflfastr.com/reference/load_player_stats.html
BugReports: https://github.com/dynastyprocess/ffscrapr/issues
Depends:
R (>= 3.0.0)
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
YEAR: 2020
YEAR: 2021
COPYRIGHT HOLDER: Tan Ho
2 changes: 1 addition & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# MIT License

Copyright (c) 2020 Tan Ho
Copyright (c) 2021 Tan Ho

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
19 changes: 18 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
# ffscrapr 1.4.3

The main goal of v1.4.3 is to patch some minor bugs.

## Minor changes

- `ff_league()` now has a column that returns the platform's season - this is most useful when running ff_league in batch. Thank you to @joeflan for the contribution! (Fixes #287)
- Added helper script in dev/ for switching between test cache versions.
- Added helper script in dev/ for rebuilding test cache.
- `ff_schedule()` for Sleeper now should extend into playoff weeks. (Fixes #289)
- `ff_draft()` for Sleeper now has an auction_amount column if it is an auction draft. (Fixes #291)
- `dp_cleannames()` now can flip names originally presented in LastName, FirstName order into First Last, and also has a custom name database to convert common alternate names to a unified one.
- `nflfastr_stat_mapping` and `dp_name_mapping` are namespaced within the package, so that they can be used internally and externally a little more robustly.
- Rebuilt test cache in ffscrapr-tests.

---

# ffscrapr 1.4.2

The main goal of v1.4.2 is to patch some minor bugs.
Expand Down Expand Up @@ -157,7 +174,7 @@ Here is a list of new functions available at the top level (ie for all platforms
Almost all functions now have Sleeper methods - implemented in what hopes to be relatively familiar manner to MFL. Outlining the specifics of what ***isn't*** the same:

- `sleeper_userleagues()` is a wrapper on `ff_userleagues()` that makes it easier to look up user leagues without first creating a connection object.
- `ff_playerscores()` is not available for Sleeper because Sleeper removed the player stats endpoint - it will generate a warning (rather than an error). Thinking about creating some functions to calculate scoring based on [nflfastr](https://www.nflfastr.com).
- `ff_playerscores()` is not available for Sleeper because Sleeper removed the player stats endpoint - it will generate a warning (rather than an error). Thinking about creating some functions to calculate scoring based on [nflfastr](https://nflfastr.com/).
- `sleeper_getendpoint()` is a little more simple than MFL's equivalent - just pass a string url (minus api.sleeper.app/v1) or pass in chunks of code, the function will automatically paste them together with "/".
- Added generic and method for `ff_userleagues()` - Sleeper league IDs are more annoying than MFL to handle, so the more intuitive way is to look up the user's league_ids by username first. MFL does have a parallel feature even if used for different purposes.
- Added two vignettes, showing "Getting Started" as well as one for custom API calls
Expand Down
2 changes: 1 addition & 1 deletion R/0_utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ NULL

#' Pipe operator
#'
#' See `magrittr::[\%>\%][magrittr::pipe]` for details.
#' See [`magrittr::%>%`](https://magrittr.tidyverse.org/reference/pipe.html) for details.
#'
#' @name %>%
#' @rdname pipe
Expand Down
48 changes: 42 additions & 6 deletions R/1_import_dp.R
Original file line number Diff line number Diff line change
Expand Up @@ -71,30 +71,66 @@ dp_playerids <- function() {

#' Clean Names
#'
#' Applies some name-cleaning heuristics to facilitate joins.
#' May eventually refer to a name-cleaning database, for now will just include basic regex.
#' Applies some name-cleaning heuristics to facilitate joins. These heuristics may include:
#' - removing periods and apostrophes
#' - removing common suffixes, such as Jr, Sr, II, III, IV
#' - converting to lowercase
#' - using `dp_name_mapping` to do common name substitutions, such as Mitch Trubisky to Mitchell Trubisky
#'
#' @param player_name a character (or character vector)
#' @param lowercase defaults to FALSE - if TRUE, converts to lowercase
#' @param convert_lastfirst converts names from "Last, First" to "First Last" (i.e. MFL style)
#' @param use_name_database uses internal name database to do common substitutions (Mitchell Trubisky to Mitch Trubisky etc)
#'
#' @examples
#' \donttest{
#' dp_cleannames(c("A.J. Green", "Odell Beckham Jr.", "Le'Veon Bell Sr."))
#'
#' dp_cleannames(c("Trubisky, Mitch", "Atwell, Chatarius", "Elliott, Zeke", "Elijah Moore"),
#' convert_lastfirst = TRUE,
#' use_name_database = TRUE)
#' }
#'
#' @seealso `dp_name_mapping`
#'
#' @return a character vector of cleaned names
#'
#' @export

dp_cleannames <- function(player_name, lowercase = FALSE) {
checkmate::assert_logical(lowercase)
dp_cleannames <- function(player_name, lowercase = FALSE, convert_lastfirst = TRUE, use_name_database = TRUE) {
checkmate::assert_character(player_name)
checkmate::assert_flag(lowercase)
checkmate::assert_flag(convert_lastfirst)
checkmate::assert_flag(use_name_database)

n <- stringr::str_remove_all(player_name, "( Jr\\.$)|( Sr\\.$)|( III$)|( II$)|( IV$)|( V$)|(\\')|(\\.)")
n <- player_name

if (lowercase) n <- tolower(n)
if(convert_lastfirst) n <- stringr::str_replace_all(n, "^(.+), (.+)$", "\\2 \\1")

n <- stringr::str_remove_all(n, "( Jr\\.$)|( Sr\\.$)|( III$)|( II$)|( IV$)|( V$)|(\\')|(\\.)")

n <- stringr::str_squish(n)

if(use_name_database) n <- unname(dplyr::coalesce(ffscrapr::dp_name_mapping[n],n))

if(lowercase) n <- tolower(n)

return(n)
}

#' Alternate name mappings
#'
#' A named character vector mapping common alternate names
#'
#' @examples
#' \donttest{
#' dp_name_mapping[c("Chatarius Atwell", "Robert Kelley")]
#' }
#'
#' @format A named character vector
#' \describe{
#' \item{name attribute}{The "alternate" name.}
#' \item{value attribute}{The "correct" name.}
#' }
#'
"dp_name_mapping"
1 change: 1 addition & 0 deletions R/espn_league.R
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ ff_league.espn_conn <- function(conn) {
tibble::tibble(
league_id = conn$league_id,
league_name = league_endpoint$content$settings$name,
season = as.integer(conn$season),
league_type = .espn_is_keeper(league_endpoint),
franchise_count = franchise_count,
qb_type = .espn_is_qbtype(league_endpoint)$type,
Expand Down
2 changes: 1 addition & 1 deletion R/espn_scoringhistory.R
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ ff_scoringhistory.espn_conn <- function(conn, season = 1999:2020, ...) {
league_rules <-
ff_scoring(conn) %>%
dplyr::left_join(
nflfastr_stat_mapping %>% dplyr::filter(.data$platform == "espn"),
ffscrapr::nflfastr_stat_mapping %>% dplyr::filter(.data$platform == "espn"),
by = c("stat_name" = "ff_event"))

# Use custom ffscrapr function to get positions fron nflfastR rosters
Expand Down
1 change: 1 addition & 0 deletions R/flea_league.R
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ ff_league.flea_conn <- function(conn) {
tibble::tibble(
league_id = as.character(conn$league_id),
league_name = league_endpoint$league$name,
season = as.integer(conn$season),
league_type = .flea_isdyno(league_endpoint),
franchise_count = as.numeric(league_endpoint$league[["capacity"]]),
qb_type = .flea_qbtype(league_endpoint)$type,
Expand Down
2 changes: 1 addition & 1 deletion R/flea_scoringhistory.R
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ ff_scoringhistory.flea_conn <- function(conn, season = 1999:2020, ...) {
league_rules <-
ff_scoring(conn) %>%
dplyr::left_join(
nflfastr_stat_mapping %>%
ffscrapr::nflfastr_stat_mapping %>%
dplyr::filter(.data$platform == "fleaflicker") %>%
dplyr::mutate(ff_event = as.integer(.data$ff_event)),
by = c("event_id" = "ff_event"))
Expand Down
1 change: 1 addition & 0 deletions R/mfl_league.R
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ ff_league.mfl_conn <- function(conn) {
tibble::tibble(
league_id = conn$league_id,
league_name = league_endpoint$name,
season = as.integer(conn$season),
franchise_count = as.numeric(league_endpoint$franchises$count),
qb_type = .mfl_is_qbtype(league_endpoint)$type,
idp = .mfl_is_idp(league_endpoint),
Expand Down
2 changes: 1 addition & 1 deletion R/mfl_scoringhistory.R
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ ff_scoringhistory.mfl_conn <- function(conn, season = 1999:2020, ...) {
.fns = as.numeric
)) %>%
dplyr::left_join(
nflfastr_stat_mapping %>% dplyr::filter(.data$platform == "mfl"),
ffscrapr::nflfastr_stat_mapping %>% dplyr::filter(.data$platform == "mfl"),
by = c("event" = "ff_event")) %>%
dplyr::select(
"pos","points","lower_range","upper_range","event", "nflfastr_event", "short_desc"
Expand Down
1 change: 1 addition & 0 deletions R/sleeper_draft.R
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ ff_draft.sleeper_conn <- function(conn, ...) {
"season",
"round",
"pick",
"auction_amount",
"franchise_id",
"franchise_name",
"player_id",
Expand Down
13 changes: 11 additions & 2 deletions R/sleeper_draftpicks.R
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,17 @@ ff_draftpicks.sleeper_conn <- function(conn, ...) {
picks <- glue::glue("draft/{draft_id}/picks") %>%
sleeper_getendpoint() %>%
purrr::pluck("content") %>%
purrr::map_dfr(`[`, c("round", "draft_slot", "roster_id", "player_id")) %>%
dplyr::select(dplyr::any_of(c("round", "pick" = "draft_slot", "franchise_id" = "roster_id", "player_id")))
purrr::map(`[`, c("round", "draft_slot", "roster_id", "player_id", "metadata")) %>%
tibble::tibble() %>%
tidyr::unnest_wider(1) %>%
tidyr::hoist("metadata","auction_amount"="amount") %>%
dplyr::select(dplyr::any_of(c("round", "pick" = "draft_slot", "franchise_id" = "roster_id", "player_id","auction_amount")))

if(all(is.na(picks$auction_amount))) {
picks$auction_amount <- NULL
} else {
picks$auction_amount <- as.numeric(picks$auction_amount)
}

return(picks)
}
Expand Down
1 change: 1 addition & 0 deletions R/sleeper_league.R
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ ff_league.sleeper_conn <- function(conn) {
tibble::tibble(
league_id = as.character(conn$league_id),
league_name = league_endpoint$name,
season = as.integer(conn$season),
league_type = .sleeper_isdyno(league_endpoint),
franchise_count = as.numeric(league_endpoint$total_rosters),
qb_type = .sleeper_qbtype(starting_positions)$type,
Expand Down
22 changes: 13 additions & 9 deletions R/sleeper_schedule.R
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,20 @@ ff_schedule.sleeper_conn <- function(conn, ...) {
last_scored_week <- sleeper_getendpoint(league_path) %>%
purrr::pluck("content", "settings", "last_scored_leg")

weeks <- seq_len(regular_season_end)
max_week <- max(c(regular_season_end, last_scored_week), na.rm = TRUE)

weeks <- seq_len(max_week)

matchups <- purrr::map_dfr(weeks, .sleeper_matchup, conn, last_scored_week)

return(matchups)
}

#' Individual sleeper matchup
#'
#'
#' @keywords internal
#'
.sleeper_matchup <- function(week, conn, last_scored_week) {
endpoint <- glue::glue("league/{conn$league_id}/matchups/{week}")

Expand All @@ -49,14 +55,12 @@ ff_schedule.sleeper_conn <- function(conn, ...) {

df_matchups <- df_matchup %>%
dplyr::left_join(
dplyr::select(
df_matchup,
dplyr::any_of(c(
"opponent_id" = "franchise_id",
"opponent_score" = "franchise_score",
"matchup_id"
))
),
dplyr::select(df_matchup,
dplyr::any_of(c(
"opponent_id" = "franchise_id",
"opponent_score" = "franchise_score",
"matchup_id"))) %>%
dplyr::filter(!is.na(.data$matchup_id)),
by = "matchup_id"
) %>%
dplyr::filter(.data$franchise_id != .data$opponent_id) %>%
Expand Down
2 changes: 1 addition & 1 deletion R/sleeper_scoringhistory.R
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ ff_scoringhistory.sleeper_conn <- function(conn, season = 1999:2020, ...) {
league_rules <-
ff_scoring(conn) %>%
dplyr::left_join(
nflfastr_stat_mapping %>% dplyr::filter(.data$platform == "sleeper"),
ffscrapr::nflfastr_stat_mapping %>% dplyr::filter(.data$platform == "sleeper"),
by = c("event" = "ff_event"))

# Use custom ffscrapr function to get positions fron nflfastR rosters
Expand Down
29 changes: 21 additions & 8 deletions README.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -23,37 +23,43 @@ eval <- TRUE
tryCatch(expr = {
download.file("https://github.com/dynastyprocess/ffscrapr-tests/archive/1.4.2.zip","f.zip")
download.file("https://github.com/dynastyprocess/ffscrapr-tests/archive/main.zip","f.zip")
unzip('f.zip', exdir = ".")
httptest::.mockPaths(new = "ffscrapr-tests-1.4.2")},
httptest::.mockPaths(new = "ffscrapr-tests-main")},
warning = function(e) eval <<- FALSE,
error = function(e) eval <<- FALSE)
httptest::use_mock_api()
```

# ffscrapr <a href='#'><img src="man/figures/logo.png" align="right" width="25%" min-width="120px"/></a>
# ffscrapr <a href='#'><img src="man/figures/logo.svg" align="right" width="25%" min-width="120px"/></a>

*An R Client for Fantasy Football League APIs*

<!-- badges: start -->

[![CRAN status](https://img.shields.io/cran/v/ffscrapr?style=flat-square&logo=R&label=CRAN)](https://CRAN.R-project.org/package=ffscrapr) [![Dev status](https://img.shields.io/github/r-package/v/dynastyprocess/ffscrapr/dev?label=dev&style=flat-square&logo=github)](https://ffscrapr.dynastyprocess.com/dev/) [![Lifecycle: stable](https://img.shields.io/badge/lifecycle-stable-green.svg?style=flat-square)](https://lifecycle.r-lib.org/articles/stages.html) [![Codecov test coverage](https://img.shields.io/codecov/c/github/dynastyprocess/ffscrapr?label=codecov&style=flat-square&logo=codecov)](https://codecov.io/gh/DynastyProcess/ffscrapr?branch=main) [![R build status](https://img.shields.io/github/workflow/status/dynastyprocess/ffscrapr/R-CMD-check?label=R%20check&style=flat-square&logo=github)](https://github.com/DynastyProcess/ffscrapr/actions) [![API status](https://img.shields.io/github/workflow/status/dynastyprocess/ffscrapr/Test%20APIs?label=API%20check&style=flat-square&logo=github)](https://github.com/DynastyProcess/ffscrapr/actions) [![nflverse discord](https://img.shields.io/discord/591914197219016707.svg?color=5865F2&label=nflverse%20discord&logo=discord&logoColor=5865F2&style=flat-square)](https://discord.com/invite/5Er2FBnnQa)
[![CRAN status](https://img.shields.io/cran/v/ffscrapr?style=flat-square&logo=R&label=CRAN)](https://CRAN.R-project.org/package=ffscrapr)
[![Dev status](https://img.shields.io/github/r-package/v/dynastyprocess/ffscrapr/dev?label=dev&style=flat-square&logo=github)](https://ffscrapr.dynastyprocess.com/dev/)
[![Lifecycle: stable](https://img.shields.io/badge/lifecycle-stable-green.svg?style=flat-square)](https://lifecycle.r-lib.org/articles/stages.html)
[![Codecov test coverage](https://img.shields.io/codecov/c/github/dynastyprocess/ffscrapr?label=codecov&style=flat-square&logo=codecov)](https://codecov.io/gh/DynastyProcess/ffscrapr?branch=main)
[![R build status](https://img.shields.io/github/workflow/status/dynastyprocess/ffscrapr/R-CMD-check?label=R%20check&style=flat-square&logo=github)](https://github.com/DynastyProcess/ffscrapr/actions)
[![API status](https://img.shields.io/github/workflow/status/dynastyprocess/ffscrapr/Test%20APIs?label=API%20check&style=flat-square&logo=github)](https://github.com/DynastyProcess/ffscrapr/actions)
[![nflverse discord](https://img.shields.io/discord/591914197219016707.svg?color=5865F2&label=nflverse%20discord&logo=discord&logoColor=5865F2&style=flat-square)](https://discord.com/invite/5Er2FBnnQa)

<!-- badges: end -->

Helps access various Fantasy Football APIs (currently MFL, Sleeper, Fleaflicker, and ESPN - eventually Yahoo, potentially others) by handling authentication/rate-limiting/caching, forming appropriate calls, and returning tidy dataframes which can be easily connected to other data sources.

### Installation

Version 1.4.2 is now on CRAN :tada: and can be installed with:
Version 1.4.3 is now on CRAN :tada: and can be installed with:

```{r eval = FALSE}
install.packages("ffscrapr")
# or from GitHub release with the remotes package via:
# install.packages("remotes")
remotes::install_github("dynastyprocess/ffscrapr", ref = "v1.4.2")
remotes::install_github("dynastyprocess/ffscrapr", ref = "v1.4.3")
```

Install the development version from GitHub with:
Expand All @@ -68,7 +74,7 @@ The dev version has a [separate documentation site here](https://ffscrapr.dynast

All `ffscrapr` functions start with a connection object created by `ff_connect()`, which stores connection, authentication, and other user-defined parameters. This object is used by all other functions to help return the correct data.

```{r eval = eval}
```{r eval = eval, message = FALSE}
library(ffscrapr)
ssb <- ff_connect(platform = "mfl", league_id = "54040", season = 2020)
Expand All @@ -91,6 +97,13 @@ Platform-specific guides on getting started with ffscrapr are here:

There are also some more advanced guides for custom API calls in the [Articles section](https://ffscrapr.dynastyprocess.com/articles/), as well as some guides on [optimizing ffscrapr's performance](https://ffscrapr.dynastyprocess.com/articles/ffscrapr_caching.html).

### Support

The best places to get help on this package are:

- the [nflverse discord](https://discord.com/invite/5Er2FBnnQa) (for both this package as well as anything R/NFL related)
- opening [an issue](https://github.com/DynastyProcess/ffscrapr/issues/new/choose)

### Contributing

Many hands make light work! Here are some ways you can contribute to this project:
Expand All @@ -109,5 +122,5 @@ The APIs and data accessed by this package belong to their respective owners, an

```{r include = FALSE}
httptest::stop_mocking()
unlink(c("ffscrapr-tests-1.4.2","f.zip"), recursive = TRUE, force = TRUE)
unlink(c("ffscrapr-tests-main","f.zip"), recursive = TRUE, force = TRUE)
```
Loading

0 comments on commit 4e7bda8

Please sign in to comment.