Skip to content

Commit

Permalink
Get league tables
Browse files Browse the repository at this point in the history
  • Loading branch information
g-martin772 committed Apr 14, 2024
1 parent 5f360ce commit af40b54
Showing 1 changed file with 101 additions and 50 deletions.
151 changes: 101 additions & 50 deletions MPM-Betting.Services/Data/FootballApi.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
using Microsoft.AspNetCore.Builder;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Newtonsoft.Json.Linq;

namespace MPM_Betting.Services.Data;

public static class FootballApi
{
record LeagueEntry(string Name, string Country, int Id);
record TeamEntry(int Id, string Name);
record PlayerEntry(string Name, string Position, int Id);
record League(string Name, string Country, int Id);
record Team(int Id, string Name);
record Player(string Name, string Position, int Id);
record LeagueTable(League League, List<LeagueTableEntry> Table, string Season, List<string> Seasons); //TODO: add ongoing, last 5 and promotion/relegation
record LeagueTableEntry(Team Team, int Rank, int Played, int Won, int Drawn, int Lost, int GoalsFor, int GoalsAgainst, int Points);

public static WebApplication MapFootballEndpoints(this WebApplication app)
{
Expand All @@ -27,15 +29,74 @@ public static WebApplication MapFootballEndpoints(this WebApplication app)
.WithName("GetAllFootballPlayers")
.WithOpenApi();

app.MapGet("/football/table", async (IDistributedCache cache, [FromQuery] int league, [FromQuery] string? season) => await GetLeagueTable(cache, league, season))
.WithName("GetTable")
.WithOpenApi();

return app;
}

private static async Task<List<PlayerEntry> > GetAllFootballPlayers(IDistributedCache cache)
private static async Task<LeagueTable> GetLeagueTable(IDistributedCache cache, int leagueId, string? season)
{
return await Utils.GetViaCache(cache, TimeSpan.FromMinutes(1), $"leagueTable-{leagueId}-{season ?? "latest"}", async () =>
{
var client = new HttpClient();
var url = $"https://www.fotmob.com/api/leagues?id={leagueId}";
var response = await Utils.GetViaCache(cache, TimeSpan.FromMinutes(1), url,
async () => await client.GetAsync(url));
var json = await response.Content.ReadAsStringAsync();
var jObject = JObject.Parse(json);
var details = jObject["details"]!;
var leagueName = details["name"]!.Value<string>()!;
var country = details["country"]!.Value<string>()!;
var selectedSeason = details["selectedSeason"]!.Value<string>()!;
var allAvailableSeasons = (JArray)jObject["allAvailableSeasons"]!;
var seasons = allAvailableSeasons.Select(availableSeason => availableSeason.Value<string>()!).ToList();
if (season is null || !seasons.Contains(season))
{
season = seasons[0];
}
var data = jObject["table"]![0]!["data"]!;
if (season != selectedSeason)
{
url = $"https://www.fotmob.com/api/table?url=https%3A%2F%2Fdata.fotmob.com%2Ftables.ext.{leagueId}.fot&selectedSeason={UrlEncoder.Default.Encode(season)}";
response = await Utils.GetViaCache(cache, TimeSpan.FromMinutes(1), url,
async () => await client.GetAsync(url));
json = await response.Content.ReadAsStringAsync();
jObject = JObject.Parse(json);
data = jObject;
}
var table = (JArray)data["table"]!["all"]!;
var entries = (
from entry in table
let name = entry["name"]!.Value<string>()!
let id = entry["id"]!.Value<int>()
let rank = entry["idx"]!.Value<int>()
let played = entry["played"]!.Value<int>()
let wins = entry["wins"]!.Value<int>()
let draws = entry["draws"]!.Value<int>()
let losses = entry["losses"]!.Value<int>()
let goalsFor = entry["scoresStr"]!.Value<string>()!.Split('-')[0]
let goalsAgainst = entry["scoresStr"]!.Value<string>()!.Split('-')[1]
let points = entry["pts"]!.Value<int>()
select new LeagueTableEntry(new Team(id, name), rank, played, wins, draws, losses, int.Parse(goalsFor), int.Parse(goalsAgainst), points)).ToList();
return new LeagueTable(new League(leagueName, country, leagueId), entries, season, seasons);
});
}

private static async Task<List<Player> > GetAllFootballPlayers(IDistributedCache cache)
{
return await Utils.GetViaCache(cache, TimeSpan.FromDays(1), $"footballPlayers", async () =>
{
var allTeams = await GetAllFootballTeams(cache);
var allPlayers = new List<PlayerEntry>();
var allPlayers = new List<Player>();
var tasks = allTeams.Select(async team =>
{
Expand All @@ -49,11 +110,11 @@ private static async Task<List<PlayerEntry> > GetAllFootballPlayers(IDistributed
});
}

private static async Task<List<PlayerEntry>> GetPlayersFromTeam(IDistributedCache cache, int teamId)
private static async Task<List<Player>> GetPlayersFromTeam(IDistributedCache cache, int teamId)
{
return await Utils.GetViaCache(cache, TimeSpan.FromDays(1), $"footballPlayers-{teamId}", async () =>
{
var allPlayers = new List<PlayerEntry>();
var allPlayers = new List<Player>();
try
{
var client = new HttpClient();
Expand All @@ -65,17 +126,14 @@ private static async Task<List<PlayerEntry>> GetPlayersFromTeam(IDistributedCach
var squad = (JArray)jObject["squad"]!;
foreach (var position in squad)
{
var title = position["title"]!.Value<string>()!;
var members = (JArray)position["members"]!;
foreach (var member in members)
{
var id = member["id"]!.Value<int>();
var name = member["name"]!.Value<string>()!;
allPlayers.Add(new PlayerEntry(name, title, id));
}
}
allPlayers.AddRange(
from position in squad
let title = position["title"]!.Value<string>()!
let members = (JArray)position["members"]!
from member in members
let id = member["id"]!.Value<int>()
let name = member["name"]!.Value<string>()!
select new Player(name, title, id));
}
catch (Exception e)

Check warning on line 138 in MPM-Betting.Services/Data/FootballApi.cs

View workflow job for this annotation

GitHub Actions / build

The variable 'e' is declared but never used

Check warning on line 138 in MPM-Betting.Services/Data/FootballApi.cs

View workflow job for this annotation

GitHub Actions / build

The variable 'e' is declared but never used
{
Expand All @@ -86,11 +144,11 @@ private static async Task<List<PlayerEntry>> GetPlayersFromTeam(IDistributedCach
});
}

private static async Task<List<TeamEntry>> GetTeamsFromLeague(IDistributedCache cache, int leagueId)
private static async Task<List<Team>> GetTeamsFromLeague(IDistributedCache cache, int leagueId)
{
return await Utils.GetViaCache(cache, TimeSpan.FromDays(1), $"footballTeams-{leagueId}", async () =>
{
var allTeams = new List<TeamEntry>();
var allTeams = new List<Team>();
try
{
var client = new HttpClient();
Expand All @@ -104,12 +162,11 @@ private static async Task<List<TeamEntry>> GetTeamsFromLeague(IDistributedCache
table ??= ((JArray)jObject["table"]!)[0]["data"]!["tables"]![0]!["table"]!;
var all = (JArray)table["all"]!;
foreach (var team in all)
{
var name = team["name"]!.Value<string>()!;
var id = team["id"]!.Value<int>();
allTeams.Add(new TeamEntry(id, name));
}
allTeams.AddRange(
from team in all
let name = team["name"]!.Value<string>()!
let id = team["id"]!.Value<int>()
select new Team(id, name));
}
catch (Exception e)

Check warning on line 171 in MPM-Betting.Services/Data/FootballApi.cs

View workflow job for this annotation

GitHub Actions / build

The variable 'e' is declared but never used

Check warning on line 171 in MPM-Betting.Services/Data/FootballApi.cs

View workflow job for this annotation

GitHub Actions / build

The variable 'e' is declared but never used
{
Expand All @@ -120,11 +177,11 @@ private static async Task<List<TeamEntry>> GetTeamsFromLeague(IDistributedCache
});
}

private static async Task<List<TeamEntry>> GetAllFootballTeams(IDistributedCache cache)
private static async Task<List<Team>> GetAllFootballTeams(IDistributedCache cache)
{
return await Utils.GetViaCache(cache, TimeSpan.FromDays(1), "footballTeams", async () =>
{
var allTeams = new List<TeamEntry>();
var allTeams = new List<Team>();
var allLeagues = await GetAllFootballLeagues(cache);
var tasks = allLeagues.Select(async leagueEntry =>
Expand All @@ -143,12 +200,10 @@ private static async Task<List<TeamEntry>> GetAllFootballTeams(IDistributedCache
});
}

private static async Task<List<LeagueEntry>> GetAllFootballLeagues(IDistributedCache cache)
private static async Task<List<League>> GetAllFootballLeagues(IDistributedCache cache)
{
return await Utils.GetViaCache(cache, TimeSpan.FromDays(1), "footballLeagues", async () =>
{
var allLeagues = new List<LeagueEntry>();
var client = new HttpClient();
var response = await client.GetAsync("https://www.fotmob.com/api/allLeagues");
Expand All @@ -158,26 +213,22 @@ private static async Task<List<LeagueEntry>> GetAllFootballLeagues(IDistributedC
var international = (JArray)jObject["international"]!;
var internationalLeagues = international[0]["leagues"]!;
foreach (var league in internationalLeagues)
{
var leagueName = league["name"]!.Value<string>()!;
var leagueId = league["id"]!.Value<int>();
allLeagues.Add(new LeagueEntry(leagueName, "international", leagueId));
}
var allLeagues = (
from league in internationalLeagues
let leagueName = league["name"]!.Value<string>()!
let leagueId = league["id"]!.Value<int>()
select new League(leagueName, "international", leagueId)).ToList();
var countries = (JArray)jObject["countries"]!;
foreach (var jToken in countries)
{
var countryName = jToken["name"]!.Value<string>()!;
var leagues = (JArray)jToken["leagues"]!;
foreach (var league in leagues)
{
var leagueName = league["name"]!.Value<string>()!;
var leagueId = league["id"]!.Value<int>();
allLeagues.Add(new LeagueEntry(leagueName, countryName, leagueId));
}
}
allLeagues.AddRange(
from jToken in countries
let countryName = jToken["name"]!.Value<string>()!
let leagues = (JArray)jToken["leagues"]!
from league in leagues
let leagueName = league["name"]!.Value<string>()!
let leagueId = league["id"]!.Value<int>()
select new League(leagueName, countryName, leagueId));
return allLeagues;
});
Expand Down

0 comments on commit af40b54

Please sign in to comment.