Greasy Fork is available in English.
实现知识星球内的论文分享一键跳转,仅适配Cver,需要科学上网
// ==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);
})();