pwnwriter/haylxon

A way to run arbitrary javascript on the page being screenshot

andxyz opened this issue · 10 comments

Description

Previously in a different tool I would run it with something along the lines of

--js='window.setTimeout(function() {window.scrollTo(0,document.body.scrollHeight);}, 100);window.setTimeout(function() {window.scrollTo(0,0);}, 400)'

I know that js looks ugly. But, this way I could capture images that relied on scrolling past them to load. Lazy loading images make the page look empty when I capture with something like

hxn -b /Applications/Chromium.app/Contents/MacOS/Chromium --width 1440 --fullpage --url "$url"

Any thoughts on a workaround.
Or adding this as a feature?

My thought is that, as a workaround, I could also write an extension for chromium that does this for me, and perhaps your program would end up autoloading my javascript extension on every webpage.

Related Documentation or Links

  • The old tool I was using 10 plus years ago was called webkit2png, I believe it was written in python2 and used webkit (I am pretty sure it is unmaintained and does not work anymore without all the old dependencies)
  • https://paulhammond.org/webkit2png

Hey,

Thanks for bringing this up!

Lazy loading images make the page look empty.

As a temporary solution, you can try the --delay argument.

I'll investigate this further over the weekend. Your idea to actually run arbitrary javascript is interesting and might be a good approach. I'll keep you updated on any progress :3

I've added a way to run arbitrary js inside the page. Can you clone from feat/js branch and test if that suits your case?

you can add your preferred js from --javascript option.

Okay! I can try out that branch, thank you. Please don't spend too much more time. I've also been working on an approach that uses puppeteer/puppeteer.

By the way, I tried the --delay command. It didn't work, the images wait to lazy load until the viewport scrolls over them.

No worries! I implemented it during my break. Could you test the branch and let me know. I'll merge it into the main branch to release the new version.

I can confirm that the javascript feature is working.

POC:

Screencast.2024-06-20.12.45.41.mp4

FYI: Here's the snippet of code to test out this feature.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Change Background Color via Console</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            text-align: center;
            margin-top: 50px;
        }
    </style>
</head>
<body>
    <h1>Change Background Color via Console</h1>
    <p>Open the browser console and use the <code>changeBackgroundColor(color)</code> function to change the background color.</p>

    <script>
        function changeBackgroundColor(color) {
            document.body.style.backgroundColor = color;
        }
    </script>
</body>
</html>

You can change the color using : changeBackgroundColor('color');

Thanks for confirming @subash0302 !

@pwnwriter I ended up testing this out, thanks for merging into master.

Here was what worked for me on a page with lazy loading images

hxn --url 'https://www.urbanstrategies.com/projects/' --binary '/Applications/Chromium.app/Contents/MacOS/Chromium'  --delay 2 -x 1440 -y 5000 --javascript '!function(){async function e(e){return new Promise(n=>setTimeout(n,e))}function n(){(async()=>{console.log("hello from app"),scroll_max_height=Math.max(6e3,document.body.scrollHeight),scroll_jump_size=900,console.log(scroll_max_height),console.log(scroll_jump_size);for(let n=0;n<scroll_max_height;n+=scroll_jump_size)window.scrollTo(0,n),await e(600);window.scrollTo(0,0)})()}(function e(n){return n=n||0,new Promise(e=>e(chrome.runtime)).then(o=>o?Promise.resolve():n>3?Promise.reject("Failed waiting for chrome.runtime"):(n+=1,new Promise(e=>window.setTimeout(e,500)).then(()=>e(n))))})().then(n).catch(e=>{console.error(e),n()})}();'

I ended up having to:

  • set a delay
  • set the y height, otherwise it wouldn't capture the full height of the webpage.
  • compress my javascript payload onto one line.
urbanstrategies.com/projects page

The final command line is a tad long, but it works! Thanks for this! ❤️

Note:

I previously tried a custom chrome extension to run my custom js but it was hard to make work from the commandline.
And my third attempt using a puppeteer script setup works, but is a bit too much to maintain for me.

In conclusion

This is a really nice solution. Thanks again for taking the time to add this feature

Glad It worked!

This is a really nice solution. Thanks again for taking the time to add this feature

Always happy to help :D

Amazing !