From e6c37327ee1f4e201949a61141f5b949799dc0ca Mon Sep 17 00:00:00 2001 From: Samuel Pua Date: Wed, 3 Jan 2024 00:26:58 +0800 Subject: [PATCH] Feat(captcha): Pre-solve captcha --- .../ktmtrainbot/backgroundbookingjob.go | 85 ++++++++++++------- 1 file changed, 56 insertions(+), 29 deletions(-) diff --git a/backend/internal/ktmtrainbot/backgroundbookingjob.go b/backend/internal/ktmtrainbot/backgroundbookingjob.go index 87de235..fd417ca 100644 --- a/backend/internal/ktmtrainbot/backgroundbookingjob.go +++ b/backend/internal/ktmtrainbot/backgroundbookingjob.go @@ -447,23 +447,17 @@ func selectBookingSlot(ctx context.Context, page *rod.Page, timeCode string) *ro time.Sleep(1000 * time.Millisecond) } - // Wait for 1215am - if needToWait { - log.Println("Waiting for 1215am") - destinationTime := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), 0, 15, 1, 0, time.Now().Location()) - needToWaitTimer := time.NewTimer(time.Until(destinationTime)) - select { - case <-ctx.Done(): - return page - case <-needToWaitTimer.C: - log.Println("1215am reached") - } - } - // Start probing reportedTicketDetails := false completed := false + retries := 2 for !completed { + if retries <= 0 { + log.Println("Used up retries. Exiting.") + completed = true + break + } + page.MustWaitLoad() // Checks for context before proceeding @@ -502,51 +496,82 @@ func selectBookingSlot(ctx context.Context, page *rod.Page, timeCode string) *ro default: } + // Wait for 1214am + if needToWait { + log.Println("Waiting for 1214am") + destinationTime := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), 0, 14, 0, 0, time.Now().Location()) + needToWaitTimer := time.NewTimer(time.Until(destinationTime)) + select { + case <-ctx.Done(): + return page + case <-needToWaitTimer.C: + log.Println("1214am reached") + } + } + selectButtonElement := rowElement.MustElement("a") selectButtonElement.Eval(`this.click()`) page.MustWaitLoad() time.Sleep(500 * time.Millisecond) + // Check if there is captcha + if strings.Contains(bodyText, "Please complete the reCAPTCHA") { + // Reset Body text + time.Sleep(500 * time.Millisecond) + + log.Println("Captcha detected") + currURL := "https://shuttleonline.ktmb.com.my/ShuttleTrip" + // Regex research for Google Captcha V2 API Key + gcaptchaElement := page.MustElement(".g-recaptcha") + googleRecaptchaKey := gcaptchaElement.MustAttribute("data-sitekey") + log.Printf("Google CAPTCHA V2 Key: %s", *googleRecaptchaKey) + captchaAnswer := captchasolver.Provider2CaptchaV2E2E(twoCaptchaAPIKey, currURL, *googleRecaptchaKey) + page.MustElement("#g-recaptcha-response").Eval(`this.innerHTML = "` + captchaAnswer + `"`) + + // Wait for 1215am + if needToWait { + log.Println("Waiting for 1215am") + destinationTime := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), 0, 15, 1, 0, time.Now().Location()) + needToWaitTimer := time.NewTimer(time.Until(destinationTime)) + select { + case <-ctx.Done(): + return page + case <-needToWaitTimer.C: + log.Println("1215am reached") + } + } + + page.Eval(`RecaptchaCallback()`) + } + // Check before exiting bodyText := page.MustElement("body").MustText() if strings.Contains(bodyText, "System maintenance scheduled at 23:00 to 00:15 (UTC+8).") { + log.Println("Maintenance modal detected on booking page after captcha") completed = false closeModalButton := page.MustElement("#popupModalCloseButton") closeModalButton.Eval(`this.click()`) time.Sleep(1000 * time.Millisecond) + retries -= 1 continue } // Repeat if there's no seats -- seats might be released later if strings.Contains(bodyText, "Not enough seat for onward trip") { + log.Println("Not enough seat for onward trip") completed = false closeModalButton := page.MustElement("#popupModalCloseButton") closeModalButton.Eval(`this.click()`) time.Sleep(1000 * time.Millisecond) + retries -= 1 continue } - // Check if there is captcha - if strings.Contains(bodyText, "Please complete the reCAPTCHA") { - // Reset Body text - time.Sleep(500 * time.Millisecond) - - log.Println("Captcha detected") - currURL := "https://shuttleonline.ktmb.com.my/ShuttleTrip" - // Regex research for Google Captcha V2 API Key - gcaptchaElement := page.MustElement(".g-recaptcha") - googleRecaptchaKey := gcaptchaElement.MustAttribute("data-sitekey") - log.Printf("Google CAPTCHA V2 Key: %s", *googleRecaptchaKey) - captchaAnswer := captchasolver.Provider2CaptchaV2E2E(twoCaptchaAPIKey, currURL, *googleRecaptchaKey) - page.MustElement("#g-recaptcha-response").Eval(`this.innerHTML = "` + captchaAnswer + `"`) - page.Eval(`RecaptchaCallback()`) - } - styleAttribute := selectButtonElement.MustAttribute("style") if styleAttribute == nil || !strings.Contains(*styleAttribute, "display: none") { completed = false @@ -555,6 +580,8 @@ func selectBookingSlot(ctx context.Context, page *rod.Page, timeCode string) *ro completed = true } + retries -= 1 + } // Checks for context before clicking