This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using System.Linq;
|
||||
using Xunit;
|
||||
using SuccessfulCodeTools.LowLevelHttpClient;
|
||||
|
||||
namespace BritishHorseRacingApi.Tests
|
||||
{
|
||||
public class ApiClientTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task GetToken()
|
||||
{
|
||||
//Arrange
|
||||
var client = new ApiClient();
|
||||
//Act
|
||||
var token = await client.GetNewToken();
|
||||
//Assert
|
||||
Assert.False(String.IsNullOrWhiteSpace(token));
|
||||
}
|
||||
private const string _userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36";
|
||||
|
||||
[Fact]
|
||||
public async Task Test()
|
||||
{
|
||||
//Arrange
|
||||
var client = new CustomHttpClient(13718);
|
||||
var message = new CustomHttpRequestMessage(HttpMethod.Get, "http://www.britishhorseracing.com/feeds/v1/token/request");
|
||||
message.Headers.Add("Accept", "application/json, text/plain, */*");
|
||||
message.Headers.Add("User-Agent", _userAgent);
|
||||
message.Headers.Add("Host", "www.britishhorseracing.com");
|
||||
message.Headers.Add("Connection", "close");
|
||||
message.Headers.Add("accept-encoding", "gzip, deflate");
|
||||
var result = await client.SendAsync(message);
|
||||
Assert.NotNull(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetRaceResult()
|
||||
{
|
||||
//Arrange
|
||||
var client = new ApiClient();
|
||||
var token = await client.GetNewToken();
|
||||
//Act
|
||||
var result = await client.GetRaceResults(2018, 42638, 0);
|
||||
//Assert
|
||||
Assert.Equal(6, result.Total);
|
||||
Assert.Equal(6, result.Data.Length);
|
||||
Assert.Equal(42638, result.Data[0].RaceId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetFixtures()
|
||||
{
|
||||
//Arrange
|
||||
var client = new ApiClient();
|
||||
var token = await client.GetNewToken();
|
||||
//Act
|
||||
var result = await client.GetFixtures(2019, 2);
|
||||
//Assert
|
||||
Assert.Equal(111, result.Total);
|
||||
Assert.Equal(10, result.Data.Length);
|
||||
Assert.Equal(18142, result.Data[0].FixtureId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetAllFixturesForDay()
|
||||
{
|
||||
//Arrange
|
||||
var client = new ApiClient();
|
||||
var token = await client.GetNewToken();
|
||||
//Act
|
||||
var results = await client.GetAllFixturesForDay(2019, 2, 28);
|
||||
//Assert
|
||||
Assert.True(results.All(e => e.FixtureDate.Day == 28));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetAllRacesForDay()
|
||||
{
|
||||
var client = new ApiClient();
|
||||
var token = await client.GetNewToken();
|
||||
var results = await client.GetAllRacesForDay(2019, 2, 28);
|
||||
Assert.True(results.Count > 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetRaceRunners()
|
||||
{
|
||||
var client = new ApiClient();
|
||||
var token = await client.GetNewToken();
|
||||
var results = await client.GetRaceRunners(2020, 50144, 0);
|
||||
Assert.Equal(13, results.Data.Length);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetAllRaceResultsForDay()
|
||||
{
|
||||
var client = new ApiClient();
|
||||
var token = await client.GetNewToken();
|
||||
var results = await client.GetAllRaceResultsForDay(2020, 2, 23);
|
||||
Assert.True(results.Count > 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetRaces()
|
||||
{
|
||||
//Arrange
|
||||
var client = new ApiClient();
|
||||
var token = await client.GetNewToken();
|
||||
//Act
|
||||
var result = await client.GetRaces(2019, 18188);
|
||||
//Arrange
|
||||
Assert.Equal(6, result.Total);
|
||||
Assert.Equal(6, result.Data.Length);
|
||||
Assert.Equal(46136, result.Data[0].RaceId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetRaceCourse()
|
||||
{
|
||||
//Arrange
|
||||
var client = new ApiClient();
|
||||
var token = await client.GetNewToken();
|
||||
//Act
|
||||
var result = await client.GetRacecourse(18);
|
||||
//Arrange
|
||||
Assert.Equal(18, result.CourseId);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BritishHorseRacingApi\BritishHorseRacingApi.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,39 @@
|
||||
using BritishHorseRacingApi.Helpers;
|
||||
using System;
|
||||
using Xunit;
|
||||
|
||||
namespace BritishHorseRacingApi.Tests
|
||||
{
|
||||
public class DataConverterHelperTests
|
||||
{
|
||||
[Theory()]
|
||||
[InlineData("1m 24.73s", 1, 24, 73)]
|
||||
[InlineData("5m 42s", 5, 42, 0)]
|
||||
[InlineData("7m 2.9s", 7, 2, 9)]
|
||||
public void TestStopWatchStringConversion(string time, int mins, int seconds, int milliseconds)
|
||||
{
|
||||
//Arrange
|
||||
//Act
|
||||
var totalMilliseconds = DataConverterHelper.StopWatchStringToMilliseconds(time);
|
||||
//Assert
|
||||
var timeSpan = TimeSpan.FromMilliseconds((double)totalMilliseconds);
|
||||
Assert.Equal(mins, timeSpan.Minutes);
|
||||
Assert.Equal(seconds, timeSpan.Seconds);
|
||||
Assert.Equal(milliseconds, timeSpan.Milliseconds);
|
||||
}
|
||||
|
||||
[Theory()]
|
||||
[InlineData("1m 1f 104y", 2084)]
|
||||
[InlineData("1f 104y", 324)]
|
||||
[InlineData("104y", 104)]
|
||||
public void TestDistanceStringToYardsConversion(string distance, int expectedResult)
|
||||
{
|
||||
//Arrange
|
||||
//Act
|
||||
var result = DataConverterHelper.DistanceStringToYards(distance);
|
||||
//Assert
|
||||
Assert.True(result.HasValue);
|
||||
Assert.Equal(expectedResult, result.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29728.190
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BritishHorseRacingApi", "BritishHorseRacingApi\BritishHorseRacingApi.csproj", "{A8C8795B-EDA8-4AB5-9B85-3DA8E883CBD6}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BritishHorseRacingApi.Tests", "BritishHorseRacingApi.Tests\BritishHorseRacingApi.Tests.csproj", "{64B65FA2-BE79-40E5-810D-70C13514A791}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{A8C8795B-EDA8-4AB5-9B85-3DA8E883CBD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A8C8795B-EDA8-4AB5-9B85-3DA8E883CBD6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A8C8795B-EDA8-4AB5-9B85-3DA8E883CBD6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A8C8795B-EDA8-4AB5-9B85-3DA8E883CBD6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{64B65FA2-BE79-40E5-810D-70C13514A791}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{64B65FA2-BE79-40E5-810D-70C13514A791}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{64B65FA2-BE79-40E5-810D-70C13514A791}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{64B65FA2-BE79-40E5-810D-70C13514A791}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {7724F108-F427-47FD-87ED-81C538932C80}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,285 @@
|
||||
using BritishHorseRacingApi.Models;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using SuccessfulCodeTools;
|
||||
using SuccessfulCodeTools.LowLevelHttpClient;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
||||
namespace BritishHorseRacingApi
|
||||
{
|
||||
public class ApiClient : BaseApiClient
|
||||
{
|
||||
private const int _waitTimeAfterFail = 10;
|
||||
private const string _userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36";
|
||||
|
||||
public ApiClient(TimeSpan? delay = null) : base(delay) { }
|
||||
|
||||
public static class Endpoints
|
||||
{
|
||||
public const string Endpoint = "https://www.britishhorseracing.com/feeds";
|
||||
private const string V1Endpoint = Endpoint + "/v1";
|
||||
private const string V3Endpoint = Endpoint + "/v3";
|
||||
public const string Fixtures = V3Endpoint + "/fixtures";
|
||||
public const string Races = Fixtures + "/{0}/{1}/races";
|
||||
public const string Runners = Races + "/races/{0}/{1}/{2}/entries";
|
||||
public const string RaceResults = V3Endpoint + "/races/{0}/{1}/{2}/results";
|
||||
public const string Racecourses = V1Endpoint + "/racecourses";
|
||||
public const string Jockeys = V3Endpoint + "/jockeys";
|
||||
public const string Animals = V3Endpoint + "/racehorses/{0}";
|
||||
}
|
||||
|
||||
public virtual string CurrentToken { get; set; }
|
||||
|
||||
public async Task<string> GetNewToken()
|
||||
{
|
||||
await DelayBetweenRequests();
|
||||
var message = CreateTokenMessage();
|
||||
var response = await _client.SendAsync(message);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
throw new Exception("Token not retrieved");
|
||||
}
|
||||
|
||||
var content = response.Content;
|
||||
while (content.StartsWith("<"))
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromMinutes(_waitTimeAfterFail));
|
||||
//_client.OutgoingPort++;
|
||||
message = CreateTokenMessage();
|
||||
response = await _client.SendAsync(message);
|
||||
content = response.Content;
|
||||
}
|
||||
|
||||
var tokenResponse = content.DeserializeJson<TokenResponse>();
|
||||
CurrentToken = tokenResponse.Token;
|
||||
|
||||
return tokenResponse.Token;
|
||||
}
|
||||
|
||||
private static CustomHttpRequestMessage CreateTokenMessage()
|
||||
{
|
||||
var message = new CustomHttpRequestMessage(HttpMethod.Get, "http://www.britishhorseracing.com/feeds/v1/token/request");
|
||||
message.Headers.Add("Accept", "application/json, text/plain, */*");
|
||||
message.Headers.Add("Accept-Language", "en-US,en;q=0.9");
|
||||
message.Headers.Add("User-Agent", _userAgent);
|
||||
message.Headers.Add("Host", "www.britishhorseracing.com");
|
||||
message.Headers.Add("cache-control", "no-cache");
|
||||
message.Headers.Add("Postman-Token", "887efa5f-fe8e-4ce5-bfc1-810789691391");
|
||||
message.Headers.Add("Connection", "close");
|
||||
|
||||
message.Headers.Add("accept-encoding", "gzip, deflate");
|
||||
return message;
|
||||
}
|
||||
|
||||
public async Task<List<Race>> GetAllRacesForDay(int year, int month, int day)
|
||||
{
|
||||
var fixtures = await GetAllFixturesForDay(year, month, day);
|
||||
var races = new List<Race>();
|
||||
foreach(var fixture in fixtures)
|
||||
{
|
||||
var page = await GetRaces(year, fixture.FixtureId);
|
||||
races.AddRange(page.Data);
|
||||
}
|
||||
|
||||
return races;
|
||||
}
|
||||
|
||||
public async Task<List<RunnerResult>> GetAllRaceResultsForDay(int year, int month, int day)
|
||||
{
|
||||
var races = await GetAllRacesForDay(year, month, day);
|
||||
var runnerResults = new List<RunnerResult>();
|
||||
foreach (var race in races)
|
||||
{
|
||||
var page = await GetRaceResults(year, race.RaceId, race.DivisionSequence);
|
||||
runnerResults.AddRange(page.Data);
|
||||
}
|
||||
return runnerResults;
|
||||
}
|
||||
|
||||
public async Task<PagedResult<JockeySummary>> GetJockeys(int page = 1, int perPage = 2)
|
||||
{
|
||||
var uriBuilder = new UriBuilder(Endpoints.Jockeys)
|
||||
{
|
||||
Port = -1
|
||||
};
|
||||
var query = HttpUtility.ParseQueryString(uriBuilder.Query);
|
||||
query["page"] = page.ToString();
|
||||
query["per_page"] = perPage.ToString();
|
||||
uriBuilder.Query = query.ToString();
|
||||
|
||||
var results = await ExecuteRequestForPagedResults<JockeySummary>(uriBuilder.ToString());
|
||||
return results;
|
||||
}
|
||||
|
||||
public async Task<Jockey> GetJockey(int id)
|
||||
{
|
||||
var result = await ExecuteRequest<SingleResult<Jockey>>(Endpoints.Jockeys + $"/{id}", (token) => {
|
||||
return !(token["data"] is JArray);
|
||||
});
|
||||
|
||||
if(result == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return result.Data;
|
||||
}
|
||||
|
||||
public async Task<PagedResult<RunnerResult>> GetRaceResults(int year, int raceId, int divisionSequence = 0)
|
||||
{
|
||||
var requestUrl = String.Format(Endpoints.RaceResults, year, raceId, divisionSequence);
|
||||
return await ExecuteRequestForPagedResults<RunnerResult>(requestUrl);
|
||||
}
|
||||
|
||||
public async Task<PagedResult<Runner>> GetRaceRunners(int year, int raceId, int divisionSequence = 0)
|
||||
{
|
||||
var requestUrl = String.Format(Endpoints.Runners, year, raceId, divisionSequence);
|
||||
return await ExecuteRequestForPagedResults<Runner>(requestUrl);
|
||||
}
|
||||
|
||||
public async Task<PagedResult<Racecourse>> GetRacecourses()
|
||||
{
|
||||
return await ExecuteRequestForPagedResults<Racecourse>(Endpoints.Racecourses);
|
||||
}
|
||||
|
||||
public async Task<Racecourse> GetRacecourse(int id)
|
||||
{
|
||||
var result = await ExecuteRequest<SingleResult<Racecourse>>(Endpoints.Racecourses + "/" + id);
|
||||
return result.Data;
|
||||
}
|
||||
|
||||
public async Task<PagedResult<Race>> GetRaces(int year, int fixtureId)
|
||||
{
|
||||
var finalUrl = String.Format(Endpoints.Races, year, fixtureId);
|
||||
return await ExecuteRequestForPagedResults<Race>(finalUrl);
|
||||
}
|
||||
|
||||
public async Task<Animal> GetAnimal(int id)
|
||||
{
|
||||
var endpoint = String.Format(Endpoints.Animals, id);
|
||||
var result = await ExecuteRequest<SingleResult<Animal>>(endpoint, (token) => !(token["data"] is JArray));
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return result.Data;
|
||||
}
|
||||
|
||||
public async Task<List<Fixture>> GetAllFixturesForDay(int year, int month, int day)
|
||||
{
|
||||
var fixtures = new List<Fixture>();
|
||||
var pages = 1;
|
||||
|
||||
for(var i = 1; i <= pages; i++)
|
||||
{
|
||||
var resultsPage = await GetFixtures(year, month, i);
|
||||
|
||||
foreach(var item in resultsPage.Data)
|
||||
{
|
||||
//Items returned day descending, skip until relevant day
|
||||
if (item.FixtureDate.Day > day)
|
||||
continue;
|
||||
|
||||
//If we hit another day dont bother getting more
|
||||
if (item.FixtureDate.Day < day)
|
||||
return fixtures;
|
||||
|
||||
fixtures.Add(item);
|
||||
}
|
||||
|
||||
if (resultsPage.CurrentPage == resultsPage.LastPage)
|
||||
return fixtures;
|
||||
|
||||
pages++;
|
||||
}
|
||||
|
||||
return fixtures;
|
||||
}
|
||||
|
||||
public async Task<PagedResult<Fixture>> GetFixtures(int? year = null, int? month = null, int page = 1, int perPage = 10, string order = "desc", bool? resultsAvailable = true)
|
||||
{
|
||||
var uriBuilder = new UriBuilder(Endpoints.Fixtures);
|
||||
var query = HttpUtility.ParseQueryString(uriBuilder.Query);
|
||||
query["page"] = page.ToString();
|
||||
query["per_page"] = perPage.ToString();
|
||||
query["order"] = order;
|
||||
if (year != null)
|
||||
{
|
||||
query["year"] = year.ToString();
|
||||
}
|
||||
|
||||
if(month != null)
|
||||
{
|
||||
query["month"] = month.ToString();
|
||||
}
|
||||
|
||||
if(resultsAvailable != null)
|
||||
{
|
||||
query["resultAvailable"] = resultsAvailable.Value.ToString();
|
||||
}
|
||||
|
||||
uriBuilder.Query = query.ToString();
|
||||
var finalUrl = uriBuilder.ToString();
|
||||
return await ExecuteRequestForPagedResults<Fixture>(finalUrl);
|
||||
}
|
||||
|
||||
private Task<PagedResult<T>> ExecuteRequestForPagedResults<T>(string endpoint)
|
||||
{
|
||||
return ExecuteRequest<PagedResult<T>>(endpoint);
|
||||
}
|
||||
|
||||
private async Task<T> ExecuteRequest<T>(string endpoint, Func<JToken, bool> preDeserilizationValidation = null)
|
||||
{
|
||||
var response = await SendRequest(endpoint);
|
||||
|
||||
if(response.StatusCode == HttpStatusCode.Unauthorized)
|
||||
{
|
||||
await GetNewToken();
|
||||
response = await SendRequest(endpoint);
|
||||
}
|
||||
|
||||
var content = response.Content;
|
||||
while (content.StartsWith("<"))
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromMinutes(_waitTimeAfterFail));
|
||||
//_client.OutgoingPort++;
|
||||
await GetNewToken();
|
||||
response = await SendRequest(endpoint);
|
||||
content = response.Content;
|
||||
}
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
throw new Exception($"Unexpected error: {content}" );
|
||||
}
|
||||
|
||||
if(preDeserilizationValidation != null && !preDeserilizationValidation(JToken.Parse(content)))
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
|
||||
var deserializedResponse = content.DeserializeJson<T>();
|
||||
return deserializedResponse;
|
||||
}
|
||||
|
||||
protected override async Task PresendRequestAlterations(CustomHttpRequestMessage message)
|
||||
{
|
||||
message.Headers.Add("User-Agent", _userAgent);
|
||||
if (CurrentToken == null)
|
||||
{
|
||||
await GetNewToken();
|
||||
}
|
||||
//message.Headers.TryAddWithoutValidation("Authorization", CurrentToken);
|
||||
message.Headers.Add("Authorization", CurrentToken);
|
||||
message.Headers.Add("Accept", "application/json");
|
||||
message.Headers.Add("accept-encoding", "gzip, deflate");
|
||||
message.Headers.Add("Accept-Language", "en-US,en;q=0.9");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using SuccessfulCodeTools.LowLevelHttpClient;
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BritishHorseRacingApi
|
||||
{
|
||||
public abstract class BaseApiClient
|
||||
{
|
||||
private const int _startPort = 55948;
|
||||
protected readonly CustomHttpClient _client = new CustomHttpClient(_startPort);
|
||||
private readonly TimeSpan? _delay;
|
||||
private DateTime _lastRequest = DateTime.UtcNow;
|
||||
|
||||
public BaseApiClient(TimeSpan? delay = null)
|
||||
{
|
||||
_delay = delay;
|
||||
_client.DefaultHeaders.Add("Cookie", "bha-ie-test=true; D_SID=188.172.158.138:JT/OEx87nl5ScspTQk38UsDfuIz94DbCf5CYsIC7WpU; _ga=GA1.2.578018316.1549102711; __utmz=36595059.1549187117.8.2.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=(not%20provided); __utma=36595059.578018316.1549102711.1550365414.1551216842.16; __utmc=36595059; D_IID=80C3F85C-C90F-31DF-8830-AF181B9C7A2E; D_UID=33DA8B87-0FB7-3D76-9DA6-A650196A2B16; D_ZID=68EA5585-B6A0-34F7-939A-A0C1B40036B3; D_ZUID=0E647F3A-6570-32D2-9673-8B49FFEBE647; D_HID=EBE66F1F-FA2C-3373-8163-110008C50265");
|
||||
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
|
||||
}
|
||||
|
||||
protected async Task DelayBetweenRequests()
|
||||
{
|
||||
if (!_delay.HasValue)
|
||||
{
|
||||
_lastRequest = DateTime.UtcNow;
|
||||
return;
|
||||
}
|
||||
|
||||
var timeSinceLastRequest = DateTime.UtcNow - _lastRequest;
|
||||
var timeToWait = _delay.Value - timeSinceLastRequest;
|
||||
if (timeToWait.TotalMilliseconds > 0)
|
||||
{
|
||||
await Task.Delay(timeToWait);
|
||||
}
|
||||
_lastRequest = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
protected async Task<CustomHttpResponseMessage> SendRequest(string endpoint)
|
||||
{
|
||||
await DelayBetweenRequests();
|
||||
|
||||
var message = new CustomHttpRequestMessage(HttpMethod.Get, endpoint);
|
||||
message.Headers.Add("Accept", "application/json, text/plain, */*");
|
||||
|
||||
await PresendRequestAlterations(message);
|
||||
|
||||
var response = await _client.SendAsync(message);
|
||||
return response;
|
||||
}
|
||||
|
||||
protected abstract Task PresendRequestAlterations(CustomHttpRequestMessage message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SuccessfulCodeTools" Version="1.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,28 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace BritishHorseRacingApi
|
||||
{
|
||||
public class FalseOrObjectConverter : JsonConverter
|
||||
{
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
writer.WriteValue(((bool)value) ? 1 : 0);
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if(reader.Value != null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return serializer.Deserialize(reader, objectType);
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace BritishHorseRacingApi.Helpers
|
||||
{
|
||||
public static class DataConverterHelper
|
||||
{
|
||||
private static Regex _stopwatchTimeRegex = new Regex(@"^(?'minutes'[0-9]*(?=m))?m? ?(?'seconds'[0-9\.]*)s ?(?:\(\+)?(?'lossDifference'[0-9\.]*)(?:s\))?", RegexOptions.Compiled);
|
||||
public static int? StopWatchStringToMilliseconds(string stopwatchValue)
|
||||
{
|
||||
var match = _stopwatchTimeRegex.Match(stopwatchValue);
|
||||
var minutes = GetComponent(match, "minutes", 0);
|
||||
var secondsAndMilliseconds = GetComponent(match, "seconds", "0").Split('.');
|
||||
|
||||
var seconds = int.Parse(secondsAndMilliseconds[0]);
|
||||
var milliseconds = secondsAndMilliseconds.Length > 1 ? int.Parse(secondsAndMilliseconds[1]) : 0;
|
||||
|
||||
var timespan = new TimeSpan(0, 0, minutes, seconds, milliseconds);
|
||||
|
||||
return (int)timespan.TotalMilliseconds;
|
||||
}
|
||||
|
||||
private static Regex _distanceExtractorRegex = new Regex(BuildExtractComponentsRegex(
|
||||
("miles", "m"),
|
||||
("furlongs", "f"),
|
||||
("yards", "y")), RegexOptions.Compiled);
|
||||
|
||||
public static int? DistanceStringToYards(string distance)
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(distance))
|
||||
return null;
|
||||
|
||||
var match = _distanceExtractorRegex.Match(distance);
|
||||
var miles = GetComponent(match, "miles", 0);
|
||||
var furlongs = GetComponent(match, "furlongs", 0);
|
||||
var yards = GetComponent(match, "yards", 0);
|
||||
var totalYards = (miles * 1760) + (furlongs * 220) + yards;
|
||||
|
||||
return totalYards;
|
||||
}
|
||||
|
||||
private static string BuildExtractComponentsRegex(params (string label, string indicator)[] pairs)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
Array.ForEach(pairs, e => sb.AppendFormat(@"(?'{0}'[0-9\.]*(?={1}))?{1}? ?", e.label, e.indicator));
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static T GetComponent<T>(Match match, string component, T defaultValue = default)
|
||||
{
|
||||
var group = match.Groups[component];
|
||||
if (String.IsNullOrWhiteSpace(group.Value))
|
||||
return defaultValue;
|
||||
|
||||
return (T)Convert.ChangeType(group.Value, typeof(T));
|
||||
}
|
||||
|
||||
public static int StopwatchStringDifferenceToMilliseconds(string timeDifferenceString)
|
||||
{
|
||||
var match = _stopwatchTimeRegex.Match(timeDifferenceString);
|
||||
var lossDifference = GetComponent(match, "lossDifference", 0);
|
||||
return (int)TimeSpan.FromSeconds(lossDifference).TotalMilliseconds;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
public class Animal
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public DateTime DateOfBirth { get; set; }
|
||||
public DateTime? DeathDate { get; set; }
|
||||
public string DeathNote { get; set; }
|
||||
public string Moniker { get; set; }
|
||||
public string Sex { get; set; }
|
||||
public string TrainerName { get; set; }
|
||||
public int? TrainerId { get; set; }
|
||||
public string OwnerName { get; set; }
|
||||
public int? OwnerId { get; set; }
|
||||
public decimal? RatingAwt { get; set; }
|
||||
public decimal? RatingChase { get; set; }
|
||||
public decimal? RatingFlat { get; set; }
|
||||
public decimal? RatingHurdle { get; set; }
|
||||
public string NameWithNoCountry { get; set; }
|
||||
public PerformanceDetail[] PerformanceDetails { get; set; }
|
||||
public Lineage Lineage { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
public partial class Career
|
||||
{
|
||||
public int Wins { get; set; }
|
||||
public int Rides { get; set; }
|
||||
public decimal WinsToRides { get; set; }
|
||||
public int GroupListedWins { get; set; }
|
||||
public decimal PrizeMoney { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
public enum Country { Uk };
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
public class Fixture
|
||||
{
|
||||
public int FixtureId { get; set; }
|
||||
public int FixtureYear { get; set; }
|
||||
public DateTime FixtureDate { get; set; }
|
||||
public string Distance { get; set; }
|
||||
public string CourseName { get; set; }
|
||||
public DateTime? FirstRace { get; set; }
|
||||
public bool ResultsAvailable { get; set; }
|
||||
public bool RacecardAvailable { get; set; }
|
||||
public bool EntriesAvailable { get; set; }
|
||||
public int BlackTypeRaces { get; set; }
|
||||
public int BcsEvent { get; set; }
|
||||
public int NumberOfRaces { get; set; }
|
||||
public string FixtureName { get; set; }
|
||||
public FixtureType FixtureType { get; set; }
|
||||
public int MeetingId { get; set; }
|
||||
public RacingTrackType RacingTrackType { get; set; }
|
||||
public RacePlanningCode RacePlanningCode { get; set; }
|
||||
public int CourseId { get; set; }
|
||||
public string TicketsLink { get; set; }
|
||||
public int? MajorEvent { get; set; }
|
||||
public string Going { get; set; }
|
||||
public string Weather { get; set; }
|
||||
public string Other { get; set; }
|
||||
public string Stalls { get; set; }
|
||||
public string Rail { get; set; }
|
||||
public int AbandonedReasonCode { get; set; }
|
||||
public FixtureSession FixtureSession { get; set; }
|
||||
public string GoingUpdatedDate { get; set; }
|
||||
public string GoingUpdatedTime { get; set; }
|
||||
public Official[] Officials { get; set; }
|
||||
public NonRunner[] NonRunners { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
public enum FixtureSession { Afternoon, Evening, Floodlit };
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
public enum FixtureType { Flat, Jump, Mixed };
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
public class Jockey
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string County { get; set; }
|
||||
public DateTimeOffset DateOfBirth { get; set; }
|
||||
public int Age { get; set; }
|
||||
public int LowestRidingWeight { get; set; }
|
||||
public int? DaysSinceLastWin { get; set; }
|
||||
public string LicenseType { get; set; }
|
||||
public string JockeyImage { get; set; }
|
||||
public Career Career { get; set; }
|
||||
public RecentPerformance[] RecentPerformances { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
public class JockeySummary
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string County { get; set; }
|
||||
public int Age { get; set; }
|
||||
public int? DaysSinceLastWin { get; set; }
|
||||
public string LicenseType { get; set; }
|
||||
public string JockeyImage { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
public partial class LastRun
|
||||
{
|
||||
[JsonProperty("raceType")]
|
||||
public string RaceType { get; set; }
|
||||
|
||||
[JsonProperty("days")]
|
||||
public int Days { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
public class Lineage
|
||||
{
|
||||
[JsonConverter(typeof(FalseOrObjectConverter))]
|
||||
public LineageAnimal Dam { get; set; }
|
||||
[JsonConverter(typeof(FalseOrObjectConverter))]
|
||||
public LineageAnimal Sire { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
public class LineageAnimal
|
||||
{
|
||||
public int AnimalId { get; set; }
|
||||
public string AnimalName { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
public class NonRunner
|
||||
{
|
||||
[JsonProperty("fixtureId")]
|
||||
public long FixtureId { get; set; }
|
||||
|
||||
[JsonProperty("fixtureYear")]
|
||||
public int FixtureYear { get; set; }
|
||||
|
||||
[JsonProperty("raceId")]
|
||||
public long RaceId { get; set; }
|
||||
|
||||
[JsonProperty("divisionSequence")]
|
||||
public long DivisionSequence { get; set; }
|
||||
|
||||
[JsonProperty("raceName")]
|
||||
public string RaceName { get; set; }
|
||||
|
||||
[JsonProperty("horseName")]
|
||||
public string HorseName { get; set; }
|
||||
|
||||
[JsonProperty("fixtureDate")]
|
||||
public DateTime FixtureDate { get; set; }
|
||||
|
||||
[JsonProperty("raceTime")]
|
||||
public TimeSpan RaceTime { get; set; }
|
||||
|
||||
[JsonProperty("declaredDate")]
|
||||
public DateTime? DeclaredDate { get; set; }
|
||||
|
||||
[JsonProperty("declaredTime")]
|
||||
public TimeSpan DeclaredTime { get; set; }
|
||||
|
||||
[JsonProperty("declaredReason")]
|
||||
public string DeclaredReason { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
public partial class Official
|
||||
{
|
||||
public string Category { get; set; }
|
||||
public string[] Officials { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
public class PagedResult<T>
|
||||
{
|
||||
public int Total { get; set; }
|
||||
[JsonProperty("per_page")]
|
||||
public int PerPage { get; set; }
|
||||
[JsonProperty("current_page")]
|
||||
public int CurrentPage { get; set; }
|
||||
[JsonProperty("last_page")]
|
||||
public int LastPage { get; set; }
|
||||
public int From { get; set; }
|
||||
public int To { get; set; }
|
||||
public T[] Data { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
public class PerformanceDetail
|
||||
{
|
||||
public int TotalWins { get; set; }
|
||||
public int TotalRuns { get; set; }
|
||||
public int TotalPlaces { get; set; }
|
||||
public decimal? TotalPrizeMoney { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using BritishHorseRacingApi.Helpers;
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
public class Race
|
||||
{
|
||||
public int RaceId { get; set; }
|
||||
public int YearOfRace { get; set; }
|
||||
public int DivisionSequence { get; set; }
|
||||
public DateTime RaceDate { get; set; }
|
||||
public TimeSpan RaceTime { get; set; }
|
||||
public string RaceName { get; set; }
|
||||
public string AgeLimit { get; set; }
|
||||
public int PrizeAmount { get; set; }
|
||||
public string PrizeCurrency { get; set; }
|
||||
public int RaceClass { get; set; }
|
||||
public string RatingBand { get; set; }
|
||||
public string RawDistanceText { get; set; }
|
||||
public string DistanceUnits { get; set; }
|
||||
public int DistanceValue { get; set; }
|
||||
public string DistanceText { get; set; }
|
||||
public string DistanceChange { get; set; }
|
||||
public string RaceCriteriaRaceType { get; set; }
|
||||
public int AbandonedReasonCode { get; set; }
|
||||
public int BlackTypeRace { get; set; }
|
||||
public string DistanceChangeText { get; set; }
|
||||
public bool Plus10 { get; set; }
|
||||
public WinnersDetail[] WinnersDetails { get; set; }
|
||||
|
||||
public Regex _distanceExtractorRegex = new Regex(@"(?'miles'[0-9\.]*(?=m))?m? ?(?'furlongs'[0-9\.]*(?=f))?f? ?.*?(?'yards'[0-9\.]*(?=y))", RegexOptions.Compiled);
|
||||
|
||||
public int? DistanceInYards() => DataConverterHelper.DistanceStringToYards(DistanceText);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
public enum RacePlanningCode { Normal };
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
public class Racecourse
|
||||
{
|
||||
public int CourseId { get; set; }
|
||||
public string Name { get; set; }
|
||||
[JsonProperty("Type")]
|
||||
public TrackStyle TrackStyle { get; set; }
|
||||
public Region Region { get; set; }
|
||||
public string Phone { get; set; }
|
||||
public string Email { get; set; }
|
||||
public string Web { get; set; }
|
||||
public string Logo { get; set; }
|
||||
public string Address1 { get; set; }
|
||||
public string Address2 { get; set; }
|
||||
public string Address3 { get; set; }
|
||||
public string Address4 { get; set; }
|
||||
public string Address5 { get; set; }
|
||||
public string Postcode { get; set; }
|
||||
public Country? Country { get; set; }
|
||||
public string Latitude { get; set; }
|
||||
public string Longitude { get; set; }
|
||||
public DateTime? FirstRace { get; set; }
|
||||
public DateTime NextFixtureDate { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
public enum RacingTrackType { Awt, Turf, Mixed };
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
public class RecentPerformance
|
||||
{
|
||||
public int? RaceId { get; set; }
|
||||
public int? YearOfRace { get; set; }
|
||||
public int? DivisionSequence { get; set; }
|
||||
public int? CourseId { get; set; }
|
||||
public string CourseName { get; set; }
|
||||
public int? RaceRunners { get; set; }
|
||||
public int? ResultPosition { get; set; }
|
||||
public string BettingRatio { get; set; }
|
||||
public int? AnimalId { get; set; }
|
||||
public string AnimalName { get; set; }
|
||||
public int? JockeyId { get; set; }
|
||||
public string JockeyName { get; set; }
|
||||
public int? WeightCarried { get; set; }
|
||||
public int? TrainerId { get; set; }
|
||||
public string TrainerName { get; set; }
|
||||
public DateTimeOffset? RaceDateTime { get; set; }
|
||||
public DateTimeOffset? RaceDate { get; set; }
|
||||
public DateTimeOffset? RaceTime { get; set; }
|
||||
public int? RaceClass { get; set; }
|
||||
public TrackStyle RaceType { get; set; }
|
||||
public string RaceDistanceText { get; set; }
|
||||
public string RaceName { get; set; }
|
||||
public string PrizeMoney { get; set; }
|
||||
public string Going { get; set; }
|
||||
public int? FlatRating { get; set; }
|
||||
public object AwtRating { get; set; }
|
||||
public object ChaseRating { get; set; }
|
||||
public object HurdleRating { get; set; }
|
||||
public Status Status { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
public enum Region { Midlands, North, South };
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
public partial class Runner
|
||||
{
|
||||
[JsonProperty("raceId")]
|
||||
public int RaceId { get; set; }
|
||||
|
||||
[JsonProperty("yearOfRace")]
|
||||
public int YearOfRace { get; set; }
|
||||
|
||||
[JsonProperty("divisionSequence")]
|
||||
public int DivisionSequence { get; set; }
|
||||
|
||||
[JsonProperty("animalId")]
|
||||
public int AnimalId { get; set; }
|
||||
|
||||
[JsonProperty("racehorseName")]
|
||||
public string RacehorseName { get; set; }
|
||||
|
||||
[JsonProperty("ageYears")]
|
||||
public int AgeYears { get; set; }
|
||||
|
||||
[JsonProperty("bred")]
|
||||
public string Bred { get; set; }
|
||||
|
||||
[JsonProperty("clothNumber")]
|
||||
public int ClothNumber { get; set; }
|
||||
|
||||
[JsonProperty("drawnStall")]
|
||||
public int? DrawnStall { get; set; }
|
||||
|
||||
[JsonProperty("reserveNumber")]
|
||||
public string ReserveNumber { get; set; }
|
||||
|
||||
[JsonProperty("bhaRating")]
|
||||
public string BhaRating { get; set; }
|
||||
|
||||
[JsonProperty("formFigures")]
|
||||
public string FormFigures { get; set; }
|
||||
|
||||
[JsonProperty("weightValue")]
|
||||
public string WeightValue { get; set; }
|
||||
|
||||
[JsonProperty("penaltyValue")]
|
||||
public int PenaltyValue { get; set; }
|
||||
|
||||
[JsonProperty("sexType")]
|
||||
public SexType SexType { get; set; }
|
||||
|
||||
[JsonProperty("nonRunnerDeclaredReason")]
|
||||
public string NonRunnerDeclaredReason { get; set; }
|
||||
|
||||
[JsonProperty("nonRunnerDeclaredDate")]
|
||||
public string NonRunnerDeclaredDate { get; set; }
|
||||
|
||||
[JsonProperty("nonRunnerDeclaredTime")]
|
||||
public string NonRunnerDeclaredTime { get; set; }
|
||||
|
||||
[JsonProperty("runner")]
|
||||
public int RunnerNumber { get; set; }
|
||||
|
||||
[JsonProperty("status")]
|
||||
public Status Status { get; set; }
|
||||
|
||||
[JsonProperty("jockeyId")]
|
||||
public int JockeyId { get; set; }
|
||||
|
||||
[JsonProperty("jockeyName")]
|
||||
public string JockeyName { get; set; }
|
||||
|
||||
[JsonProperty("weightsJockeyClaiming")]
|
||||
public int WeightsJockeyClaiming { get; set; }
|
||||
|
||||
[JsonProperty("headGearWearingCode")]
|
||||
public string HeadGearWearingCode { get; set; }
|
||||
|
||||
[JsonProperty("headGearWearingSheepSkin")]
|
||||
public int HeadGearWearingSheepSkin { get; set; }
|
||||
|
||||
[JsonProperty("headGearDescription")]
|
||||
public string HeadGearDescription { get; set; }
|
||||
|
||||
[JsonProperty("headGearAbbreviation")]
|
||||
public string HeadGearAbbreviation { get; set; }
|
||||
|
||||
[JsonProperty("jockeyProfile")]
|
||||
public int JockeyProfile { get; set; }
|
||||
|
||||
[JsonProperty("courseWinner")]
|
||||
public string CourseWinner { get; set; }
|
||||
|
||||
[JsonProperty("distanceWinner")]
|
||||
public string DistanceWinner { get; set; }
|
||||
|
||||
[JsonProperty("windSurgeryFirstRun")]
|
||||
public string WindSurgeryFirstRun { get; set; }
|
||||
|
||||
[JsonProperty("trainerId")]
|
||||
public int TrainerId { get; set; }
|
||||
|
||||
[JsonProperty("trainerName")]
|
||||
public string TrainerName { get; set; }
|
||||
|
||||
[JsonProperty("ownerId")]
|
||||
public int OwnerId { get; set; }
|
||||
|
||||
[JsonProperty("ownerName")]
|
||||
public string OwnerName { get; set; }
|
||||
|
||||
[JsonProperty("wbSilkCode")]
|
||||
public string WbSilkCode { get; set; }
|
||||
|
||||
[JsonProperty("wbSilkDescription")]
|
||||
public string WbSilkDescription { get; set; }
|
||||
|
||||
[JsonProperty("silkImage")]
|
||||
public string SilkImage { get; set; }
|
||||
|
||||
[JsonProperty("plus10")]
|
||||
public int Plus10 { get; set; }
|
||||
|
||||
[JsonProperty("forecastPriceNumerator")]
|
||||
public string ForecastPriceNumerator { get; set; }
|
||||
|
||||
[JsonProperty("forecastPriceDenominator")]
|
||||
public string ForecastPriceDenominator { get; set; }
|
||||
|
||||
[JsonProperty("weightText")]
|
||||
public string WeightText { get; set; }
|
||||
|
||||
[JsonProperty("odds")]
|
||||
public string Odds { get; set; }
|
||||
|
||||
[JsonProperty("lastRuns")]
|
||||
public LastRun[] LastRuns { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using BritishHorseRacingApi.Helpers;
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
public class RunnerResult
|
||||
{
|
||||
public int RaceId { get; set; }
|
||||
public int YearOfRace { get; set; }
|
||||
public int DivisionSequence { get; set; }
|
||||
public int HorseId { get; set; }
|
||||
public int AnimalId { get; set; }
|
||||
public int? ResultFinishPos { get; set; }
|
||||
public string Status { get; set; }
|
||||
public int Ran { get; set; }
|
||||
public string NonRunnerDeclaredReason { get; set; }
|
||||
public DateTime? NonRunnerDeclaredDate { get; set; }
|
||||
public TimeSpan? NonRunnerDeclaredTime { get; set; }
|
||||
public string RacehorseName { get; set; }
|
||||
public int AgeYear { get; set; }
|
||||
public string Bred { get; set; }
|
||||
public int? ClothNumber { get; set; }
|
||||
public int? DrawnStall { get; set; }
|
||||
public int? WeightValue { get; set; }
|
||||
public string SexType { get; set; }
|
||||
public int? JockeyId { get; set; }
|
||||
public string JockeyName { get; set; }
|
||||
public int JockeyProfile { get; set; }
|
||||
public int? TrainerId { get; set; }
|
||||
public string TrainerName { get; set; }
|
||||
public int? OwnerId { get; set; }
|
||||
public string OwnerName { get; set; }
|
||||
public string WbSilkCode { get; set; }
|
||||
public string WbSilkDescription { get; set; }
|
||||
public string SilkImage { get; set; }
|
||||
public int Plus10 { get; set; }
|
||||
public string ResultBtnDistance { get; set; }
|
||||
public string PositionFinishTime { get; set; }
|
||||
public string BettingRatio { get; set; }
|
||||
public string PerformanceFigure { get; set; }
|
||||
public int? RatingFlat { get; set; }
|
||||
public string RatingAwt { get; set; }
|
||||
public string RatingChase { get; set; }
|
||||
public string RatingHurdle { get; set; }
|
||||
public string RaceCriteriaRaceType { get; set; }
|
||||
public int Hro { get; set; }
|
||||
public string FinishTime { get; set; }
|
||||
public int? FinishTimeInMilliseconds() => DataConverterHelper.StopWatchStringToMilliseconds(FinishTime);
|
||||
|
||||
public int LossMilliseconds() => DataConverterHelper.StopwatchStringDifferenceToMilliseconds(FinishTime);
|
||||
|
||||
public string RacehorseNameWithoutConuntry => RacehorseName.Split('(')[0].Trim();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
public enum SexType { Filly, Gelding };
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
|
||||
public class SingleResult<T>
|
||||
{
|
||||
public T Data { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
public enum Status { Runner, Dnf, Withdrawn };
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
public class TokenResponse
|
||||
{
|
||||
[JsonProperty("token")]
|
||||
public string Token { get; set; }
|
||||
public string Session { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
public enum TrackStyle { Flat, Jump, Mixed };
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
|
||||
namespace BritishHorseRacingApi.Models
|
||||
{
|
||||
public class WinnersDetail
|
||||
{
|
||||
public int Position { get; set; }
|
||||
public string JockeyName { get; set; }
|
||||
public string Trainername { get; set; }
|
||||
public Uri SilkImage { get; set; }
|
||||
public string RacehorseName { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
Vendored
+37
@@ -0,0 +1,37 @@
|
||||
pipeline
|
||||
{
|
||||
agent { dockerfile true }
|
||||
stages
|
||||
{
|
||||
stage('Build')
|
||||
{
|
||||
steps
|
||||
{
|
||||
sh 'dotnet restore'
|
||||
sh 'dotnet build -c Release --no-restore'
|
||||
sh "dotnet pack -c Release --no-restore --no-build -p:PackageVersion=1.0.${env.BUILD_NUMBER}"
|
||||
}
|
||||
}
|
||||
|
||||
stage('Archive artifacts')
|
||||
{
|
||||
steps
|
||||
{
|
||||
archiveArtifacts artifacts:'*/bin/Release/**/*.nupkg'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Publish nuget artifacts')
|
||||
{
|
||||
steps
|
||||
{
|
||||
sh "./JenkinsfileScripts/PublishNugetArtifacts.sh ${env.BUILD_NUMBER}"
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
deleteDir() /* clean up our workspace */
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user