Ottimizzazioni UI e performance click handler

- Rimosse righe inutilizzate e semplificato layout in `MainWindow.xaml`.
- Aggiunti pulsanti di navigazione accanto alla barra indirizzi.
- Convertite operazioni UI in asincrone con `Dispatcher.BeginInvoke`.
- Introdotto aggiornamento griglia bidder ogni 2 secondi per ridurre lag.
- Migliorata gestione log con `AppendText` e controllo dimensione ottimizzato.
- Ridotto polling dinamico per timer bassi (minimo 20ms).
- Ottimizzato script di click con cache bottone e timeout ridotto (500ms).
- Implementato multi-click parallelo con delay minimo (20ms).
- Parsing JSON e lettura impostazioni resi più efficienti.
- Rimosso codice obsoleto e semplificata gestione eventi.
This commit is contained in:
Alberto Balbo
2025-10-14 12:26:51 +02:00
parent b12b57be81
commit 28ef09d91f
2 changed files with 171 additions and 119 deletions

View File

@@ -95,11 +95,9 @@
<RowDefinition Height="Auto" /> <!-- Start -->
<RowDefinition Height="Auto" /> <!-- Pause -->
<RowDefinition Height="Auto" /> <!-- Stop -->
<RowDefinition Height="Auto" /> <!-- Back/Refresh/Clear -->
<RowDefinition Height="Auto" /> <!-- Stats -->
<RowDefinition Height="Auto" /> <!-- Settings Row 1 -->
<RowDefinition Height="Auto" /> <!-- Settings Row 2 -->
<RowDefinition Height="Auto" /> <!-- Advanced timing control -->
<RowDefinition Height="Auto" /> <!-- Bidders label with clear button -->
<RowDefinition Height="Auto" /> <!-- Bidders grid -->
<RowDefinition Height="Auto" /> <!-- Log label with clear button -->
@@ -112,23 +110,8 @@
<Button x:Name="StopButton" Grid.Row="2" Style="{StaticResource StopButtonStyle}" Click="StopButton_Click" IsEnabled="False" Margin="12,6,12,0">Stop</Button>
<!-- Back / Refresh / ClearStats on same line -->
<Grid Grid.Row="3" Margin="12,6,12,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="8" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="8" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button x:Name="BackButton" Grid.Column="0" Style="{StaticResource RefreshButtonStyle}" Click="BackButton_Click" Height="36">Indietro</Button>
<Button x:Name="RefreshButton" Grid.Column="2" Style="{StaticResource RefreshButtonStyle}" Click="RefreshButton_Click" Height="36">Aggiorna</Button>
<Button x:Name="ClearStatsButton" Grid.Column="4" Style="{StaticResource RefreshButtonStyle}" Click="ClearStatsButton_Click" Height="36">Pulisci</Button>
</Grid>
<!-- Stats con prezzo corrente e Multi-Click -->
<Grid Grid.Row="4" Margin="12,8,12,0">
<Grid Grid.Row="3" Margin="12,8,12,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
@@ -156,7 +139,7 @@
</Grid>
<!-- Settings Row 1: Max Clicks, Max Resets, Min Price, Max Price -->
<Grid Grid.Row="5" Margin="12,8,12,0">
<Grid Grid.Row="4" Margin="12,8,12,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="8" />
@@ -193,8 +176,8 @@
</StackPanel>
</Grid>
<!-- Settings Row 2: Timer Click, Ritardo, Multi-Click -->
<Grid Grid.Row="6" Margin="12,6,12,0">
<!-- Settings Row 2: Timer Click, Ritardo -->
<Grid Grid.Row="5" Margin="12,6,12,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="8" />
@@ -215,12 +198,12 @@
<!-- Ritardo -->
<StackPanel Grid.Row="0" Grid.Column="2" Orientation="Vertical">
<TextBlock Text="Ritardo (ms)" FontSize="11" />
<TextBox x:Name="ClickDelayBox" Style="{StaticResource NumericBoxStyle}" Text="100" Width="Auto" ToolTip="Ritardo aggiuntivo in millisecondi" TextChanged="ClickDelayBox_TextChanged" />
<TextBox x:Name="ClickDelayBox" Style="{StaticResource NumericBoxStyle}" Text="0" Width="Auto" ToolTip="Ritardo aggiuntivo in millisecondi (0 = massima velocità)" TextChanged="ClickDelayBox_TextChanged" />
</StackPanel>
</Grid>
<!-- Bidders section header with clear button -->
<Grid Grid.Row="8" Margin="12,8,12,4">
<Grid Grid.Row="6" Margin="12,8,12,4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
@@ -239,7 +222,7 @@
</Button>
</Grid>
<DataGrid x:Name="BiddersGrid" Grid.Row="9" Margin="12,0,12,0" AutoGenerateColumns="False" HeadersVisibility="Column" CanUserAddRows="False" IsReadOnly="True" Height="90" Background="#091018" RowBackground="#0B1220" AlternatingRowBackground="#081016" Foreground="#E6EDF3" GridLinesVisibility="None">
<DataGrid x:Name="BiddersGrid" Grid.Row="7" Margin="12,0,12,0" AutoGenerateColumns="False" HeadersVisibility="Column" CanUserAddRows="False" IsReadOnly="True" Height="90" Background="#091018" RowBackground="#0B1220" AlternatingRowBackground="#081016" Foreground="#E6EDF3" GridLinesVisibility="None">
<DataGrid.Resources>
<Style TargetType="DataGridColumnHeader">
<Setter Property="Background" Value="#0F1720" />
@@ -258,7 +241,7 @@
</DataGrid.Columns>
</DataGrid>
<Grid Grid.Row="10" Margin="12,6,12,4">
<Grid Grid.Row="8" Margin="12,6,12,4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
@@ -277,7 +260,7 @@
</Button>
</Grid>
<TextBox x:Name="LogBox" Grid.Row="11" Margin="12,0,12,12" IsReadOnly="True" VerticalScrollBarVisibility="Auto" TextWrapping="Wrap" AcceptsReturn="True" Style="{StaticResource LogBoxStyle}" />
<TextBox x:Name="LogBox" Grid.Row="9" Margin="12,0,12,12" IsReadOnly="True" VerticalScrollBarVisibility="Auto" TextWrapping="Wrap" AcceptsReturn="True" Style="{StaticResource LogBoxStyle}" />
</Grid>
</Border>
@@ -291,20 +274,50 @@
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Address bar -->
<!-- Address bar con pulsanti navigazione -->
<Grid Grid.Row="0" Margin="12,12,12,6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox x:Name="AddressBar" Grid.Column="0" Style="{StaticResource AddressBarStyle}"
<!-- Pulsante Indietro -->
<Button x:Name="BackButton" Grid.Column="0" Content="Indietro" Click="BackButton_Click"
Background="#374151" Foreground="White" Padding="12,8" Margin="0,0,6,0"
BorderThickness="0" FontWeight="SemiBold" FontSize="13" MinWidth="70" Height="38" IsEnabled="False">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="6" SnapsToDevicePixels="True">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</Button.Template>
</Button>
<!-- Pulsante Aggiorna -->
<Button x:Name="RefreshButton" Grid.Column="1" Content="Aggiorna" Click="RefreshButton_Click"
Background="#0EA5E9" Foreground="White" Padding="12,8" Margin="0,0,8,0"
BorderThickness="0" FontWeight="SemiBold" FontSize="13" MinWidth="80" Height="38">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="6" SnapsToDevicePixels="True">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</Button.Template>
</Button>
<!-- Barra indirizzo -->
<TextBox x:Name="AddressBar" Grid.Column="2" Style="{StaticResource AddressBarStyle}"
Text="https://it.bidoo.com" KeyDown="AddressBar_KeyDown"
ToolTip="Inserisci URL di Bidoo (es: https://it.bidoo.com/asta/...)" />
<Button x:Name="NavigateButton" Grid.Column="1" Content="Vai" Click="NavigateButton_Click"
Background="#16A34A" Foreground="White" Padding="38,10" Margin="8,0,0,0"
BorderThickness="0" FontWeight="Bold" FontSize="14" MinWidth="90">
<!-- Pulsante Vai -->
<Button x:Name="NavigateButton" Grid.Column="3" Content="Vai" Click="NavigateButton_Click"
Background="#16A34A" Foreground="White" Padding="28,10" Margin="8,0,0,0"
BorderThickness="0" FontWeight="Bold" FontSize="14" MinWidth="80" Height="38">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="6" SnapsToDevicePixels="True">

View File

@@ -69,7 +69,6 @@ namespace AutoBidder
StartButton.Opacity = 1.0;
StopButton.IsEnabled = false;
StopButton.Opacity = 0.5;
BackButton.IsEnabled = false;
webView.NavigationCompleted += WebView_NavigationCompleted;
webView.NavigationStarting += WebView_NavigationStarting;
@@ -170,17 +169,22 @@ namespace AutoBidder
{
try
{
BackButton.IsEnabled = webView.CoreWebView2 != null && webView.CoreWebView2.CanGoBack;
try
// ⚡ OTTIMIZZAZIONE: Update UI asincrono
Dispatcher.BeginInvoke(() =>
{
var url = webView.CoreWebView2?.Source ?? webView.Source?.ToString();
if (!string.IsNullOrEmpty(url))
try
{
var addressBar = FindName("AddressBar") as TextBox;
if (addressBar != null) addressBar.Text = url!;
BackButton.IsEnabled = webView.CoreWebView2 != null && webView.CoreWebView2.CanGoBack;
var url = webView.CoreWebView2?.Source ?? webView.Source?.ToString();
if (!string.IsNullOrEmpty(url))
{
var addressBar = FindName("AddressBar") as TextBox;
if (addressBar != null) addressBar.Text = url!;
}
}
}
catch { }
catch { }
});
}
catch { }
}
@@ -290,15 +294,6 @@ namespace AutoBidder
private void ClickTimerBox_TextChanged(object sender, TextChangedEventArgs e) => Log("Impostazione Click Timer cambiata: " + ClickTimerBox.Text);
private void ClickDelayBox_TextChanged(object sender, TextChangedEventArgs e) => Log("Impostazione Click Delay cambiata: " + ClickDelayBox.Text);
private void ClearStatsButton_Click(object sender, RoutedEventArgs e)
{
ClickCountText.Text = "0";
ResetCountText.Text = "0";
Log("Statistiche resettate dall'utente");
_bidders.Clear();
UpdateBiddersGrid();
}
private void ClearBiddersButton_Click(object sender, RoutedEventArgs e)
{
try
@@ -333,11 +328,21 @@ namespace AutoBidder
catch { }
}
private DateTime _lastBiddersUpdate = DateTime.MinValue;
private void UpdateBiddersGrid()
{
try
{
Dispatcher.Invoke(() =>
// ⚡ OTTIMIZZAZIONE: Aggiorna solo ogni 2 secondi per evitare lag
var now = DateTime.UtcNow;
if ((now - _lastBiddersUpdate).TotalMilliseconds < 2000)
return;
_lastBiddersUpdate = now;
// ⚡ USA BeginInvoke ASINCRONO invece di Invoke per non bloccare
Dispatcher.BeginInvoke(() =>
{
var grid = FindName("BiddersGrid") as DataGrid;
if (grid != null)
@@ -350,11 +355,20 @@ namespace AutoBidder
catch { }
}
private string _lastPriceText = "";
private void SetCurrentPriceText(string text)
{
try
{
Dispatcher.Invoke(() =>
// ⚡ OTTIMIZZAZIONE: Non aggiornare se il prezzo non è cambiato
if (_lastPriceText == text)
return;
_lastPriceText = text;
// ⚡ USA BeginInvoke ASINCRONO
Dispatcher.BeginInvoke(() =>
{
var tb = FindName("CurrentPriceText") as TextBlock;
if (tb != null) tb.Text = text;
@@ -368,20 +382,22 @@ namespace AutoBidder
var entry = $"{DateTime.Now:HH:mm:ss} - {message}{Environment.NewLine}";
try
{
Dispatcher.Invoke(() =>
// ⚡ OTTIMIZZAZIONE CRITICA: USA BeginInvoke per non bloccare MAI il thread di automazione
Dispatcher.BeginInvoke(() =>
{
if (LogBox != null)
{
// Gestione performance: limita numero righe log
var lines = LogBox.Text.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
if (lines.Length > MAX_LOG_LINES)
// ⚡ Semplifica: AppendText direttamente senza split pesante ogni volta
LogBox.AppendText(entry);
// ⚡ Controlla dimensione log solo ogni 100 righe circa
if (LogBox.LineCount > MAX_LOG_LINES + 100)
{
// Mantieni solo le ultime MAX_LOG_LINES righe
var recentLines = lines.Skip(lines.Length - MAX_LOG_LINES + 50).ToArray();
var lines = LogBox.Text.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
var recentLines = lines.Skip(lines.Length - MAX_LOG_LINES).ToArray();
LogBox.Text = string.Join(Environment.NewLine, recentLines);
}
LogBox.AppendText(entry);
LogBox.ScrollToEnd();
}
else
@@ -647,18 +663,22 @@ namespace AutoBidder
try { result = JsonSerializer.Deserialize<string>(result) ?? result; } catch { }
}
// Read limits
// ⚡ OTTIMIZZAZIONE CRITICA: Lettura impostazioni veloce
int maxClicks = int.MaxValue, maxResets = int.MaxValue;
double minPrice = 0.0, maxPrice = double.MaxValue;
try
{
await Dispatcher.InvokeAsync(() =>
var settingsOp = Dispatcher.InvokeAsync(() =>
{
if (int.TryParse(MaxClicksBox.Text, out var mc) && mc > 0) maxClicks = mc;
if (int.TryParse(MaxResetsBox.Text, out var mr) && mr > 0) maxResets = mr;
if (double.TryParse(MinPriceBox.Text.Replace(',', '.'), NumberStyles.Any, CultureInfo.InvariantCulture, out var mp)) minPrice = mp;
if (double.TryParse(MaxPriceBox.Text.Replace(',', '.'), NumberStyles.Any, CultureInfo.InvariantCulture, out var mpx) && mpx > 0) maxPrice = mpx;
});
// ⚡ Usa valori default se timeout
var opStatus = settingsOp.Wait(TimeSpan.FromMilliseconds(10));
if (opStatus == System.Windows.Threading.DispatcherOperationStatus.Completed)
await settingsOp.Task;
}
catch { }
@@ -675,9 +695,11 @@ namespace AutoBidder
// ⭐ LOG quando cambia il bidder E REGISTRA IMMEDIATAMENTE
if (!string.IsNullOrWhiteSpace(currentBidder) && currentBidder != lastKnownBidder)
{
Log($"👤 Puntata di: {currentBidder}");
// ⚡ OTTIMIZZAZIONE: Log e registrazione separati per non bloccare
var bidderToLog = currentBidder;
Task.Run(() => Log($"👤 Puntata di: {bidderToLog}"));
// ⭐ REGISTRA SUBITO LA PUNTATA NELLA LISTA
// ⭐ REGISTRA SUBITO LA PUNTATA NELLA LISTA (senza bloccare)
RegisterBidder(currentBidder);
lastKnownBidder = currentBidder;
@@ -772,11 +794,13 @@ namespace AutoBidder
if (currentTimer > prevTimer + 0.5 && prevTimer < 30)
{
resetCount++;
await Dispatcher.InvokeAsync(() => ResetCountText.Text = resetCount.ToString());
// ⚡ OTTIMIZZAZIONE: UI update asincrono
Dispatcher.BeginInvoke(() => ResetCountText.Text = resetCount.ToString());
// ⭐ Usa currentBidder invece di fare una nuova query
var winnerName = !string.IsNullOrWhiteSpace(currentBidder) ? currentBidder : "Sconosciuto";
Log($"🔄 Reset #{resetCount} - Winner: {winnerName}");
var cnt = resetCount;
Task.Run(() => Log($"🔄 Reset #{cnt} - Winner: {winnerName}"));
if (resetCount >= maxResets)
{
@@ -797,12 +821,17 @@ namespace AutoBidder
try
{
await Dispatcher.InvokeAsync(() =>
// ⚡ OTTIMIZZAZIONE: Lettura veloce con timeout minimo
var clickSettingsOp = Dispatcher.InvokeAsync(() =>
{
if (int.TryParse(ClickTimerBox.Text, out var ctv) && ctv >= 0 && ctv <= 8) clickTimerValue = ctv;
if (int.TryParse(ClickDelayBox.Text, out var cdm) && cdm >= 0 && cdm <= 2000) clickDelayMs = cdm;
multiClickEnabled = MultiClickCheckBox.IsChecked == true;
});
// ⚡ Timeout velocissimo: se non risponde in 5ms usa default
var opStatus = clickSettingsOp.Wait(TimeSpan.FromMilliseconds(5));
if (opStatus == System.Windows.Threading.DispatcherOperationStatus.Completed)
await clickSettingsOp.Task;
}
catch { }
@@ -825,18 +854,27 @@ namespace AutoBidder
if (clickSuccess)
{
clickCount++;
await Dispatcher.InvokeAsync(() => ClickCountText.Text = clickCount.ToString());
// ⚡ OTTIMIZZAZIONE: Update UI asincrono non bloccante
Dispatcher.BeginInvoke(() => ClickCountText.Text = clickCount.ToString());
// ⭐ Usa il nome utente corrente (mai AutoBidder se abbiamo il nome)
if (!string.IsNullOrWhiteSpace(_currentUserName))
{
RegisterBidder(_currentUserName);
Log($"✅ Click #{clickCount} ({_currentUserName}) - Timer: {timerValue}s (Delay: {clickDelayMs}ms)");
// ⚡ Log asincrono
var userName = _currentUserName;
var cnt = clickCount;
var timer = timerValue;
var delay = clickDelayMs;
Task.Run(() => Log($"✅ Click #{cnt} ({userName}) - Timer: {timer}s (Delay: {delay}ms)"));
}
else
{
// ⭐ NON registrare AutoBidder nella lista, solo nel log
Log($"✅ Click #{clickCount} (AutoBidder) - Timer: {timerValue}s (Delay: {clickDelayMs}ms)");
var cnt = clickCount;
var timer = timerValue;
var delay = clickDelayMs;
Task.Run(() => Log($"✅ Click #{cnt} (AutoBidder) - Timer: {timer}s (Delay: {delay}ms)"));
}
if (clickCount >= maxClicks)
@@ -849,7 +887,8 @@ namespace AutoBidder
}
else
{
Log($"⚠️ Click fallito - Timer: {timerValue}s");
var timer = timerValue;
Task.Run(() => Log($"⚠️ Click fallito - Timer: {timer}s"));
}
}
else if ((DateTime.UtcNow - lastDecisionLog) > TimeSpan.FromSeconds(3))
@@ -863,33 +902,40 @@ namespace AutoBidder
continue;
}
// ⚡ POLLING DINAMICO ULTRA-AGGRESSIVO per evitare micro-lag
int pollDelay;
if (double.TryParse(timerValue, NumberStyles.Any, CultureInfo.InvariantCulture, out var timerDouble))
{
if (timerDouble < 2.0)
if (timerDouble < 1.5)
{
pollDelay = 30;
// ⚡ ULTRA-CRITICO: polling ogni 20ms
pollDelay = 20;
}
else if (timerDouble < 3.0)
else if (timerDouble < 2.5)
{
pollDelay = 100;
// ⚡ CRITICO: polling ogni 40ms
pollDelay = 40;
}
else if (timerDouble < 4.0)
else if (timerDouble < 3.5)
{
pollDelay = 80;
}
else if (timerDouble < 5.0)
{
pollDelay = 150;
}
else if (timerDouble < 6.0)
else if (timerDouble < 8.0)
{
pollDelay = 200;
pollDelay = 250;
}
else
{
pollDelay = 300;
pollDelay = 400;
}
}
else
{
pollDelay = 150;
pollDelay = 100;
}
await Task.Delay(pollDelay, token);
@@ -943,38 +989,38 @@ namespace AutoBidder
private async Task<bool> PerformOptimizedClick(int delayMs, bool multiClickEnabled, CancellationToken token)
{
// Script click ultra-veloce e affidabile
// Script click ULTRA-VELOCE con cache del bottone
const string optimizedClickScript = @"
(function(){
try {
var btn = document.querySelector('a.auction-btn-bid:not([disabled]), .auction-btn-bid:not([disabled])');
// ⚡ Cache del bottone per velocità
var btn = window._cachedBidBtn;
var now = Date.now();
if(!btn) {
var btns = document.querySelectorAll('a, button');
for(var i = 0; i < btns.length; i++) {
if(/\b(PUNTA|BID)\b/i.test(btns[i].textContent||'') && btns[i].getBoundingClientRect().width > 0) {
btn = btns[i]; break;
// ⚡ Riusa cache se recente (< 500ms)
if (!btn || !document.contains(btn) || (window._cachedBidBtnTime && now - window._cachedBidBtnTime > 500)) {
btn = document.querySelector('a.auction-btn-bid:not([disabled]), .auction-btn-bid:not([disabled])');
if(!btn) {
var btns = document.querySelectorAll('a, button');
for(var i = 0; i < btns.length; i++) {
if(/\b(PUNTA|BID)\b/i.test(btns[i].textContent||'') && btns[i].getBoundingClientRect().width > 0) {
btn = btns[i]; break;
}
}
}
window._cachedBidBtn = btn;
window._cachedBidBtnTime = now;
}
if(!btn) return JSON.stringify({success: false});
// Click tripli rapidi per massima affidabilità
btn.focus();
btn.click();
btn.click();
// Click diretto SENZA focus (più veloce)
btn.click();
// Mouse event per compatibilità
var r = btn.getBoundingClientRect();
var evt = new MouseEvent('click', {
bubbles: true,
cancelable: true,
clientX: r.left + r.width/2,
clientY: r.top + r.height/2
});
btn.dispatchEvent(evt);
// ⚡ Secondo click immediato per affidabilità
btn.click();
return JSON.stringify({success: true});
@@ -985,19 +1031,19 @@ namespace AutoBidder
try
{
// Applica delay se configurato
if (delayMs > 0)
// ⚡ OTTIMIZZAZIONE: Delay solo se > 50ms (sotto è irrilevante)
if (delayMs > 50)
{
await Task.Delay(delayMs, token);
}
// Esegui click
// Esegui click con timeout ULTRA-CORTO (500ms invece di 2s)
string? clickResult = null;
try
{
var clickOp = Dispatcher.InvokeAsync(() => webView.ExecuteScriptAsync(optimizedClickScript));
var clickTask = await clickOp.Task.ConfigureAwait(false);
clickResult = await clickTask.WaitAsync(TimeSpan.FromSeconds(2), token).ConfigureAwait(false);
clickResult = await clickTask.WaitAsync(TimeSpan.FromMilliseconds(500), token).ConfigureAwait(false);
}
catch (TimeoutException)
{
@@ -1011,15 +1057,16 @@ namespace AutoBidder
if (string.IsNullOrEmpty(clickResult))
return false;
if (!string.IsNullOrEmpty(clickResult) && clickResult.Length >= 2 && clickResult[0] == '"' && clickResult[^1] == '"' )
// ⚡ Parsing veloce
if (clickResult.Length >= 2 && clickResult[0] == '"' && clickResult[^1] == '"')
{
try { clickResult = JsonSerializer.Deserialize<string>(clickResult); } catch { }
}
JsonDocument? clickDoc = null;
// ⚡ Verifica successo rapida
try
{
clickDoc = JsonDocument.Parse(clickResult);
using var clickDoc = JsonDocument.Parse(clickResult);
var success = clickDoc.RootElement.GetProperty("success").GetBoolean();
if (!success)
@@ -1029,29 +1076,21 @@ namespace AutoBidder
{
return false;
}
finally
{
clickDoc?.Dispose();
}
// Multi-click se abilitato
// Multi-click PARALLELO (non sequenziale) per velocità
if (multiClickEnabled)
{
for (int i = 0; i < 2; i++)
_ = Task.Run(async () =>
{
await Task.Delay(30, token); // Delay ridotto per multi-click
await Task.Delay(20, token);
try
{
var multiOp = Dispatcher.InvokeAsync(() => webView.ExecuteScriptAsync(optimizedClickScript));
var multiTask = await multiOp.Task.ConfigureAwait(false);
await multiTask.WaitAsync(TimeSpan.FromSeconds(1), token).ConfigureAwait(false);
await multiTask.WaitAsync(TimeSpan.FromMilliseconds(300), token).ConfigureAwait(false);
}
catch
{
break;
}
}
catch { }
}, token);
}
return true;