mkreiser / ESPN-Fantasy-Football-API

Connect to ESPN's fantasy football API via this JS API client for web and NodeJS. Available as an npm package.
http://espn-fantasy-football-api.s3-website.us-east-2.amazonaws.com/
GNU Lesser General Public License v3.0
311 stars 79 forks source link

Converting from ESPN v2 API to v3 #95

Closed mkreiser closed 5 years ago

mkreiser commented 5 years ago

ESPN have updated their fantasy football API from v2 to v3. This project is built for v2 and requires significant work for update to v3. This issue tracks the necessary tasks to complete this conversion. The conversion work will occur on the v3-api-conversion branch (protected).

mkreiser commented 5 years ago

πŸŽ‰ Update README with conversion work notice

96

mkreiser commented 5 years ago

πŸŽ‰ Investigate new route structure

So ESPN's v3 api is... interesting. ESPN has maintained a minimal route structure, returning most of the data through a single route. Params are passed that affects how the response is populated.

http://fantasy.espn.com/apis/v3/games/ffl/seasons/2018/segments/0/leagues/336358?view=mDraftDetail&view=mLiveScoring&view=mMatchupScore&view=mPendingTransactions&view=mPositionalRatings&view=mSettings&view=mTeam&view=modular&view=mNav

So

http://fantasy.espn.com/apis/v3/games/ffl/seasons/<SEASON_ID>/segments/0/leagues/<LEAGUE_ID>?<PARAMS>

This does not align with the structure of this project well, again :(

Other routes include:

ALL PLAYERS http://fantasy.espn.com/apis/v3/games/ffl/seasons/2018/players?scoringPeriodId=0&view=players_wl
ALL FREE AGENTS http://fantasy.espn.com/apis/v3/games/ffl/seasons/2019/segments/0/leagues/336358?scoringPeriodId=0&view=kona_player_info
Pro League organization info https://site.web.api.espn.com/apis/site/v2/teams?region=us&lang=en&leagues=nfl%2Cnba%2Cmlb%2Cnhl
Pro team schedule http://fantasy.espn.com/apis/v3/games/ffl/seasons/2019/?view=proTeamSchedules
Roster at a given week http://fantasy.espn.com/apis/v3/games/ffl/seasons/2018/segments/0/leagues/336358?forTeamId=9&scoringPeriodId=13&view=mRoster

Now, there is an easy way to get player information, which should enable some interesting data analysis tools.

mkreiser commented 5 years ago

πŸŽ‰ Compare v3 route structure to the class design of this project

At face value, the new route structure does not line up with the existing project. The mono route does not work with the existing design of this project, which attempts to take advantage of a couple different routes. However, the v3 route handles many params that construct different data responses. This project may be able to utilize this pattern instead of the route pattern. The route pattern is significantly more desirable, but we've got what we've got.

mkreiser commented 5 years ago

πŸŽ‰ Design new classes, reusing existing structure where appropriate

Existing classes:

BaseObject: Should be fine as is BaseCacheableObject: Should be fine as is BaseAPIObject: Needs significant adjustments to handle new route structure + route params

Boxscore classes: Need to investigate data response more. Should be able to generalize BoxscorePlayerStats League: Should be able to mirror organization of new response NFLGame: Should be able to hookup to API NFLTeam: Should be able to hookup to API Player: Basic mapping updates. May be able to add more support with new player info routes Roster: Needs a good bit of clean up Scoreboard classes: Need to investigate data more Team: Basic mapping updates

New classes

Will design as I dig into the data more

mkreiser commented 5 years ago

πŸŽ‰ Prep codebase on v3-api-conversion branch for new design (remove deprecated code, etc)

98. Will move code in from the master branch as development progresses.

Note: Removed support for Node 6, which was EOL'ed end of April 2019.

mkreiser commented 5 years ago

πŸ‘· Make changes to base classes (BaseObject, etc)

99 in progress

mpcen commented 5 years ago

Any ideas on how to get previous seasons BoxScores yet?

mkreiser commented 5 years ago

@mpcen Hit http://fantasy.espn.com/apis/v3/games/ffl/seasons/<SEASON_ID>/segments/0/leagues/<LEAGUE_ID>?view=mBoxscore&view=mMatchupScore&view=mSchedule&view=mScoreboard&view=mSettings&view=mStatus&view=mTeam&view=mRoster&view=modular&view=mNav

The schedule attribute contains every box score of every game of the season. Be warned, the response was +650000 lines for my 8 league, 17 week league 😱. You can filter down the response by removing view parameters and setting X-Fantasy-Filter: {"schedule":{"filterIds":{"value":[<ID_FROM_SCHEDULE_ARRAY_THING>]}}} on the request header.

This project is going to (try to) simplify this significantly like it did for the v2 API.

mkreiser commented 5 years ago

:tada: Make changes to base classes (BaseObject, etc)

99 is merged. Will probably need updates in the future to support filtering data on requests.

mkreiser commented 5 years ago

Starting with player data next, since it'll probably 🀞be easier to start with than boxscore/scoreboard data.

mpcen commented 5 years ago

Looks like it only gets boxscores from 2018. Nothing prior - huge RIP

mkreiser commented 5 years ago

@mpcen Yup. Last year ESPN decided to no longer preserve that data. There's a few reddit threads on it. From now on, there's only current and previous year available in detail, so download any data you wish to preserve.

travisryan commented 5 years ago

Hey, glad it looks like you're making progress. I'm wanting to use this to run a playoff combining two different leagues after 13 week regular season. Basically I'd only need the scoreboard info, etc for each team of a league. It looks like you've checked in the meat of the project. Any way I can get started on my project with the v3 branch?

mkreiser commented 5 years ago

πŸ‘· Implement new designs

Player done with #101

mkreiser commented 5 years ago

@travisryan Not yet for scoreboard info. Still a work in progress.

mkreiser commented 5 years ago

πŸ‘· Implement new designs

Team handled in #102. Boxscore model handled in #103.

Next, take a basic shot at a client class to call the ESPN API. May start an alpha package with that.

travisryan commented 5 years ago

I'm new to Node but would like to test some of these changes. I have the new branch checked out and then built the module. Copied the dist folder to my new test project. And have the following code:

// From local build var League = require ('./dist/index-node.js');

var express = require('express'); var app = express(); app.get('/', function (req, res) { res.send('Hello World!'); }); app.listen(3001, function () { console.log('Example app listening on port 3000!'); //const league = League({ leagueId: 1209139, seasonId: 2018 }); const league = new League({ leagueId: 1209139, seasonId: 2018 }); league.read().then(() => console.log(league)); // Prints loaded league

});

It didn't like the "new" word for League, and I tried without and that was just as bad. What might I be doing wrong, etc?

Thanks!

mkreiser commented 5 years ago

@travisryan That's the old branch that corresponds to the v2 ESPN API, which ESPN deleted. So that code won't work (it'll blow up on the read call).

if you want to play with the new stuff, you'll need to check out the v3-api-conversion branch. Currently nothing is hooked up to the API, so it doesn't really do anything. I'm working on a basic client on the client branch (branches from v3-api-conversion). I think it works once exported on index.js but I haven't tested it yet.

travisryan commented 5 years ago

ok cool. Thanks for the info. I THINK i checked out the v3 one but I def didn't get far. :) I'll be watching this closely as I think this project is pretty cool and hope to use it. Let me know if I can help at all.

travisryan commented 5 years ago

Would love to try the client. Any updates? :) Is the client something we need or just a test client so you know if your code works etc?

mkreiser commented 5 years ago

@travisryan Will put some work in on and off this long-ish weekend. Definitely trying to get something out the door soon so people can start building with this. The client is very close to being done and merged. I'm going to try to finish testing it today and get that code merged. Then going to update the README with new instructions and try to merge this feature branch into the master branch and publish a beta package.

travisryan commented 5 years ago

@mkreiser Awesome! Thanks for all your work!

mkreiser commented 5 years ago

πŸ‘· Implement new designs

106 starts a base client with Boxscore + free agent player data. Gonna update READMEs, then merge this into master. Then publish a beta package.

shibdib commented 5 years ago

Looking forward to the v3 update. I'll dig in a bit and see if I can contribute some PR's

mkreiser commented 5 years ago

Merged current work to master and published as 0.9.0. README is updated with how to use the new stuff.

travisryan commented 5 years ago

@mkreiser ok I'm a bit of a noob I guess with NodeJS in some respects. I've tried adding your update module via npm install and also built it with your scripts and keep running into different errors just trying to test. I'm testing it in a .js or .mjs file on the commandline. What's the best way to get a simple example to work? I've gotten errors on the import where it didn't like the { char. For that I added --experimental-modules but then it says Client isn't in the packages, etc.

HELP! :)

TylerJAllen commented 5 years ago

When I call .getBoxscoreForWeek(), I am receiving numerical values for homeTeamId and awayTeamId. I am seeing a team.js file in the code that has a schema (Team.responseMap) but I'm not seeing how to actually receive a populated team object that includes the actual team nickname. Instructions would be appreciated!

travisryan commented 5 years ago

@TylerJAllen how are you calling the code? can you past a simple example? Are you launching Express, or calling from nodejs commandline, etc?

TylerJAllen commented 5 years ago

I'm using express and calling node app.js in terminal.

here is a shortened version of my code:

const { Client } = require("espn-fantasy-football-api/node");
const myClient = new Client({ leagueId: my league id here });

myClient.setCookies({ espnS2: "my espnS2 string", SWID: "my SWID string"});

let data;

myClient.getBoxscoreForWeek({ seasonId: 2018, scoringPeriodId: 5, matchupPeriodId: 5 }).then((boxscores) => {
   data = boxscores;
});

app.get("/", function (req, res) {
    res.status(200).send(data);
});

app.listen(3000, function () {
  console.log("Example app listening on port 3000!");
});

When viewing the data in localhost: 3000, I'm seeing this:

[  
  {
    "homeScore": 93.14,
    "homeTeamId": 16,
    "homeRoster": [ //populated with player objects ],
    "awayScore": 122.3,
    "awayTeamId": 9,
    "awayRoster": [ //populated with player objects ]
  },
{
    "homeScore": 104.02,
    "homeTeamId": 12,
    "homeRoster": [ //populated with player objects ],
    "awayScore": 86.5,
    "awayTeamId": 17,
    "awayRoster": [ //populated with player objects ]
  },
{
    "homeScore": 86.18,
    "homeTeamId": 18,
    "homeRoster": [ //populated with player objects ],
    "awayScore": 108.44,
    "awayTeamId": 10,
    "awayRoster": [ //populated with player objects ]
  },
{
    "homeScore": 66.3,
    "homeTeamId": 5,
    "homeRoster": [ //populated with player objects ],
    "awayScore": 81.72,
    "awayTeamId": 1,
    "awayRoster": [ //populated with player objects ]
  },
{
    "homeScore": 98.32,
    "homeTeamId": 15,
    "homeRoster": [ //populated with player objects ],
    "awayScore": 112.7,
    "awayTeamId": 3,
    "awayRoster": [ //populated with player objects ]
  },
{
    "homeScore": 95.4,
    "homeTeamId": 14,
    "homeRoster": [ //populated with player objects ],
    "awayScore": 108.98,
    "awayTeamId": 11,
    "awayRoster": [ //populated with player objects ]
  },
]

I tried using const { Team } = require("espn-fantasy-football-api/node"); to see if I could get the team nicknames and team stats but haven't figured out how.

travisryan commented 5 years ago

I'm also not sure how to use the Team object to get the names.

mkreiser commented 5 years ago

@TylerJAllen @travisryan I built the model but didn't connect it to anything. Will connect via client soonβ„’

travisryan commented 5 years ago

@mkreiser that makes sense. I thought looking at the client that you just had a couple functions so far. Figured you had more work to do. It's just exciting you're so close. Thanks!

shibdib commented 5 years ago

Looking forward to you fleshing this out, already have the current functionality added to a slack bot I'm working on

https://i.imgur.com/ReknIfc.png

travisryan commented 5 years ago

Any more updates on this? Getting really excited for football season in general! :)

pejmanjohn commented 5 years ago

I'm in a similar place as @TylerJAllen. Using express and seeing my league data with getBoxscoreforWeek call. Excited to see more wired up in client. Thanks for pushing it so far.

travisryan commented 5 years ago

@mkreiser any more progress? We're only a few weeks away. Hope everything is going well for you, and appreciate all you do for this project!

mkreiser commented 5 years ago

Sorry for taking forever on this. Been tired by the time I get home. Banged it out tonight. https://github.com/mkreiser/ESPN-Fantasy-Football-API/pull/114

Published as 0.10.0. Let me know what you guys want next. My current idea is NFL team schedules.

ajg102 commented 5 years ago

Hey just wanted to say great work on this so far @mkreiser.

Something I noticed with the recent teams addition is that you have the teams function as getTeams in the README, but left it as getTeamsAtWeek in the client. Nbd, just figured I'd put it here in case anyone else gets a 'getTeams' is not a function error.

Also, right now it seems to be returning the most recent standings regardless of period. Is that supposed to happen right now as Im not entirely sure ESPN keeps standings by individual week?

mkreiser commented 5 years ago

@ajg102 Good catch. I'll update that (made the change right before merging).

Yes right now those standings are the latest always. Can see if there's another data point that is week dependent.

travishenson commented 5 years ago

First off, I wanted to say great work and thank you for doing all of this work. It's definitely shaping up to be a really powerful tool! @mkreiser

One question I have is if you know of a way to display the "Schedule" of each time based on a team ID. My league uses a custom power rankings formula that I'm attempting to automate. The formula uses the highest and lowest points for of each team, and I was wondering if you knew of a way to access those data points.

Once again, thanks a ton for all of this work!

travisryan commented 5 years ago

Ok I was able to add logo, logoType, and fix the space in the name. I've never pushed to a remote repository I didn't own. Can anyone help me figure out how to submit it? :)

travisryan commented 5 years ago

Here are the changes in src/team/teams.js. name is edited with a space, and lines below are added for logo.

name: { key: 'location', manualParse: (responseData, data) => ${data.location} ${data.nickname} }, logo: 'logo', logoType: 'logoType',

joe-salomon commented 5 years ago

@travisryan, you can fork the project and do a pull request with your changes: Github's Fork & Pull Workflow

mkreiser commented 5 years ago

Hey all. Sorry for disappearing. Work has been hectic and it's been hard to get time and motivation to this. My FF team is also probably going to suffer lol.

@travishenson From this project, you could pull all of the boxscores per week (scoringPeriodId). Definitely not ideal but could work. Can look into a schedule route.

@travisryan I've got a PR up at #120 for the spacing. Will throw a few more PRs up here to deal with the raised items.

cosmoburn commented 5 years ago

Hi, just found this today. Was surprised nothing else exists out there. How close are you all? Can I help with anything?

travisryan commented 5 years ago

I'm trying to use getBoxscoreForWeek and using a different scoring/matchup period. I only get the first week matchup even if I specify a scoringPeriodId = 2. Can anyone else verify if this works for them?

NEVERMIND. I think I'm a moron. :)

Ikendiken commented 5 years ago

I'm not sure it matters, but I switched out the espnS2 and the SWID cookies for the 'espnAuth' cookie containing just the swid and it seems to be working fine.

axios.interceptors.request.use(request => {
  if (client.isAuthenticated) {
    request.headers['Cookie'] = `espnAuth: {"swid":"${client.swid}"`
  }
  return request
})