Auto Load Next Page

自动加载下一页内容和图片

질문, 리뷰하거나, 이 스크립트를 신고하세요.
// ==UserScript==
// @name         Auto Load Next Page
// @namespace    http://tampermonkey.net/
// @version      0.2
// @description  自动加载下一页内容和图片
// @author       mr.p@email
// @match        *://misskon.com/*
// @grant        GM_xmlhttpRequest
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // 配置参数
    const config = {
        // 需要监听滚动的容器元素选择器
        containerSelector: 'body',
        // 下一页按钮的选择器
        nextPageSelector: '.post-page-numbers:not(.current)',
        // 分页数字选择器
        pageNumbersSelector: '.post-page-numbers',
        // 内容容器的选择器
        contentSelector: '.entry',
        // 滚动到页面高度的百分比时触发加载(0.3表示30%)
        scrollThresholdPercent: 0.3,
        // 检查间隔(毫秒)
        checkInterval: 1000,
        // 图片选择器
        imageSelector: 'img.aligncenter.lazy:not(.loaded)',
        // 是否启用连续加载(加载完一页后自动检查并加载下一页)
        continuousLoading: true,
        // 是否自动探测总页数(如果为false,则使用maxPageNumber作为总页数)
        autoDetectTotalPages: true,
        // 最大页数(如果autoDetectTotalPages为false,则使用此值作为总页数)
        maxPageNumber: 10
    };

    // 状态标记
    let isLoading = false;
    let checkTimer = null;
    // 页面计数器
    let currentPageNumber = 1;
    // 总页数
    let totalPageNumber = null;

    // 处理页面可见性变化
    document.addEventListener('visibilitychange', function() {
        if (document.visibilityState === 'visible') {
            startAutoCheck();
        } else {
            stopAutoCheck();
        }
    });

    // 启动定时检查
    function startAutoCheck() {
        if (!checkTimer) {
            // 先探测总页数
            detectTotalPages();
            
            checkTimer = setInterval(function() {
                if (isNearBottom()) {
                    loadNextPage();
                }
            }, config.checkInterval);
        }
    }
    
    // 探测总页数
    function detectTotalPages() {
        if (!config.autoDetectTotalPages) {
            totalPageNumber = config.maxPageNumber;
            console.log(`[Debug] 使用配置的最大页数: ${totalPageNumber}`);
            return;
        }
        
        try {
            // 获取所有分页链接
            const pageLinks = document.querySelectorAll(config.pageNumbersSelector);
            if (pageLinks && pageLinks.length > 0) {
                // 找出最大页码
                let maxPage = 1;
                pageLinks.forEach(link => {
                    const pageNum = parseInt(link.textContent.trim());
                    if (!isNaN(pageNum) && pageNum > maxPage) {
                        maxPage = pageNum;
                    }
                });
                
                totalPageNumber = maxPage;
                console.log(`[Debug] 探测到总页数: ${totalPageNumber}`);
            } else {
                // 如果没有找到分页链接,使用配置的最大页数
                totalPageNumber = config.maxPageNumber;
                console.log(`[Debug] 未找到分页链接,使用配置的最大页数: ${totalPageNumber}`);
            }
        } catch (error) {
            console.error('[Error] 探测总页数时出错:', error);
            totalPageNumber = config.maxPageNumber;
            console.log(`[Debug] 探测出错,使用配置的最大页数: ${totalPageNumber}`);
        }
    }

    // 停止定时检查
    function stopAutoCheck() {
        if (checkTimer) {
            clearInterval(checkTimer);
            checkTimer = null;
        }
    }

    // 检查是否滚动到触发加载的位置
    function isNearBottom() {
        try {
            const scrollHeight = Math.max(
                document.documentElement.scrollHeight,
                document.body.scrollHeight
            );
            const scrollTop = window.pageYOffset ||
                document.documentElement.scrollTop ||
                document.body.scrollTop;
            const clientHeight = window.innerHeight ||
                document.documentElement.clientHeight ||
                document.body.clientHeight;
            
            // 计算已滚动的百分比
            const scrolledPercent = scrollTop / (scrollHeight - clientHeight);
            // 检查是否已滚动到设定的阈值百分比
            const reachedThreshold = scrolledPercent >= config.scrollThresholdPercent;
            const hasNextPage = getNextPageUrl() !== null;
            // 检查是否已达到最大页数
            const notReachedMaxPage = totalPageNumber === null || currentPageNumber < totalPageNumber;
            
            return reachedThreshold && hasNextPage && !isLoading && notReachedMaxPage;
        } catch (error) {
            console.error('[Error] 滚动检测出错:', error);
            return false;
        }
    }

    // 获取下一页URL
    function getNextPageUrl() {
        const nextPageLink = document.querySelector(config.nextPageSelector);
        return nextPageLink ? nextPageLink.href : null;
    }

    // 加载下一页内容
    function loadNextPage() {
        try {
            if (isLoading) {
                console.log('[Debug] 正在加载中,跳过新的加载请求');
                return;
            }
            
            const nextPageUrl = getNextPageUrl();
            if (!nextPageUrl) {
                console.log('[Debug] 没有找到下一页URL');
                return;
            }

            // 检查是否已达到最大页数
            if (totalPageNumber !== null && currentPageNumber >= totalPageNumber) {
                console.log(`[Debug] 已达到最大页数 ${totalPageNumber},停止加载`);
                return;
            }
            
            currentPageNumber++;
            console.log(`[Debug] 开始加载第 ${currentPageNumber}/${totalPageNumber || '?'} 页:`, nextPageUrl);
            isLoading = true;

            GM_xmlhttpRequest({
                method: 'GET',
                url: nextPageUrl,
                onload: function(response) {
                    try {
                        console.log('[Debug] 页面内容加载成功,开始解析');
                        const parser = new DOMParser();
                        const doc = parser.parseFromString(response.responseText, 'text/html');
                        const content = doc.querySelector(config.contentSelector);

                        if (content) {
                            const container = document.querySelector(config.contentSelector);
                            container.appendChild(content);
                            console.log(`[Debug] 第 ${currentPageNumber} 页内容已添加到页面`);

                            // 加载新添加内容中的图片
                            const images = content.querySelectorAll(config.imageSelector);
                            console.log(`[Debug] 第 ${currentPageNumber} 页: 找到 ${images.length} 张待加载的图片`);
                            images.forEach((img, index) => {
                                try {
                                    img.loading = 'eager';
                                    if (img.dataset.src) {
                                        console.log(`[Debug] 第 ${currentPageNumber} 页: 加载第 ${index + 1}/${images.length} 张图片:`, img.dataset.src);
                                        img.src = img.dataset.src;
                                    }
                                    img.classList.remove('lazy');
                                    img.classList.add('loaded');
                                    img.style.display = 'block';
                                } catch (imgError) {
                                    console.error(`[Error] 处理第 ${index + 1} 张图片时出错:`, imgError);
                                }
                            });
                        } else {
                            console.warn('[Warning] 未找到内容容器');
                        }
                    } catch (parseError) {
                        console.error('[Error] 解析页面内容时出错:', parseError);
                    } finally {
                        isLoading = false;
                        console.log(`[Debug] 第 ${currentPageNumber}/${totalPageNumber || '?'} 页加载完成,重置加载状态`);
                        
                        // 如果启用了连续加载,检查是否需要继续加载下一页
                        if (config.continuousLoading && getNextPageUrl()) {
                            console.log('[Debug] 启用连续加载,检查是否需要加载更多页面');
                            // 使用setTimeout避免可能的递归调用堆栈溢出
                            setTimeout(function() {
                                if (isNearBottom()) {
                                    loadNextPage();
                                }
                            }, 500);
                        }
                    }
                },
                onerror: function(error) {
                    console.error('[Error] 加载下一页失败:', error);
                    isLoading = false;
                }
            });
        } catch (error) {
            console.error('[Error] 加载下一页过程中出错:', error);
            isLoading = false;
        }
    }

    // 监听滚动事件
    window.addEventListener('scroll', function() {
        if (isNearBottom()) {
            loadNextPage();
        }
    });

    // 初始化自动检查
    startAutoCheck();
})();