Greasy Fork

Greasy Fork is available in English.

Cver Paper Downloader

实现知识星球内的论文分享一键跳转,仅适配Cver,需要科学上网

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Cver Paper Downloader
// @version      0.3.1
// @description  实现知识星球内的论文分享一键跳转,仅适配Cver,需要科学上网
// @author       Curtains
// @match        *://*.zsxq.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=zsxq.com
// @grant        none
// @license MIT
// @namespace http://greasyfork.icu/users/1224766
// ==/UserScript==

(function() {
    'use strict';

    const LOGIN_PHRASE  = '星球禁止搜索和分享';
    const TOPIC_PREFIX  = 'https://wx.zsxq.com/topic/';
    const button = document.createElement('button');

    button.id = 'cverPaperBtn';
    button.style.cssText = `
        position: fixed;
        left: 50px;
        top: 50%;
        transform: translateY(-50%);
        background: rgba(0,0,0,0.5);
        color: white;
        padding: 10px 20px;
        border: none;
        border-radius: 5px;
        cursor: pointer;
        z-index: 9999;
        display: none;   /* 初始隐藏 */
    `;

    function isNotLoggedIn() {
        const text = document.body.innerText || '';
        console.log('[CverDownloader] 登录提示:', text.includes(LOGIN_PHRASE));
        return text.includes(LOGIN_PHRASE);
    }

    function onTopicClick() {
        const fileNameDiv = document.querySelector('.file-name');
        if (!fileNameDiv) {
            button.innerText = '未找到 .file-name';
            return;
        }
        let name = fileNameDiv.innerText.trim();
        const idx = name.indexOf('】');
        if (idx !== -1) name = name.slice(idx + 1).trim();
        name = name.replace(/\.pdf$/i, '');

        navigator.clipboard.writeText(name)
            .then(() => button.innerText = '文件名已复制')
            .catch(() => button.innerText = '复制失败');

        setTimeout(() => {
            window.open('https://duckduckgo.com/?q=!ducky+' + encodeURIComponent(name),
                        '_blank', 'noopener,noreferrer');
        }, 800);
    }

    function initButton() {
        // 先确保 append,只 append 一次
        if (!document.body.contains(button)) {
            document.body.appendChild(button);
        }

        if (isNotLoggedIn()) {
            button.style.display = 'block';
            button.innerText = '需登录后查看,点击去登录';
            button.onclick = () => {
                window.open('https://wx.zsxq.com/login', '_blank');
                setTimeout(() => location.reload(), 10_000);
            };
        }
        else if (location.href.startsWith(TOPIC_PREFIX)) {
            button.style.display = 'block';
            button.innerText = '跳转paper';
            button.onclick = onTopicClick;
        }
        else {
            button.style.display = 'none';
        }
    }

    // 先跑一次,接着再 observer
    initButton();
    const obs = new MutationObserver(() => {
        if (isNotLoggedIn() || location.href.startsWith(TOPIC_PREFIX)) {
            initButton();
            obs.disconnect();
        }
    });
    obs.observe(document.body, { childList: true, subtree: true });
    setTimeout(() => obs.disconnect(), 5_000);
})();