7b405ed78e
- Rimossa la sezione "Impostazioni Export" dalla UI e dal code-behind, inclusi controlli, eventi e file legacy di export. - Aggiunta configurazione del livello minimo di log (ErrorOnly, Normal, Informational, Debug, Trace) con guida e legenda colori. - La funzione di log ora filtra i messaggi in base al livello selezionato. - Aggiornati modelli di impostazioni e enum LogLevel per supportare i nuovi livelli. - Refactoring commenti e uniformità sezioni impostazioni. - Migliorata la chiarezza del log di avvio applicazione.
658 lines
28 KiB
C#
658 lines
28 KiB
C#
using System;
|
||
using System.Linq;
|
||
using System.Threading.Tasks;
|
||
using System.Windows;
|
||
using AutoBidder.Models;
|
||
using AutoBidder.ViewModels;
|
||
using AutoBidder.Utilities;
|
||
using AutoBidder.Services; // ? AGGIUNTO per RequestPriority e HtmlResponse
|
||
|
||
namespace AutoBidder
|
||
{
|
||
/// <summary>
|
||
/// Auction management: Add, Remove, Update
|
||
/// </summary>
|
||
public partial class MainWindow
|
||
{
|
||
private async Task AddAuctionById(string input)
|
||
{
|
||
try
|
||
{
|
||
if (string.IsNullOrWhiteSpace(input))
|
||
{
|
||
MessageBox.Show("Input non valido!", "Errore", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||
return;
|
||
}
|
||
|
||
string auctionId;
|
||
string? productName = null;
|
||
string originalUrl;
|
||
|
||
// Verifica se è un URL o solo un ID
|
||
if (input.Contains("bidoo.com") || input.Contains("http"))
|
||
{
|
||
// È un URL - estrai ID e nome prodotto dall'URL stesso
|
||
originalUrl = input.Trim();
|
||
auctionId = ExtractAuctionId(originalUrl);
|
||
if (string.IsNullOrEmpty(auctionId))
|
||
{
|
||
MessageBox.Show("Impossibile estrarre ID dall'URL!", "Errore", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||
return;
|
||
}
|
||
|
||
productName = ExtractProductName(originalUrl);
|
||
}
|
||
else
|
||
{
|
||
// È solo un ID numerico - costruisci URL generico
|
||
auctionId = input.Trim();
|
||
originalUrl = $"https://it.bidoo.com/auction.php?a=asta_{auctionId}";
|
||
}
|
||
|
||
// Verifica duplicati
|
||
if (_auctionViewModels.Any(a => a.AuctionId == auctionId))
|
||
{
|
||
MessageBox.Show("Asta già monitorata!", "Duplicato", MessageBoxButton.OK, MessageBoxImage.Information);
|
||
return;
|
||
}
|
||
|
||
// ? MODIFICATO: Nome senza ID (già nella colonna separata)
|
||
var displayName = string.IsNullOrEmpty(productName)
|
||
? $"Asta {auctionId}"
|
||
: DecodeAllHtmlEntities(productName);
|
||
|
||
// CARICA IMPOSTAZIONI PREDEFINITE SALVATE
|
||
var settings = Utilities.SettingsManager.Load();
|
||
|
||
// ? Determina stato iniziale dalla configurazione
|
||
bool isActive = false;
|
||
bool isPaused = false;
|
||
|
||
switch (settings.DefaultNewAuctionState)
|
||
{
|
||
case "Active":
|
||
isActive = true;
|
||
isPaused = false;
|
||
break;
|
||
case "Paused":
|
||
isActive = true;
|
||
isPaused = true;
|
||
break;
|
||
case "Stopped":
|
||
default:
|
||
isActive = false;
|
||
isPaused = false;
|
||
break;
|
||
}
|
||
|
||
// Crea model con valori dalle impostazioni salvate e stato configurato
|
||
var auction = new AuctionInfo
|
||
{
|
||
AuctionId = auctionId,
|
||
Name = DecodeAllHtmlEntities(displayName),
|
||
OriginalUrl = originalUrl,
|
||
BidBeforeDeadlineMs = settings.DefaultBidBeforeDeadlineMs,
|
||
CheckAuctionOpenBeforeBid = settings.DefaultCheckAuctionOpenBeforeBid,
|
||
IsActive = isActive,
|
||
IsPaused = isPaused
|
||
};
|
||
|
||
// Aggiungi al monitor
|
||
_auctionMonitor.AddAuction(auction);
|
||
|
||
// Crea ViewModel con valori dalle impostazioni
|
||
var vm = new AuctionViewModel(auction)
|
||
{
|
||
MinPrice = settings.DefaultMinPrice,
|
||
MaxPrice = settings.DefaultMaxPrice,
|
||
MaxClicks = settings.DefaultMaxClicks
|
||
};
|
||
_auctionViewModels.Add(vm);
|
||
|
||
// ? Auto-start del monitoraggio se l'asta è attiva e il monitoraggio è fermo
|
||
if (isActive && !_isAutomationActive)
|
||
{
|
||
_auctionMonitor.Start();
|
||
_isAutomationActive = true;
|
||
Log($"[AUTO-START] Monitoraggio avviato automaticamente per nuova asta: {vm.Name}", LogLevel.Info);
|
||
}
|
||
|
||
SaveAuctions();
|
||
UpdateTotalCount();
|
||
UpdateGlobalControlButtons();
|
||
|
||
var stateText = isActive ? (isPaused ? "Paused" : "Active") : "Stopped";
|
||
Log($"[ADD] Asta aggiunta con stato={stateText}, Anticipo={settings.DefaultBidBeforeDeadlineMs}ms", Utilities.LogLevel.Info);
|
||
|
||
// ? NUOVO: Se il nome non è stato estratto, recuperalo in background DOPO l'aggiunta
|
||
if (string.IsNullOrEmpty(productName))
|
||
{
|
||
_ = FetchAuctionNameInBackgroundAsync(auction, vm);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Log($"Errore aggiunta asta: {ex.Message}");
|
||
MessageBox.Show($"Errore: {ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Recupera il nome dell'asta in background e aggiorna l'UI quando completa
|
||
/// </summary>
|
||
private async Task FetchAuctionNameInBackgroundAsync(AuctionInfo auction, AuctionViewModel vm)
|
||
{
|
||
try
|
||
{
|
||
// ? USA IL SERVIZIO CENTRALIZZATO invece di HttpClient diretto
|
||
var response = await _htmlCacheService.GetHtmlAsync(
|
||
auction.OriginalUrl,
|
||
RequestPriority.Normal,
|
||
bypassCache: false // Usa cache se disponibile
|
||
);
|
||
|
||
if (!response.Success)
|
||
{
|
||
Log($"[WARN] Impossibile recuperare nome per asta {auction.AuctionId}: {response.Error}", LogLevel.Warning);
|
||
return;
|
||
}
|
||
|
||
// Estrai nome dal <title>
|
||
var match = System.Text.RegularExpressions.Regex.Match(response.Html, @"<title>([^<]+)</title>");
|
||
|
||
if (match.Success)
|
||
{
|
||
var productName = match.Groups[1].Value.Trim().Replace(" - Bidoo", "");
|
||
// ? Decodifica entity HTML (incluse quelle non standard)
|
||
productName = DecodeAllHtmlEntities(productName);
|
||
// ? MODIFICATO: Nome senza ID
|
||
var newName = productName;
|
||
|
||
// Aggiorna il nome su thread UI
|
||
Dispatcher.Invoke(() =>
|
||
{
|
||
auction.Name = newName;
|
||
// Forza refresh della griglia per mostrare il nuovo nome
|
||
var tempSource = MultiAuctionsGrid.ItemsSource;
|
||
MultiAuctionsGrid.ItemsSource = null;
|
||
MultiAuctionsGrid.ItemsSource = tempSource;
|
||
SaveAuctions(); // Salva il nome aggiornato
|
||
Log($"[NAME] Nome recuperato per asta {auction.AuctionId}: {productName}{(response.FromCache ? " (cached)" : "")}", LogLevel.Info);
|
||
});
|
||
}
|
||
else
|
||
{
|
||
Log($"[WARN] Nome non trovato nell'HTML per asta {auction.AuctionId}", LogLevel.Warning);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Log($"[WARN] Errore recupero nome per asta {auction.AuctionId}: {ex.Message}", LogLevel.Warning);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Decodifica tutte le entity HTML, incluse quelle non standard come +
|
||
/// </summary>
|
||
private string DecodeAllHtmlEntities(string text)
|
||
{
|
||
if (string.IsNullOrEmpty(text))
|
||
return text;
|
||
|
||
// Prima decodifica entity standard
|
||
var decoded = System.Net.WebUtility.HtmlDecode(text);
|
||
|
||
// ? Poi sostituisci entity non standard che WebUtility.HtmlDecode non gestisce
|
||
decoded = decoded.Replace("+", "+");
|
||
decoded = decoded.Replace("=", "=");
|
||
decoded = decoded.Replace("−", "-");
|
||
decoded = decoded.Replace("×", "×");
|
||
decoded = decoded.Replace("÷", "÷");
|
||
decoded = decoded.Replace("%", "%");
|
||
decoded = decoded.Replace("$", "$");
|
||
decoded = decoded.Replace("€", "€");
|
||
decoded = decoded.Replace("£", "£");
|
||
|
||
return decoded;
|
||
}
|
||
|
||
private async Task AddAuctionFromUrl(string url)
|
||
{
|
||
try
|
||
{
|
||
if (!IsValidAuctionUrl(url))
|
||
{
|
||
MessageBox.Show("URL asta non valido!", "Errore", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||
return;
|
||
}
|
||
|
||
var auctionId = ExtractAuctionId(url);
|
||
if (string.IsNullOrEmpty(auctionId))
|
||
{
|
||
MessageBox.Show("Impossibile estrarre ID asta!", "Errore", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||
return;
|
||
}
|
||
|
||
// Verifica duplicati
|
||
if (_auctionViewModels.Any(a => a.AuctionId == auctionId))
|
||
{
|
||
MessageBox.Show("Asta già monitorata!", "Duplicato", MessageBoxButton.OK, MessageBoxImage.Information);
|
||
return;
|
||
}
|
||
|
||
// Fetch nome (opzionale)
|
||
var name = $"Asta {auctionId}";
|
||
try
|
||
{
|
||
// ? USA IL SERVIZIO CENTRALIZZATO
|
||
var response = await _htmlCacheService.GetHtmlAsync(url, RequestPriority.Normal);
|
||
|
||
if (response.Success)
|
||
{
|
||
var match2 = System.Text.RegularExpressions.Regex.Match(response.Html, @"<title>([^<]+)</title>");
|
||
if (match2.Success)
|
||
{
|
||
name = DecodeAllHtmlEntities(match2.Groups[1].Value.Trim().Replace(" - Bidoo", ""));
|
||
}
|
||
}
|
||
}
|
||
catch { }
|
||
|
||
// CARICA IMPOSTAZIONI PREDEFINITE SALVATE
|
||
var settings = Utilities.SettingsManager.Load();
|
||
|
||
// ? Determina stato iniziale dalla configurazione
|
||
bool isActive = false;
|
||
bool isPaused = false;
|
||
|
||
switch (settings.DefaultNewAuctionState)
|
||
{
|
||
case "Active":
|
||
isActive = true;
|
||
isPaused = false;
|
||
break;
|
||
case "Paused":
|
||
isActive = true;
|
||
isPaused = true;
|
||
break;
|
||
case "Stopped":
|
||
default:
|
||
isActive = false;
|
||
isPaused = false;
|
||
break;
|
||
}
|
||
|
||
// Crea model con valori dalle impostazioni salvate e stato configurato
|
||
var auction = new AuctionInfo
|
||
{
|
||
AuctionId = auctionId,
|
||
Name = DecodeAllHtmlEntities(name),
|
||
OriginalUrl = url,
|
||
BidBeforeDeadlineMs = settings.DefaultBidBeforeDeadlineMs,
|
||
CheckAuctionOpenBeforeBid = settings.DefaultCheckAuctionOpenBeforeBid,
|
||
IsActive = isActive,
|
||
IsPaused = isPaused
|
||
};
|
||
|
||
// Aggiungi al monitor
|
||
_auctionMonitor.AddAuction(auction);
|
||
|
||
// Crea ViewModel con valori dalle impostazioni
|
||
var vm = new AuctionViewModel(auction)
|
||
{
|
||
MinPrice = settings.DefaultMinPrice,
|
||
MaxPrice = settings.DefaultMaxPrice,
|
||
MaxClicks = settings.DefaultMaxClicks
|
||
};
|
||
_auctionViewModels.Add(vm);
|
||
|
||
// ? Auto-start del monitoraggio se l'asta è attiva e il monitoraggio è fermo
|
||
if (isActive && !_isAutomationActive)
|
||
{
|
||
_auctionMonitor.Start();
|
||
_isAutomationActive = true;
|
||
Log($"[AUTO-START] Monitoraggio avviato automaticamente per nuova asta: {vm.Name}", LogLevel.Info);
|
||
}
|
||
|
||
SaveAuctions();
|
||
UpdateTotalCount();
|
||
UpdateGlobalControlButtons();
|
||
|
||
var stateText = isActive ? (isPaused ? "Paused" : "Active") : "Stopped";
|
||
Log($"[ADD] Asta aggiunta con stato={stateText}, Anticipo={settings.DefaultBidBeforeDeadlineMs}ms", Utilities.LogLevel.Info);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Log($"[ERRORE] Errore aggiunta asta: {ex.Message}");
|
||
MessageBox.Show($"Errore: {ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Aggiorna manualmente il nome di un'asta recuperandolo dall'HTML
|
||
/// </summary>
|
||
public async Task RefreshAuctionNameAsync(AuctionViewModel vm)
|
||
{
|
||
if (vm == null) return;
|
||
|
||
try
|
||
{
|
||
Log($"[NAME REFRESH] Aggiornamento nome per: {vm.Name}", LogLevel.Info);
|
||
await FetchAuctionNameInBackgroundAsync(vm.AuctionInfo, vm);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Log($"[ERRORE] Refresh nome asta: {ex.Message}", LogLevel.Error);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Controlla se ci sono aste con nomi generici e prova a recuperarli dopo un delay
|
||
/// </summary>
|
||
private async Task RetryFailedAuctionNamesAsync()
|
||
{
|
||
try
|
||
{
|
||
// Aspetta 30 secondi prima di ritentare (dà tempo alle altre richieste di completare)
|
||
await System.Threading.Tasks.Task.Delay(TimeSpan.FromSeconds(30));
|
||
|
||
// Trova aste con nomi generici "Asta XXXX"
|
||
var auctionsWithGenericNames = _auctionViewModels
|
||
.Where(vm => vm.Name.StartsWith("Asta ") && !vm.Name.Contains("Shop") && !vm.Name.Contains("€"))
|
||
.ToList();
|
||
|
||
if (auctionsWithGenericNames.Count > 0)
|
||
{
|
||
Log($"[NAME RETRY] Trovate {auctionsWithGenericNames.Count} aste con nomi generici. Ritento recupero...", LogLevel.Info);
|
||
|
||
// Ritenta il recupero per ognuna (con delay tra una e l'altra per non sovraccaricare)
|
||
foreach (var vm in auctionsWithGenericNames)
|
||
{
|
||
await FetchAuctionNameInBackgroundAsync(vm.AuctionInfo, vm);
|
||
await System.Threading.Tasks.Task.Delay(2000); // 2 secondi tra una richiesta e l'altra
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Log($"[WARN] Errore retry nomi aste: {ex.Message}", LogLevel.Warning);
|
||
}
|
||
}
|
||
|
||
private void SaveAuctions()
|
||
{
|
||
try
|
||
{
|
||
var auctions = _auctionMonitor.GetAuctions();
|
||
Utilities.PersistenceManager.SaveAuctions(auctions);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Log($"[ERRORE] Errore salvataggio: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
private void LoadSavedAuctions()
|
||
{
|
||
try
|
||
{
|
||
// ? Carica impostazioni
|
||
var settings = Utilities.SettingsManager.Load();
|
||
|
||
// Ottieni username corrente dalla sessione per ripristinare IsMyBid
|
||
var session = _auctionMonitor.GetSession();
|
||
var currentUsername = session?.Username ?? string.Empty;
|
||
|
||
var auctions = Utilities.PersistenceManager.LoadAuctions();
|
||
foreach (var auction in auctions)
|
||
{
|
||
// Protezione: rimuovi eventuali BidHistory null
|
||
auction.BidHistory = auction.BidHistory?.Where(b => b != null).ToList() ?? new System.Collections.Generic.List<BidHistory>();
|
||
|
||
// ? Decode HTML entities (incluse quelle non standard)
|
||
try { auction.Name = DecodeAllHtmlEntities(auction.Name ?? string.Empty); } catch { }
|
||
|
||
// ? Ripristina IsMyBid per tutte le puntate in RecentBids
|
||
if (auction.RecentBids != null && auction.RecentBids.Count > 0 && !string.IsNullOrEmpty(currentUsername))
|
||
{
|
||
foreach (var bid in auction.RecentBids)
|
||
{
|
||
bid.IsMyBid = bid.Username.Equals(currentUsername, StringComparison.OrdinalIgnoreCase);
|
||
}
|
||
}
|
||
|
||
|
||
// ? NUOVO: Gestione stato in base a RememberAuctionStates
|
||
if (settings.RememberAuctionStates)
|
||
{
|
||
// MODO 1: Ripristina lo stato salvato di ogni asta (IsActive e IsPaused vengono dal file salvato)
|
||
// Non serve fare nulla, lo stato è già quello salvato nel file
|
||
}
|
||
else
|
||
{
|
||
// MODO 2: Applica DefaultStartAuctionsOnLoad a tutte le aste
|
||
var loadState = settings.DefaultStartAuctionsOnLoad;
|
||
switch (loadState)
|
||
{
|
||
case "Active":
|
||
auction.IsActive = true;
|
||
auction.IsPaused = false;
|
||
break;
|
||
case "Paused":
|
||
auction.IsActive = true;
|
||
auction.IsPaused = true;
|
||
break;
|
||
case "Stopped":
|
||
default:
|
||
auction.IsActive = false;
|
||
auction.IsPaused = false;
|
||
break;
|
||
}
|
||
}
|
||
|
||
_auctionMonitor.AddAuction(auction);
|
||
var vm = new AuctionViewModel(auction);
|
||
_auctionViewModels.Add(vm);
|
||
}
|
||
|
||
// ? Avvia monitoraggio se ci sono aste in stato Active O Paused
|
||
bool hasActiveOrPausedAuctions = auctions.Any(a => a.IsActive);
|
||
|
||
if (hasActiveOrPausedAuctions && auctions.Count > 0)
|
||
{
|
||
_auctionMonitor.Start();
|
||
_isAutomationActive = true;
|
||
|
||
if (settings.RememberAuctionStates)
|
||
{
|
||
var activeCount = auctions.Count(a => a.IsActive && !a.IsPaused);
|
||
var pausedCount = auctions.Count(a => a.IsActive && a.IsPaused);
|
||
Log($"[AUTO-START] Monitoraggio avviato: {activeCount} attive, {pausedCount} in pausa (stati ripristinati)", LogLevel.Info);
|
||
}
|
||
else
|
||
{
|
||
var loadState = settings.DefaultStartAuctionsOnLoad;
|
||
if (loadState == "Active")
|
||
{
|
||
Log($"[AUTO-START] Monitoraggio avviato automaticamente per {auctions.Count} aste caricate in stato attivo", LogLevel.Info);
|
||
}
|
||
else if (loadState == "Paused")
|
||
{
|
||
Log($"[AUTO-START] Monitoraggio avviato automaticamente per {auctions.Count} aste caricate in pausa", LogLevel.Info);
|
||
}
|
||
}
|
||
}
|
||
|
||
UpdateTotalCount();
|
||
UpdateGlobalControlButtons();
|
||
|
||
// Log sempre mostrato (anche con 0 aste)
|
||
if (auctions.Count > 0)
|
||
{
|
||
if (settings.RememberAuctionStates)
|
||
{
|
||
Log($"[LOAD] {auctions.Count} aste caricate con stati individuali ripristinati", LogLevel.Info);
|
||
}
|
||
else
|
||
{
|
||
Log($"[LOAD] {auctions.Count} aste caricate con stato iniziale: {settings.DefaultStartAuctionsOnLoad}", LogLevel.Info);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Log("[LOAD] Nessuna asta salvata", LogLevel.Info);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Log($"[ERRORE] Caricamento aste: {ex.Message}", LogLevel.Error);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Aggiorna i dettagli dell'asta selezionata nel pannello Info Prodotto
|
||
/// </summary>
|
||
private void UpdateSelectedAuctionDetails(AuctionViewModel? vm)
|
||
{
|
||
if (vm == null || vm.AuctionInfo == null)
|
||
{
|
||
// Resetta campi se nessuna asta selezionata
|
||
AuctionMonitor.ProductBuyNowPriceText.Text = "-";
|
||
AuctionMonitor.ProductShippingCostText.Text = "-";
|
||
AuctionMonitor.ProductWinLimitText.Text = "-";
|
||
return;
|
||
}
|
||
|
||
var auction = vm.AuctionInfo;
|
||
|
||
// CARICA AUTOMATICAMENTE INFO PRODOTTO SE NON PRESENTI
|
||
if (!auction.BuyNowPrice.HasValue && !auction.ShippingCost.HasValue)
|
||
{
|
||
// Carica in background senza bloccare l'UI
|
||
_ = LoadProductInfoInBackgroundAsync(auction);
|
||
}
|
||
|
||
// Aggiorna i campi delle impostazioni
|
||
UpdateAuctionSettingsDisplay(vm);
|
||
|
||
// Aggiorna Valore (Compra Subito)
|
||
if (auction.BuyNowPrice.HasValue)
|
||
{
|
||
AuctionMonitor.ProductBuyNowPriceText.Text = $"{auction.BuyNowPrice.Value:F2}€";
|
||
}
|
||
else
|
||
{
|
||
AuctionMonitor.ProductBuyNowPriceText.Text = "-";
|
||
}
|
||
|
||
// Aggiorna Spese di Spedizione
|
||
if (auction.ShippingCost.HasValue)
|
||
{
|
||
AuctionMonitor.ProductShippingCostText.Text = $"{auction.ShippingCost.Value:F2}€";
|
||
}
|
||
else
|
||
{
|
||
AuctionMonitor.ProductShippingCostText.Text = "-";
|
||
}
|
||
|
||
// Aggiorna Limiti di Vincita
|
||
if (auction.HasWinLimit && !string.IsNullOrWhiteSpace(auction.WinLimitDescription))
|
||
{
|
||
AuctionMonitor.ProductWinLimitText.Text = auction.WinLimitDescription;
|
||
}
|
||
else if (!auction.HasWinLimit)
|
||
{
|
||
AuctionMonitor.ProductWinLimitText.Text = "Nessun limite";
|
||
}
|
||
else
|
||
{
|
||
AuctionMonitor.ProductWinLimitText.Text = "-";
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Carica le informazioni del prodotto (e nome se generico) in background quando selezioni un'asta
|
||
/// </summary>
|
||
private async System.Threading.Tasks.Task LoadProductInfoInBackgroundAsync(AuctionInfo auction)
|
||
{
|
||
try
|
||
{
|
||
bool hasGenericName = auction.Name.StartsWith("Asta ") &&
|
||
!auction.Name.Contains("Shop") &&
|
||
!auction.Name.Contains("€") &&
|
||
!auction.Name.Contains("Buono") &&
|
||
!auction.Name.Contains("Carburante");
|
||
|
||
Log($"[PRODUCT INFO] Caricamento automatico per: {auction.Name}{(hasGenericName ? " (+ nome generico)" : "")}", Utilities.LogLevel.Info);
|
||
|
||
// ? USA IL SERVIZIO CENTRALIZZATO
|
||
var response = await _htmlCacheService.GetHtmlAsync(
|
||
auction.OriginalUrl,
|
||
RequestPriority.High, // Priorità alta per info prodotto
|
||
bypassCache: false
|
||
);
|
||
|
||
if (!response.Success)
|
||
{
|
||
Log($"[PRODUCT INFO] Errore caricamento: {response.Error}", Utilities.LogLevel.Warning);
|
||
return;
|
||
}
|
||
|
||
bool updated = false;
|
||
|
||
// 1. ? Se nome generico, estrai nome reale dal <title>
|
||
if (hasGenericName)
|
||
{
|
||
var matchTitle = System.Text.RegularExpressions.Regex.Match(response.Html, @"<title>([^<]+)</title>");
|
||
if (matchTitle.Success)
|
||
{
|
||
var productName = matchTitle.Groups[1].Value.Trim().Replace(" - Bidoo", "");
|
||
productName = DecodeAllHtmlEntities(productName);
|
||
// ? MODIFICATO: Nome senza ID
|
||
var newName = productName;
|
||
|
||
auction.Name = newName;
|
||
updated = true;
|
||
Log($"[NAME] Nome recuperato: {productName}{(response.FromCache ? " (cached)" : "")}", LogLevel.Info);
|
||
}
|
||
}
|
||
|
||
// 2. ? Estrai informazioni prodotto (prezzo, spedizione, limiti)
|
||
var extracted = Utilities.ProductValueCalculator.ExtractProductInfo(response.Html, auction);
|
||
if (extracted)
|
||
{
|
||
updated = true;
|
||
Log($"[PRODUCT INFO] Valore={auction.BuyNowPrice:F2}€, Spedizione={auction.ShippingCost:F2}€{(response.FromCache ? " (cached)" : "")}", Utilities.LogLevel.Success);
|
||
}
|
||
|
||
// 3. ? Salva e aggiorna UI solo se qualcosa è cambiato
|
||
if (updated)
|
||
{
|
||
SaveAuctions();
|
||
|
||
Dispatcher.Invoke(() =>
|
||
{
|
||
// Refresh griglia per mostrare nome aggiornato
|
||
if (hasGenericName)
|
||
{
|
||
var tempSource = MultiAuctionsGrid.ItemsSource;
|
||
MultiAuctionsGrid.ItemsSource = null;
|
||
MultiAuctionsGrid.ItemsSource = tempSource;
|
||
}
|
||
|
||
// Refresh dettagli se ancora selezionata
|
||
if (_selectedAuction != null && _selectedAuction.AuctionId == auction.AuctionId)
|
||
{
|
||
UpdateSelectedAuctionDetails(_selectedAuction);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Log($"[PRODUCT INFO] Errore caricamento: {ex.Message}", Utilities.LogLevel.Warning);
|
||
}
|
||
}
|
||
}
|
||
}
|