分享discourse油猴脚本

// ==UserScript==
// @name         LinuxDo论坛小涵自用脚本
// @namespace    https://linux.do/u/xiaohan17/summary
// @version      0.0.1
// @description  优化 linux.do 论坛布局动态加载;悬停链接后按空格弹窗预览(最小化/最大化/关闭)
// @license      GPL-3.0-or-later
// @match        https://linux.do/*
// @match        https://nodeloc.cc/*
// @grant        none
// @run-at       document-start
// @downloadURL https://update.greasyfork.org/scripts/527768/LinuxDo%E8%AE%BA%E5%9D%9B%E5%B0%8F%E6%B6%B5%E8%87%AA%E7%94%A8%E8%84%9A%E6%9C%AC.user.js
// @updateURL https://update.greasyfork.org/scripts/527768/LinuxDo%E8%AE%BA%E5%9D%9B%E5%B0%8F%E6%B6%B5%E8%87%AA%E7%94%A8%E8%84%9A%E6%9C%AC.meta.js
// ==/UserScript==

(function() {
    'use strict';

    // ==================== 1. 布局优化 & 动态内容监控 ====================
    const style = document.createElement('style');
    style.textContent = `
        /* ========== 论坛布局优化相关 ========== */
        /* 隐藏发帖者列 */
        .topic-list .topic-list-data.posters {
            display: none !important;
        }
        /* 隐藏浏览量和回复数列 */
        .topic-list .topic-list-data.views,
        .topic-list .topic-list-data.posts {
            display: none !important;
        }
        /* 强制显示主题列表表头 */
        .topic-list-header {
            display: table-header-group !important;
        }
        /* 统计图标样式 */
        .stats-icon {
            width: 14px;
            height: 14px;
            vertical-align: middle;
            margin-right: 2px;
        }
        .stats-count {
            display: inline-flex;
            align-items: center;
            margin-left: 8px;
            color: #666;
            font-size: 12px;
        }
        .stats-container {
            display: inline-flex;
            align-items: center;
            gap: 8px;
            margin-left: 8px;
        }
        /* 让 show-more 按钮铺满一行、保持在正常文档流中 */
        .show-more.has-topics {
            position: relative !important;
            display: block !important;
            width: 100% !important;
            box-sizing: border-box !important;
            margin: 0 0 10px 0 !important;
            border: 1px solid #e9ecef;
            background: #f8f9fa;
            border-radius: 4px;
        }
        .show-more.has-topics a {
            padding: 8px 15px;
            display: block;
            text-align: center;
            color: #0066cc !important;
            font-size: 14px;
            text-decoration: none !important;
        }
        .show-more.has-topics a:hover {
            background: #e9ecef;
            text-decoration: none !important;
        }
    `;
    document.documentElement.appendChild(style);

    function debounce(func, wait) {
        let timeout;
        return function(...args) {
            clearTimeout(timeout);
            timeout = setTimeout(() => func.apply(this, args), wait);
        };
    }

    function initializeEnhancedLayout() {
        // 生成统计容器(浏览量/回复数)
        function processStats(row) {
            if (row.dataset.statsProcessed) return;
            let anchor = row.querySelector('.discourse-tags');
            if (!anchor) {
                const badge = row.querySelector('.link-bottom-line .badge-category__wrapper');
                if (badge) {
                    anchor = badge;
                } else {
                    anchor = row.querySelector('.link-bottom-line');
                }
            }
            if (anchor && (!anchor.nextElementSibling || !anchor.nextElementSibling.classList.contains('stats-container'))) {
                const viewsCell = row.querySelector('.views');
                const postsCell = row.querySelector('.posts');
                const viewsCount = viewsCell?.querySelector('.number')?.textContent?.trim();
                const postsCount = postsCell?.querySelector('.number')?.textContent?.trim();
                if (viewsCount || postsCount) {
                    const statsContainer = document.createElement('div');
                    statsContainer.className = 'stats-container';
                    if (viewsCount) {
                        const viewsSpan = document.createElement('span');
                        viewsSpan.className = 'stats-count';
                        viewsSpan.innerHTML = `
                            <svg class="stats-icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
                              <path d="M512 237.568c-270.6432 0-409.6 274.432-409.6 274.432s104.8576 274.432 409.6 274.432c275.968 0 409.6-273.3568 409.6-273.3568S786.944 237.568 512 237.568z m0.6144 445.952c-98.9696 0-170.496-75.0592-170.496-171.52s71.68-171.52 170.496-171.52 170.496 75.008 170.496 171.52-71.68 171.52-170.496 171.52z m0-274.4832a102.9632 102.9632 0 1 0 102.4 102.9632 103.8336 103.8336 0 0 0-102.4-102.9632z" fill="#666666"/>
                            </svg>
                            ${viewsCount}
                        `;
                        statsContainer.appendChild(viewsSpan);
                    }
                    if (postsCount) {
                        const postsSpan = document.createElement('span');
                        postsSpan.className = 'stats-count';
                        postsSpan.innerHTML = `
                            <svg class="stats-icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
                              <path d="M356.126 735.19c22.654-3.926 42.96-4.366 63.686 1.068C449.358 744.006 480.312 748 512 748c173.682 0 310-119.278 310-260 0-140.722-136.318-260-310-260s-310 119.278-310 260c0 65.1 28.846 126.948 81.14 175.018 22.016 20.238 32.164 45.3 35.566 72.908a163.2 163.2 0 0 1 0.786 8.044c13.228-3.896 25.37-6.828 36.634-8.78zM512 838c-39.98 0-78.592-5.132-115.02-14.686-23.648-6.2-88.642 15.36-194.98 64.686 28.444-92.068 35.188-144.976 20.232-158.724C153.926 666.49 112 581.53 112 488c0-193.3 179.086-350 400-350s400 156.7 400 350-179.086 350-400 350z m-159-304c-24.852 0-45-20.148-45-45s20.148-45 45-45 45 20.148 45 45-20.148 45-45 45z m160 0c-24.852 0-45-20.148-45-45s20.148-45 45-45 45 20.148 45 45-20.148 45-45 45z m160 0c-24.852 0-45-20.148-45-45s20.148-45 45-45 45 20.148 45 45-20.148 45-45 45z" fill="#666666"/>
                            </svg>
                            ${postsCount}
                        `;
                        statsContainer.appendChild(postsSpan);
                    }
                    anchor.insertAdjacentElement('afterend', statsContainer);
                }
            }
            row.dataset.statsProcessed = 'true';
        }

        function processRowImmediate(row) {
            processStats(row);
        }

        function processAllRows() {
            const rows = document.querySelectorAll('.topic-list-item');
            rows.forEach(row => {
                processRowImmediate(row);
            });
        }

        function moveShowMoreAlert() {
            const showMore = document.querySelector('.show-more.has-topics');
            const topicTable = document.querySelector('.topic-list');
            if (showMore && topicTable && showMore.parentNode !== topicTable.parentNode) {
                topicTable.parentNode.insertBefore(showMore, topicTable);
            }
        }

        function handleShowMore() {
            const showMoreBtn = document.querySelector('.show-more.has-topics a');
            if (showMoreBtn && !showMoreBtn.dataset.listenerAdded) {
                showMoreBtn.addEventListener('click', () => {
                    setTimeout(() => {
                        processAllRows();
                    }, 200);
                }, false);
                showMoreBtn.dataset.listenerAdded = 'true';
            }
        }

        function setupDynamicContentHandler() {
            const ioOptions = {
                root: null,
                rootMargin: '100px',
                threshold: 0.1
            };
            const io = new IntersectionObserver((entries) => {
                entries.forEach(entry => {
                    if (entry.isIntersecting) {
                        processRowImmediate(entry.target);
                    }
                });
            }, ioOptions);

            function observeNewRows() {
                const rows = document.querySelectorAll('.topic-list-item:not([data-observed])');
                rows.forEach(row => {
                    io.observe(row);
                    row.dataset.observed = 'true';
                });
            }

            const mutationCallback = debounce((mutationsList) => {
                let shouldProcess = false;
                mutationsList.forEach(mutation => {
                    mutation.addedNodes.forEach(node => {
                        if (node.nodeType === 1) {
                            if (node.classList.contains('topic-list-item') ||
                                node.querySelector?.('.topic-list-item') ||
                                node.classList.contains('show-more') ||
                                node.querySelector?.('.show-more')) {
                                shouldProcess = true;
                            }
                        }
                    });
                });
                if (shouldProcess) {
                    moveShowMoreAlert();
                    observeNewRows();
                    processAllRows();
                    handleShowMore();
                }
            }, 300);

            const container = document.querySelector('.topic-list')?.parentNode || document.body;
            const mo = new MutationObserver(mutationCallback);
            mo.observe(container, {
                childList: true,
                subtree: true
            });

            return () => {
                io.disconnect();
                mo.disconnect();
            };
        }

        moveShowMoreAlert();
        processAllRows();
        handleShowMore();
        const cleanupDynamic = setupDynamicContentHandler();

        // 周期性检查
        const periodicCheck = setInterval(processAllRows, 2000);

        function onPopState() {
            moveShowMoreAlert();
            processAllRows();
            handleShowMore();
        }
        window.addEventListener('popstate', onPopState);

        window.addEventListener('unload', () => {
            cleanupDynamic();
            clearInterval(periodicCheck);
            window.removeEventListener('popstate', onPopState);
        });
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', () => {
            setTimeout(initializeEnhancedLayout, 100);
        });
    } else {
        setTimeout(initializeEnhancedLayout, 100);
    }

    // ==================== 2. 弹窗预览链接功能 ====================
    (function(){
        'use strict';

        // ========== A. 基础样式(遮罩层 & 弹窗容器) ==========
        const modalStyle = document.createElement('style');
        modalStyle.textContent = `
            /* 遮罩层 */
            #custom-modal-overlay {
                position: fixed;
                top: 0; left: 0;
                width: 100vw; height: 100vh;
                background: rgba(0, 0, 0, 0.5);
                z-index: 9999;
                display: none; /* 初始隐藏 */
                pointer-events: auto;
            }
            /* 弹窗容器(默认normal) - 放在 overlay 内 */
            #custom-modal {
                position: absolute;
                left: 10%;
                top: 10%;
                width: 80%;
                height: 80%;
                background: #fff;
                border-radius: 8px;
                overflow: hidden;
                display: flex;
                flex-direction: column;
                z-index: 10000; /* 保证弹窗本身在最前 */
            }
            /* 顶部header - 我们将使用flex布局,以便中间能放一个链接 */
            #custom-modal-header {
                display: flex;
                align-items: center;
                justify-content: space-between; /* 左右两边对齐 */
                height: 30px;
                background: #f0f0f0;
                padding: 0 10px;
                border-bottom: 1px solid #ddd;
                cursor: move;
            }
            #custom-modal-header .header-left a {
                margin: 0 20px;
                text-decoration: none;
                color: #0077AA;
            }
            #custom-modal-header .header-right button {
                background: none;
                border: none;
                font-size: 16px;
                margin-left: 8px;
                cursor: pointer;
            }
            /* iframe 区域 */
            #custom-modal iframe {
                flex-grow: 1;
                width: 100%;
                border: none;
                display: block;
            }
            /* 右下角拖拽手柄 */
            #custom-modal-resizer {
                position: absolute;
                bottom: 0;
                right: 0;
                width: 16px;
                height: 16px;
                cursor: se-resize;
                background: transparent;
            }
        `;
        document.documentElement.appendChild(modalStyle);

        // ========== B. 全局变量与初始状态 ==========
        let currentState = 'normal'; // normal, minimized, maximized
        let overlay = null;
        let modal = null;
        let header = null;
        let iframe = null;
        let resizer = null;

        let linkXiaohan17 = null;

        let normalRect = {
            left: '10%',
            top: '10%',
            width: '80%',
            height: '80%'
        };

        // 随机跳转链接数组
        const linkTargets = [
            'https://linux.do/u/xiaohan17/summary',
            'https://www.violet17.com/'
        ];
        function getRandomLink() {
            const idx = Math.floor(Math.random() * linkTargets.length);
            return linkTargets[idx];
        }

        // ========== C. 打开弹窗(只在首次时创建DOM) ==========
        function openModal(url) {
            if (!overlay) {
                // 1) 遮罩层
                overlay = document.createElement('div');
                overlay.id = 'custom-modal-overlay';

                // 2) 弹窗
                modal = document.createElement('div');
                modal.id = 'custom-modal';

                // 3) header
                header = document.createElement('div');
                header.id = 'custom-modal-header';

                const headerLeft = document.createElement('div');
                headerLeft.className = 'header-left';

                // xiaohan17 链接(随机跳转)
                linkXiaohan17 = document.createElement('a');
                linkXiaohan17.textContent = 'xiaohan17';
                linkXiaohan17.href = '#';
                linkXiaohan17.target = '_blank';
                linkXiaohan17.addEventListener('click', (e) => {
                    e.preventDefault();
                    window.open(getRandomLink(), '_blank');
                });
                headerLeft.appendChild(linkXiaohan17);

                // header右侧
                const headerRight = document.createElement('div');
                headerRight.className = 'header-right';

                // 按钮:最小化、最大化、关闭
                const btnMinimize = document.createElement('button');
                btnMinimize.innerHTML = '–';
                const btnMaximize = document.createElement('button');
                btnMaximize.innerHTML = '□';
                const btnClose = document.createElement('button');
                btnClose.innerHTML = '×';

                headerRight.appendChild(btnMinimize);
                headerRight.appendChild(btnMaximize);
                headerRight.appendChild(btnClose);

                // 组装 header
                header.appendChild(headerLeft);
                header.appendChild(headerRight);

                // 4) iframe
                iframe = document.createElement('iframe');

                // 5) 右下角拖拽
                resizer = document.createElement('div');
                resizer.id = 'custom-modal-resizer';

                modal.appendChild(header);
                modal.appendChild(iframe);
                modal.appendChild(resizer);
                overlay.appendChild(modal);
                document.body.appendChild(overlay);

                // ---------- 按钮事件 ----------
                btnClose.addEventListener('click', () => {
                    closeModal();
                });
                btnMaximize.addEventListener('click', () => {
                    if (currentState === 'maximized') {
                        restoreToNormal();
                    } else if (currentState === 'minimized') {
                        restoreToNormal();
                    } else {
                        maximizeModal();
                    }
                });
                btnMinimize.addEventListener('click', () => {
                    if (currentState === 'minimized') {
                        restoreToNormal();
                    } else {
                        minimizeModal();
                    }
                });

                // ========== header拖动 ==========
                let isDragging = false;
                let dragOffsetX = 0;
                let dragOffsetY = 0;

                header.addEventListener('mousedown', (e) => {
                    if (currentState !== 'maximized') {
                        isDragging = true;
                        const rect = modal.getBoundingClientRect();
                        dragOffsetX = e.clientX - rect.left;
                        dragOffsetY = e.clientY - rect.top;
                    }
                });
                document.addEventListener('mousemove', (e) => {
                    if (isDragging && currentState !== 'maximized') {
                        e.preventDefault();
                        let newLeft = e.clientX - dragOffsetX;
                        let newTop = e.clientY - dragOffsetY;
                        modal.style.left = newLeft + 'px';
                        modal.style.top = newTop + 'px';
                    }
                });
                document.addEventListener('mouseup', () => {
                    isDragging = false;
                });

                // ========== 右下角拖拽大小 ==========
                let isResizing = false;
                let resizeStartX = 0;
                let resizeStartY = 0;
                let startWidth = 0;
                let startHeight = 0;

                resizer.addEventListener('mousedown', (e) => {
                    if (currentState === 'normal') {
                        e.preventDefault();
                        isResizing = true;
                        const rect = modal.getBoundingClientRect();
                        resizeStartX = e.clientX;
                        resizeStartY = e.clientY;
                        startWidth = rect.width;
                        startHeight = rect.height;
                    }
                });
                document.addEventListener('mousemove', (e) => {
                    if (isResizing && currentState === 'normal') {
                        e.preventDefault();
                        let newWidth = startWidth + (e.clientX - resizeStartX);
                        let newHeight = startHeight + (e.clientY - resizeStartY);
                        if (newWidth < 300) newWidth = 300;
                        if (newHeight < 150) newHeight = 150;
                        modal.style.width = newWidth + 'px';
                        modal.style.height = newHeight + 'px';
                    }
                });
                document.addEventListener('mouseup', () => {
                    isResizing = false;
                });
            }

            // 打开 => normal 状态
            currentState = 'normal';
            overlay.style.display = 'block';
            overlay.style.background = 'rgba(0,0,0,0.5)';
            overlay.style.pointerEvents = 'auto';

            modal.style.display = 'flex';
            modal.style.position = 'absolute';
            modal.style.left = normalRect.left;
            modal.style.top = normalRect.top;
            modal.style.width = normalRect.width;
            modal.style.height = normalRect.height;
            modal.style.borderRadius = '8px';

            if (iframe.src !== url) {
                iframe.src = url;
            }
            iframe.style.display = 'block';

            updateHeaderLinkVisibility();
        }

        function updateHeaderLinkVisibility() {
            if (!linkXiaohan17) return;
            if (currentState === 'normal' || currentState === 'maximized') {
                linkXiaohan17.style.display = 'inline-block';
            } else {
                linkXiaohan17.style.display = 'none';
            }
        }

        // ========== 关闭 ==========
        function closeModal() {
            if (!overlay) return;
            overlay.style.display = 'none';
        }

        // ========== 最大化 ==========
        function maximizeModal() {
            if (!modal) return;
            if (currentState === 'normal') {
                const rect = modal.getBoundingClientRect();
                normalRect.left = rect.left + 'px';
                normalRect.top = rect.top + 'px';
                normalRect.width = rect.width + 'px';
                normalRect.height = rect.height + 'px';
            }
            currentState = 'maximized';
            overlay.style.background = 'rgba(0,0,0,0.5)';
            overlay.style.pointerEvents = 'auto';

            modal.style.left = '0px';
            modal.style.top = '0px';
            modal.style.width = '100%';
            modal.style.height = '100%';
            modal.style.borderRadius = '0';
            iframe.style.display = 'block';

            updateHeaderLinkVisibility();
        }

        // ========== 还原 normal ==========
        function restoreToNormal() {
            if (!modal) return;
            currentState = 'normal';
            overlay.style.background = 'rgba(0,0,0,0.5)';
            overlay.style.pointerEvents = 'auto';

            modal.style.display = 'flex';
            modal.style.position = 'absolute';
            modal.style.left = normalRect.left;
            modal.style.top = normalRect.top;
            modal.style.width = normalRect.width;
            modal.style.height = normalRect.height;
            modal.style.borderRadius = '8px';
            iframe.style.display = 'block';

            updateHeaderLinkVisibility();
        }

        // ========== 最小化 ==========
        function minimizeModal() {
            if (!modal) return;
            if (currentState === 'normal') {
                const rect = modal.getBoundingClientRect();
                normalRect.left = rect.left + 'px';
                normalRect.top = rect.top + 'px';
                normalRect.width = rect.width + 'px';
                normalRect.height = rect.height + 'px';
            }
            currentState = 'minimized';

            overlay.style.background = 'transparent';
            overlay.style.pointerEvents = 'none';

            modal.style.display = 'flex';
            modal.style.pointerEvents = 'auto';
            modal.style.position = 'absolute';
            modal.style.width = '300px';
            modal.style.height = '30px';
            modal.style.borderRadius = '4px';
            modal.style.left = (window.innerWidth - 310) + 'px';
            modal.style.top = (window.innerHeight - 40) + 'px';

            iframe.style.display = 'none';

            updateHeaderLinkVisibility();
        }

        // ========== 拦截空格按键,若非输入域则弹窗 ==========
        document.addEventListener('keydown', function(e) {
            // 如果正在输入框/文本域/可编辑内容中,就不阻止空格
            const tagName = e.target.tagName?.toLowerCase();
            const isEditable = e.target.isContentEditable;
            if (
                tagName === 'input' ||
                tagName === 'textarea' ||
                isEditable
            ) {
                return; // 让空格在输入时生效
            }

            // 否则执行弹窗逻辑
            if (e.code === 'Space' || e.key === ' ') {
                e.preventDefault();

                // 判断悬停的链接
                const hoveredElements = document.querySelectorAll(':hover');
                let hoveredLink = null;
                hoveredElements.forEach(el => {
                    if (el.tagName?.toLowerCase() === 'a' && el.href) {
                        hoveredLink = el;
                    }
                });
                if (hoveredLink) {
                    openModal(hoveredLink.href);
                }
            }
        }, false);

    })();
})();

加了条

// @match https://nodeloc.cc/*
适配本站
另外用ai写的折叠广告块的油猴脚本

// ==UserScript==
// @name         NodeLoc.cc Ad Toggle
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  在右上角添加按钮控制 nodeloc.cc 网站的广告栏显示
// @author       Your Name
// @match        https://nodeloc.cc/*
// @match        http://nodeloc.cc/*
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    // 获取当前广告显示状态(默认隐藏)
    let adsHidden = localStorage.getItem('nodeloc_ads_hidden') !== 'false';

    // 创建样式元素
    const style = document.createElement('style');
    document.head.appendChild(style);

    // 更新样式函数
    function updateStyles() {
        style.textContent = `
            /* 控制广告栏 */
            .sidebar-ads-wrapper {
                display: ${adsHidden ? 'none' : 'block'} !important;
            }

            /* 调整为只有一个间隙的两列布局 */
            .wrap {
                grid-template-columns: auto 1fr !important;
                grid-gap: 1rem !important;
            }

            /* 广告控制按钮样式 */
            .header-dropdown-toggle.ads-toggle-btn {
                display: flex;
                align-items: center;
                padding: 6px;
                margin: 0 0.2em;
                border: 1px solid transparent;
                border-radius: 3px;
                transition: all 0.1s;
                background: transparent;
                cursor: pointer;
                color: var(--header-primary);
                position: relative;
            }

            .header-dropdown-toggle.ads-toggle-btn:hover {
                background-color: var(--primary-low);
                color: var(--primary);
            }

            .header-dropdown-toggle.ads-toggle-btn svg {
                width: 1.2em;
                height: 1.2em;
                fill: currentColor;
            }

            /* 显示/隐藏的指示点 */
            .ads-toggle-btn .ads-indicator {
                position: absolute;
                top: 2px;
                right: 2px;
                width: 8px;
                height: 8px;
                border-radius: 50%;
                background: var(--success);
                display: none;
            }

            .ads-toggle-btn.ads-shown .ads-indicator {
                display: block;
            }

            /* 工具提示 */
            .ads-toggle-btn[data-tooltip]:hover:after {
                content: attr(data-tooltip);
                position: absolute;
                bottom: -30px;
                left: 50%;
                transform: translateX(-50%);
                background: var(--primary-very-high);
                color: var(--secondary);
                padding: 4px 8px;
                border-radius: 3px;
                font-size: 12px;
                white-space: nowrap;
                z-index: 1000;
            }
        `;
    }

    // 初始更新样式
    updateStyles();

    // 等待页面加载完成,确保头部元素存在
    function addToggleButton() {
        // 查找放置按钮的合适位置(右上角的用户控制区域)
        const userMenu = document.querySelector('.header-buttons');

        if (!userMenu) {
            // 如果没找到合适位置,过一会再试
            setTimeout(addToggleButton, 500);
            return;
        }

        // 创建广告切换按钮
        const toggleButton = document.createElement('button');
        toggleButton.className = `header-dropdown-toggle ads-toggle-btn ${adsHidden ? '' : 'ads-shown'}`;
        toggleButton.setAttribute('data-tooltip', adsHidden ? '显示广告栏' : '隐藏广告栏');
        toggleButton.setAttribute('aria-label', adsHidden ? '显示广告栏' : '隐藏广告栏');

        // 添加SVG图标(使用眼睛图标表示显示/隐藏)
        toggleButton.innerHTML = `
            <svg class="fa d-icon d-icon-eye" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">
                <path d="M288 144a110.94 110.94 0 0 0-31.24 5 55.4 55.4 0 0 1 7.24 27 56 56 0 0 1-56 56 55.4 55.4 0 0 1-27-7.24A111.71 111.71 0 1 0 288 144zm284.52 97.4C518.29 135.59 410.93 64 288 64S57.68 135.64 3.48 241.41a32.35 32.35 0 0 0 0 29.19C57.71 376.41 165.07 448 288 448s230.32-71.64 284.52-177.41a32.35 32.35 0 0 0 0-29.19zM288 400c-98.65 0-189.09-55-237.93-144C98.91 167 189.34 112 288 112s189.09 55 237.93 144C477.1 345 386.66 400 288 400z"></path>
            </svg>
            <span class="ads-indicator"></span>
        `;

        // 添加点击事件
        toggleButton.addEventListener('click', function() {
            adsHidden = !adsHidden;
            localStorage.setItem('nodeloc_ads_hidden', adsHidden);

            // 更新按钮状态
            toggleButton.setAttribute('data-tooltip', adsHidden ? '显示广告栏' : '隐藏广告栏');
            toggleButton.setAttribute('aria-label', adsHidden ? '显示广告栏' : '隐藏广告栏');
            toggleButton.classList.toggle('ads-shown', !adsHidden);

            // 更新样式
            updateStyles();
        });

        // 将按钮添加到用户菜单区域
        const headerIcons = userMenu.querySelector('.d-header-icons');
        if (headerIcons) {
            headerIcons.insertBefore(toggleButton, headerIcons.firstChild);
        } else {
            userMenu.insertBefore(toggleButton, userMenu.firstChild);
        }
    }

    // 尝试添加按钮
    addToggleButton();
})();

粘贴到油猴即可使用 :winking_face_with_tongue:

5 Likes

淘气 :laughing:

讨厌 :zany_face:

:laughing: :laughing: :laughing:

这是 L 站的

对的,通用 :face_savoring_food:

添加自动签到功能

// ==UserScript==
// @name         NodeLoc.cc Ad Toggle & Auto Check-in
// @namespace    http://tampermonkey.net/
// @version      1.2
// @description  在右上角添加按钮控制 nodeloc.cc 网站的广告栏显示,并提供自动签到功能
// @author       Your Name
// @match        https://nodeloc.cc/*
// @match        http://nodeloc.cc/*
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    // 获取当前广告显示状态(默认隐藏)
    let adsHidden = localStorage.getItem('nodeloc_ads_hidden') !== 'false';

    // 获取当前签到状态
    const today = new Date().toISOString().slice(0, 10); // 格式为 YYYY-MM-DD
    let checkedInToday = localStorage.getItem('nodeloc_checkin_date') === today;

    // 创建样式元素
    const style = document.createElement('style');
    document.head.appendChild(style);

    // 更新样式函数
    function updateStyles() {
        style.textContent = `
            /* 控制广告栏 */
            .sidebar-ads-wrapper {
                display: ${adsHidden ? 'none' : 'block'} !important;
            }

            /* 调整为只有一个间隙的两列布局 */
            .wrap {
                grid-template-columns: auto 1fr !important;
                grid-gap: 1rem !important;
            }

            /* 广告控制按钮样式 */
            .header-dropdown-toggle.ads-toggle-btn {
                display: flex;
                align-items: center;
                padding: 6px;
                margin: 0 0.2em;
                border: 1px solid transparent;
                border-radius: 3px;
                transition: all 0.1s;
                background: transparent;
                cursor: pointer;
                color: var(--header-primary);
                position: relative;
            }

            .header-dropdown-toggle.ads-toggle-btn:hover {
                background-color: var(--primary-low);
                color: var(--primary);
            }

            .header-dropdown-toggle.ads-toggle-btn svg {
                width: 1.2em;
                height: 1.2em;
                fill: currentColor;
            }

            /* 显示/隐藏的指示点 */
            .ads-toggle-btn .ads-indicator {
                position: absolute;
                top: 2px;
                right: 2px;
                width: 8px;
                height: 8px;
                border-radius: 50%;
                background: var(--success);
                display: none;
            }

            .ads-toggle-btn.ads-shown .ads-indicator {
                display: block;
            }

            /* 工具提示 */
            .ads-toggle-btn[data-tooltip]:hover:after {
                content: attr(data-tooltip);
                position: absolute;
                bottom: -30px;
                left: 50%;
                transform: translateX(-50%);
                background: var(--primary-very-high);
                color: var(--secondary);
                padding: 4px 8px;
                border-radius: 3px;
                font-size: 12px;
                white-space: nowrap;
                z-index: 1000;
            }
        `;
    }

    // 初始更新样式
    updateStyles();

    // 等待页面加载完成,确保头部元素存在
    function addToggleButton() {
        // 查找放置按钮的合适位置(右上角的用户控制区域)
        const userMenu = document.querySelector('.header-buttons');

        if (!userMenu) {
            // 如果没找到合适位置,过一会再试
            setTimeout(addToggleButton, 500);
            return;
        }

        // 创建广告切换按钮
        const toggleButton = document.createElement('button');
        toggleButton.className = `header-dropdown-toggle ads-toggle-btn ${adsHidden ? '' : 'ads-shown'}`;
        toggleButton.setAttribute('data-tooltip', adsHidden ? '显示广告栏' : '隐藏广告栏');
        toggleButton.setAttribute('aria-label', adsHidden ? '显示广告栏' : '隐藏广告栏');

        // 添加SVG图标(使用眼睛图标表示显示/隐藏)
        toggleButton.innerHTML = `
            <svg class="fa d-icon d-icon-eye" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">
                <path d="M288 144a110.94 110.94 0 0 0-31.24 5 55.4 55.4 0 0 1 7.24 27 56 56 0 0 1-56 56 55.4 55.4 0 0 1-27-7.24A111.71 111.71 0 1 0 288 144zm284.52 97.4C518.29 135.59 410.93 64 288 64S57.68 135.64 3.48 241.41a32.35 32.35 0 0 0 0 29.19C57.71 376.41 165.07 448 288 448s230.32-71.64 284.52-177.41a32.35 32.35 0 0 0 0-29.19zM288 400c-98.65 0-189.09-55-237.93-144C98.91 167 189.34 112 288 112s189.09 55 237.93 144C477.1 345 386.66 400 288 400z"></path>
            </svg>
            <span class="ads-indicator"></span>
        `;

        // 添加点击事件
        toggleButton.addEventListener('click', function() {
            adsHidden = !adsHidden;
            localStorage.setItem('nodeloc_ads_hidden', adsHidden);

            // 更新按钮状态
            toggleButton.setAttribute('data-tooltip', adsHidden ? '显示广告栏' : '隐藏广告栏');
            toggleButton.setAttribute('aria-label', adsHidden ? '显示广告栏' : '隐藏广告栏');
            toggleButton.classList.toggle('ads-shown', !adsHidden);

            // 更新样式
            updateStyles();
        });

        // 将按钮添加到用户菜单区域
        const headerIcons = userMenu.querySelector('.d-header-icons');
        if (headerIcons) {
            headerIcons.insertBefore(toggleButton, headerIcons.firstChild);
        } else {
            userMenu.insertBefore(toggleButton, userMenu.firstChild);
        }
    }

    // 自动签到函数
    function autoCheckin() {
        // 如果今天已经签到,则不再自动签到
        if (checkedInToday) {
            console.log('今日已签到,不再执行自动签到');
            return;
        }

        // 等待页面完全加载
        setTimeout(() => {
            // 查找页面上的签到按钮
            const checkinButton = document.querySelector('.header-dropdown-toggle.checkin-icon');

            if (checkinButton) {
                console.log('找到签到按钮,执行自动签到');
                checkinButton.click();

                // 更新状态
                checkedInToday = true;
                localStorage.setItem('nodeloc_checkin_date', today);

                console.log('自动签到成功');
            } else {
                console.log('未找到签到按钮,无法自动签到');

                // 如果没找到按钮,可能是因为页面结构变化,尝试延迟再查找一次
                setTimeout(() => {
                    const retryButton = document.querySelector('.header-dropdown-toggle.checkin-icon');
                    if (retryButton) {
                        console.log('重试找到签到按钮,执行自动签到');
                        retryButton.click();
                        checkedInToday = true;
                        localStorage.setItem('nodeloc_checkin_date', today);
                    }
                }, 3000);
            }
        }, 2000); // 等待2秒确保页面元素加载完成
    }

    // 尝试添加广告切换按钮
    addToggleButton();

    // 执行自动签到
    autoCheckin();
})();