LINUX.DO 自动加载新话题

智能自动加载新话题,带有错误处理和检测优化

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name                 LINUX.DO Auto Load New Topics
// @name:zh-CN           LINUX.DO 自动加载新话题
// @namespace            https://www.pipecraft.net/
// @homepageURL          https://github.com/utags/userscripts#readme
// @supportURL           https://github.com/utags/userscripts/issues
// @version              0.1.2
// @description          Auto load new topics with smart detection and error handling
// @description:zh-CN    智能自动加载新话题,带有错误处理和检测优化
// @author               Pipecraft
// @license              MIT
// @match                https://linux.do/*
// @icon                 https://www.google.com/s2/favicons?sz=64&domain=linux.do
// @grant                none
// ==/UserScript==

;(function () {
  'use strict'

  // Configuration constants
  const CONFIG = {
    CHECK_INTERVAL: 3000, // Check every 3 seconds
    MAX_RETRIES: 3, // Maximum retry attempts
    SELECTORS: [
      '#list-area .show-more .clickable',
      // '.show-more-topics .clickable',
      // "[data-action='show-more']",
    ],
    DEBUG: false, // Set to true for debug logging
  }

  let retryCount = 0
  let lastClickTime = 0
  let intervalId = null

  /**
   * Apply CSS styles to hide show-more elements
   */
  function applyStyles() {
    const style = document.createElement('style')
    style.textContent = `
      #list-area .show-more {
        display: none !important;
      }
    `
    document.head.appendChild(style)
  }

  /**
   * Log debug messages if debug mode is enabled
   * @param {string} message - The message to log
   * @param {any} data - Optional data to log
   */
  function debugLog(message, data = null) {
    if (CONFIG.DEBUG) {
      console.log(`[LINUX.DO Auto Loader] ${message}`, data || '')
    }
  }

  /**
   * Check if a modal dialog is currently open
   * @returns {boolean} True if a modal is open
   */
  function isModalOpen() {
    const modals = document.querySelectorAll('[role="dialog"]')
    for (const modal of modals) {
      if (
        modal &&
        modal.offsetParent !== null &&
        modal.offsetHeight > 0 &&
        modal.offsetWidth > 0
      ) {
        return true
      }
    }
    return false
  }

  /**
   * Find the clickable element using multiple selectors
   * @returns {HTMLElement|null} The clickable element or null
   */
  function findClickableElement() {
    for (const selector of CONFIG.SELECTORS) {
      const element = document.querySelector(selector)
      if (element) {
        return element
      }
    }
    return null
  }

  /**
   * Check if enough time has passed since last click
   * @returns {boolean} True if enough time has passed
   */
  function canClick() {
    const now = Date.now()
    return now - lastClickTime > CONFIG.CHECK_INTERVAL
  }

  /**
   * Attempt to click the show more button
   * @returns {boolean} True if click was successful
   */
  function attemptClick() {
    try {
      // Check if modal is open and pause auto-loading
      if (isModalOpen()) {
        debugLog('Modal dialog is open, pausing auto-loader')
        return false
      }

      const clickable = findClickableElement()

      if (!clickable) {
        debugLog('No clickable element found')
        return false
      }

      if (!canClick()) {
        debugLog('Too soon since last click')
        return false
      }

      // Simulate a more natural click
      const event = new MouseEvent('click', {
        bubbles: true,
        cancelable: true,
        view: window,
      })

      clickable.dispatchEvent(event)
      lastClickTime = Date.now()
      retryCount = 0 // Reset retry count on successful click

      debugLog('Successfully clicked show more button', clickable)
      return true
    } catch (error) {
      debugLog('Error clicking element:', error)
      retryCount++

      if (retryCount >= CONFIG.MAX_RETRIES) {
        debugLog('Max retries reached, stopping auto-loader')
        stopAutoLoader()
      }

      return false
    }
  }

  /**
   * Start the auto-loader interval
   */
  function startAutoLoader() {
    if (intervalId) {
      clearInterval(intervalId)
    }

    debugLog('Starting auto-loader')
    intervalId = setInterval(attemptClick, CONFIG.CHECK_INTERVAL)
  }

  /**
   * Stop the auto-loader interval
   */
  function stopAutoLoader() {
    if (intervalId) {
      clearInterval(intervalId)
      intervalId = null
      debugLog('Auto-loader stopped')
    }
  }

  /**
   * Initialize the script when DOM is ready
   */
  function initialize() {
    // Apply CSS styles to hide show-more elements
    applyStyles()

    // Wait for DOM to be ready
    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', startAutoLoader)
    } else {
      startAutoLoader()
    }

    // Handle page visibility changes
    document.addEventListener('visibilitychange', () => {
      if (document.hidden) {
        stopAutoLoader()
      } else {
        startAutoLoader()
      }
    })

    // Stop when navigating away
    window.addEventListener('beforeunload', stopAutoLoader)
  }

  // Initialize the script
  initialize()
})()