From 98c648e9415cee1ac36429847141041c2efe3a9c Mon Sep 17 00:00:00 2001 From: Samuel Pua Date: Wed, 17 Jan 2024 01:38:16 +0800 Subject: [PATCH] Fix(background-booking): Body checks --- .../ktmtrainbot/backgroundbookingjob.go | 46 +++++++++++-------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/backend/internal/ktmtrainbot/backgroundbookingjob.go b/backend/internal/ktmtrainbot/backgroundbookingjob.go index fd417ca..933d3ae 100644 --- a/backend/internal/ktmtrainbot/backgroundbookingjob.go +++ b/backend/internal/ktmtrainbot/backgroundbookingjob.go @@ -84,7 +84,8 @@ func (env *Env) BackgroundJobRunner() { } else { // if there's job to do // Create next run where it's not the past (either from old NextRun or now()) timeNow := time.Now() - startTime := time.Date(timeNow.Year(), timeNow.Month(), timeNow.Day(), 00, 10, 0, 0, timeNow.Location()) + // Run at 12:13am + startTime := time.Date(timeNow.Year(), timeNow.Month(), timeNow.Day(), 00, 13, 0, 0, timeNow.Location()) endTime := startTime.Add(15 * time.Minute) if forceStartBooking || (timeNow.After(startTime) && timeNow.Before(endTime)) { @@ -232,7 +233,8 @@ func (env *Env) startBooking(job *Booking, username string, password string, cre currPage := getBookingSlots(browser, onwardDate, reverse) log.Println("Booking page loaded.") - currPage = selectBookingSlot(getBookingSlotCtx, currPage, timeCode) + delay := int(-5 + i) + currPage = selectBookingSlot(getBookingSlotCtx, currPage, timeCode, delay) log.Println("Booking slot selected.") // Make sure page completes loading @@ -290,7 +292,10 @@ func (env *Env) startBooking(job *Booking, username string, password string, cre <-filledPassengerDetailContext.Done() - passthroughLaggingPage = chooseAndMakePayment(timerCtx, creditCardType, creditCard, creditCardCVV, creditCardExpiry, browser, page) + envSkipMakePayment := os.Getenv("SKIP_MAKE_PAYMENT") + if strings.ToUpper(envSkipMakePayment) != "TRUE" { + passthroughLaggingPage = chooseAndMakePayment(timerCtx, creditCardType, creditCard, creditCardCVV, creditCardExpiry, browser, page) + } // Exits if context cancelled select { @@ -430,8 +435,7 @@ func getBookingSlots(browser *rod.Browser, onwardDate string, reverse bool) *rod return page } -func selectBookingSlot(ctx context.Context, page *rod.Page, timeCode string) *rod.Page { - time.Sleep(5 * time.Second) +func selectBookingSlot(ctx context.Context, page *rod.Page, timeCode string, delay int) *rod.Page { twoCaptchaAPIKey := os.Getenv("TWOCAPTCHA_API_KEY") needToWait := false @@ -450,10 +454,10 @@ func selectBookingSlot(ctx context.Context, page *rod.Page, timeCode string) *ro // Start probing reportedTicketDetails := false completed := false - retries := 2 + retries := 3 for !completed { if retries <= 0 { - log.Println("Used up retries. Exiting.") + log.Printf("[%d] Used up retries. Exiting.", delay) completed = true break } @@ -478,7 +482,7 @@ func selectBookingSlot(ctx context.Context, page *rod.Page, timeCode string) *ro } if rowElement == nil { - log.Println("No timeslot found. Waiting till context cancelled.") + log.Printf("[%d] No timeslot found. Waiting till context cancelled.", delay) <-ctx.Done() return nil } @@ -498,14 +502,15 @@ func selectBookingSlot(ctx context.Context, page *rod.Page, timeCode string) *ro // Wait for 1214am if needToWait { - log.Println("Waiting for 1214am") + log.Printf("[%d] Waiting for 1214am", delay) destinationTime := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), 0, 14, 0, 0, time.Now().Location()) + destinationTime = destinationTime.Add(time.Duration(delay) * time.Second) needToWaitTimer := time.NewTimer(time.Until(destinationTime)) select { case <-ctx.Done(): return page case <-needToWaitTimer.C: - log.Println("1214am reached") + log.Printf("[%d] 1214am reached", delay) } } @@ -514,13 +519,14 @@ func selectBookingSlot(ctx context.Context, page *rod.Page, timeCode string) *ro page.MustWaitLoad() time.Sleep(500 * time.Millisecond) + bodyText = page.MustElement("body").MustText() // Check if there is captcha - if strings.Contains(bodyText, "Please complete the reCAPTCHA") { + if strings.Contains(strings.ToLower(bodyText), "please complete the recaptcha") { // Reset Body text time.Sleep(500 * time.Millisecond) - log.Println("Captcha detected") + log.Printf("[%d] Captcha detected", delay) currURL := "https://shuttleonline.ktmb.com.my/ShuttleTrip" // Regex research for Google Captcha V2 API Key gcaptchaElement := page.MustElement(".g-recaptcha") @@ -531,24 +537,28 @@ func selectBookingSlot(ctx context.Context, page *rod.Page, timeCode string) *ro // Wait for 1215am if needToWait { - log.Println("Waiting for 1215am") + log.Printf("[%d] Waiting for 1215am", delay) destinationTime := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), 0, 15, 1, 0, time.Now().Location()) + destinationTime = destinationTime.Add(time.Duration(delay) * time.Second) needToWaitTimer := time.NewTimer(time.Until(destinationTime)) select { case <-ctx.Done(): return page case <-needToWaitTimer.C: - log.Println("1215am reached") + log.Printf("[%d] 1215am reached", delay) } } page.Eval(`RecaptchaCallback()`) + time.Sleep(500 * time.Millisecond) + page.MustWaitLoad() + log.Printf("[%d] Submitting captcha", delay) } // Check before exiting - bodyText := page.MustElement("body").MustText() + 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") + log.Printf("[%d] Maintenance modal detected on booking page after captcha", delay) completed = false closeModalButton := page.MustElement("#popupModalCloseButton") @@ -561,7 +571,7 @@ func selectBookingSlot(ctx context.Context, page *rod.Page, timeCode string) *ro // 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") + log.Printf("[%d] Not enough seat for onward trip", delay) completed = false closeModalButton := page.MustElement("#popupModalCloseButton") @@ -576,7 +586,7 @@ func selectBookingSlot(ctx context.Context, page *rod.Page, timeCode string) *ro if styleAttribute == nil || !strings.Contains(*styleAttribute, "display: none") { completed = false } else { - log.Println("Completed probing") + log.Printf("[%d] Completed probing", delay) completed = true }