From 9b38adfd5f947d61f31e8cb5366b390883898ff8 Mon Sep 17 00:00:00 2001 From: Alberto Balbo Date: Tue, 7 Oct 2025 11:26:37 +0200 Subject: [PATCH] =?UTF-8?q?Miglioramenti=20reattivit=C3=A0=20e=20gestione?= =?UTF-8?q?=20aste?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Rimosso codice obsoleto e migliorata leggibilità. - Aggiornati log con messaggi più chiari e leggibili. - Ottimizzato script JS per monitoraggio ultra-reattivo. - Introdotto aggiornamento dinamico lista partecipanti (bidders). - Migliorata gestione timer con polling adattivo. - Ridotti ritardi e timeout per maggiore reattività. - Aggiornata logica di clic con supporto a timer precisi. - Migliorata gestione errori e casi limite. - Reso thread-safe l'aggiornamento dell'interfaccia utente. - Ottimizzata gestione reset e decisioni di clic. - Introdotto triplo clic rapido per massima affidabilità. - Aggiunti log per strategie e cronologia puntate. - Migliorate prestazioni generali e ridotti tempi di risposta. --- Mimante/MainWindow.xaml.cs | 302 +++++++++++++++++++++++++++---------- 1 file changed, 220 insertions(+), 82 deletions(-) diff --git a/Mimante/MainWindow.xaml.cs b/Mimante/MainWindow.xaml.cs index ba4ced5..118a3a1 100644 --- a/Mimante/MainWindow.xaml.cs +++ b/Mimante/MainWindow.xaml.cs @@ -25,7 +25,7 @@ namespace AutoBidder private DateTime _lastMissingLogUtc = DateTime.MinValue; private string _currentUserName = ""; private DateTime _lastUserNameFetch = DateTime.MinValue; - private const int MAX_LOG_LINES = 500; // Limite per performance log + private const int MAX_LOG_LINES = 500; public MainWindow() { @@ -407,7 +407,7 @@ namespace AutoBidder try { if (webView.CoreWebView2 == null) await webView.EnsureCoreWebView2Async(); } catch (Exception ex) { Log("Errore inizializzazione WebView2: " + ex.Message); StartButton.IsEnabled = true; StopButton.IsEnabled = false; return; } - Log("Avviato: WebView inizializzato. Avvio monitoraggio pagina."); + Log("✅ WebView inizializzato - Avvio sistema ultra-reattivo"); // primo tentativo recupero nome utente try { await FetchUserNameAsync(); } catch { } _cts = new CancellationTokenSource(); @@ -432,7 +432,7 @@ namespace AutoBidder if (_currentUserName != raw) { _currentUserName = raw.Trim(); - Log("Utente rilevato: " + _currentUserName); + Log("👤 Utente rilevato: " + _currentUserName); } } _lastUserNameFetch = DateTime.UtcNow; @@ -445,7 +445,7 @@ namespace AutoBidder int clickCount = 0; int resetCount = 0; string? previousTimer = null; - const int postClickDelayMs = 800; // Ridotto per maggiore reattività + const int postClickDelayMs = 800; int consecutiveErrors = 0; const int maxConsecutiveErrors = 5; @@ -454,17 +454,16 @@ namespace AutoBidder DateTime lastDecisionLog = DateTime.MinValue; DateTime lastMissingLogUtc = DateTime.MinValue; DateTime lastSuccessfulRead = DateTime.UtcNow; + DateTime lastBidderUpdate = DateTime.MinValue; // ⭐ NUOVO: per limitare frequency update bidders - // Script JS ultra-ottimizzato con cache e selezioni più veloci - const string findScript = @" + const string ultraFastScript = @" (function(){ try{ - // Cache ottimizzata per ridurre query DOM var cache = window._abCache || {}; var now = Date.now(); - // Riutilizza cache se ancora valida (< 100ms) - if (cache.data && cache.timestamp && (now - cache.timestamp) < 100) { + // ⚡ Cache ULTRA-CORTA (20ms) per massima reattività + if (cache.data && cache.timestamp && (now - cache.timestamp) < 20) { return cache.data; } @@ -474,69 +473,86 @@ namespace AutoBidder return r.width > 0 && r.height > 0; } - // Prezzo - ricerca veloce + // ⭐⭐⭐ LETTURA DIRETTA VARIABILI REALI BIDOO ⭐⭐⭐ + var realRemainingTime = null; + var realTimerSource = 'none'; + + // Metodo 1: Variabili globali window.scad_auct e window.timeRec (PRIORITÀ MASSIMA) + if (typeof window.scad_auct !== 'undefined' && typeof window.timeRec !== 'undefined') { + try { + var remaining = window.scad_auct - parseFloat(window.timeRec); + if (remaining >= 0 && remaining <= 60) { + realRemainingTime = remaining.toFixed(3); + realTimerSource = 'window_vars'; + } + } catch(e) {} + } + + // Metodo 2: Lettura da oggetti asta se disponibili + if (!realRemainingTime && typeof window.auction !== 'undefined' && window.auction) { + try { + if (window.auction.timeRemaining !== undefined) { + realRemainingTime = parseFloat(window.auction.timeRemaining).toFixed(3); + realTimerSource = 'auction_obj'; + } else if (window.auction.timer !== undefined) { + realRemainingTime = parseFloat(window.auction.timer).toFixed(3); + realTimerSource = 'auction_timer'; + } + } catch(e) {} + } + + // Prezzo - ricerca ultra-veloce var priceVal = null; - var priceEl = document.querySelector('.auction-action-price strong, .auction-action-price, .current-price'); + var priceEl = document.querySelector('.auction-action-price strong, .auction-price, .current-price'); if(priceEl) { var txt = priceEl.textContent.replace('€','').replace(/\./g,'').replace(',','.'); var m = txt.match(/(\d+(?:\.\d+)?)/); if(m) priceVal = m[1]; } - // Bottone - ricerca veloce e diretta + // Bottone - ricerca diretta e velocissima var btn = null; - var btnSels = ['a.auction-btn-bid', '.auction-btn-bid', 'a.bid-button']; + var btnSels = ['a.auction-btn-bid:not([disabled])', '.auction-btn-bid:not([disabled])', 'a.bid-button']; for(var i = 0; i < btnSels.length && !btn; i++) { var b = document.querySelector(btnSels[i]); - if(b && isVis(b) && !b.disabled && !b.classList.contains('disabled')) btn = b; + if(b && isVis(b) && !b.classList.contains('disabled')) btn = b; } - if(!btn) { - // Fallback rapido - var candidates = document.querySelectorAll('a[href*=bid], button[onclick*=bid]'); - for(var j = 0; j < candidates.length; j++) { - if(isVis(candidates[j])) { btn = candidates[j]; break; } - } - } - - if(btn && /\b(INIZIA|STARTING|SOON)\b/i.test(btn.textContent||'')) { + if(btn && /\b(INIZIA|STARTING|RIAPRE)\b/i.test(btn.textContent||'')) { return JSON.stringify({status:'soon', price: priceVal, btnFound: true}); } - // Timer - ricerca ultra-veloce - var timerVal = null; - var timerEl = document.querySelector('.text-countdown-progressbar, .countdown-timer'); + // Timer DOM (fallback) + var domTimerVal = null; + var timerEl = document.querySelector('.text-countdown-progressbar, .countdown-timer, .auction-timer'); if(timerEl && isVis(timerEl)) { var t = timerEl.textContent.trim(); - var tm = t.match(/(\d+)/); - if(tm) timerVal = tm[1]; + var tm = t.match(/(\d+(?:\.\d+)?)/); + if(tm) domTimerVal = tm[1]; } - // Se non trovato timer ma c'è bottone, cerca numeri vicini - if(!timerVal && btn) { - var parent = btn.closest('.auction-section, .bid-section') || btn.parentElement; - if(parent) { - var allText = parent.textContent || ''; - var nums = allText.match(/\b(\d+)\b/g); - if(nums) { - for(var k = 0; k < nums.length; k++) { - var n = parseInt(nums[k]); - if(n >= 0 && n <= 60) { timerVal = nums[k]; break; } - } - } - } - } + // ⭐ PRIORITÀ ASSOLUTA: timer reale se disponibile + var finalTimer = realRemainingTime || domTimerVal; var result; if(!btn) { result = JSON.stringify({status:'no-button', price: priceVal}); - } else if(!timerVal) { + } else if(!finalTimer) { result = JSON.stringify({status:'no-timer', price: priceVal, btnFound: true}); } else { - result = JSON.stringify({status:'found', timer: timerVal, price: priceVal, btnFound: true}); + result = JSON.stringify({ + status:'found', + timer: finalTimer, + timerSource: realTimerSource, + realTimer: realRemainingTime, + domTimer: domTimerVal, + price: priceVal, + btnFound: true, + timestamp: now + }); } - // Salva in cache + // Cache ultra-corta window._abCache = {data: result, timestamp: now}; return result; @@ -560,7 +576,53 @@ namespace AutoBidder } })();"; - Log("🚀 Avvio loop automazione con script ultra-ottimizzati"); + // ⭐⭐⭐ NUOVO SCRIPT: Legge TUTTA la cronologia puntate dalla tabella + const string getAllBiddersScript = @" +(function(){ + try { + var bidders = {}; + + // Cerca la tabella cronologia (auction-history, bid-history, ecc.) + var historyTable = document.querySelector('#DStorico, .auction-history table, .bid-history table, table.table-condensed'); + + if(historyTable) { + var rows = historyTable.querySelectorAll('tbody tr'); + + for(var i = 0; i < rows.length; i++) { + var cells = rows[i].querySelectorAll('td'); + if(cells.length >= 4) { + // Ultima colonna (4a) di solito è l'username + var username = (cells[3].textContent || cells[3].innerText || '').trim(); + + // Filtro nomi validi + if(username && username.length > 0 && username.length < 50 && username !== ' ') { + if(bidders[username]) { + bidders[username]++; + } else { + bidders[username] = 1; + } + } + } + } + } + + // Converti in array + var result = []; + for(var name in bidders) { + result.push({name: name, count: bidders[name]}); + } + + return JSON.stringify({status:'found', bidders: result}); + + } catch(e) { + return JSON.stringify({status:'error', error: e.message}); + } +})();"; + + Log("🚀 Loop ULTRA-AGGRESSIVO avviato!"); + Log("⚡ Strategia: Polling lento >2s, MASSIMA reattività <2s"); + Log("📊 Lettura diretta variabili JavaScript Bidoo"); + Log("👥 Tracciamento COMPLETO cronologia puntate"); while (!token.IsCancellationRequested) { @@ -572,14 +634,52 @@ namespace AutoBidder try { await FetchUserNameAsync(); } catch { } } - // Fetch auction state con timeout ridotto + // ⭐ AGGIORNA LISTA BIDDERS ogni 2 secondi leggendo la tabella cronologia + if ((DateTime.UtcNow - lastBidderUpdate) > TimeSpan.FromSeconds(2)) + { + try + { + var biddersResult = await ExecuteScriptWithTimeoutAsync(getAllBiddersScript, TimeSpan.FromMilliseconds(1000), token); + if (!string.IsNullOrEmpty(biddersResult)) + { + using var jd = JsonDocument.Parse(biddersResult ?? "{}"); + if (jd.RootElement.GetProperty("status").GetString() == "found") + { + var biddersArray = jd.RootElement.GetProperty("bidders"); + + // Aggiorna dizionario bidders + foreach (var bidder in biddersArray.EnumerateArray()) + { + var name = bidder.GetProperty("name").GetString() ?? ""; + var count = bidder.GetProperty("count").GetInt32(); + + if (!string.IsNullOrWhiteSpace(name)) + { + // Aggiorna sempre con il count più alto + if (!_bidders.ContainsKey(name) || _bidders[name].Count < count) + { + _bidders[name] = (count, DateTime.Now); + } + } + } + + UpdateBiddersGrid(); + } + } + } + catch { } + + lastBidderUpdate = DateTime.UtcNow; + } + + // ⚡ ESECUZIONE SCRIPT ULTRA-VELOCE con timeout ridotto string? result = null; try { using var cts = CancellationTokenSource.CreateLinkedTokenSource(token); - cts.CancelAfter(TimeSpan.FromSeconds(3)); // Timeout ridotto a 3 secondi + cts.CancelAfter(TimeSpan.FromMilliseconds(1500)); - var op = Dispatcher.InvokeAsync(() => webView.ExecuteScriptAsync(findScript)); + var op = Dispatcher.InvokeAsync(() => webView.ExecuteScriptAsync(ultraFastScript)); var innerTask = await op.Task.ConfigureAwait(false); result = await innerTask.WaitAsync(cts.Token).ConfigureAwait(false); @@ -601,7 +701,7 @@ namespace AutoBidder } catch { } } - await Task.Delay(500, token); + await Task.Delay(150, token); continue; } catch (Exception ex) @@ -613,7 +713,7 @@ namespace AutoBidder StopAutomation($"Troppi errori consecutivi"); return; } - await Task.Delay(500, token); + await Task.Delay(150, token); continue; } @@ -651,7 +751,6 @@ namespace AutoBidder var root = doc.RootElement; var status = root.GetProperty("status").GetString() ?? string.Empty; - // Gestione stati switch (status) { case "no-button": @@ -674,27 +773,35 @@ namespace AutoBidder { Log($"❌ Script error: {errorEl.GetString()}"); } - await Task.Delay(500, token); + await Task.Delay(200, token); continue; case "found": break; default: - await Task.Delay(300, token); + await Task.Delay(200, token); continue; } - // Processa risultato "found" var timerValue = root.GetProperty("timer").GetString(); - var oldTimer = previousTimer; - if (timerValue != oldTimer) + + if (root.TryGetProperty("timerSource", out var sourceEl)) { - Log($"⏱️ Timer: {timerValue}"); + var source = sourceEl.GetString(); + if (source != "none" && timerValue != previousTimer) + { + var sourceLabel = source == "window_vars" ? "📊 REAL" : "🖥️ DOM"; + Log($"⏱️ Timer: {timerValue}s [{sourceLabel}]"); + } } + else if (timerValue != previousTimer) + { + Log($"⏱️ Timer: {timerValue}s"); + } + previousTimer = timerValue; - // Price handling if (root.TryGetProperty("price", out var pEl) && pEl.ValueKind != JsonValueKind.Null) { var pStr = pEl.GetString(); @@ -724,17 +831,17 @@ namespace AutoBidder } } - // Reset detection - if (int.TryParse(timerValue, out var currentTimerInt) && int.TryParse(oldTimer, out var prevTimerInt)) + if (double.TryParse(timerValue, NumberStyles.Any, CultureInfo.InvariantCulture, out var currentTimer) && + double.TryParse(previousTimer, NumberStyles.Any, CultureInfo.InvariantCulture, out var prevTimer)) { - if (oldTimer != null && currentTimerInt > prevTimerInt && prevTimerInt < 30) + if (previousTimer != null && currentTimer > prevTimer + 0.5 && prevTimer < 30) { resetCount++; await Dispatcher.InvokeAsync(() => ResetCountText.Text = resetCount.ToString()); try { - var bidderResult = await ExecuteScriptWithTimeoutAsync(getLastBidderScript, TimeSpan.FromSeconds(2), token); + var bidderResult = await ExecuteScriptWithTimeoutAsync(getLastBidderScript, TimeSpan.FromMilliseconds(800), token); if (!string.IsNullOrEmpty(bidderResult)) { using var jd = JsonDocument.Parse(bidderResult ?? "{}"); @@ -756,7 +863,6 @@ namespace AutoBidder } } - // Click logic ottimizzata bool shouldClick = false; int clickTimerValue = 0; int clickDelayMs = 100; @@ -766,16 +872,16 @@ namespace AutoBidder { await Dispatcher.InvokeAsync(() => { - if (int.TryParse(ClickTimerBox.Text, out var ctv) && ctv >= 0 && ctv <= 3) clickTimerValue = ctv; + 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; }); } catch { } - if (int.TryParse(timerValue, out var tInt)) + if (double.TryParse(timerValue, NumberStyles.Any, CultureInfo.InvariantCulture, out var preciseTimer)) { - if (tInt == clickTimerValue && !_pauseBids) + if (preciseTimer >= clickTimerValue && preciseTimer < clickTimerValue + 1.0 && !_pauseBids) { shouldClick = true; } @@ -794,7 +900,7 @@ namespace AutoBidder clickCount++; await Dispatcher.InvokeAsync(() => ClickCountText.Text = clickCount.ToString()); RegisterBidder(_currentUserName); - Log($"✅ Click #{clickCount} - Timer: {timerValue} (Delay: {clickDelayMs}ms)"); + Log($"✅ Click #{clickCount} - Timer: {timerValue}s (Delay: {clickDelayMs}ms)"); if (clickCount >= maxClicks) { @@ -806,7 +912,7 @@ namespace AutoBidder } else { - Log($"⚠️ Click fallito - Timer: {timerValue}"); + Log($"⚠️ Click fallito - Timer: {timerValue}s"); } } else if ((DateTime.UtcNow - lastDecisionLog) > TimeSpan.FromSeconds(3)) @@ -820,8 +926,36 @@ namespace AutoBidder continue; } - // Delay ottimizzato - più reattivo - await Task.Delay(100, token); + int pollDelay; + if (double.TryParse(timerValue, NumberStyles.Any, CultureInfo.InvariantCulture, out var timerDouble)) + { + if (timerDouble < 2.0) + { + pollDelay = 30; + } + else if (timerDouble < 3.0) + { + pollDelay = 100; + } + else if (timerDouble < 4.0) + { + pollDelay = 150; + } + else if (timerDouble < 6.0) + { + pollDelay = 200; + } + else + { + pollDelay = 300; + } + } + else + { + pollDelay = 150; + } + + await Task.Delay(pollDelay, token); } catch (OperationCanceledException) { break; } catch (Exception ex) @@ -833,7 +967,7 @@ namespace AutoBidder StopAutomation($"Troppi errori"); return; } - await Task.Delay(500, token); + await Task.Delay(150, token); } } @@ -889,10 +1023,11 @@ namespace AutoBidder if(!btn) return JSON.stringify({success: false}); - // Click multipli rapidi per massima affidabilità + // Click tripli rapidi per massima affidabilità btn.focus(); btn.click(); - btn.click(); // Doppio click immediato + btn.click(); + btn.click(); // Mouse event per compatibilità var r = btn.getBoundingClientRect(); @@ -925,7 +1060,7 @@ namespace AutoBidder { var clickOp = Dispatcher.InvokeAsync(() => webView.ExecuteScriptAsync(optimizedClickScript)); var clickTask = await clickOp.Task.ConfigureAwait(false); - clickResult = await clickTask.WaitAsync(TimeSpan.FromSeconds(3), token).ConfigureAwait(false); + clickResult = await clickTask.WaitAsync(TimeSpan.FromSeconds(2), token).ConfigureAwait(false); } catch (TimeoutException) { @@ -939,7 +1074,7 @@ namespace AutoBidder if (string.IsNullOrEmpty(clickResult)) return false; - if (!string.IsNullOrEmpty(clickResult) && clickResult.Length >= 2 && clickResult[0] == '"' && clickResult[^1] == '"') + if (!string.IsNullOrEmpty(clickResult) && clickResult.Length >= 2 && clickResult[0] == '"' && clickResult[^1] == '"' ) { try { clickResult = JsonSerializer.Deserialize(clickResult); } catch { } } @@ -967,13 +1102,13 @@ namespace AutoBidder { for (int i = 0; i < 2; i++) { - await Task.Delay(50, token); + await Task.Delay(30, token); // Delay ridotto per multi-click try { var multiOp = Dispatcher.InvokeAsync(() => webView.ExecuteScriptAsync(optimizedClickScript)); var multiTask = await multiOp.Task.ConfigureAwait(false); - await multiTask.WaitAsync(TimeSpan.FromSeconds(2), token).ConfigureAwait(false); + await multiTask.WaitAsync(TimeSpan.FromSeconds(1), token).ConfigureAwait(false); } catch { @@ -1023,10 +1158,13 @@ namespace AutoBidder private void StopAutomation(string reason) { try { _cts?.Cancel(); } catch { } - StartButton.IsEnabled = true; - StopButton.IsEnabled = false; - StartButton.Opacity = 1.0; - StopButton.Opacity = 0.5; + Dispatcher.Invoke(() => + { + StartButton.IsEnabled = true; + StopButton.IsEnabled = false; + StartButton.Opacity = 1.0; + StopButton.Opacity = 0.5; + }); Log("⏹️ STOP: " + reason); }