auto-run-script-for-every-task

try to take over the world!

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         auto-run-script-for-every-task
// @namespace    https://x181.cn
// @version      0.1
// @description  try to take over the world!
// @author       tt
// @match        https://*/*
// @match        http://*/*
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function() {
  'use strict';

  // next: 'once'
  const scripts = [
    {
      match: /https:\/\/mp\.weixin\.qq\.com\/s.*/,
      script: weixinScriptTask,
      once: stopImmediatePropagation,
    },
    {
      match: 'http://uz.yurixu.com/',
      script: yurixuTask,
      interval: 0.2
    },
    {
      match: 'https://www.flickr.com/photos/',
      script: removeFlickerZoomLayerTask,
    },
    {
      match: 'https://helloacm.com/',
      script: removeRemovedAdBlockerModal
    },
    {
      match: 'link.zhihu.com',
      script: zhihuAutoRedirectTask,
      interval: 'once'
    },
    {
      match: /^https?:\/\/.*?\.zhihu\.com/,
      script: zhihuConvertLinkTask,
    },
    {
      match: /t\.cn/i,
      script: weiboLinkTask,
    }
  ]

  function weiboLinkTask() {
    let node = document.querySelector('.link')
    let text = node.innerText.trim()
    if (/https?:\/\//i.test(text)) {
      location.href = text
      return;
    }
  }

  function zhihuConvertLinkTask() {
    let links = document.querySelectorAll('a[href^="https://link.zhihu.com/"], a[href^="http://link.zhihu.com/"]')
    Array.from(links).forEach(node => {
      let href = node.href
      let url = new URL(href)
      let search = new URLSearchParams(url.search)
      let target = search.get('target')
      node.href = decodeURIComponent(target)
    })
  }

  function zhihuAutoRedirectTask() {
    if (location.host === 'link.zhihu.com') {
      let search = new URLSearchParams(location.search)
      let target = search.get('target')
      location.href = decodeURIComponent(target)
    }
  }

  function removeRemovedAdBlockerModal() {
    let nodes = document.querySelectorAll('cloudflare-app')
    Array.from(nodes).forEach(node => {
      let style = window.getComputedStyle(node, null)
      let zIndex = style.getPropertyValue('z-index') // style.zIndex
      if (zIndex >= 400) {
        node.style.display = 'none'
      }
    })
  }

  function removeFlickerZoomLayerTask() {
    let selectors = [
      '.facade-of-protection-zoom'
    ]
    selectors.forEach(selector => {
      let nodes = document.querySelectorAll(selector)
      nodes.forEach(node => {
        node.style.display = 'none';
      })
    })
  }

  // 微信公众号文章支持超链接
  function weixinScriptTask() {
    if (document.body == null) {
      return sleep(0.2).then(() => {
        return nextTick(weixinScriptTask)
      })
    }
    let walker = document.createTreeWalker(
      document.body,
      NodeFilter.SHOW_TEXT,
      {
        acceptNode: node => {
          let p = node.parentNode
          while(p && (['A', 'SCRIPT', 'STYLE'].indexOf(p.nodeName) === -1)) {
            p = p.parentNode
          }
          if (p) return NodeFilter.FILTER_SKIP
          let text = node.data
          if (/https?:\/\//i.test(text)) {
            return NodeFilter.FILTER_ACCEPT
          }
        }
      },
      true
    )

    let links = []
    while(walker.nextNode()) {
      let node = walker.currentNode
      let text = node.data.toLowerCase()
      let offset = text.indexOf('http')
      let linkTextNode = node.splitText(offset)
      let spaceOffset = linkTextNode.nodeValue.search(/\s/)
      let linkNode = linkTextNode
      if (spaceOffset > -1) {
        linkNode =linkTextNode.splitText(spaceOffset).previousSibling
      }
      let a = document.createElement('a')
      a.href = linkNode.nodeValue
      a.setAttribute('target', '_blank')
      linkNode.parentNode.insertBefore(a, linkNode)
      a.appendChild(linkNode)
      links.push(a)
    }
    if (links.length) {
      suptolink(links)
    }
  }

  function suptolink(links) {
    let sups = document.querySelectorAll('sup');
    let lastFindedNode = null;
    [...sups].reverse().forEach(sup => {
      let text = sup.innerText.trim()
      if (text === '') return
      // Todo. 判定是 [1] 形式.
      let link = findLinkByText(text, lastFindedNode || links[links.length - 1])
      if (link == null) return
      console.log('find.end:', link)
      lastFindedNode = link
      let a = document.createElement('a')
      a.href = link.href
      a.setAttribute('target', '_blank')
      sup.parentNode.insertBefore(a, sup)
      a.appendChild(sup)
    })
  }

  function findLinkByText(text, link) {
    let find
    let node = link.previousSibling || link.parentNode
    while(node && (node.nodeType == 1 || node.nodeType === 3)) {
      let t = node.innerText || node.nodeValue || ''
      if (node.nodeType === 1) {
        if (node.nodeName === 'A') link = node
        else {
          let a = node.querySelector('a')
          if (a) link = a
        }
      }
      if (t.indexOf(text) > -1) {
        find = link
        break
      }
      node = node.previousSibling || node.parentNode
    }
    return find
  }

  function stopImmediatePropagation() {
    ['click'].forEach(name => {
      document.addEventListener(name, function (e) {
        e.stopImmediatePropagation()
      }, true)
    })
  }

  // 租房
  function yurixuTask() {
    var links = document.querySelectorAll('a');
    [...links].forEach(link => {
      if (link.protocol === 'http:' && link.host === 'www.newsmth.net') {
        link.href = link.href.replace(/^http:/i, 'https:')
      }
    })
  }

  async function run(task, n = 0) {
    console.log('start run task = ', task.name || 'an')
    if ('function' === typeof task.once) {
      task.once(task)
      task.once = null
    }
    if ('function' === typeof task.prescript) task.prescript(task)
    if ('function' === typeof task.script) task.script(task)
    if ('function' === typeof task.postscript) task.postscript(task)

    let interval = task.interval
    if (interval === 'once') return
    // 默认策略
    if (interval === 'exponential' || interval == null) {
      await sleep(Math.pow(2, n))
      run(task, ++n)
      return
    }
    if (typeof interval === 'number') {
      await sleep(interval)
      run(task, ++n)
      return
    }
    if (typeof interval === 'function') {
      interval(() => run(task))
      return
    }
  }

  function init() {
    let url = location.href
    let tasks = scripts.filter(task => match(task.match, url))
    for (let i = 0; i < tasks.length; ++i) {
      run(tasks[i])
    }
  }

  init()

  function sleep(n) {
    return new Promise(function (resolve) {
      setTimeout(resolve, n * 1000)
    })
  }

  function match(rule, url) {
    if (typeof rule === 'boolean') return rule
    if (typeof rule === 'string') return url.includes(rule)
    if (rule.test) return rule.test(url)
    if (rule.sort) return rule.every(m => match(m, url))
    if (typeof rule === 'function') return rule(url)
    return false
  }

  function nextTick(fn) {
    let p = Promise.resolve()
    p.then(fn)
  }
})();