diff --git a/Mimante/MainWindow.xaml b/Mimante/MainWindow.xaml index a18b448..2f6006d 100644 --- a/Mimante/MainWindow.xaml +++ b/Mimante/MainWindow.xaml @@ -156,10 +156,22 @@ - + + + + + - + + diff --git a/Mimante/MainWindow.xaml.cs b/Mimante/MainWindow.xaml.cs index 7273f93..61afc05 100644 --- a/Mimante/MainWindow.xaml.cs +++ b/Mimante/MainWindow.xaml.cs @@ -9,6 +9,8 @@ using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Imaging; using Microsoft.Web.WebView2.Core; +using System.Text.RegularExpressions; +using System.Globalization; namespace AutoBidder { @@ -17,7 +19,7 @@ namespace AutoBidder private CancellationTokenSource? _cts; private Task? _automationTask; private volatile bool _pauseBids = false; - private readonly Dictionary _bidders = new(StringComparer.OrdinalIgnoreCase); + private readonly Dictionary _bidders = new(StringComparer.OrdinalIgnoreCase); private readonly List _pendingLogs = new(); public MainWindow() @@ -126,7 +128,7 @@ namespace AutoBidder var grid = FindName("BiddersGrid") as DataGrid; if (grid != null) { - var list = _bidders.Select(kvp => new { Name = kvp.Key, Count = kvp.Value }).OrderByDescending(x => x.Count).ToList(); + var list = _bidders.Select(kvp => new { Name = kvp.Key, Count = kvp.Value.Count, LastBid = kvp.Value.LastBid.ToString("g") }).OrderByDescending(x => x.Count).ToList(); grid.ItemsSource = list; } }); @@ -214,14 +216,18 @@ namespace AutoBidder private async Task AutomationLoop(CancellationToken token) { - int clickCount = 0; int resetCount = 0; string? previousTimer = null; + int clickCount = 0; + int resetCount = 0; + string? previousTimer = null; const int postClickDelayMs = 1200; - const string findScript = @"(function(){ function isVisible(el){ if(!el) return false; try{ var r=el.getBoundingClientRect(); var s=window.getComputedStyle(el); return r.width>0 && r.height>0 && s.visibility!=='hidden' && s.display!=='none'; }catch(e){ return false; } } var priceText=''; try{ var p=document.querySelector('.auction-action-price strong, .auction-action-price'); if(p) priceText=(p.textContent||p.innerText||'').trim(); }catch(e){} var priceVal=null; try{ if(priceText){ var p=priceText.replace('€','').replace(/\./g,'').replace(',','.').match(/\d+(?:\.\d+)?/); if(p) priceVal=p[0]; } }catch(e){} var btn=document.querySelector('a.auction-btn-bid, a.bid-button, .auction-btn-bid'); if(btn && isVisible(btn)){ var txt=(btn.textContent||btn.innerText||'').trim(); if(/\bINIZIA\b/i.test(txt)) return JSON.stringify({status:'soon', debug:txt, price: priceVal}); } try{ var direct=document.querySelector('.text-countdown-progressbar'); if(direct && isVisible(direct)){ var t=(direct.textContent||'').trim(); var m=t.match(/\d+/); if(m) return JSON.stringify({status:'found', timer:m[0], price: priceVal, debug: direct.outerHTML}); } }catch(e){} if(!btn || !isVisible(btn)){ var candidates=Array.from(document.querySelectorAll('a, button, div, span')).filter(e=> e && (e.innerText||e.textContent) && /\bPUNTA\b/i.test((e.innerText||e.textContent)) && isVisible(e)); if(candidates.length>0) btn=candidates[0]; } if(!btn) return JSON.stringify({status:'no-button', price: priceVal}); var nodeList=Array.from(document.querySelectorAll('div, span, p, strong, b, i, em, label, small, a, svg text')); var nums=nodeList.map(e=>{ try{return {el:e, text:(e.textContent||'').trim(), rect:e.getBoundingClientRect(), html:(e.outerHTML||'')}; }catch(err){ return null; }}).filter(x=> x && /\d+/.test(x.text)).map(x=>({el:x.el, text:x.text, rect:x.rect, html:x.html})); if(nums.length==0) return JSON.stringify({status:'no-timer', price: priceVal}); function distanceRect(a,b){ var ax=(a.left+a.right)/2, ay=(a.top+a.bottom)/2; var bx=(b.left+b.right)/2, by=(b.top+b.bottom)/2; return Math.hypot(ax-bx, ay-by); } var btnRect; try{ btnRect = btn.getBoundingClientRect(); }catch(e){ btnRect = {top:0,left:0,right:0,bottom:0,width:0,height:0}; } nums.sort(function(a,b){ var da = distanceRect(a.rect, btnRect); var db = distanceRect(b.rect, btnRect); var ya = btnRect.top - a.rect.bottom; var yb = btnRect.top - b.rect.bottom; var pref = (ya>=0?0:200) - (yb>=0?0:200); return (da - db) + pref; }); var best=nums[0]; var m=(best.text||'').match(/\d+/); if(!m) return JSON.stringify({status:'no-timer-extracted', debug: best.html, price: priceVal}); return JSON.stringify({status:'found', timer:m[0], price: priceVal, debug: best.html}); })();"; + const string findScript = @"(function(){ try{ function isVisible(el){ if(!el) return false; var r=el.getBoundingClientRect(); var s=window.getComputedStyle(el); return r.width>0 && r.height>0 && s.visibility!=='hidden' && s.display!=='none'; } var priceText=''; try{ var p=document.querySelector('.auction-action-price strong, .auction-action-price'); if(p) priceText=(p.textContent||p.innerText||'').trim(); }catch(e){} var priceVal=null; try{ if(priceText){ var p=priceText.replace('€','').replace(/\./g,'').replace(',','.').match(/\d+(?:\.\d+)?/); if(p) priceVal=p[0]; } }catch(e){} var btn=document.querySelector('a.auction-btn-bid, a.bid-button, .auction-btn-bid'); if(btn && isVisible(btn)){ var txt=(btn.textContent||btn.innerText||'').trim(); if(/\bINIZIA\b/i.test(txt)) return JSON.stringify({status:'soon', debug:txt, price: priceVal}); } try{ var direct=document.querySelector('.text-countdown-progressbar'); if(direct && isVisible(direct)){ var t=(direct.textContent||'').trim(); var m=t.match(/\d+/); if(m) return JSON.stringify({status:'found', timer:m[0], price: priceVal, debug: direct.outerHTML}); } }catch(e){} if(!btn || !isVisible(btn)){ var candidates=Array.from(document.querySelectorAll('a, button, div, span')).filter(e=> e && (e.innerText||e.textContent) && /\bPUNTA\b/i.test((e.InnerText||e.textContent)) && isVisible(e)); if(candidates.length>0) btn=candidates[0]; } if(!btn) return JSON.stringify({status:'no-button', price: priceVal}); var nodeList=Array.from(document.querySelectorAll('div, span, p, strong, b, i, em, label, small, a, svg text')); var nums=nodeList.map(e=>{ try{return {el:e, text:(e.textContent||'').trim(), rect:e.getBoundingClientRect(), html:(e.outerHTML||'')}; }catch(err){ return null; }}).filter(x=> x && /\d+/.test(x.text)).map(x=>({el:x.el, text:x.text, rect:x.rect, html:x.html})); if(nums.length==0) return JSON.stringify({status:'no-timer', price: priceVal}); function distanceRect(a,b){ var ax=(a.left+a.right)/2, ay=(a.top+a.bottom)/2; var bx=(b.left+b.right)/2, by=(b.top+b.bottom)/2; return Math.hypot(ax-bx, ay-by); } var btnRect; try{ btnRect = btn.getBoundingClientRect(); }catch(e){ btnRect = {top:0,left:0,right:0,bottom:0,width:0,height:0}; } nums.sort(function(a,b){ var da = distanceRect(a.rect, btnRect); var db = distanceRect(b.rect, btnRect); var ya = btnRect.top - a.rect.bottom; var yb = btnRect.top - b.rect.bottom; var pref = (ya>=0?0:200) - (yb>=0?0:200); return (da - db) + pref; }); var best=nums[0]; var m=(best.text||'').match(/\d+/); if(!m) return JSON.stringify({status:'no-timer-extracted', debug: best.html, price: priceVal}); return JSON.stringify({status:'found', timer:m[0], price: priceVal, debug: best.html}); }catch(e){ return JSON.stringify({status:'error', error: (e && e.message?e.message: e)}); } })();"; - const string clickScript = @"(function(){ var btn=document.querySelector('a.auction-btn-bid, a.bid-button, .auction-btn-bid'); if(!btn){ var candidates=Array.from(document.querySelectorAll('a, button, div, span')).filter(e=> e && (e.innerText||e.textContent) && /\bPUNTA\b/i.test((e.innerText||e.textContent))); if(candidates.length>0) btn=candidates[0]; } if(!btn) return 'no-button'; try{ btn.click(); return 'clicked'; }catch(e){ try{ var evt=document.createEvent('MouseEvents'); evt.initEvent('click', true, true); btn.dispatchEvent(evt); return 'dispatched'; }catch(ex){ return 'error:'+ (ex && ex.message?ex.message:ex); } } })();"; + const string clickScript = @"(function(){ try{ var btn=document.querySelector('a.auction-btn-bid, a.bid-button, .auction-btn-bid'); if(!btn){ var candidates=Array.from(document.querySelectorAll('a, button, div, span')).filter(e=> e && (e.innerText||e.textContent) && /\bPUNTA\b/i.test((e.InnerText||e.textContent))); if(candidates.length>0) btn=candidates[0]; } if(!btn) return 'no-button'; try{ btn.click(); return 'clicked'; }catch(e){ try{ var evt=document.createEvent('MouseEvents'); evt.initEvent('click', true, true); btn.dispatchEvent(evt); return 'dispatched'; }catch(ex){ return 'error:'+ (ex && ex.message?ex.message:ex); } } }catch(e){ return 'error:'+ (e && e.message?e.message:e); } })();"; - const string getLastBidderScript = @"(function(){ try{ var el=document.querySelector('.auction-current-winner'); if(el){ var name=(el.textContent||el.innerText||'').trim(); if(name) return JSON.stringify({status:'found', bidder:name}); } }catch(e){} return JSON.stringify({status:'not-found'}); })();"; + const string getLastBidderScript = @"(function(){ try{ var el=document.querySelector('.auction-current-winner'); if(el){ var name=(el.textContent||el.innerText||'').trim(); if(name) return JSON.stringify({status:'found', bidder:name}); } return JSON.stringify({status:'not-found'}); }catch(e){ return JSON.stringify({status:'error', error:(e&&e.message?e.message:e)}); } })();"; + + const string closedCountdownScript = @"(function(){ try{ var s=document.querySelector('.auction-action-countdown'); if(!s) return null; var ps=Array.from(s.querySelectorAll('p')).map(p=> (p.textContent||p.innerText||'').trim()); return JSON.stringify(ps); }catch(e){ return null; } })();"; const string pricePollScript = @"(function(){ var p=document.querySelector('.auction-action-price strong, .auction-action-price'); if(!p) return null; var t=(p.textContent||p.innerText||'').trim(); var num=t.replace('€','').replace(/\./g,'').replace(',','.').match(/\d+(?:\.\d+)?/); return num?num[0]:null; })();"; @@ -242,31 +248,33 @@ namespace AutoBidder return; } - string json = result ?? string.Empty; - if (json.Length >= 2 && json[0] == '"' && json[^1] == '"') json = JsonSerializer.Deserialize(json) ?? json; + if (!string.IsNullOrEmpty(result) && result.Length >= 2 && result[0] == '"' && result[^1] == '"') result = JsonSerializer.Deserialize(result) ?? result; - // read limits each iteration - int maxClicks = int.MaxValue, maxResets = int.MaxValue; double minPrice = 0.0, maxPrice = double.MaxValue; + // read limits each iteration (on UI thread) + int maxClicks = int.MaxValue, maxResets = int.MaxValue; + double minPrice = 0.0, maxPrice = double.MaxValue; try { - 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(',', '.'), System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out var mp)) minPrice = mp; - if (double.TryParse(MaxPriceBox.Text.Replace(',', '.'), System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out var mxa)) maxPrice = mxa > 0 ? mxa : double.MaxValue; + Dispatcher.Invoke(() => + { + try { if (int.TryParse(MaxClicksBox.Text, out var mc) && mc > 0) maxClicks = mc; } catch { } + try { if (int.TryParse(MaxResetsBox.Text, out var mr) && mr > 0) maxResets = mr; } catch { } + try { if (double.TryParse(MinPriceBox.Text.Replace(',', '.'), System.Globalization.NumberStyles.Any, CultureInfo.InvariantCulture, out var mp)) minPrice = mp; } catch { } + try { if (double.TryParse(MaxPriceBox.Text.Replace(',', '.'), System.Globalization.NumberStyles.Any, CultureInfo.InvariantCulture, out var mxa)) maxPrice = mxa > 0 ? mxa : double.MaxValue; } catch { } + }); } catch { } try { - using var doc = JsonDocument.Parse(json); + using var doc = JsonDocument.Parse(string.IsNullOrEmpty(result) ? "{}" : result); var root = doc.RootElement; - var status = root.GetProperty("status").GetString(); + var status = root.GetProperty("status").GetString() ?? string.Empty; - // price update if (root.TryGetProperty("price", out var priceEl) && priceEl.ValueKind != JsonValueKind.Null) { var priceStr = priceEl.GetString(); - if (!string.IsNullOrEmpty(priceStr) && double.TryParse(priceStr.Replace(',', '.').Trim(), System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out var pval)) + if (!string.IsNullOrEmpty(priceStr) && double.TryParse(priceStr.Replace(',', '.').Trim(), NumberStyles.Any, CultureInfo.InvariantCulture, out var pval)) { SetCurrentPriceText(pval.ToString("0.##") + " €"); } @@ -277,7 +285,7 @@ namespace AutoBidder Log("Stato: INIZIA TRA POCO. In attesa che appaia il pulsante PUNTA..."); while (!token.IsCancellationRequested) { - var op2 = Dispatcher.InvokeAsync(() => webView.ExecuteScriptAsync(@"(function(){ var b=document.querySelector('a.auction-btn-bid, a.bid-button'); if(!b) return 'no'; var t=(b.textContent||b.innerText||'').trim(); return /PUNTA/i.test(t)?'yes':'no'; })();")); + var op2 = Dispatcher.InvokeAsync(() => webView.ExecuteScriptAsync("(function(){ var b=document.querySelector('a.auction-btn-bid, a.bid-button'); if(!b) return 'no'; var t=(b.textContent||b.innerText||'').trim(); return /PUNTA/i.test(t)?'yes':'no'; })();")); var inner2 = await op2.Task.ConfigureAwait(false); var chk = await inner2.ConfigureAwait(false); if (!string.IsNullOrEmpty(chk)) @@ -291,36 +299,87 @@ namespace AutoBidder continue; } - if (status == "no-button") { Log("Nessun pulsante PUNTA trovato; arresto"); StopAutomation("Nessun pulsante PUNTA trovato; arresto"); return; } + if (status == "no-button") + { + Log("Nessun pulsante PUNTA trovato; arresto"); + StopAutomation("Nessun pulsante PUNTA trovato; arresto"); + return; + } + if (status == "no-timer" || status == "no-timer-extracted") { Log("Timer non trovato: pausa in corso, verrà ripreso quando il timer ricompare"); - bool resumed = false; - while (!token.IsCancellationRequested) + + // detect closed countdown / scheduled opening + try { - var op3 = Dispatcher.InvokeAsync(() => webView.ExecuteScriptAsync(findScript)); - var inner3 = await op3.Task.ConfigureAwait(false); - var pollResult = await inner3.ConfigureAwait(false); - var pollStr = pollResult ?? string.Empty; - if (pollStr.Length >= 2 && pollStr[0] == '"' && pollStr[^1] == '"') pollStr = JsonSerializer.Deserialize(pollStr) ?? pollStr; - try + var closedOp = Dispatcher.InvokeAsync(() => webView.ExecuteScriptAsync(closedCountdownScript)); + var closedInner = await closedOp.Task.ConfigureAwait(false); + var closedRaw = await closedInner.ConfigureAwait(false); + + if (!string.IsNullOrEmpty(closedRaw)) { - using var doc2 = JsonDocument.Parse(pollStr); - var st2 = doc2.RootElement.GetProperty("status").GetString(); - if (st2 == "found" || st2 == "soon") { Log("Timer ricomparso, ripresa."); resumed = true; break; } - if (st2 == "no-button") { Log("Nessun pulsante durante pausa; arresto"); StopAutomation("Nessun pulsante durante pausa"); return; } + if (closedRaw.Length >= 2 && closedRaw[0] == '"' && closedRaw[^1] == '"') closedRaw = JsonSerializer.Deserialize(closedRaw) ?? closedRaw; + try + { + var paragraphs = JsonSerializer.Deserialize(closedRaw); + var combined = paragraphs != null ? string.Join(" ", paragraphs.Where(p => !string.IsNullOrWhiteSpace(p))) : string.Empty; + if (!string.IsNullOrWhiteSpace(combined) && (combined.IndexOf("RIAPRE", StringComparison.OrdinalIgnoreCase) >= 0 || combined.IndexOf("L'asta inizia", StringComparison.OrdinalIgnoreCase) >= 0)) + { + Log("Asta in pausa rilevata: '" + combined + "'. Inizio countdown verso apertura."); + var m = Regex.Match(combined, "(\\d{1,2}:\\d{2})"); + DateTime? target = null; + if (m.Success) + { + var timeStr = m.Groups[1].Value; + if (combined.IndexOf("Oggi", StringComparison.OrdinalIgnoreCase) >= 0) + { + if (DateTime.TryParseExact(timeStr, "H:mm", CultureInfo.GetCultureInfo("it-IT"), DateTimeStyles.None, out var tod)) + { + target = DateTime.Today.Add(tod.TimeOfDay); + if (target <= DateTime.Now) target = target.Value.AddDays(1); + } + else if (TimeSpan.TryParse(timeStr, out var ts)) target = DateTime.Today.Add(ts); + } + else if (combined.IndexOf("Domani", StringComparison.OrdinalIgnoreCase) >= 0) + { + if (TimeSpan.TryParse(timeStr, out var ts2)) target = DateTime.Today.AddDays(1).Add(ts2); + } + else if (TimeSpan.TryParse(timeStr, out var ts3)) target = DateTime.Today.Add(ts3); + } + + if (target.HasValue) + { + Log($"Apertura programmata: {target.Value:g}. Log minuto-per-minuto avviato."); + while (!token.IsCancellationRequested && DateTime.Now < target.Value) + { + var remaining = target.Value - DateTime.Now; + Log($"Tempo rimanente all'apertura: {Math.Floor(remaining.TotalHours)}h {remaining.Minutes}m {remaining.Seconds}s"); + try { await Task.Delay(TimeSpan.FromMinutes(1), token).ConfigureAwait(false); } catch (OperationCanceledException) { break; } + } + + if (!token.IsCancellationRequested) Log("Orario di apertura raggiunto. Riprendo monitoraggio normale."); + continue; + } + + Log("Apertura programmata rilevata ma orario non interpretabile: '" + combined + "'"); + try { await Task.Delay(TimeSpan.FromMinutes(5), token).ConfigureAwait(false); } catch (OperationCanceledException) { break; } + continue; + } + } + catch { } } - catch { } - await Task.Delay(800, token).ConfigureAwait(false); } - if (!resumed) break; + catch { } + + try { await Task.Delay(800, token).ConfigureAwait(false); } catch (OperationCanceledException) { break; } continue; } if (status == "found") { var timerValue = root.GetProperty("timer").GetString(); - if (timerValue != previousTimer) { Log("Timer rilevato: " + timerValue); } + if (timerValue != previousTimer) Log("Timer rilevato: " + timerValue); try { @@ -329,30 +388,28 @@ namespace AutoBidder if (curr > prev) { resetCount++; - ResetCountText.Dispatcher.Invoke(() => ResetCountText.Text = resetCount.ToString()); + Dispatcher.Invoke(() => ResetCountText.Text = resetCount.ToString()); - // Attempt to read current winner from page and update bidders list try { - var opWin = Dispatcher.InvokeAsync(() => webView.ExecuteScriptAsync(getLastBidderScript)); - var innerWin = await opWin.Task.ConfigureAwait(false); - var lastWinRaw = await innerWin.ConfigureAwait(false); - if (!string.IsNullOrEmpty(lastWinRaw)) + var winOp = Dispatcher.InvokeAsync(() => webView.ExecuteScriptAsync(getLastBidderScript)); + var winInner = await winOp.Task.ConfigureAwait(false); + var winRaw = await winInner.ConfigureAwait(false); + if (!string.IsNullOrEmpty(winRaw) && winRaw.Length >= 2 && winRaw[0] == '"' && winRaw[^1] == '"') winRaw = JsonSerializer.Deserialize(winRaw) ?? winRaw; + if (!string.IsNullOrEmpty(winRaw)) { - if (lastWinRaw.Length >= 2 && lastWinRaw[0] == '"' && lastWinRaw[^1] == '"') lastWinRaw = JsonSerializer.Deserialize(lastWinRaw) ?? lastWinRaw; try { - using var docW = JsonDocument.Parse(lastWinRaw); - var rootW = docW.RootElement; - if (rootW.GetProperty("status").GetString() == "found") + using var dw = JsonDocument.Parse(winRaw); + var rw = dw.RootElement; + if (rw.GetProperty("status").GetString() == "found") { - var winnerName = rootW.GetProperty("bidder").GetString(); - if (!string.IsNullOrEmpty(winnerName)) - { - if (_bidders.ContainsKey(winnerName)) _bidders[winnerName]++; else _bidders[winnerName] = 1; - UpdateBiddersGrid(); - Log("Offerente registrato/reset: " + winnerName); - } + var winner = rw.GetProperty("bidder").GetString() ?? "Sconosciuto"; + var now = DateTime.Now; + if (_bidders.ContainsKey(winner)) _bidders[winner] = (_bidders[winner].Count + 1, now); + else _bidders[winner] = (1, now); + UpdateBiddersGrid(); + Log("Offerente registrato/reset: " + winner + " (" + now.ToString("g") + ")"); } } catch { } @@ -370,113 +427,92 @@ namespace AutoBidder previousTimer = timerValue; // price bounds handling - if (root.TryGetProperty("price", out var pEl2) && pEl2.ValueKind != JsonValueKind.Null && double.TryParse((pEl2.GetString() ?? "").Replace(',', '.'), System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out var pcur)) + if (root.TryGetProperty("price", out var pEl2) && pEl2.ValueKind != JsonValueKind.Null) { - if (pcur < minPrice) + var priceStr2 = pEl2.GetString(); + if (!string.IsNullOrEmpty(priceStr2) && double.TryParse(priceStr2.Replace(',', '.').Trim(), NumberStyles.Any, CultureInfo.InvariantCulture, out var pcur)) { - Log($"Prezzo {pcur:0.##}€ sotto limite minimo ({minPrice:0.##}). Pausa."); - while (!token.IsCancellationRequested) + if (pcur < minPrice) { - string? pricePoll = null; - try + Log($"Prezzo {pcur:0.##}€ sotto limite minimo ({minPrice:0.##}). Pausa."); + while (!token.IsCancellationRequested) { var opP = Dispatcher.InvokeAsync(() => webView.ExecuteScriptAsync(pricePollScript)); var innerP = await opP.Task.ConfigureAwait(false); - pricePoll = await innerP.ConfigureAwait(false); - } - catch { pricePoll = null; } - - if (!string.IsNullOrEmpty(pricePoll)) - { - if (pricePoll.Length >= 2 && pricePoll[0] == '"' && pricePoll[^1] == '"') pricePoll = JsonSerializer.Deserialize(pricePoll) ?? pricePoll; - if (double.TryParse(pricePoll.Replace(',', '.'), System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out var pp)) + var pricePoll = await innerP.ConfigureAwait(false); + if (!string.IsNullOrEmpty(pricePoll) && pricePoll.Length >= 2 && pricePoll[0] == '"' && pricePoll[^1] == '"') pricePoll = JsonSerializer.Deserialize(pricePoll) ?? pricePoll; + if (!string.IsNullOrEmpty(pricePoll) && double.TryParse(pricePoll.Replace(',', '.'), NumberStyles.Any, CultureInfo.InvariantCulture, out var pp)) { SetCurrentPriceText(pp.ToString("0.##") + " €"); if (pp >= minPrice) { Log("Prezzo salito sopra il minimo; ripresa esecuzione."); break; } } + try { await Task.Delay(700, token).ConfigureAwait(false); } catch (OperationCanceledException) { break; } } - - await Task.Delay(700, token).ConfigureAwait(false); } - } - - if (pcur > maxPrice) - { - Log($"Prezzo {pcur:0.##}€ sopra limite massimo ({maxPrice:0.##}). Pausa."); - while (!token.IsCancellationRequested) + else if (pcur > maxPrice) { - string? pricePoll = null; - try + Log($"Prezzo {pcur:0.##}€ sopra limite massimo ({maxPrice:0.##}). Pausa."); + while (!token.IsCancellationRequested) { var opP = Dispatcher.InvokeAsync(() => webView.ExecuteScriptAsync(pricePollScript)); var innerP = await opP.Task.ConfigureAwait(false); - pricePoll = await innerP.ConfigureAwait(false); - } - catch { pricePoll = null; } - - if (!string.IsNullOrEmpty(pricePoll)) - { - if (pricePoll.Length >= 2 && pricePoll[0] == '"' && pricePoll[^1] == '"') pricePoll = JsonSerializer.Deserialize(pricePoll) ?? pricePoll; - if (double.TryParse(pricePoll.Replace(',', '.'), System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out var pp)) + var pricePoll = await innerP.ConfigureAwait(false); + if (!string.IsNullOrEmpty(pricePoll) && pricePoll.Length >= 2 && pricePoll[0] == '"' && pricePoll[^1] == '"') pricePoll = JsonSerializer.Deserialize(pricePoll) ?? pricePoll; + if (!string.IsNullOrEmpty(pricePoll) && double.TryParse(pricePoll.Replace(',', '.'), NumberStyles.Any, CultureInfo.InvariantCulture, out var pp)) { SetCurrentPriceText(pp.ToString("0.##") + " €"); if (pp <= maxPrice) { Log("Prezzo sceso sotto il massimo; ripresa esecuzione."); break; } } + try { await Task.Delay(700, token).ConfigureAwait(false); } catch (OperationCanceledException) { break; } } - - await Task.Delay(700, token).ConfigureAwait(false); } } } if (timerValue == "0") { - // get last bidder name from page - string? lastBidderResult = null; + string? lastBidder = null; try { - var op3 = Dispatcher.InvokeAsync(() => webView.ExecuteScriptAsync(getLastBidderScript)); - var inner3 = await op3.Task.ConfigureAwait(false); - lastBidderResult = await inner3.ConfigureAwait(false); - } - catch { lastBidderResult = null; } - - string? bidderName = null; - if (!string.IsNullOrEmpty(lastBidderResult)) - { - if (lastBidderResult.Length >= 2 && lastBidderResult[0] == '"' && lastBidderResult[^1] == '"') lastBidderResult = JsonSerializer.Deserialize(lastBidderResult) ?? lastBidderResult; - try { using var d3 = JsonDocument.Parse(lastBidderResult); var r3 = d3.RootElement; if (r3.GetProperty("status").GetString() == "found") bidderName = r3.GetProperty("bidder").GetString(); } - catch { } + var opL = Dispatcher.InvokeAsync(() => webView.ExecuteScriptAsync(getLastBidderScript)); + var innerL = await opL.Task.ConfigureAwait(false); + var lr = await innerL.ConfigureAwait(false); + if (!string.IsNullOrEmpty(lr) && lr.Length >= 2 && lr[0] == '"' && lr[^1] == '"') lr = JsonSerializer.Deserialize(lr) ?? lr; + if (!string.IsNullOrEmpty(lr)) + { + try { using var d = JsonDocument.Parse(lr); var r = d.RootElement; if (r.GetProperty("status").GetString() == "found") lastBidder = r.GetProperty("bidder").GetString(); } + catch { lastBidder = lr; } + } } + catch { } if (!_pauseBids) { - string? clickResult = null; try { - var op2 = Dispatcher.InvokeAsync(() => webView.ExecuteScriptAsync(clickScript)); - var inner2 = await op2.Task.ConfigureAwait(false); - clickResult = await inner2.ConfigureAwait(false); + var opClick = Dispatcher.InvokeAsync(() => webView.ExecuteScriptAsync(clickScript)); + var innerClick = await opClick.Task.ConfigureAwait(false); + var clickRes = await innerClick.ConfigureAwait(false); + if (!string.IsNullOrEmpty(clickRes) && clickRes.Length >= 2 && clickRes[0] == '"' && clickRes[^1] == '"') clickRes = JsonSerializer.Deserialize(clickRes) ?? clickRes; + Log("Click eseguito: " + clickRes); + } + catch (Exception ex) + { + Log("Errore durante click JS: " + ex.Message); } - catch { clickResult = null; } - - if (!string.IsNullOrEmpty(clickResult) && clickResult.Length >= 2 && clickResult[0] == '"' && clickResult[^1] == '"') clickResult = JsonSerializer.Deserialize(clickResult) ?? clickResult; clickCount++; Dispatcher.Invoke(() => ClickCountText.Text = clickCount.ToString()); - Log("Click eseguito: " + clickResult + " (totale: " + clickCount + ")"); - try - { - var id = !string.IsNullOrEmpty(bidderName) ? bidderName : "AutoBidder"; - if (_bidders.ContainsKey(id)) _bidders[id]++; else _bidders[id] = 1; - UpdateBiddersGrid(); - } - catch { } + var id = !string.IsNullOrEmpty(lastBidder) ? lastBidder! : "AutoBidder"; + var now = DateTime.Now; + if (_bidders.ContainsKey(id)) _bidders[id] = (_bidders[id].Count + 1, now); + else _bidders[id] = (1, now); + UpdateBiddersGrid(); if (clickCount >= maxClicks) { StopAutomation($"Limite click raggiunto: {clickCount}"); return; } - await Task.Delay(postClickDelayMs, token).ConfigureAwait(false); + try { await Task.Delay(postClickDelayMs, token).ConfigureAwait(false); } catch (OperationCanceledException) { break; } continue; } } @@ -486,7 +522,10 @@ namespace AutoBidder { Log("Errore parsing JSON: " + ex.Message); } - catch (OperationCanceledException) { break; } + catch (OperationCanceledException) + { + break; + } catch (Exception ex) { Log("Errore loop: " + ex.Message); @@ -494,17 +533,11 @@ namespace AutoBidder return; } - await Task.Delay(200, token).ConfigureAwait(false); + try { await Task.Delay(200, token).ConfigureAwait(false); } catch (OperationCanceledException) { break; } } Dispatcher.Invoke(() => { StartButton.IsEnabled = true; StopButton.IsEnabled = false; StartButton.Opacity = 1.0; StopButton.Opacity = 0.5; }); Log("Automazione terminata"); } - - protected override void OnClosed(EventArgs e) - { - try { _cts?.Cancel(); } catch { } - base.OnClosed(e); - } } } \ No newline at end of file