SPB Git

Repository Public Research preview

applescript-recipes.md 8.1 KB 204 lines markdown

1# AppleScript recipes23Each file in `scripts/recipes/` is a complete program for `osascript`, tested against Safari on a local4site. Values are passed as arguments, never pasted into source. Typical sequence:56```bash7W=$(osascript scripts/recipes/open-window.applescript "https://example.org/")8osascript scripts/recipes/wait-for-load.applescript "$W" 1 309osascript scripts/recipes/get-text.applescript "$W" 110osascript scripts/recipes/fill-field.applescript "$W" 1 'input[name="q"]' "tide tables"11osascript scripts/recipes/click.applescript "$W" 1 'button[type="submit"]'12osascript scripts/recipes/wait-for-load.applescript "$W" 1 3013osascript scripts/recipes/fetch-base64.applescript "$W" 1 /export.csv | base64 -D > export.csv14screencapture -x -o -l "$W" page.png        # the window id is the system window number15osascript scripts/recipes/close-window.applescript "$W"16```1718Keep the window id from the first step and use it everywhere. Wait after every step that19navigates. `fill-field` and `click` print `not-found` when the selector matches nothing: check it.2021## `open-window.applescript`2223```applescript24-- Open a URL in a NEW Safari window and print that window's id.25-- Usage: osascript open-window.applescript "https://example.com/"26-- Keep the id: it is stable for the life of the window, unlike "window 1" or "front window",27-- which change whenever the user clicks another window.28on run argv29	tell application "Safari"30		make new document with properties {URL:(item 1 of argv)}31		return id of window 132	end tell33end run34```3536## `wait-for-load.applescript`3738```applescript39-- Wait until a tab has finished navigating. Prints "loaded" or "timeout".40-- Usage: osascript wait-for-load.applescript <window-id> <tab-index> [timeout-seconds]41-- Safari sets "URL of tab" to the destination as soon as a navigation starts, while the old42-- document is still the one that answers JavaScript. The page is ready when the document's own43-- URL has caught up AND readyState is "complete" — checking readyState alone reports the OLD page.44on run argv45	set w to (item 1 of argv) as integer46	set t to (item 2 of argv) as integer47	set limit to 3048	if (count of argv) > 2 then set limit to (item 3 of argv) as integer49	set deadline to (current date) + limit50	set calm to 051	repeat while (current date) < deadline52		try53			tell application "Safari"54				set tabURL to URL of tab t of window id w55				set state to do JavaScript "location.href + '\\n' + document.readyState" in tab t of window id w56			end tell57			if state is (tabURL & linefeed & "complete") then58				set calm to calm + 159				if calm ≥ 2 then return "loaded"60			else61				set calm to 062			end if63		on error64			set calm to 0 -- the tab is between documents: try again65		end try66		delay 0.267	end repeat68	return "timeout"69end run70```7172## `list-tabs.applescript`7374```applescript75-- List the tabs of one window: index, URL and title, tab-separated, one per line.76-- Usage: osascript list-tabs.applescript <window-id>77on run argv78	set w to (item 1 of argv) as integer79	set out to ""80	-- Inside a Safari "tell" block the word "tab" means a browser tab, not the tab character:81	-- name the separator outside it.82	set sep to character id 983	tell application "Safari"84		repeat with t in tabs of window id w85			set u to URL of t86			if u is missing value then set u to ""87			set n to name of t88			if n is missing value then set n to ""89			set out to out & (index of t) & sep & u & sep & n & (character id 10)90		end repeat91	end tell92	return out93end run94```9596## `run-js.applescript`9798```applescript99-- Run JavaScript in a tab and print the result.100-- Usage: osascript run-js.applescript <window-id> <tab-index> '<javascript>'101-- The code travels as an argument, so it needs no AppleScript escaping.102-- Return a string (JSON.stringify(...)): objects, undefined and promises come back empty.103on run argv104	set w to (item 1 of argv) as integer105	set t to (item 2 of argv) as integer106	tell application "Safari"107		set r to do JavaScript (item 3 of argv) in tab t of window id w108	end tell109	try110		return r111	on error112		return ""113	end try114end run115```116117## `get-text.applescript`118119```applescript120-- Print the visible text of a tab.121-- Usage: osascript get-text.applescript <window-id> <tab-index>122on run argv123	set w to (item 1 of argv) as integer124	set t to (item 2 of argv) as integer125	tell application "Safari"126		return do JavaScript "document.body ? document.body.innerText : ''" in tab t of window id w127	end tell128end run129```130131## `fill-field.applescript`132133```applescript134-- Set the value of a form field so that the page's own code notices.135-- Usage: osascript fill-field.applescript <window-id> <tab-index> '<css-selector>' '<value>'136-- Assigning el.value alone is ignored by React, Vue and similar frameworks: they patch the137-- property. Calling the native setter and then firing "input" and "change" works everywhere.138-- Prints "ok", or "not-found".139on run argv140	set w to (item 1 of argv) as integer141	set t to (item 2 of argv) as integer142	set js to "(function(sel, val){var el=document.querySelector(sel); if(!el) return 'not-found';" & ¬143		"var proto = el.tagName==='TEXTAREA' ? HTMLTextAreaElement.prototype : el.tagName==='SELECT' ? HTMLSelectElement.prototype : HTMLInputElement.prototype;" & ¬144		"Object.getOwnPropertyDescriptor(proto,'value').set.call(el, val);" & ¬145		"el.dispatchEvent(new Event('input',{bubbles:true})); el.dispatchEvent(new Event('change',{bubbles:true})); return 'ok';})"146	-- JSON.stringify-style quoting of the two arguments is done in JavaScript, not here.147	set call to js & "(decodeURIComponent('" & my encode(item 3 of argv) & "'), decodeURIComponent('" & my encode(item 4 of argv) & "'))"148	tell application "Safari"149		return do JavaScript call in tab t of window id w150	end tell151end run152153-- Percent-encode every byte, so no character of the value can break out of the JavaScript string.154on encode(s)155	return do shell script "/usr/bin/python3 -c 'import sys,urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=\"\"))' " & quoted form of s156end encode157```158159## `click.applescript`160161```applescript162-- Click the first element matching a CSS selector. Prints "ok" or "not-found".163-- Usage: osascript click.applescript <window-id> <tab-index> '<css-selector>'164-- el.click() runs the page's handlers and follows links. It does not move the real pointer.165on run argv166	set w to (item 1 of argv) as integer167	set t to (item 2 of argv) as integer168	set sel to do shell script "/usr/bin/python3 -c 'import sys,urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=\"\"))' " & quoted form of (item 3 of argv)169	tell application "Safari"170		return do JavaScript "(function(s){var el=document.querySelector(s); if(!el) return 'not-found'; el.scrollIntoView({block:'center'}); el.click(); return 'ok';})(decodeURIComponent('" & sel & "'))" in tab t of window id w171	end tell172end run173```174175## `fetch-base64.applescript`176177```applescript178-- Download a URL from inside the page — with the site's cookies and sign-in — and print it as179-- base64. Pipe the output into a file:180--   osascript fetch-base64.applescript <window-id> <tab-index> '/path/or/url' | base64 -D > file.bin181-- Prints "HTTP <status>" on stderr-like first line when the server refuses. Same-origin URLs only182-- (the browser's own rules). Suited to files up to a few megabytes; larger ones need chunking.183on run argv184	set w to (item 1 of argv) as integer185	set t to (item 2 of argv) as integer186	set u to do shell script "/usr/bin/python3 -c 'import sys,urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=\"\"))' " & quoted form of (item 3 of argv)187	-- do JavaScript cannot wait for a promise, so the request is synchronous.188	set js to "(function(u){var x=new XMLHttpRequest(); x.open('GET',u,false); x.overrideMimeType('text/plain; charset=x-user-defined'); x.send();" & ¬189		"if(x.status<200||x.status>=300) return 'HTTP '+x.status; var s=x.responseText, b=''; for(var i=0;i<s.length;i++) b+=String.fromCharCode(s.charCodeAt(i)&255); return btoa(b);})(decodeURIComponent('" & u & "'))"190	tell application "Safari"191		return do JavaScript js in tab t of window id w192	end tell193end run194```195196## `close-window.applescript`197198```applescript199-- Close a window by id. Usage: osascript close-window.applescript <window-id>200on run argv201	tell application "Safari" to close window id ((item 1 of argv) as integer)202end run203```204
Files main
Menu

Theme