Greasy Fork

Greasy Fork is available in English.

知识星球吖

1. 去掉 disabled-copy 类及水印遮挡;2. 自动点击"展开"按钮保持全文展开;3. 点击时间复制帖子内容;4. 15秒无鼠标活动自动刷新;5. 界面美化和侧边栏控制

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

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         知识星球吖
// @namespace    https://axutongxue.com/
// @version      2.6
// @license      MIT
// @description  1. 去掉 disabled-copy 类及水印遮挡;2. 自动点击"展开"按钮保持全文展开;3. 点击时间复制帖子内容;4. 15秒无鼠标活动自动刷新;5. 界面美化和侧边栏控制
// @author       kejin——公众号:懒人股选
// @match        *://wx.zsxq.com/*
// @grant        GM_addStyle
// ==/UserScript==
(function () {
    'use strict';
    
    /* ************** 样式注入 ************** */
    // 添加自定义样式
    if (typeof GM_addStyle !== 'undefined') {
        GM_addStyle(`
            .group-list-container {
                transition: transform 0.2s ease-out;
                background: #fff;
                z-index: 10;
            }
            #toggle-sidebar {
                height: 20px;
                font-size: 12px;
                margin-left: 10px;
                padding: 0px 6px;
                border-radius: 4px;
                cursor: pointer;
                color: rgb(80, 234, 203);
                background-color: rgba(52, 146, 112, 0.05);
                border: 1px solid rgba(65,183,140,.2);
            }
            #toggle-sidebar:hover {
                background-color: #e0e0e0;
            }
        `);
    } else {
        // 如果 GM_addStyle 不可用,使用传统方式
        const style = document.createElement('style');
        style.textContent = `
            .group-list-container {
                transition: transform 0.2s ease-out;
                background: #fff;
                z-index: 10;
            }
            #toggle-sidebar {
                height: 20px;
                font-size: 12px;
                margin-left: 10px;
                padding: 0px 6px;
                border-radius: 4px;
                cursor: pointer;
                color: rgb(80, 234, 203);
                background-color: rgba(52, 146, 112, 0.05);
                border: 1px solid rgba(65,183,140,.2);
            }
            #toggle-sidebar:hover {
                background-color: #e0e0e0;
            }
        `;
        document.head.appendChild(style);
    }

    /* ************** 通用工具 ************** */
    function waitForKeyElements(selectorOrFunction, callback, waitOnce = true, interval = 300, maxIntervals = -1) {
        const select = () => (typeof selectorOrFunction === 'function' ? selectorOrFunction() : document.querySelectorAll(selectorOrFunction));
        const tick = () => {
            const nodes = select();
            if (nodes.length) {
                nodes.forEach(n => {
                    if (n.dataset.alreadyFound) return;
                    const cancel = callback(n);
                    if (!cancel) n.dataset.alreadyFound = '1';
                });
            }
            if (--maxIntervals !== 0 && !(waitOnce && nodes.length)) {
                setTimeout(tick, interval);
            }
        };
        tick();
    }

    /* ************** 1. 解除复制限制 ************** */
    waitForKeyElements('.disabled-copy', el => el.classList.remove('disabled-copy'), false, 1000);
    waitForKeyElements('[watermark]', el => el.setAttribute('style', 'padding:10px;'), false, 1000);

    /* ************** 2. 帖子自动展开 ************** */
    const processed = new WeakSet();
    function smartClick(btn) {
        if (!btn || processed.has(btn)) return;
        const txt = btn.textContent.trim();
        if (!/展[开示]/.test(txt)) return;
        btn.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }));
        processed.add(btn);
    }
    function expandAll() {
        document.querySelectorAll('p.showAll, button.showAll, span.showAll').forEach(smartClick);
    }
    // 首次+动态
    window.addEventListener('load', () => {
        expandAll();
        new MutationObserver(() => expandAll()).observe(document.body, { childList: true, subtree: true });
        window.addEventListener('hashchange', expandAll);
    });

    /* ************** 3. 点击时间复制帖子内容 ************** */
    const timeClickProcessed = new WeakSet();

    function findPostContent(timeElement) {
        // 向上查找帖子容器
        let container = timeElement.closest('[class*="topic"], [class*="post"], [class*="feed-item"]');
        if (!container) {
            container = timeElement.closest('div[class*="item"]');
        }
        
        if (!container) return null;

        // 查找内容区域(尝试多种可能的选择器)
        const contentSelectors = [
            '.content',
            '[class*="content"]',
            '.text',
            '[class*="text"]',
            '.description',
            '[class*="description"]'
        ];

        for (const selector of contentSelectors) {
            const content = container.querySelector(selector);
            if (content && content.textContent.trim()) {
                return content.textContent.trim();
            }
        }

        return null;
    }

    function copyToClipboard(text) {
        if (navigator.clipboard && navigator.clipboard.writeText) {
            navigator.clipboard.writeText(text).then(() => {
                showCopyTip('复制成功!');
            }).catch(() => {
                fallbackCopy(text);
            });
        } else {
            fallbackCopy(text);
        }
    }

    function fallbackCopy(text) {
        const textarea = document.createElement('textarea');
        textarea.value = text;
        textarea.style.position = 'fixed';
        textarea.style.opacity = '0';
        document.body.appendChild(textarea);
        textarea.select();
        try {
            document.execCommand('copy');
            showCopyTip('复制成功!');
        } catch (err) {
            showCopyTip('复制失败,请手动复制');
        }
        document.body.removeChild(textarea);
    }

    function showCopyTip(message) {
        const tip = document.createElement('div');
        tip.textContent = message;
        tip.style.cssText = `
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: rgba(0, 0, 0, 0.8);
            color: white;
            padding: 12px 24px;
            border-radius: 6px;
            font-size: 14px;
            z-index: 10000;
            pointer-events: none;
        `;
        document.body.appendChild(tip);
        setTimeout(() => tip.remove(), 2000);
    }

    function addTimeClickListener(timeElement) {
        if (timeClickProcessed.has(timeElement)) return;
        
        // 添加样式提示可点击
        timeElement.style.cursor = 'pointer';
        timeElement.title = '点击复制帖子内容';
        
        timeElement.addEventListener('click', (e) => {
            e.preventDefault();
            e.stopPropagation();
            
            const content = findPostContent(timeElement);
            if (content) {
                copyToClipboard(content);
            } else {
                showCopyTip('未找到帖子内容');
            }
        });
        
        timeClickProcessed.add(timeElement);
    }

    // 监听时间元素(尝试多种可能的选择器)
    function attachTimeListeners() {
        const timeSelectors = [
            '[class*="time"]',
            '[class*="date"]',
            'time',
            'span[title*="202"]', // 匹配包含年份的时间
        ];

        timeSelectors.forEach(selector => {
            waitForKeyElements(selector, (el) => {
                // 检查是否是时间格式
                const text = el.textContent.trim();
                if (/\d{4}-\d{2}-\d{2}/.test(text) || /\d{2}:\d{2}/.test(text)) {
                    addTimeClickListener(el);
                }
            }, false, 1000);
        });
    }

    // 启动时间点击监听
    window.addEventListener('load', () => {
        attachTimeListeners();
    });

    /* ************** 4. 15秒无鼠标活动自动刷新 ************** */
    let inactivityTimer = null;
    const INACTIVITY_TIMEOUT = 15000; // 15秒

    function resetInactivityTimer() {
        // 清除现有计时器
        if (inactivityTimer) {
            clearTimeout(inactivityTimer);
        }
        
        // 设置新计时器
        inactivityTimer = setTimeout(() => {
            console.log('15秒无活动,刷新页面');
            location.reload();
        }, INACTIVITY_TIMEOUT);
    }

    // 监听鼠标活动
    const mouseEvents = ['mousemove', 'mousedown', 'click', 'scroll', 'keypress', 'touchstart'];
    mouseEvents.forEach(event => {
        document.addEventListener(event, resetInactivityTimer, true);
    });

    // 页面加载后启动计时器
    window.addEventListener('load', () => {
        resetInactivityTimer();
        console.log('自动刷新功能已启动:15秒无活动将自动刷新');
    });

    /* ************** 5. 界面优化功能 ************** */
    
    // 5.1 为精华帖添加红色边框
    function addRedBorder() {
        const listItems = document.querySelectorAll('.ng-star-inserted');
        listItems.forEach((item) => {
            const headerContainer = item.querySelector('.header-container');
            if (headerContainer) {
                const topicFlag = headerContainer.querySelector('.topic-flag');
                if (topicFlag) {
                    const digestElement = topicFlag.querySelector('.digest');
                    if (digestElement) {
                        const topicContainer = item.querySelector('.topic-container');
                        if (topicContainer) {
                            topicContainer.style.border = '1px solid rgb(80, 234, 203)';
                            topicContainer.style.backgroundColor = 'rgba(80, 234, 203, 0.1)';
                        }
                    }
                }
            }
        });
    }

    // 5.2 设置侧边栏切换功能
    function setupSidebarToggle() {
        const sidebar = document.querySelector('.group-list-container');
        const logoContainer = document.querySelector('.logo-container');
        if (!sidebar || !logoContainer) return;

        // 避免重复添加按钮
        if (document.getElementById('toggle-sidebar')) return;

        const toggleButton = document.createElement('button');
        toggleButton.id = 'toggle-sidebar';
        toggleButton.textContent = '切换目录';
        logoContainer.appendChild(toggleButton);

        // 获取视口宽度
        const clientWidth = document.documentElement.clientWidth;
        const transX = clientWidth - 1526 / 2;

        // 默认隐藏侧边栏
        sidebar.classList.add('hide');
        // 设置hide样式
        if (sidebar.classList.contains('hide')) {
            sidebar.style.transform = 'translateX(calc(-100% - ' + transX + 'px))';
        } else {
            sidebar.style.transform = 'translateX(0)';
        }

        toggleButton.addEventListener('click', () => {
            sidebar.classList.toggle('hide');

            if (sidebar.classList.contains('hide')) {
                sidebar.style.transform = 'translateX(calc(-100% - ' + transX + 'px))';
            } else {
                sidebar.style.transform = 'translateX(0)';
            }
        });
    }

    // 5.3 隐藏不必要的界面元素
    function hideElements() {
        // 头部
        const headerContainer = document.querySelector('.header-container');

        if (headerContainer) {
            const redirect = headerContainer.querySelector('.redirect');
            const userAvatar = headerContainer.querySelector('.user-avatar');

            if (redirect) {
                redirect.style.display = 'none';
            }
            if (userAvatar) {
                userAvatar.style.display = 'none';
            }
        }

        const leftLogo = document.querySelector('.logo-container .left');
        const noteLogo = document.querySelector('.logo-container .note');
        if (leftLogo) {
            leftLogo.style.display = 'none';
        }
        if (noteLogo) {
            noteLogo.style.display = 'none';
        }

        // .topic-flow-container
        const topicFlowContainer = document.querySelector('.topic-flow-container');
        if (topicFlowContainer) {
            topicFlowContainer.style.setProperty('width', '100%', 'important');
            topicFlowContainer.style.setProperty('padding-left', '100px', 'important');
            topicFlowContainer.style.setProperty('padding-right', '100px', 'important');
        }

        // 主体上部分
        const topicContainer = document.querySelector('.topic-container');
        if (topicContainer) {
            const ngStarInserted = topicContainer.querySelector('.ng-star-inserted');
            if (ngStarInserted) {
                ngStarInserted.style.display = 'none';
            }
        }

        // 主体中部分
        const mainContentContainer = document.querySelector('.main-content-container');
        if (mainContentContainer) {
            mainContentContainer.style.setProperty('margin-left', '10%', 'important');
            mainContentContainer.style.setProperty('margin-right', '10%', 'important');
        }

        // 右侧边栏
        const groupPreviewContainer = document.querySelector('.group-preview-container');
        if (groupPreviewContainer) {
            groupPreviewContainer.style.display = 'none';
        }
    }

    // 5.4 启动界面优化功能
    function initUIEnhancements() {
        addRedBorder();
        setupSidebarToggle();
        hideElements();
        
        // 监听DOM变化,持续应用样式
        const observer = new MutationObserver(() => {
            addRedBorder();
            setupSidebarToggle();
            hideElements();
        });
        
        observer.observe(document.body, { childList: true, subtree: true });
    }

    // 页面加载完成后执行界面优化
    window.addEventListener('load', () => {
        setTimeout(initUIEnhancements, 500);
    });
})();