renderthis icon indicating copy to clipboard operation
renderthis copied to clipboard

Error: Chromote: timed out waiting for event Page.loadEventFired

Open beausoleilmo opened this issue 1 year ago • 5 comments

I'm using renderthis::to_pdf to print a pdf from an HTML file. However, I get Error: Chromote: timed out waiting for event Page.loadEventFired. Is there a way to fix this? The HTML file is 33.9MB.

library(pdftools)    # version 3.4.0 
library(renderthis) # version 0.2.1
library(chromote)   # version 0.2.0.9

renderthis::to_pdf(from = "presentation/my_pres.html",
                   to = "presentation/my_pres.pdf",
                   delay = 1, 
                   complex_slides = TRUE,
                   partial_slides = TRUE)
R version 4.3.1 (2023-06-16)
Platform: aarch64-apple-darwin20 (64-bit)
Running under: macOS Sonoma 14.3.1

Chrome (Version 124.0.6367.201 (Official Build) (arm64)) is installed on my computer.

When setting complex_slides = FALSE and partial_slides = FALSE, I only get the first slide.

beausoleilmo avatar May 13 '24 04:05 beausoleilmo

I sometimes get this as well with larger files. Can you check that things work with a relatively simple and small html page? Often times I just quit RStudio and restart and try again and it works.

jhelvy avatar May 13 '24 12:05 jhelvy

I restarted my computer, RStudio but still no luck.

This is an attempt at making it work and probably not a fix. I commented a bunch of lines (e.g., b$Page$loadEventFired()) to diagnose the problem and now I'm able to make it work. Don't know why specifically, but I'm glad I'm able to export the slides now. Also, it appeared that the get.ratio() command was reading the information too fast and so wasn't returning the ratio of the presentation. So I added a wait time of 10 seconds for the presentation to load Sys.sleep(10).

to_pdf_complex_mod = function (input, output_file, partial_slides, delay) 
{
  if (!requireNamespace("chromote", quietly = TRUE)) {
    stop("`chromote` is required: devtools::install_github('rstudio/chromote')")
  }
  if (!requireNamespace("pdftools", quietly = TRUE)) {
    stop("`pdftools` is required: install.packages('pdftools')")
  }
  b <- chromote::ChromoteSession$new()
  on.exit(b$close(), add = TRUE)
  b$Page$navigate(input, wait_ = TRUE)
  # b$Page$loadEventFired()
  has_remark <- b$Runtime$evaluate("typeof slideshow !== 'undefined'")$result$value
  # if (!has_remark) {
  #   stop("Input does not appear to be xaringan or quarto slides: ", 
  #        input)
  # }
  current_slide <- function() {
    x <- b$Runtime$evaluate("slideshow.getCurrentSlideIndex()")$result$value
    as.integer(x) + 1L
  }
  slide_is_continuation <- function() {
    b$Runtime$evaluate("document.querySelector('.remark-visible').matches('.has-continuation')")$result$value
  }
  hash_current_slide <- function() {
    digest::digest(b$Runtime$evaluate("document.querySelector('.remark-visible').innerHTML")$result$value)
  }
  get_ratio <- function() {
    r <- b$Runtime$evaluate("slideshow.getRatio()")$result$value
    r <- lapply(strsplit(r, ":"), as.integer)
    width <- r[[1]][1]
    height <- r[[1]][2]
    page_width <- 8/width * width
    list(width = as.integer(908 * width/height), height = 681L, 
         page = list(width = page_width, height = page_width * 
                       height/width))
  }
  message("Waiting to load...") # ADDED 
  Sys.sleep(10)                 # ADDED 
  slide_size <- get_ratio()
  expected_slides <- as.integer(b$Runtime$evaluate("slideshow.getSlideCount()")$result$value)
  max_slides <- expected_slides * 4
  # b$Browser$setWindowBounds(1, bounds = list(width = slide_size$width,
  #                                            height = slide_size$height))
  b$Emulation$setEmulatedMedia("print")
  b$Runtime$evaluate(paste0("let style = document.createElement('style')\n", 
                            "style.innerText = '@media print { ", ".remark-slide-container:not(.remark-visible){ display:none; }", 
                            if (partial_slides) 
                              " .has-continuation { display: block }", "}'\n", 
                            "document.head.appendChild(style)"))
  # proc <- cli_build_start(input, output_file)
  pb <- progress::progress_bar$new(format = "Slide :slide (:part) [:bar] Eta: :eta", 
                                   total = expected_slides)
  idx_slide <- current_slide()
  last_hash <- ""
  idx_part <- 0L
  pdf_files <- c()
  for (i in seq_len(max_slides)) {
    if (i > 1) {
      b$Input$dispatchKeyEvent("rawKeyDown", windowsVirtualKeyCode = 39, 
                               code = "ArrowRight", key = "ArrowRight", wait_ = TRUE)
    }
    if (current_slide() == idx_slide) {
      step <- 0L
      idx_part <- idx_part + 1L
    }
    else {
      step <- 1L
      idx_part <- 1L
    }
    idx_slide <- current_slide()
    pb$tick(step, tokens = list(slide = idx_slide, part = idx_part))
    if (!isTRUE(partial_slides) && slide_is_continuation()) 
      next
    Sys.sleep(delay)
    this_hash <- hash_current_slide()
    if (identical(last_hash, this_hash)) 
      break
    last_hash <- this_hash
    pdf_file_promise <- b$Page$printToPDF(landscape = TRUE, 
                                          printBackground = TRUE, paperWidth = 12, paperHeight = 9, 
                                          marginTop = 0, marginRight = 0, marginBottom = 0, 
                                          marginLeft = 0, pageRanges = "1", preferCSSPageSize = TRUE, 
                                          wait_ = FALSE)$then(function(value) {
                                            filename <- tempfile(fileext = ".pdf")
                                            writeBin(jsonlite::base64_dec(value$data), filename)
                                            filename
                                          })
    pdf_files <- c(pdf_files, b$wait_for(pdf_file_promise))
  }
  pdftools::pdf_combine(pdf_files, output = output_file)
  fs::file_delete(pdf_files)
  # cli::cli_process_done(proc)
  invisible(output_file)
  message("Done!") # ADDED 
}

I used the input "file:///pathto/presentation/my_pres.html#1". I hope this can help in finding a solution.

beausoleilmo avatar May 13 '24 13:05 beausoleilmo

It works! @gadenbuie what do you think about adding an argument like sleep = 0 or load_sleep = 0 so users can optionally provide a sleep delay to allow the slides to load? Either that or perhaps we could find some way of checking that the page has loaded before going forward. That's probably the better solution as the sleep thing is a bit hacky, but I don't readily know how to confirm that a page has loaded.

jhelvy avatar May 13 '24 15:05 jhelvy

Good! Actually, I tried a bunch of values for sleep time. 8 was working, but I went for 10 to be sure. I was wondering if there was a function that could indeed confirm that the page is loaded... but im not aware of any. Also, not sure why b$Page$loadEventFired() is causing the Error: Chromote: timed out waiting for event Page.loadEventFired and if it's needed for the function to work.

beausoleilmo avatar May 13 '24 16:05 beausoleilmo

I added an option in chromote called chromote.timeout, but unfortunately it doesn't set the timeout in the right place to affect this call. I think it should though, so I'll look into fixing that.

Even then, you probably don't want to elevate every timeout, just the page load timeout. The easiest way to do that would be to add an argument like timeout_page_load to to_pdf_complex() that gets passed to b$Page$LoadEventFired(timeout_ = timeout_page_load).

@beausoleilmo if you could try that out and let us know if it works, that'd be great! I'd also be very happy to review a PR 😉

gadenbuie avatar May 14 '24 01:05 gadenbuie