diff --git a/docs/multi.md b/docs/multi.md index a818837..7dc039b 100644 --- a/docs/multi.md +++ b/docs/multi.md @@ -43,6 +43,55 @@ To take a screenshot of just the area of a page defined by a CSS selector, add ` selector: "#bighead" ``` +Use `--macro` to run JavaScript before every shot is taken: + + shot-scraper multi shots.yml --macro macros.yaml + +Macros can be a `script` or a `function`: + +* `script` is executed immediately +* `function` exposes a function that can be called in your `javascript` block: + +Sample `macros.yaml`: + +```yaml +- type: script + javascript: | + function (){ + console.log("This runs before the shot is taken") + } + +- type: function + name: sayHello + javascript: | + function (){ + console.log("Hello World") + } + +``` + +Sample `shots.yaml`: + +```yaml +- output: demo.png + url: https://example.com + width: 1920 + height: 1080 + javascript: | + function(){ + console.log("Taking a shot"); + sayHello(); + } +``` + +Expected output (if using `--log-console`): + +``` +This runs before the shot is taken +Taking a shot +Hello World +``` + You can pass more than one selector using a `selectors:` list. You can also use `padding:` to specify additional padding: ```yaml diff --git a/shot_scraper/cli.py b/shot_scraper/cli.py index b37f94e..db31bf2 100644 --- a/shot_scraper/cli.py +++ b/shot_scraper/cli.py @@ -389,6 +389,11 @@ def _browser_context( help="Just take shots matching these output files", multiple=True, ) +@click.option( + "--macro", + type=click.File("r"), + help="Apply the macros contained in this file to all shots", +) @browser_option @user_agent_option @reduced_motion_option @@ -403,6 +408,7 @@ def multi( fail_on_error, noclobber, outputs, + macro, browser, user_agent, reduced_motion, @@ -426,6 +432,14 @@ def multi( https://shot-scraper.datasette.io/en/stable/multi.html """ + # Load macros config + macroConfig = [] + if macro: + macroConfig = yaml.safe_load(macro) + if not isinstance(macroConfig, list): + raise click.ClickException("Macro file must contain a list") + + # Load shots config shots = yaml.safe_load(config) if shots is None: shots = [] @@ -451,6 +465,7 @@ def multi( if outputs and shot.get("output") not in outputs: continue try: + shot['macros'] = macroConfig take_shot( context, shot, @@ -1004,6 +1019,17 @@ def on_response(response): if wait: time.sleep(wait / 1000) + macros = shot.get("macros") + if macros: + for macro in macros: + if macro['type'] == 'script': + _evaluate_js(page, macro['javascript']) + elif macro['type'] == 'function': + _evaluate_js(page, "function(){{ window.{} = {} }}".format(macro['name'], macro['javascript'])) + else: + raise click.ClickException("Invalid macro type: '{}'".format(macro['type'])) + + javascript = shot.get("javascript") if javascript: _evaluate_js(page, javascript)