Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add fleaflicker start #118

Merged
merged 8 commits into from
Nov 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.1.0.9001
Version: 1.1.0.9002
Authors@R:
person(given = "Tan",
family = "Ho",
Expand Down
7 changes: 7 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ S3method(ff_playerscores,default)
S3method(ff_playerscores,mfl_conn)
S3method(ff_playerscores,sleeper_conn)
S3method(ff_rosters,default)
S3method(ff_rosters,flea_conn)
S3method(ff_rosters,mfl_conn)
S3method(ff_rosters,sleeper_conn)
S3method(ff_schedule,default)
Expand All @@ -34,8 +35,11 @@ S3method(ff_transactions,default)
S3method(ff_transactions,mfl_conn)
S3method(ff_transactions,sleeper_conn)
S3method(ff_userleagues,default)
S3method(ff_userleagues,flea_conn)
S3method(ff_userleagues,mfl_conn)
S3method(ff_userleagues,sleeper_conn)
S3method(print,flea_conn)
S3method(print,fleaflicker_api)
S3method(print,mfl_api)
S3method(print,mfl_conn)
S3method(print,sleeper_api)
Expand All @@ -57,6 +61,9 @@ export(ff_standings)
export(ff_starters)
export(ff_transactions)
export(ff_userleagues)
export(fleaflicker_connect)
export(fleaflicker_getendpoint)
export(fleaflicker_userleagues)
export(mfl_connect)
export(mfl_getendpoint)
export(mfl_players)
Expand Down
12 changes: 11 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
# ffscrapr (development version)

Currently undecided on next platform. Amassing some tweaks and hotfixes for a patch version (probably with improved vignettes).
Fleaflicker looks like it's going to be the next platform.

Also amassing some tweaks and hotfixes for a patch version (probably with improved vignettes).

### Tweaks to be released with 1.1.1

- Patched bug in `sleeper_getendpoint()` - was appending a "/" to the end of every url by accident, breaking URL parameters
- Small copyedits to existing vignettes. (1.1.0.9000)
- Added filesystem cache capabilities and a vignette to detailing how to use it (1.1.0.9001)

### Fleaflicker Progress

- Added `fleaflicker_getendpoint()` (1.1.0.9002)
- Added `ff_connect()` (1.1.0.9002)
- Added `ff_rosters()` (1.1.0.9002)
- Added `ff_userleagues()` - interestingly, has feature for looking up by email but doesn't return actual user ID? (1.1.0.9002)


# ffscrapr 1.1.0

The main goal of ffscrapr 1.1.0 is to add a full set of methods for Sleeper. Also adds two new generics: `ff_userleagues()` and `ff_starters()`.
Expand Down
94 changes: 94 additions & 0 deletions R/flea_api.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#### FLEAFLICKER API ####

#' GET any Fleaflicker endpoint
#'
#' The endpoint names and HTTP parameters (i.e. argument names) are CASE SENSITIVE and should be passed in exactly as displayed on the Fleaflicker API reference page.
#'
#' Check out the vignette for more details and example usage.
#'
#' @param endpoint a string defining which endpoint to return from the API
#' @param ... Arguments which will be passed as "argumentname = argument" in an HTTP query parameter
#'
#' @seealso \url{https://www.fleaflicker.com/api-docs/index.html}
#' @seealso \code{vignette("fleaflicker_getendpoint")}
#'
#' @return A list object containing the query, response, and parsed content.
#' @export

fleaflicker_getendpoint <- function(endpoint, ...) {

# PREP URL

url_query <- httr::modify_url(
url = glue::glue("https://www.fleaflicker.com/api/{endpoint}"),
query = list(
...
)
)

## GET FFSCRAPR ENV

fn_get <- get("get.sleeper", envir = .ffscrapr_env, inherits = TRUE)

user_agent <- get("user_agent", envir = .ffscrapr_env, inherits = TRUE)

## DO QUERY

response <- fn_get(url_query, user_agent)

## CHECK QUERY
# nocov start

if (httr::http_error(response) && httr::status_code(response) == 429) {
stop(glue::glue("You've hit a rate limit wall! Please adjust the
built-in rate_limit arguments in fleaflicker_connect()!"), call. = FALSE)
}

if (httr::http_error(response)) {
stop(glue::glue("Fleaflicker API request failed with error: <{httr::status_code(response)}> \n
while calling <{url_query}>"), call. = FALSE)
}

if (httr::http_type(response) != "application/json") {
warning(glue::glue("Fleaflicker API did not return json while calling {url_query}"),
call. = FALSE
)
}

if (httr::http_type(response) == "application/json") {
parsed <- jsonlite::parse_json(httr::content(x = response, as = "text"))
}

if (!is.null(parsed$error)) {
warning(glue::glue("Fleaflicker says: {parsed$error[[1]]}"), call. = FALSE)
}

# nocov end

## RETURN S3

structure(
list(
content = parsed,
query = url_query,
response = response
),
class = "fleaflicker_api"
)
}

## PRINT METHOD SLEEPER_API OBJ ##
#' @noRd
#' @export
print.fleaflicker_api <- function(x, ...) {

# nocov start

cat("<Fleaflicker - GET ", x$query, ">\n", sep = "")

str(x$content)

invisible(x)

# nocov end
}
73 changes: 73 additions & 0 deletions R/flea_connect.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#' Connect to Fleaflicker League
#'
#' This function creates a connection object which stores parameters and a user ID if available.
#'
#' @param season Season to access on Fleaflicker - if missing, will guess based on system date (current year if March or later, otherwise previous year)
#' @param league_id League ID
#' @param user_email Optional - attempts to get user's user ID by email
#' @param user_agent User agent to self-identify (optional)
#' @param rate_limit TRUE by default - turn off rate limiting with FALSE
#' @param rate_limit_number number of calls per \code{rate_limit_seconds}, suggested is under 1000 calls per 60 seconds
#' @param rate_limit_seconds number of seconds as denominator for rate_limit
#' @param ... other arguments (for other methods, for R compat)
#'
#' @export
#'
#' @return a list that stores Fleaflicker connection objects

fleaflicker_connect <- function(season = NULL,
league_id = NULL,
user_email = NULL,
user_agent = NULL,
rate_limit = TRUE,
rate_limit_number = NULL,
rate_limit_seconds = NULL,
...) {
# nocov start

## USER AGENT ##
# Self-identifying is mostly about being polite.
if (length(user_agent) > 1) stop("user_agent must be a character vector of length one!")
if (!is.null(user_agent)) .fn_set_useragent(user_agent)

## RATE LIMIT ##
# For more info, see: https://api.myfantasyleague.com/2020/api_info

if (!is.logical(rate_limit)) stop("rate_limit should be logical")
if (!rate_limit || !(is.null(rate_limit_number) | is.null(rate_limit_seconds))) {
.fn_set_ratelimit(rate_limit, rate_limit_number, rate_limit_seconds)
}

# nocov end

## Season ##
# Fleaflicker organizes things by league year and tends to roll over around February.
# Sensible default seems to be calling the current year if in March or later, otherwise previous year if in Jan/Feb

if (is.null(season) || is.na(season)) {
season <- .fn_choose_season()
message(glue::glue("No season supplied - choosing {season} based on system date."))
}

structure(
list(
platform = "Fleaflicker",
season = as.character(season),
user_email = user_email,
league_id = as.character(league_id)
),
class = "flea_conn"
)
}

# nocov start
#' @noRd
#' @export
print.flea_conn <- function(x, ...) {
cat("<Fleaflicker connection ", x$season, "_", x$league_id, ">\n", sep = "")
str(x)
invisible(x)
}
# nocov end


40 changes: 40 additions & 0 deletions R/flea_rosters.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#### ff_rosters (Sleeper) ####

#' Get a dataframe of roster data
#'
#' @param conn a conn object created by \code{ff_connect()}
#' @param ... arguments passed to other methods (currently none)
#'
#' @examples
#' \donttest{
#' joe_conn <- ff_connect(platform = "fleaflicker", league_id = 312861, season = 2020)
#' ff_rosters(joe_conn)
#' }
#' @describeIn ff_rosters Fleaflicker: Returns roster data (minus age as of right now)
#' @export
ff_rosters.flea_conn <- function(conn, ...) {

df_rosters <- fleaflicker_getendpoint("FetchLeagueRosters", sport = "NFL", league_id = conn$league_id) %>%
purrr::pluck('content','rosters') %>%
tibble::tibble() %>%
tidyr::unnest_wider(1) %>%
tidyr::hoist("team","franchise_id" = "id","franchise_name" = "name") %>%
dplyr::select(-"team") %>%
tidyr::unnest_longer("players") %>%
tidyr::hoist("players","proPlayer") %>%
tidyr::hoist("proPlayer",
"player_id" = "id",
"player_name" = "nameFull",
"pos" = "position",
"team" = "proTeamAbbreviation") %>%
dplyr::select(dplyr::any_of(c(
"franchise_id",
"franchise_name",
"player_id",
"player_name",
"pos",
"team"
)))

return(df_rosters)
}
57 changes: 57 additions & 0 deletions R/flea_userleagues.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#### flea MY LEAGUES ####

#' Get User Leagues
#'
#' @param conn a connection object created by \code{ff_connect()}
#' @param user_email the username to look up - defaults to user created in conn if available
#' @param season the season to look up leagues for
#' @param ... arguments that may be passed to other methods (for method consistency)
#'
#' @describeIn ff_userleagues flea: returns a listing of leagues for a given user_email
#'
#' @seealso \code{\link{fleaflicker_userleagues}} to call this function for flea leagues without first creating a connection object.
#'
#' @export

ff_userleagues.flea_conn <- function(conn = NULL, user_email = NULL, season = NULL, ...) {

if(is.null(user_email) && is.null(conn)) {stop("Please supply either a user_email or a flea_conn object!")}

if(is.null(user_email) && !is.null(conn)) user_email <- conn$user_email

if(is.null(season) && !is.null(conn)) season <- conn$season

fleaflicker_userleagues(user_email,season)
}

#' flea - Get User Leagues
#'
#' This function returns the leagues that a specific user is in.
#' This variant can be used without first creating a connection object.
#'
#' @param user_email the username to look up
#' @param season the season to return leagues from - defaults to current year based on heuristics
#'
#' @seealso \code{\link{ff_userleagues}}
#'
#' @return a dataframe of leagues for the specified user
#' @export

fleaflicker_userleagues <- function(user_email, season = NULL){

if(is.null(season)) season <- .fn_choose_season()

df_leagues <- fleaflicker_getendpoint("FetchUserLeagues", email = user_email, season = season, sport = "NFL") %>%
purrr::pluck("content","leagues") %>%
purrr::map(`[`, c("name", "id","ownedTeam")) %>%
tibble::tibble() %>%
tidyr::unnest_wider(1) %>%
dplyr::rename(league_name = .data$name,
league_id = .data$id) %>%
tidyr::hoist('ownedTeam','franchise_id'='id','franchise_name' = 'name') %>%
dplyr::select(-'ownedTeam')

return(df_leagues)
}


15 changes: 7 additions & 8 deletions R/generics.R
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

# This series of functions are designed to be the main functions - all are prefixed with "ff_" for easy of autocomplete


#### ff_connect ####

#' Connect to a League
Expand All @@ -24,18 +23,18 @@
ff_connect <- function(platform = "mfl", league_id = NULL, ...) {
platform <- tolower(platform)

if (!platform %in% c("mfl", "sleeper")) {
stop("We only have code for MFL and Sleeper so far!")
}

switch(platform,
# 'fleaflicker' = ,
# 'flea' = fleaflicker_connect(league_id = league_id,...),
x <- switch(platform,
'fleaflicker' = ,
'flea' = fleaflicker_connect(league_id = league_id,...),
# 'espn' = espn_connect(league_id = league_id,...),
# 'yahoo' = yahoo_connect(league_id = league_id,...)
"sleeper" = sleeper_connect(league_id = league_id, ...),
"mfl" = mfl_connect(league_id = league_id, ...)
)

if(is.null(x)) stop("We can't connect to that platform yet!")

x
}

#### ff_league ####
Expand Down
1 change: 1 addition & 0 deletions R/zzz.R
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
get = ratelimitr::limit_rate(httr::GET, ratelimitr::rate(60, 60)),
get.mfl = ratelimitr::limit_rate(httr::GET, ratelimitr::rate(2, 3)),
get.sleeper = ratelimitr::limit_rate(httr::GET, ratelimitr::rate(30, 2)),
get.flea = ratelimitr::limit_rate(httr::GET, ratelimitr::rate(30, 2)),
post = ratelimitr::limit_rate(httr::POST, ratelimitr::rate(60, 60))
)

Expand Down
Loading