Greasy Fork

linuxdo保活

linuxdo自动浏览帖子,自动点赞

目前为 2025-01-17 提交的版本。查看 最新版本

// ==UserScript==
// @name         linuxdo保活
// @namespace    http://tampermonkey.net/
// @version      0.1.5
// @description  linuxdo自动浏览帖子,自动点赞
// @author       zhcf1ess
// @match        https://linux.do/*
// @grant        GM_setValue
// @grant        GM_getValue
// @license      MIT
// @icon         https://linux.do/uploads/default/original/3X/9/d/9dd49731091ce8656e94433a26a3ef36062b3994.png
// @namespace    https://github.com/zhsama/linuxdo
// @supportURL   https://github.com/zhsama/linuxdo
// @homepageURL  https://github.com/zhsama/linuxdo
// ==/UserScript==

(function () {
    'use strict';

    // 配置对象
    const config = {
        scrollInterval: 300, // 滚动间隔(毫秒)
        scrollStep: 880, // 每次滚动的像素
        waitForElement: 2000, // 找不到评论的最大时间
        waitingTime: 1, // 看完评论等待 N 秒进入新帖子
        viewCountThreshold: 500, // 浏览量阈值,超过此值才会点赞
        scrollDuration: 30, // 滚动持续时间(秒)
        maxTopics: 100, // 总浏览帖子数量,达到即停
        maxRunTime: 30, // 总运行时间(分钟),达到即停
        urls: {
            base: 'https://linux.do',
            new: 'https://linux.do/new',
            connect: 'https://connect.linux.do'
        }
    };

    // 统计对象
    const stats = {
        totalViews: 0,        // 总浏览数
        totalLikes: 0,        // 总点赞数
        sessionViews: 0,      // 本次会话浏览数
        sessionLikes: 0,      // 本次会话点赞数
        startTime: Date.now() // 会话开始时间
    };

    // 加载保存的统计数据
    function loadStats() {
        const savedStats = GM_getValue('linuxdoStats', null);
        if (savedStats) {
            stats.totalViews = savedStats.totalViews || 0;
            stats.totalLikes = savedStats.totalLikes || 0;
        }
        console.log('📊 加载历史统计数据:');
        console.log(`   总浏览数:${stats.totalViews}`);
        console.log(`   总点赞数:${stats.totalLikes}`);
    }

    // 保存统计数据
    function saveStats() {
        GM_setValue('linuxdoStats', {
            totalViews: stats.totalViews,
            totalLikes: stats.totalLikes
        });
    }

    // 打印统计信息
    function printStats() {
        const runTime = Math.floor((Date.now() - stats.startTime) / 1000);
        const hours = Math.floor(runTime / 3600);
        const minutes = Math.floor((runTime % 3600) / 60);
        const seconds = runTime % 60;

        console.log('\n📊 统计信息');
        console.log('-------------------');
        console.log(`🕒 运行时间:${hours}时${minutes}分${seconds}秒`);
        console.log(`👀 本次浏览:${stats.sessionViews}帖`);
        console.log(`❤️ 本次点赞:${stats.sessionLikes}次`);
        console.log(`📈 总浏览数:${stats.totalViews}帖`);
        console.log(`💖 总点赞数:${stats.totalLikes}次`);
        console.log('-------------------\n');
    }


    // 开关状态管理
    function getSwitchState() {
        return GM_getValue('linuxdoHelperEnabled', false);
    }

    function toggleSwitch() {
        const currentState = getSwitchState();
        GM_setValue('linuxdoHelperEnabled', !currentState);

        if (!currentState) {
            window.location.href = config.urls.base
        }
        console.log(`Linuxdo助手已${!currentState ? '启用' : '禁用'}`);
    }

    // 创建开关图标
    function createSwitchIcon() {
        const iconLi = document.createElement('li');
        iconLi.className = 'header-dropdown-toggle';
        const iconLink = document.createElement('a');
        iconLink.href = 'javascript:void(0)';
        iconLink.className = 'btn no-text icon btn-flat';
        iconLink.title = getSwitchState() ? '停止Linuxdo助手' : '启动Linuxdo助手';
        iconLink.tabIndex = 0;
        const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
        svg.setAttribute('class', 'fa d-icon d-icon-rocket svg-icon prefix-icon svg-string');
        svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
        const use = document.createElementNS('http://www.w3.org/2000/svg', 'use');
        use.setAttribute('href', getSwitchState() ? '#pause' : '#play');
        svg.appendChild(use);
        iconLink.appendChild(svg);
        iconLi.appendChild(iconLink);

        // 点击事件
        iconLink.addEventListener('click', () => {
            toggleSwitch();
            const currentState = getSwitchState();
            use.setAttribute('href', currentState ? '#pause' : '#play');
            iconLink.title = currentState ? '停止Linuxdo助手' : '启动Linuxdo助手';
            iconLink.classList.toggle('active', currentState);
        });

        // 找到聊天图标并插入
        const chatIconLi = document.getElementById('search-button').parentElement;
        if (chatIconLi) {
            chatIconLi.parentNode.insertBefore(iconLi, chatIconLi.nextSibling);
        } else {
            console.log("【错误】未找到按钮!")
        }
    }

    // 检查并执行点赞
    async function checkAndLike(targetWindow = window) {
        try {
            // 获取浏览量
            const viewsElement = targetWindow.document.querySelector('.list-view-count');
            if (!viewsElement) return;

            const viewCount = parseInt(viewsElement.textContent.replace(/,/g, ''));
            if (viewCount <= config.viewCountThreshold) return;

            // 查找点赞按钮
            const likeButton = targetWindow.document.querySelector('.btn-toggle-reaction-like');
            if (!likeButton) {
                console.log('未找到点赞按钮');
                return;
            }

            // 检查是否已经点赞
            if (likeButton.title.includes('移除此赞')) {
                console.log('该帖子已点赞,跳过点赞操作。');
                return;
            }

            // 执行点赞
            likeButton.click();
            console.log('点赞帖子成功');

            // 更新统计
            stats.sessionLikes++;
            stats.totalLikes++;
            saveStats();

        } catch (error) {
            console.error('点赞操作失败:', error);
        }
    }

    // 获取帖子列表
    async function getTopicsList() {
        const topics = document.querySelectorAll('#list-area .title');
        console.log(`共找到 ${topics.length} 个帖子`);

        const topicsList = [];
        for (let i = 0; i < topics.length; i++) {
            const topic = topics[i];
            const parentElement = topic.closest('tr');

            // 检查是否是置顶帖
            const isPinned = parentElement.querySelector('.topic-statuses .pinned');
            if (isPinned) {
                console.log(`跳过置顶的帖子:${topic.textContent.trim()}`);
                continue;
            }

            // 获取浏览量
            const viewsElement = parentElement.querySelector('.num.views .number');
            const viewsTitle = viewsElement.getAttribute('title');
            const viewsCount = parseInt(viewsTitle.split('此话题已被浏览 ')[1].split(' 次')[0].replace(/,/g, ''));

            topicsList.push({
                title: topic.textContent.trim(),
                url: topic.href,
                views: viewsCount
            });
        }
        return topicsList;
    }

    // 浏览单个帖子
    async function browseTopic(topic) {
        console.log(`打开帖子:${topic.title}`);

        // 更新统计
        stats.sessionViews++;
        stats.totalViews++;
        saveStats();

        // 在新标签页中打开帖子
        const newTab = window.open(topic.url, '_blank');
        if (!newTab) {
            console.error('无法打开新标签页,请检查浏览器是否阻止弹窗');
            return;
        }

        // 等待新页面加载完成
        await new Promise(resolve => setTimeout(resolve, 3000));

        // 如果浏览量超过阈值,执行点赞
        if (topic.views > config.viewCountThreshold) {
            console.log(`📈 当前帖子浏览量为${topic.views}`);
            console.log(`🥳 当前帖子浏览量大于设定值${config.viewCountThreshold},开始进行点赞操作`);
            await checkAndLike(newTab);
        }

        // 滚动浏览帖子内容
        await new Promise((resolve) => {
            const startTime = Date.now();
            const scrollInterval = setInterval(() => {
                if (Date.now() - startTime >= config.scrollDuration * 1000) {
                    clearInterval(scrollInterval);
                    newTab.close();
                    // 打印统计信息
                    printStats();
                    resolve(); // 浏览完成后解决 Promise
                    return;
                }
                newTab.scrollBy(0, config.scrollStep);
            }, config.scrollInterval);
        });

        // 等待一段时间确保页面完全关闭
        await new Promise(resolve => setTimeout(resolve, 1000));
    }

    // 检查是否需要停止脚本
    function shouldStopScript() {
        // 检查浏览数量
        if (stats.sessionViews >= config.maxTopics) {
            console.log(`\n🛑 已达到最大浏览数量 ${config.maxTopics} 篇,停止脚本运行`);
            return true;
        }

        // 检查运行时间
        const runTime = (Date.now() - stats.startTime) / 1000;
        if (runTime >= config.maxRunTime * 60) {
            const hours = Math.floor(runTime / 3600);
            const minutes = Math.floor((runTime % 3600) / 60);
            console.log(`\n🛑 已达到最大运行时间 ${hours}时${minutes}分,停止脚本运行`);
            return true;
        }

        return false;
    }

    // 停止脚本运行
    function stopScript() {
        GM_setValue('linuxdoHelperEnabled', false);
        printStats();
        console.log('\n✨ 脚本已自动停止运行');
        window.location.href = config.urls.connect;
    }

    // 主要浏览逻辑
    async function browseTopics() {
        try {
            // 获取帖子列表
            const topics = await getTopicsList();

            // 遍历浏览帖子
            if (topics.length > 0) {
                // 随机打乱帖子列表顺序
                const shuffledTopics = topics.sort(() => Math.random() - 0.5);

                // 逐个浏览帖子
                for (const topic of shuffledTopics) {
                    // 检查是否需要停止脚本
                    if (shouldStopScript()) {
                        stopScript();
                        return;
                    }

                    if (!getSwitchState()) {
                        console.log('脚本已停止');
                        return;
                    }

                    await browseTopic(topic);

                    // 在浏览下一个帖子前等待一段随机时间
                    const waitTime = Math.floor(Math.random() * 3000) + 2000; // 2-5秒
                    await new Promise(resolve => setTimeout(resolve, waitTime));
                }
            }

        } catch (error) {
            console.error('浏览帖子时出错:', error);
        }
    }

    // 主执行函数
    async function main() {
        createSwitchIcon();
        if (!getSwitchState()) return;

        try {
            // 加载统计数据
            loadStats();

            // 如果在最新帖子页面,开始浏览帖子
            if (window.location.href.includes(config.urls.base)) {
                // 检查是否需要停止脚本
                if (shouldStopScript()) {
                    stopScript();
                    return;
                }
                await browseTopics();
            }
        } catch (error) {
            console.error('脚本执行出错:', error);
        }
    }

    // 页面加载完成后执行
    if (document.readyState === 'complete') {
        main();
    } else {
        window.addEventListener('load', main);
    }
})();