patrickmatte / scroll-capture

18 stars 5 forks source link

Feature Request: Script execution #36

Closed transportergit closed 5 months ago

transportergit commented 6 months ago

Similar to the option of adding CSS rules, it would be awesome to be able to execute javascript in the timeline.

e.g. define a custom function: myfunction(input) {}; in the beginning and later on call myfunction(300); to execute this function.

Scroll-Capture has become a very powerful and great tool! Awesome work Patrick! Keep it up. Thank you very much!

patrickmatte commented 6 months ago

Scroll capture actually launched with this functionality in 2020 but that was using extension manifest v2. Now with extension manifest v3 in effect, it is strictly prohibited to use eval or new Function so this feature had to be removed because it was now simply impossible to do.

transportergit commented 6 months ago

Ever thought about releasing the extension for Firefox and adding the script part for FF only? I know Manifest v3 is a joke, but Scroll Capture really does the trick for me and is such a great tool. The recording part is actually not really the core asset of SC, but the scripting and automation part - I think many people use either Quicktime or Xbox Game Bar on Windows for doing the recording, since this happens on OS level and not through the browser.

Many thanks for your awesome work!

patrickmatte commented 6 months ago

What do you need the javascript for? Do you have examples? My impression is that for most websites nowadays, the javascript sits in an anonymous closure that's not accessible through window unless you create an explicit hook. Someone else before has also requested this feature to be able to inject css and hide the scrollbar, so I ended up adding a CSS action and a checkbox to hide the scrollbar.

transportergit commented 6 months ago

Hi Patrick. Take this for example: https://www.omegawatches.com/de-at/planet-omega/60th-anniversary-speedmaster/broad-arrow-1957

This website captures the scroll event and translates it through its own logic. So SC is not working (at least the scrolling part).

However I have built a function that hooks into the logic and does the scrolling, ike so:

Function definition:

function customScrollByPixels(pixelAmount) {
    if (typeof app !== 'undefined' && app.scroll && typeof app.scroll.t !== 'undefined' && app.scroll.update) {
        // Convert pixelAmount to a normalized scroll value based on the total scrollable height
        var normalizedScroll = pixelAmount / app.scroll.scrollh;

        // Target normalized scroll position, ensuring it's within bounds
        var targetT = Math.max(0, Math.min(app.scroll.t + normalizedScroll, 1));

        // Use jQuery animate to smoothly transition to the target scroll position
        $({ scrollPosition: app.scroll.t }).animate({ scrollPosition: targetT }, {
            duration: 1000, // Animation duration in milliseconds
            easing: 'swing', // Easing function (can be changed as needed)
            step: function() {
                app.scroll.t = this.scrollPosition;
                app.scroll.tEase = app.scroll.t;
                app.scroll.top = -app.scroll.scrollh * (1 - app.scroll.t);
                app.scroll.update();
            }
        });
    } else {
        console.error('Scrolling system not available or incompatible.');
    }
}

Instead of using the scrolling method of SC, I'd call customScrollByPixels(500).

patrickmatte commented 5 months ago

Given V3's restrictions, I think the best I could do for now is to add a text input to indicate which function you want to call. You could compile the function in the code of the website or paste it inside the javascript console of the dev tools before playing the actions. You won't be able to capture a website intro if you paste it in the console. The function would need to return a promise that you resolve when the animation is finished. ex.: window.customScroll = function(value) { return new Promise((resolve, reject) => { animate({...., onComplete:resolve}) }); }

Then in the scroll capture input, you would just enter "window.customScroll(500)" and when the promise is resolve the next action would start.

In the future, I could use a library called "acorn" that creates an abstract syntax tree from which it is possible to build an eval function to execute any string of javascript. I've found only one eval library like this that runs in the browser without nodejs but it is using an old version of acorn so it is a bit buggy. Though I'm not sure it'd be legit to go around v3's restrictions like that...

transportergit commented 5 months ago

compile the function in the code of the website or paste it inside the javascript console of the dev tools

This is a great idea. I thought about that too. A little less convenient for the average user, but an option neverthless.

Though I'm not sure it'd be legit to go around v3's restrictions like that

stupid rules are there to be challenged :) in the end v3 is just a way for Google to maximize ad profits and cripple adblockers. so....

patrickmatte commented 5 months ago

I did some exploration last night and remembered that extension content scripts live in a different window context. So even if eval and new Function still worked, the extension would not have access to the '$' function or the 'app' property of the website. I guess I could add a version of JQuery to the scroll capture codebase for you to use but it still won't be able to access "app". And also forget about what I said earlier about pasting code in the window console, that code won't be accessible to scroll capture either. The only way to communicate with the website's scripts is to send a message to the extension as documented here https://developer.chrome.com/docs/extensions/develop/concepts/messaging "Extensions can also receive and respond to messages from other web pages, but can't send messages to web pages." I think that significantly narrows down the use of a JS action for scroll capture.

transportergit commented 5 months ago

How did you solve this problem in the prior versions of SC then? Or maybe this is really something that is better be done for Firefox. Porting shouldn't be a big challenge after all if I read it correctly? https://extensionworkshop.com/documentation/develop/porting-a-google-chrome-extension/

patrickmatte commented 5 months ago

This problem was never solved. With v2 manifest, the JS action could run code in the extension context by using 'new Function' but the context was still separate from the web page window context. You're the first person asking about accessing the code inside the web page. Firefox has a special x-ray bridge that you can use to access the web page window context but unfortunately, it can't be done with Chrome.

By the way, I added the JS action back to scroll capture last night, by using the acorn parser and a custom evaluation method, it seems to run but it hasn't been extensively tested so it could be buggy.

As for Firefox, unless I eventually turn scroll capture into a monthly / annual paid subscription service, I doubt that I will make a version for any other browser than chrome. I just spent the past 5 months fixing issues and adding new functionalities, I think I'm pretty much done for awhile. I've got other work lined-up for the next two or three months.

On the info page, there's a link to git sponsorships and so far, only two people have sponsored me for a total of just 50$. So porting this to other browsers is low priority.

I'll keep searching for a way to communicate with the web page with chrome, maybe the scroll action could be modified so it broadcast a message to the web page with the scroll value. Then you'd just have to listen for the message in the webpage and apply the scroll value to the proper method.

patrickmatte commented 5 months ago

Actually, I think I just found a way. I can call window.dispatchEvent(new Event("sc-scroll")) from scroll capture and the event also fires off in the web page! So all you'll have to do is listen for the scroll capture scroll event then call your method with the event's scrollX and ScrollY values. Easy! One problem is that the scroll action will need an input for "start value" to be added since I can't find the current scroll value of the website.

patrickmatte commented 5 months ago

Reading from this, there seem to be other otptions too. I'll dig in and come back with a solution. https://stackoverflow.com/questions/9515704/access-variables-and-functions-defined-in-page-context-from-an-extension/9517879#9517879

patrickmatte commented 5 months ago

If it gets accepted by the chrome store, you're gonna love this new version. There are two ways to do what you wanted.

  1. Paste all your code in a javascript action. It turns out that it seems possible to use new Function or eval when calling chrome.scripting.executeScript when the world property is set to "MAIN".

  2. Use the scroll action with the target set to "Custom JS method". This adds two textareas to define getter and setter scripts for x and y values. So you can use the easing, delay and timing of the scroll action but call your own code with the x and y values.

I think all this is pretty rad but I wouldn't be surprised if the chrome store rejects it because of 'eval'.

Capture d’écran, le 2024-03-15 à 10 46 10 Capture d’écran, le 2024-03-15 à 10 48 34
transportergit commented 5 months ago

fingers crossed. love you!

patrickmatte commented 5 months ago

0.3.2 is now available. Thanks for requesting the feature and the support, scroll capture is now better for it.

transportergit commented 5 months ago

Thank you very much Patrick. The new features work really well!