Aggiunte opzioni avanzate download calcio API-Football
Introdotta la classe FootballDownloadOptions per la gestione centralizzata delle opzioni di download e filtri. L’utente può ora scegliere quali endpoint scaricare (partite, quote, previsioni, classifiche, H2H, eventi, formazioni, statistiche, infortuni) e impostare parametri avanzati (ID bookmaker, pagine quote, leghe, delay API, quota minima residua, ecc.) tramite la nuova sezione UI. Rifattorizzata la logica di download per supportare il caricamento condizionale e sequenziale degli endpoint, con progress bar proporzionale e callback di stato dettagliate. Aggiunti nuovi client API per endpoint aggiuntivi e metodi di enrichment per arricchire dinamicamente la tabella delle partite. Aggiornate le impostazioni utente e la UI per supportare tutte le nuove opzioni. Aggiunto il controllo della quota API residua prima del download. Inseriti nuovi file sorgente per i client API mancanti e la gestione delle opzioni.
This commit is contained in:
@@ -54,4 +54,9 @@
|
||||
<ItemGroup Label="EmbeddedResource items now included by globbing that were not in the original project file">
|
||||
<EmbeddedResource Remove="Main.resx" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="HorseRacingPredictor\appsettings.json" Link="appsettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using RestSharp;
|
||||
|
||||
namespace HorseRacingPredictor.Football.API
|
||||
{
|
||||
/// <summary>
|
||||
/// Client per l'endpoint "fixtures/events" dell'API-Football.
|
||||
/// Restituisce gli eventi di una partita (gol, cartellini, sostituzioni, VAR).
|
||||
/// </summary>
|
||||
internal class Events : HorseRacingPredictor.Football.Manager.API
|
||||
{
|
||||
private const string Endpoint = "fixtures/events";
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene tutti gli eventi per una partita
|
||||
/// </summary>
|
||||
public RestResponse GetEventsByFixture(int fixtureId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return ExecuteRequest($"{Endpoint}?fixture={fixtureId}", ApiTypes.Fixtures);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"Errore durante il recupero degli eventi per la partita {fixtureId}: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using RestSharp;
|
||||
|
||||
namespace HorseRacingPredictor.Football.API
|
||||
{
|
||||
/// <summary>
|
||||
/// Client per l'endpoint "fixtures/statistics" dell'API-Football.
|
||||
/// Restituisce le statistiche di una partita (possesso, tiri, falli, ecc.).
|
||||
/// </summary>
|
||||
internal class FixtureStatistics : HorseRacingPredictor.Football.Manager.API
|
||||
{
|
||||
private const string Endpoint = "fixtures/statistics";
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene le statistiche per una partita
|
||||
/// </summary>
|
||||
public RestResponse GetStatisticsByFixture(int fixtureId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return ExecuteRequest($"{Endpoint}?fixture={fixtureId}", ApiTypes.Fixtures);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"Errore durante il recupero delle statistiche per la partita {fixtureId}: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using RestSharp;
|
||||
|
||||
namespace HorseRacingPredictor.Football.API
|
||||
{
|
||||
/// <summary>
|
||||
/// Client per l'endpoint "fixtures/headtohead" dell'API-Football.
|
||||
/// Restituisce lo storico degli scontri diretti tra due squadre.
|
||||
/// </summary>
|
||||
internal class HeadToHead : HorseRacingPredictor.Football.Manager.API
|
||||
{
|
||||
private const string Endpoint = "fixtures/headtohead";
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene gli scontri diretti tra due squadre
|
||||
/// </summary>
|
||||
/// <param name="teamId1">ID della prima squadra</param>
|
||||
/// <param name="teamId2">ID della seconda squadra</param>
|
||||
/// <param name="last">Numero di ultimi scontri da recuperare (default 5)</param>
|
||||
public RestResponse GetH2H(int teamId1, int teamId2, int last = 5)
|
||||
{
|
||||
try
|
||||
{
|
||||
return ExecuteRequest($"{Endpoint}?h2h={teamId1}-{teamId2}&last={last}", ApiTypes.Fixtures);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"Errore durante il recupero H2H per {teamId1} vs {teamId2}: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using RestSharp;
|
||||
|
||||
namespace HorseRacingPredictor.Football.API
|
||||
{
|
||||
/// <summary>
|
||||
/// Client per l'endpoint "injuries" dell'API-Football.
|
||||
/// Restituisce la lista di giocatori infortunati o squalificati.
|
||||
/// </summary>
|
||||
internal class Injuries : HorseRacingPredictor.Football.Manager.API
|
||||
{
|
||||
private const string Endpoint = "injuries";
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene gli infortunati per una data specifica
|
||||
/// </summary>
|
||||
public RestResponse GetInjuriesByDate(DateTime date)
|
||||
{
|
||||
try
|
||||
{
|
||||
string dateStr = date.ToString("yyyy-MM-dd");
|
||||
return ExecuteRequest($"{Endpoint}?date={dateStr}", ApiTypes.Fixtures);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"Errore durante il recupero degli infortunati per la data {date.ToShortDateString()}: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene gli infortunati per una partita specifica
|
||||
/// </summary>
|
||||
public RestResponse GetInjuriesByFixture(int fixtureId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return ExecuteRequest($"{Endpoint}?fixture={fixtureId}", ApiTypes.Fixtures);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"Errore durante il recupero degli infortunati per la partita {fixtureId}: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene gli infortunati per una lega e stagione
|
||||
/// </summary>
|
||||
public RestResponse GetInjuriesByLeague(int leagueId, int season)
|
||||
{
|
||||
try
|
||||
{
|
||||
return ExecuteRequest($"{Endpoint}?league={leagueId}&season={season}", ApiTypes.Fixtures);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"Errore durante il recupero degli infortunati per lega {leagueId}, stagione {season}: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using RestSharp;
|
||||
|
||||
namespace HorseRacingPredictor.Football.API
|
||||
{
|
||||
/// <summary>
|
||||
/// Client per l'endpoint "fixtures/lineups" dell'API-Football.
|
||||
/// Restituisce formazioni, modulo e titolari di una partita.
|
||||
/// </summary>
|
||||
internal class Lineups : HorseRacingPredictor.Football.Manager.API
|
||||
{
|
||||
private const string Endpoint = "fixtures/lineups";
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene le formazioni per una partita
|
||||
/// </summary>
|
||||
public RestResponse GetLineupsByFixture(int fixtureId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return ExecuteRequest($"{Endpoint}?fixture={fixtureId}", ApiTypes.Fixtures);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"Errore durante il recupero delle formazioni per la partita {fixtureId}: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using RestSharp;
|
||||
|
||||
namespace HorseRacingPredictor.Football.API
|
||||
{
|
||||
/// <summary>
|
||||
/// Client per l'endpoint "standings" dell'API-Football.
|
||||
/// Restituisce la classifica di un campionato per una stagione.
|
||||
/// </summary>
|
||||
internal class Standings : HorseRacingPredictor.Football.Manager.API
|
||||
{
|
||||
private const string Endpoint = "standings";
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene la classifica per una lega e una stagione
|
||||
/// </summary>
|
||||
public RestResponse GetStandings(int leagueId, int season)
|
||||
{
|
||||
try
|
||||
{
|
||||
return ExecuteRequest($"{Endpoint}?league={leagueId}&season={season}", ApiTypes.Leagues);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"Errore durante il recupero della classifica per lega {leagueId}, stagione {season}: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene la classifica per un team e una stagione
|
||||
/// </summary>
|
||||
public RestResponse GetStandingsByTeam(int teamId, int season)
|
||||
{
|
||||
try
|
||||
{
|
||||
return ExecuteRequest($"{Endpoint}?team={teamId}&season={season}", ApiTypes.Teams);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"Errore durante il recupero della classifica per team {teamId}, stagione {season}: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using RestSharp;
|
||||
|
||||
namespace HorseRacingPredictor.Football.API
|
||||
{
|
||||
/// <summary>
|
||||
/// Client per l'endpoint "status" dell'API-Football.
|
||||
/// Restituisce la quota residua giornaliera e le informazioni sull'account.
|
||||
/// Non conta come chiamata nella quota giornaliera.
|
||||
/// </summary>
|
||||
internal class Status : HorseRacingPredictor.Football.Manager.API
|
||||
{
|
||||
private const string Endpoint = "status";
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene lo stato dell'account e la quota residua
|
||||
/// </summary>
|
||||
public RestResponse GetStatus()
|
||||
{
|
||||
try
|
||||
{
|
||||
return ExecuteRequest(Endpoint);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"Errore durante il recupero dello stato API: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace HorseRacingPredictor.Football
|
||||
{
|
||||
/// <summary>
|
||||
/// Parametri configurabili per controllare quali endpoint API-Football scaricare
|
||||
/// e come filtrare i dati risultanti.
|
||||
/// </summary>
|
||||
public class FootballDownloadOptions
|
||||
{
|
||||
// ?? Endpoint da scaricare ?????????????????????????????????
|
||||
public bool DownloadFixtures { get; set; } = true;
|
||||
public bool DownloadOdds { get; set; } = true;
|
||||
public bool DownloadPredictions { get; set; } = true;
|
||||
public bool DownloadStandings { get; set; } = false;
|
||||
public bool DownloadH2H { get; set; } = false;
|
||||
public bool DownloadEvents { get; set; } = false;
|
||||
public bool DownloadLineups { get; set; } = false;
|
||||
public bool DownloadStatistics { get; set; } = false;
|
||||
public bool DownloadInjuries { get; set; } = false;
|
||||
|
||||
// ?? Filtri ????????????????????????????????????????????????
|
||||
/// <summary>
|
||||
/// Se non vuoto, scarica fixture solo per queste leghe (league IDs).
|
||||
/// Lista vuota = tutte le leghe.
|
||||
/// </summary>
|
||||
public List<int> LeagueIds { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// ID del bookmaker per le quote (default 8 = Bet365).
|
||||
/// </summary>
|
||||
public int BookmakerId { get; set; } = 8;
|
||||
|
||||
/// <summary>
|
||||
/// Numero massimo di pagine da scaricare per le quote.
|
||||
/// </summary>
|
||||
public int OddsMaxPages { get; set; } = 3;
|
||||
|
||||
/// <summary>
|
||||
/// Timezone IANA per le date delle fixture (es. "Europe/Rome").
|
||||
/// </summary>
|
||||
public string Timezone { get; set; } = "Europe/Rome";
|
||||
|
||||
/// <summary>
|
||||
/// Stagione corrente per le classifiche (calcolata automaticamente se 0).
|
||||
/// </summary>
|
||||
public int Season { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Numero massimo di fixture per cui scaricare dati aggiuntivi
|
||||
/// (H2H, events, lineups, statistics) per evitare troppe chiamate.
|
||||
/// 0 = nessun limite.
|
||||
/// </summary>
|
||||
public int MaxFixturesForDetails { get; set; } = 50;
|
||||
|
||||
/// <summary>
|
||||
/// Ritardo in millisecondi tra una chiamata API e l'altra per rispettare il rate limit.
|
||||
/// </summary>
|
||||
public int ApiDelayMs { get; set; } = 300;
|
||||
|
||||
/// <summary>
|
||||
/// Se true, controlla la quota residua prima di iniziare e si ferma quando insufficiente.
|
||||
/// </summary>
|
||||
public bool CheckQuota { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Numero minimo di richieste residue prima di fermare il download.
|
||||
/// </summary>
|
||||
public int MinRemainingQuota { get; set; } = 10;
|
||||
|
||||
/// <summary>
|
||||
/// Restituisce la stagione corrente calcolata (anno corrente o anno-1 se prima di luglio).
|
||||
/// </summary>
|
||||
public int GetEffectiveSeason()
|
||||
{
|
||||
if (Season > 0) return Season;
|
||||
var now = System.DateTime.Now;
|
||||
return now.Month >= 7 ? now.Year : now.Year - 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Conta il numero approssimativo di chiamate API previste per una data.
|
||||
/// Utile per mostrare all'utente una stima.
|
||||
/// </summary>
|
||||
public int EstimateApiCalls(int fixtureCount)
|
||||
{
|
||||
int calls = 0;
|
||||
if (DownloadFixtures) calls += 1;
|
||||
if (DownloadOdds) calls += OddsMaxPages;
|
||||
if (DownloadPredictions) calls += fixtureCount;
|
||||
if (DownloadStandings && LeagueIds.Count > 0) calls += LeagueIds.Count;
|
||||
else if (DownloadStandings) calls += 5; // stima
|
||||
if (DownloadH2H) calls += fixtureCount;
|
||||
if (DownloadEvents) calls += fixtureCount;
|
||||
if (DownloadLineups) calls += fixtureCount;
|
||||
if (DownloadStatistics) calls += fixtureCount;
|
||||
if (DownloadInjuries) calls += 1;
|
||||
if (CheckQuota) calls += 1; // status endpoint
|
||||
return calls;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,7 @@ namespace HorseRacingPredictor
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
||||
};
|
||||
|
||||
// ?? Football ????????????????????????????????????????????
|
||||
// ?? Football ??????????????????????????????????????????
|
||||
public string ApiKey { get; set; } = string.Empty;
|
||||
public string FbExportPath { get; set; } = string.Empty;
|
||||
public string FbPrefix { get; set; } = string.Empty;
|
||||
@@ -30,7 +30,27 @@ namespace HorseRacingPredictor
|
||||
public string FbDateFormat { get; set; } = "yyyy-MM-dd";
|
||||
public string FbFormat { get; set; } = "CSV";
|
||||
|
||||
// ?? Racing ??????????????????????????????????????????????
|
||||
// ?? Football Download Options ????????????????????????????
|
||||
public bool FbDownloadFixtures { get; set; } = true;
|
||||
public bool FbDownloadOdds { get; set; } = true;
|
||||
public bool FbDownloadPredictions { get; set; } = true;
|
||||
public bool FbDownloadStandings { get; set; } = false;
|
||||
public bool FbDownloadH2H { get; set; } = false;
|
||||
public bool FbDownloadEvents { get; set; } = false;
|
||||
public bool FbDownloadLineups { get; set; } = false;
|
||||
public bool FbDownloadStatistics { get; set; } = false;
|
||||
public bool FbDownloadInjuries { get; set; } = false;
|
||||
public List<int> FbLeagueIds { get; set; } = new();
|
||||
public int FbBookmakerId { get; set; } = 8;
|
||||
public int FbOddsMaxPages { get; set; } = 3;
|
||||
public string FbTimezone { get; set; } = "Europe/Rome";
|
||||
public int FbSeason { get; set; } = 0;
|
||||
public int FbMaxFixturesForDetails { get; set; } = 50;
|
||||
public int FbApiDelayMs { get; set; } = 300;
|
||||
public bool FbCheckQuota { get; set; } = true;
|
||||
public int FbMinRemainingQuota { get; set; } = 10;
|
||||
|
||||
// ?? Racing ???????????????????????????????????????????????
|
||||
public string RacingApiKey { get; set; } = string.Empty;
|
||||
public string RcExportPath { get; set; } = string.Empty;
|
||||
public string RcPrefix { get; set; } = string.Empty;
|
||||
@@ -41,7 +61,35 @@ namespace HorseRacingPredictor
|
||||
public string RcTimezone { get; set; } = "Australia/Sydney";
|
||||
public List<string> RcCountries { get; set; } = new() { "au", "nz" };
|
||||
|
||||
// ?? Persistence ?????????????????????????????????????????
|
||||
// ?? Persistence ??????????????????????????????????????
|
||||
|
||||
/// <summary>
|
||||
/// Costruisce un FootballDownloadOptions a partire dalle impostazioni salvate.
|
||||
/// </summary>
|
||||
public Football.FootballDownloadOptions ToFootballDownloadOptions()
|
||||
{
|
||||
return new Football.FootballDownloadOptions
|
||||
{
|
||||
DownloadFixtures = FbDownloadFixtures,
|
||||
DownloadOdds = FbDownloadOdds,
|
||||
DownloadPredictions = FbDownloadPredictions,
|
||||
DownloadStandings = FbDownloadStandings,
|
||||
DownloadH2H = FbDownloadH2H,
|
||||
DownloadEvents = FbDownloadEvents,
|
||||
DownloadLineups = FbDownloadLineups,
|
||||
DownloadStatistics = FbDownloadStatistics,
|
||||
DownloadInjuries = FbDownloadInjuries,
|
||||
LeagueIds = new List<int>(FbLeagueIds),
|
||||
BookmakerId = FbBookmakerId,
|
||||
OddsMaxPages = FbOddsMaxPages,
|
||||
Timezone = FbTimezone,
|
||||
Season = FbSeason,
|
||||
MaxFixturesForDetails = FbMaxFixturesForDetails,
|
||||
ApiDelayMs = FbApiDelayMs,
|
||||
CheckQuota = FbCheckQuota,
|
||||
MinRemainingQuota = FbMinRemainingQuota
|
||||
};
|
||||
}
|
||||
|
||||
public static UserSettings Load()
|
||||
{
|
||||
|
||||
@@ -765,6 +765,85 @@
|
||||
Foreground="{StaticResource BrText}"
|
||||
Click="btnBrowseFbExport_Click"/>
|
||||
</Grid>
|
||||
|
||||
<!-- ?? OPZIONI DOWNLOAD ENDPOINT ?? -->
|
||||
<Border Height="1" Background="{StaticResource BrBorder}" Margin="0,16,0,14"/>
|
||||
<TextBlock Text="Endpoint da scaricare" FontSize="13" FontFamily="Segoe UI Semibold"
|
||||
Foreground="{StaticResource BrText}" Margin="0,0,0,10"/>
|
||||
|
||||
<WrapPanel Orientation="Horizontal">
|
||||
<CheckBox x:Name="chkFbFixtures" IsChecked="True" Margin="0,0,16,6">Partite</CheckBox>
|
||||
<CheckBox x:Name="chkFbOdds" IsChecked="True" Margin="0,0,16,6">Quote</CheckBox>
|
||||
<CheckBox x:Name="chkFbPredictions" IsChecked="True" Margin="0,0,16,6">Previsioni</CheckBox>
|
||||
<CheckBox x:Name="chkFbStandings" Margin="0,0,16,6">Classifiche</CheckBox>
|
||||
<CheckBox x:Name="chkFbH2H" Margin="0,0,16,6">Scontri diretti</CheckBox>
|
||||
<CheckBox x:Name="chkFbEvents" Margin="0,0,16,6">Eventi</CheckBox>
|
||||
<CheckBox x:Name="chkFbLineups" Margin="0,0,16,6">Formazioni</CheckBox>
|
||||
<CheckBox x:Name="chkFbStatistics" Margin="0,0,16,6">Statistiche</CheckBox>
|
||||
<CheckBox x:Name="chkFbInjuries" Margin="0,0,16,6">Infortuni</CheckBox>
|
||||
</WrapPanel>
|
||||
|
||||
<!-- ?? PARAMETRI AVANZATI ?? -->
|
||||
<Border Height="1" Background="{StaticResource BrBorder}" Margin="0,10,0,14"/>
|
||||
<TextBlock Text="Parametri avanzati" FontSize="13" FontFamily="Segoe UI Semibold"
|
||||
Foreground="{StaticResource BrText}" Margin="0,0,0,10"/>
|
||||
|
||||
<Grid Margin="0,0,0,8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="165"/>
|
||||
<ColumnDefinition Width="22"/>
|
||||
<ColumnDefinition Width="165"/>
|
||||
<ColumnDefinition Width="22"/>
|
||||
<ColumnDefinition Width="165"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Text="ID Bookmaker" Foreground="{StaticResource BrSubtext0}" FontSize="11" Margin="0,0,0,4"/>
|
||||
<TextBox x:Name="txtFbBookmakerId" Style="{StaticResource FlatTb}" Text="8"/>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2">
|
||||
<TextBlock Text="Max pagine quote" Foreground="{StaticResource BrSubtext0}" FontSize="11" Margin="0,0,0,4"/>
|
||||
<TextBox x:Name="txtFbOddsMaxPages" Style="{StaticResource FlatTb}" Text="3"/>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="4">
|
||||
<TextBlock Text="Max fixture dettagli" Foreground="{StaticResource BrSubtext0}" FontSize="11" Margin="0,0,0,4"/>
|
||||
<TextBox x:Name="txtFbMaxFixtures" Style="{StaticResource FlatTb}" Text="50"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Grid Margin="0,0,0,8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="245"/>
|
||||
<ColumnDefinition Width="22"/>
|
||||
<ColumnDefinition Width="245"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Text="Timezone" Foreground="{StaticResource BrSubtext0}" FontSize="11" Margin="0,0,0,4"/>
|
||||
<TextBox x:Name="txtFbTimezone" Style="{StaticResource FlatTb}" Text="Europe/Rome"/>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2">
|
||||
<TextBlock Text="ID Leghe (separati da virgola, vuoto = tutte)" Foreground="{StaticResource BrSubtext0}" FontSize="11" Margin="0,0,0,4"/>
|
||||
<TextBox x:Name="txtFbLeagueIds" Style="{StaticResource FlatTb}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Grid Margin="0,0,0,4">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="22"/>
|
||||
<ColumnDefinition Width="165"/>
|
||||
<ColumnDefinition Width="22"/>
|
||||
<ColumnDefinition Width="165"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<CheckBox x:Name="chkFbCheckQuota" Grid.Column="0" IsChecked="True">Controlla quota</CheckBox>
|
||||
<StackPanel Grid.Column="2">
|
||||
<TextBlock Text="Quota minima residua" Foreground="{StaticResource BrSubtext0}" FontSize="11" Margin="0,0,0,4"/>
|
||||
<TextBox x:Name="txtFbMinQuota" Style="{StaticResource FlatTb}" Text="10"/>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="4">
|
||||
<TextBlock Text="Delay API (ms)" Foreground="{StaticResource BrSubtext0}" FontSize="11" Margin="0,0,0,4"/>
|
||||
<TextBox x:Name="txtFbApiDelay" Style="{StaticResource FlatTb}" Text="300"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
|
||||
@@ -266,23 +266,32 @@ namespace HorseRacingPredictor
|
||||
try
|
||||
{
|
||||
pbFootball.Value = 0;
|
||||
lblStatusFb.Text = "Scaricamento elenco partite…";
|
||||
lblStatusFb.Text = "Preparazione opzioni di download…";
|
||||
btnDownloadFb.IsEnabled = false;
|
||||
dpFootball.IsEnabled = false;
|
||||
btnExportFbCsv.IsEnabled = false;
|
||||
|
||||
// Costruisci le opzioni di download dalla UI
|
||||
var options = BuildFootballDownloadOptions();
|
||||
|
||||
var progress = new Progress<int>(v => pbFootball.Value = v);
|
||||
var status = new Progress<string>(s => lblStatusFb.Text = s);
|
||||
|
||||
var table = await Task.Run(() =>
|
||||
_footballManager.GetTodayFixtures(date, progress, status));
|
||||
_footballManager.GetTodayFixtures(date, options, progress, status));
|
||||
|
||||
_footballData = table;
|
||||
|
||||
// Ensure the start time column exists and populate it (no timezone label)
|
||||
InjectRomeStartTimeColumn(_footballData, "Inizio");
|
||||
|
||||
// Nascondi le colonne interne (ID di supporto) dal DataGrid
|
||||
dgFootball.ItemsSource = _footballData?.DefaultView;
|
||||
dgFootball.AutoGeneratingColumn += (s, e) =>
|
||||
{
|
||||
if (e.PropertyName is "LeagueId" or "HomeTeamId" or "AwayTeamId")
|
||||
e.Cancel = true;
|
||||
};
|
||||
|
||||
if (_footballData != null && _footballData.Rows.Count > 0)
|
||||
{
|
||||
@@ -847,6 +856,26 @@ namespace HorseRacingPredictor
|
||||
SetComboBoxSelectionByContent(cmbFbDateFormat, s.FbDateFormat);
|
||||
SetComboBoxSelectionByContent(cmbFbFormat, s.FbFormat);
|
||||
|
||||
// Football Download Options
|
||||
chkFbFixtures.IsChecked = s.FbDownloadFixtures;
|
||||
chkFbOdds.IsChecked = s.FbDownloadOdds;
|
||||
chkFbPredictions.IsChecked = s.FbDownloadPredictions;
|
||||
chkFbStandings.IsChecked = s.FbDownloadStandings;
|
||||
chkFbH2H.IsChecked = s.FbDownloadH2H;
|
||||
chkFbEvents.IsChecked = s.FbDownloadEvents;
|
||||
chkFbLineups.IsChecked = s.FbDownloadLineups;
|
||||
chkFbStatistics.IsChecked = s.FbDownloadStatistics;
|
||||
chkFbInjuries.IsChecked = s.FbDownloadInjuries;
|
||||
txtFbBookmakerId.Text = s.FbBookmakerId.ToString();
|
||||
txtFbOddsMaxPages.Text = s.FbOddsMaxPages.ToString();
|
||||
txtFbMaxFixtures.Text = s.FbMaxFixturesForDetails.ToString();
|
||||
if (txtFbTimezone != null) txtFbTimezone.Text = s.FbTimezone;
|
||||
txtFbLeagueIds.Text = s.FbLeagueIds.Count > 0 ? string.Join(",", s.FbLeagueIds) : "";
|
||||
chkFbCheckQuota.IsChecked = s.FbCheckQuota;
|
||||
txtFbMinQuota.Text = s.FbMinRemainingQuota.ToString();
|
||||
txtFbApiDelay.Text = s.FbApiDelayMs.ToString();
|
||||
|
||||
// Racing
|
||||
txtRcExportPath.Text = s.RcExportPath;
|
||||
txtRcPrefix.Text = s.RcPrefix;
|
||||
txtRcSuffix.Text = s.RcSuffix;
|
||||
@@ -1091,6 +1120,10 @@ namespace HorseRacingPredictor
|
||||
{
|
||||
try
|
||||
{
|
||||
// Costruisci e salva le opzioni di download in un FootballDownloadOptions
|
||||
// per validazione prima del salvataggio
|
||||
var options = BuildFootballDownloadOptions();
|
||||
|
||||
var s = new UserSettings
|
||||
{
|
||||
ApiKey = txtApiKey.Text.Trim(),
|
||||
@@ -1100,6 +1133,25 @@ namespace HorseRacingPredictor
|
||||
FbIncludeDate = chkFbIncludeDate.IsChecked == true,
|
||||
FbDateFormat = (cmbFbDateFormat?.SelectedItem as ComboBoxItem)?.Content?.ToString() ?? "yyyy-MM-dd",
|
||||
FbFormat = (cmbFbFormat?.SelectedItem as ComboBoxItem)?.Content?.ToString() ?? "CSV",
|
||||
// Football Download Options
|
||||
FbDownloadFixtures = chkFbFixtures.IsChecked == true,
|
||||
FbDownloadOdds = chkFbOdds.IsChecked == true,
|
||||
FbDownloadPredictions = chkFbPredictions.IsChecked == true,
|
||||
FbDownloadStandings = chkFbStandings.IsChecked == true,
|
||||
FbDownloadH2H = chkFbH2H.IsChecked == true,
|
||||
FbDownloadEvents = chkFbEvents.IsChecked == true,
|
||||
FbDownloadLineups = chkFbLineups.IsChecked == true,
|
||||
FbDownloadStatistics = chkFbStatistics.IsChecked == true,
|
||||
FbDownloadInjuries = chkFbInjuries.IsChecked == true,
|
||||
FbBookmakerId = int.TryParse(txtFbBookmakerId.Text.Trim(), out var bId) ? bId : 8,
|
||||
FbOddsMaxPages = int.TryParse(txtFbOddsMaxPages.Text.Trim(), out var omp) ? omp : 3,
|
||||
FbMaxFixturesForDetails = int.TryParse(txtFbMaxFixtures.Text.Trim(), out var mf) ? mf : 50,
|
||||
FbTimezone = txtFbTimezone?.Text?.Trim() ?? "Europe/Rome",
|
||||
FbLeagueIds = ParseIntList(txtFbLeagueIds?.Text),
|
||||
FbCheckQuota = chkFbCheckQuota.IsChecked == true,
|
||||
FbMinRemainingQuota = int.TryParse(txtFbMinQuota.Text.Trim(), out var mq) ? mq : 10,
|
||||
FbApiDelayMs = int.TryParse(txtFbApiDelay.Text.Trim(), out var ad) ? ad : 300,
|
||||
// Racing
|
||||
RcExportPath = txtRcExportPath.Text.Trim(),
|
||||
RcPrefix = txtRcPrefix.Text.Trim(),
|
||||
RcSuffix = txtRcSuffix.Text.Trim(),
|
||||
@@ -1126,6 +1178,50 @@ namespace HorseRacingPredictor
|
||||
}
|
||||
}
|
||||
|
||||
// ???????????? FOOTBALL DOWNLOAD OPTIONS HELPERS ????????????
|
||||
|
||||
/// <summary>
|
||||
/// Costruisce un FootballDownloadOptions leggendo i valori dalla UI.
|
||||
/// </summary>
|
||||
private Football.FootballDownloadOptions BuildFootballDownloadOptions()
|
||||
{
|
||||
return new Football.FootballDownloadOptions
|
||||
{
|
||||
DownloadFixtures = chkFbFixtures.IsChecked == true,
|
||||
DownloadOdds = chkFbOdds.IsChecked == true,
|
||||
DownloadPredictions = chkFbPredictions.IsChecked == true,
|
||||
DownloadStandings = chkFbStandings.IsChecked == true,
|
||||
DownloadH2H = chkFbH2H.IsChecked == true,
|
||||
DownloadEvents = chkFbEvents.IsChecked == true,
|
||||
DownloadLineups = chkFbLineups.IsChecked == true,
|
||||
DownloadStatistics = chkFbStatistics.IsChecked == true,
|
||||
DownloadInjuries = chkFbInjuries.IsChecked == true,
|
||||
BookmakerId = int.TryParse(txtFbBookmakerId.Text.Trim(), out var bId) ? bId : 8,
|
||||
OddsMaxPages = int.TryParse(txtFbOddsMaxPages.Text.Trim(), out var omp) ? omp : 3,
|
||||
MaxFixturesForDetails = int.TryParse(txtFbMaxFixtures.Text.Trim(), out var mf) ? mf : 50,
|
||||
Timezone = txtFbTimezone?.Text?.Trim() ?? "Europe/Rome",
|
||||
LeagueIds = ParseIntList(txtFbLeagueIds?.Text),
|
||||
CheckQuota = chkFbCheckQuota.IsChecked == true,
|
||||
MinRemainingQuota = int.TryParse(txtFbMinQuota.Text.Trim(), out var mq) ? mq : 10,
|
||||
ApiDelayMs = int.TryParse(txtFbApiDelay.Text.Trim(), out var ad) ? ad : 300
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Analizza una stringa di interi separati da virgola e restituisce una lista.
|
||||
/// </summary>
|
||||
private static List<int> ParseIntList(string text)
|
||||
{
|
||||
var result = new List<int>();
|
||||
if (string.IsNullOrWhiteSpace(text)) return result;
|
||||
foreach (var part in text.Split(',', ';', ' '))
|
||||
{
|
||||
if (int.TryParse(part.Trim(), out var val))
|
||||
result.Add(val);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// ???????????????????????? VIRTUAL FOOTBALL ????????????????????????
|
||||
|
||||
private void btnVfbNavigate_Click(object sender, RoutedEventArgs e)
|
||||
|
||||
Reference in New Issue
Block a user