Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

automate chrome by script kit #329

Open
xxleyi opened this issue Feb 19, 2022 · 0 comments
Open

automate chrome by script kit #329

xxleyi opened this issue Feb 19, 2022 · 0 comments
Projects

Comments

@xxleyi
Copy link
Owner

xxleyi commented Feb 19, 2022

script kit 是一个对前端开发很友好的工具,可以使用 JS 操控 Mac,将很多事情自动化。

需求:使用 script kit 控制浏览器,具体的技术点如下

使用浏览器打开 url
使用 AppleScript 将一段 JS 注入浏览器,并执行
其中第一点很轻松,第二点折腾了很久,才踩遍其中的坑。

坑:

  • 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)
@xxleyi xxleyi added this to To do in 零碎 via automation Feb 19, 2022
@xxleyi xxleyi moved this from To do to Done in 零碎 Feb 19, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
零碎
  
Done
Development

No branches or pull requests

1 participant