Chrome 需要在 View - Developer 中打开 Allow JavaScript from AppleScript
AppleScript 中注入的 JS 需要注意一些事情
不支持顶层 await
需要将 " 转义为 \"
需要将 \u 转义为 \u
最后搞出来一个可以工作的版本:
// Name: new-learning-issue
import "@johnlindquist/kit"
var result: any
async function waitTabLoaded() {
await applescript(`if running of application "Google Chrome" then
tell application "Google Chrome"
if front window exists then
tell front window
repeat while (loading of active tab)
delay 0.1
end repeat
end tell
end if
end tell
end if`)
}
async function waitTabUrlToBe(url: string) {
await applescript(`if running of application "Google Chrome" then
tell application "Google Chrome"
if front window exists then
tell front window
repeat while (URL of active tab is not equal to "${url}")
delay 0.1
end repeat
end tell
end if
end tell
end if`)
}
/**
* @param {function} f
* - f's body will be executed in active tab by applescript
* - f's last expression value will the result of applescript which is 'success' or 'fail'
* - you should know what you are doing if you pass f into this function
*/
function extractCodeFrom(f) {
const s = f.toString()
return s.slice(s.indexOf("{") + 1, s.lastIndexOf("}"))
// escape the code
.replace(/"/g, '\\"')
}
function valueFromApplescriptIsValid(v: string) {
v = (v || '').trim()
return v && v !== 'fail' && v !== 'missing value'
}
async function makeBrowserExecute(f: () => void, isValid = valueFromApplescriptIsValid) {
const operation = f.name
const jsCode = extractCodeFrom(f)
let res = 'fail'
// 重试 10 次
for (let i = 0; i < 10; i++) {
const asInput = `
tell application "Google Chrome"
execute front window's active tab javascript "${jsCode}"
end tell`.replace(/\\u/g, '\\\\u')
res = await applescript(asInput)
if (isValid(res)) {
notify(`${operation} success: ${res}`)
console.log(`${operation} success: ${res}`)
return res
} else {
await wait(1000)
}
}
console.log(`${operation} fail: `, res)
throw new Error(`${operation} fail: ${res}`)
}
await hide()
await exec(`open 'https://github.com/xxleyi/learning_list/issues'`)
await waitTabLoaded()
function makeBrowserClickNewIssue() {
// query all buttons
let buttons = Array.from(document.querySelectorAll<HTMLLinkElement>("a[role='button']"))
// transform to array
// find the button with text "New issue"
let newIssueButton = buttons.find(button => button.textContent?.match(/new issue/i))
if (newIssueButton) {
// click the button
newIssueButton.click()
// return to applescript
result = 'success'
}
}
await makeBrowserExecute(makeBrowserClickNewIssue)
await waitTabUrlToBe('https://github.com/xxleyi/learning_list/issues/new')
await waitTabLoaded()
function makeBrowserFillTitle() {
// query title input
let titleInput = document.querySelector<HTMLInputElement>('input[name="issue[title]"]')
if (titleInput && titleInput.disabled === false) {
titleInput.focus()
// set the title
titleInput.value = '学习笔记'
// return to applescript
result = 'success'
}
}
await makeBrowserExecute(makeBrowserFillTitle)
script kit 是一个对前端开发很友好的工具,可以使用 JS 操控 Mac,将很多事情自动化。
需求:使用 script kit 控制浏览器,具体的技术点如下
使用浏览器打开 url 使用 AppleScript 将一段 JS 注入浏览器,并执行 其中第一点很轻松,第二点折腾了很久,才踩遍其中的坑。
坑:
最后搞出来一个可以工作的版本: