Greasy Fork

Greasy Fork is available in English.

知识星球·解除复制限制+帖子自动展开+点击时间复制

1. 去掉 disabled-copy 类及水印遮挡;2. 自动点击"展开"按钮保持全文展开;3. 点击时间复制帖子内容

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         知识星球·解除复制限制+帖子自动展开+点击时间复制
// @namespace    https://axutongxue.com/
// @version      1.1
// @license      MIT
// @description  1. 去掉 disabled-copy 类及水印遮挡;2. 自动点击"展开"按钮保持全文展开;3. 点击时间复制帖子内容
// @author       kejin——公众号:懒人股选
// @match        *://wx.zsxq.com/*
// @grant        none
// ==/UserScript==
(function () {
    'use strict';
    /* ************** 通用工具 ************** */
    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();
    });
})();