Created
February 1, 2025 01:17
-
-
Save k5cents/0d24bc8a1732db18c0b6de9921f2971f to your computer and use it in GitHub Desktop.
Fantasy Football Scoreboard
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
library(httr2) | |
library(tibble) | |
library(jsonlite) | |
# config ------------------------------------------------------------------ | |
league_id <- 252353 | |
season_id <- 2024 | |
team_id <- 6 | |
# request ----------------------------------------------------------------- | |
req <- request("https://lm-api-reads.fantasy.espn.com") | |
req <- req %>% | |
req_url_path_append("apis/v3/games/ffl") %>% | |
req_url_path_append("seasons", season_id) %>% | |
req_url_path_append("segments", 0) %>% | |
req_url_path_append("leagues", league_id) %>% | |
req_url_query(view = "mScoreboard", view = "mRoster") %>% | |
req_user_agent("https://github.com/k5cents/fflr/") %>% | |
req_headers("Accept" = "application/json") %>% | |
req_retry(max_tries = 3) | |
resp <- req_perform(req) | |
dat <- resp_body_json(resp, simplifyVector = TRUE) | |
# format ------------------------------------------------------------------ | |
period_id <- dat$scoringPeriodId | |
# build data frame from home and away sub-tables | |
s <- tibble( | |
currentMatchupPeriod = dat$status$currentMatchupPeriod, | |
matchupId = c( | |
dat$schedule$id, | |
dat$schedule$id | |
), | |
teamId = c( | |
dat$schedule$home$teamId, | |
dat$schedule$away$teamId | |
), | |
totalPointsLive = c( | |
dat$schedule$home$totalPointsLive, | |
dat$schedule$away$totalPointsLive | |
), | |
totalProjectedPointsLive = c( | |
dat$schedule$home$totalProjectedPointsLive, | |
dat$schedule$away$totalProjectedPointsLive | |
) | |
) | |
# filter and order the data frame | |
s <- s[!is.na(s$totalProjectedPointsLive), ] | |
# add a TRUE/FALSE if projected score is above median | |
s$bonusWin <- s$totalProjectedPointsLive > median(s$totalProjectedPointsLive) | |
# add a ranking of projected score | |
score_ranked <- sort(s$totalProjectedPointsLive, decreasing = TRUE) | |
s$scoreRank <- match(s$totalProjectedPointsLive, score_ranked) | |
# add team abbreviation by team ID | |
s$abbrev <- dat$teams$abbrev[match(s$teamId, dat$teams$id)] | |
# find match for the selected team | |
s <- s[s$matchupId == s$matchupId[s$teamId == team_id], ] | |
# reorder and remove columns | |
s <- s[, c("teamId", "abbrev", "totalPointsLive", "totalProjectedPointsLive", "scoreRank")] | |
# add player status ------------------------------------------------------- | |
# find the players starting on each team | |
rosters <- dat$teams$roster$entries[dat$teams$id %in% s$teamId] | |
out <- rep(list(NA), length(rosters)) | |
for (i in seq_along(rosters)) { | |
out[[i]] <- data.frame( | |
teamId = rosters[[i]]$playerPoolEntry$onTeamId, | |
fullName = rosters[[i]]$playerPoolEntry$player$fullName, | |
proTeamId = rosters[[i]]$playerPoolEntry$player$proTeamId, | |
slotId = rosters[[i]]$lineupSlotId, | |
locked = rosters[[i]]$playerPoolEntry$lineupLocked | |
) | |
} | |
# combine the players into a single list | |
out <- do.call("rbind", out) | |
# limit data frame to players not on bench (20) | |
out <- out[out$slotId != 20 & out$slotId != 21, ] | |
# count the players yet to start on each team | |
n_locked <- by(out$locked, out$teamId, sum) | |
n_unlocked <- by(!out$locked, out$teamId, sum) | |
locked <- data.frame( | |
teamId = names(n_locked), | |
locked = as.vector(n_locked), | |
unlocked = as.vector(n_unlocked) | |
) | |
s <- merge(s, locked) | |
s$timestamp <- Sys.time() | |
# write to json ----------------------------------------------------------- | |
# [ | |
# { | |
# "teamId": 4, | |
# "abbrev": "BILL", | |
# "totalPointsLive": 130.94, | |
# "totalProjectedPointsLive": 130.94, | |
# "scoreRank": 10, | |
# "locked": 0, | |
# "unlocked": 9, | |
# "timestamp": "2025-01-31 20:15:38" | |
# }, | |
# { | |
# "teamId": 6, | |
# "abbrev": "KIER", | |
# "totalPointsLive": 190.72, | |
# "totalProjectedPointsLive": 190.72, | |
# "scoreRank": 6, | |
# "locked": 0, | |
# "unlocked": 9, | |
# "timestamp": "2025-01-31 20:15:38" | |
# } | |
# ] | |
write_json( | |
x = s, | |
path = "scoreboard.json", | |
pretty = TRUE | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# read from local server on Raspberry Pi |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[ | |
{ | |
"teamId": 4, | |
"abbrev": "BILL", | |
"totalPointsLive": 130.94, | |
"totalProjectedPointsLive": 130.94, | |
"scoreRank": 10, | |
"locked": 0, | |
"unlocked": 9, | |
"timestamp": "2025-01-31 20:15:38" | |
}, | |
{ | |
"teamId": 6, | |
"abbrev": "KIER", | |
"totalPointsLive": 190.72, | |
"totalProjectedPointsLive": 190.72, | |
"scoreRank": 6, | |
"locked": 0, | |
"unlocked": 9, | |
"timestamp": "2025-01-31 20:15:38" | |
} | |
] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment