LINUX.DO CloudFlare 5秒盾自动跳转

当 CloudFlare 5秒盾检测失败时,自动跳转到 challenge 页面,提升 linux.do 的浏览体验

当前为 2025-10-11 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name                 LINUX.DO CloudFlare Challenge Bypass
// @name:zh-CN           LINUX.DO CloudFlare 5秒盾自动跳转
// @namespace            https://github.com/utags
// @homepageURL          https://github.com/utags/userscripts#readme
// @supportURL           https://github.com/utags/userscripts/issues
// @version              0.1.1
// @description          Automatically redirects to the challenge page when CloudFlare protection fails, improving browsing experience on linux.do
// @description:zh-CN    当 CloudFlare 5秒盾检测失败时,自动跳转到 challenge 页面,提升 linux.do 的浏览体验
// @author               Pipecraft
// @license              MIT
// @noframes
// @match                https://linux.do/*
// @icon                 https://www.google.com/s2/favicons?sz=64&domain=linux.do
// @grant                none
// ==/UserScript==

;(function () {
  'use strict'

  // 配置常量
  const CONFIG = {
    // 需要检测的错误文本
    ERROR_TEXTS: [
      '403 error',
      '该回应是很久以前创建的',
      'reaction was created too long ago',
      '我们无法加载该话题',
    ],
    // 要查找的元素选择器
    DIALOG_SELECTOR: '.dialog-body',
    // 重定向路径
    CHALLENGE_PATH: '/challenge',
    // 调试模式
    DEBUG: false,
  }

  /**
   * 日志函数,仅在调试模式下输出
   * @param {...any} args - 要记录的参数
   */
  const log = (...args) => {
    if (CONFIG.DEBUG) {
      console.log('[LINUX.DO Auto Challenge]', ...args)
    }
  }

  /**
   * 检查当前页面是否是 challenge 页面
   * @returns {boolean} - 如果是 challenge 页面则返回 true,否则返回 false
   */
  function isChallengePage() {
    return window.location.pathname.startsWith(CONFIG.CHALLENGE_PATH)
  }

  /**
   * 检查当前页面是否是 CloudFlare challenge 失败页面
   * 只检查带有 dialog-body 类的元素
   * @returns {boolean} - 如果是失败页面则返回 true,否则返回 false
   */
  function isChallengeFailure() {
    // 如果已经在 challenge 页面,不要再次检测
    if (isChallengePage()) {
      return false
    }

    try {
      // 查找页面中的 dialog-body 元素
      const dialogElement = document.querySelector(CONFIG.DIALOG_SELECTOR)
      if (!dialogElement) return false

      // 检查 dialog-body 元素的内容是否包含错误文本
      const text = dialogElement.innerText || ''
      return CONFIG.ERROR_TEXTS.some((errorText) => text.includes(errorText))
    } catch (error) {
      log('检测失败页面时出错:', error)
      return false
    }
  }

  /**
   * 重定向到 challenge URL
   */
  function redirectToChallenge() {
    try {
      // 防止在 challenge 页面重复跳转
      if (isChallengePage()) return

      const redirectUrl = `${CONFIG.CHALLENGE_PATH}?redirect=${encodeURIComponent(window.location.href)}`
      log('重定向到:', redirectUrl)
      window.location.href = redirectUrl
    } catch (error) {
      log('重定向时出错:', error)
    }
  }

  /**
   * 检查并处理 CloudFlare 失败
   * @param {MutationObserver} [observer] - 可选的观察者实例,如果提供则在检测到失败时断开
   */
  function checkAndRedirect(observer) {
    if (isChallengeFailure()) {
      if (observer) observer.disconnect()
      redirectToChallenge()
      return true
    }
    return false
  }

  /**
   * 初始化脚本
   */
  function initScript() {
    log('初始化脚本')

    // 如果已经在 challenge 页面,不需要执行脚本
    if (isChallengePage()) {
      log('已在 challenge 页面,不执行脚本')
      return
    }

    // 初始检查
    if (checkAndRedirect()) return

    // 观察 DOM 变化
    try {
      const observer = new MutationObserver((mutations, obs) => {
        checkAndRedirect(obs)
      })

      observer.observe(document.body, {
        childList: true, // 监听子节点变化
        subtree: true, // 监听所有后代节点
        characterData: true, // 监听文本内容变化
      })

      log('DOM 观察器已启动')
    } catch (error) {
      log('启动 DOM 观察器时出错:', error)
    }
  }

  // 确保 DOM 已加载后执行脚本
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', initScript)
  } else {
    initScript()
  }
})()