// ==UserScript==
// @name 解除复制限制 Lift Copy Restrictions
// @name:en Lift Copy Restrictions
// @name:zh-CN 解除复制限制
// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAB2AAAAdgB+lymcgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAALvSURBVHic7Zu7bhNBFIa/oBCaUMe5VbTwElQkAlFyqSmICBHkHeANQKkoeANQkkcgoSAyDR1CioHWkHURJcamGC+yVrvenTlzPEM0v3Qk27NzLr93zpyZnYWEhISEybgCPAUOgR4wDCQ94ADYBOZUIx7DMtBWCkgiR8CSYtyA+edjDD6XTyjfCVsRBFknT9SiBz5aOqONFWC/YPNA02BGXAQArBZsnkgVzkxosw1qki6fKPolsntJ0vkiQJOAdaCDe4LrAGuK/tXC1uEiJMHnctzALxE0c4CvxFinN+UACRIBoR0IjURAaAdCIxEQ2oHQ0CTguwcdHQ86nCGtBNcwlZykCrzVwC8R/sfVoFekHKCoW7IIKkMLeInZp+yNpA28ABZiCEDaf5KuB0zeks+A+7Jw5QFI+1fpeggMGvQZ4JmEGAhoYbc3mWE5HDRzwIxAcmwB82PfT4HnwCLmwcj26Lcc85inWF7gI3FJ8blg41nJNduFa9q+jMcwBIq3f6vEzkLhmswmyFi3xHJdRR3ei61UCIV2IDRmFXVrrA3eAdcxuWCIWS1+A3aB9/hZgf5DDLOAjf0/wFvMFDl145JZoAq3HXwYAr8xT6XECEnAI8w/6jqN9oENx7itA/BNwB1kwY+TILoTQhDQAroegs/lF+XF01QIcMEbB7t1suPqzLQJWAXOHOzWyTnmtFspYtgRynEPuNxAb9XKsQqzwN2qxpgqwZuKuiuTYUwE3FDUfa2qIYbVYN7vFHM4U8NOD7ha1hDTWuCMZgS4YFDVENMQ+Kmo+0dVQ0wEfA2hOyYC9hV177l0mnYhtIIpWjQKIaej9SFK4R0Hu3XyytWZE0tDPrCIWcD4Cr6L4LnhoaUxX1jHLGWlwfcRHrXd9OCE6zDaEJLQBx5LggfzOspRIALA3Akuw6FL+ckSJyxNmYQiWpjE2GR2OAdeo3BWYA7zbs4H7N8ikRKQYxkzLPaALyM/stHnXcztrv4WWUJCwsXDX4QDCPtESJvBAAAAAElFTkSuQmCC
// @namespace https://github.com/zhumengstarsandsea/Lift_Copy_Restrictions
// @version 1.1
// @description:en A Userscript designed to intelligently bypass copy restrictions on web pages.
// @description:zh-CN 一个旨在智能解除网页复制限制的油猴脚本。
// @author zhumengstarsandsea
// @license AGPL-3.0-only
// @match http://*/*
// @match https://*/*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_registerMenuCommand
// @grant GM_unregisterMenuCommand
// @grant unsafeWindow
// @run-at document-start
// @description 一个旨在智能解除网页复制限制的油猴脚本。
// ==/UserScript==
'use strict';
(function (global) {
const currentHostname = global.location.hostname;
const currentHref = global.location.href;
// =================================================================================
// == SECTION 1: 特殊网站名单与专属处理逻辑
// =================================================================================
const SPECIAL_SITES = {
'doc88.com': {
regexp: /.*doc88\.com\/.+/,
init: function() {
global.addEventListener("DOMContentLoaded", () => {
const original_html = document.body.innerHTML;
setTimeout(() => { document.body.innerHTML = original_html; }, 5000);
});
}
},
'segmentfault.com': {
regexp: /.*segmentfault\.com\/.+/,
init: function() {
const body = document.querySelector("body");
if (body) { body.classList.add("_sf_adjust_body"); }
}
},
'wk.baidu.com': {
regexp: /.*wk\.baidu\.com\/view\/.+/,
init: function() {
if (unsafeWindow.sf) { unsafeWindow.sf.canCopy = 1; }
}
},
'zhihu.com': {
regexp: /.*zhihu\.com\/.*/,
init: function() {
const observer = new MutationObserver((mutationsList) => {
for (const mutation of mutationsList) {
for (const node of mutation.addedNodes) {
if (node.nodeType === 1 && node.querySelector('.Modal-wrapper')) { node.remove(); }
}
}
});
observer.observe(document.body, { childList: true, subtree: true });
}
},
'docs.qq.com': {
regexp: /.*docs\.qq\.com\/(doc|sheet|slide)\/.+/,
init: function() {
document.addEventListener('DOMContentLoaded', () => {
if(unsafeWindow.pad?.editor){
unsafeWindow.pad.editor.isCopyable = () => true;
}
});
}
},
'wenku.baidu.com': {
regexp: /wenku.baidu.com/,
init: function() {
// 使用一个内部变量来存储 pageData,防止无限循环
let _internalPageData = undefined;
Object.defineProperty(unsafeWindow, 'pageData', {
set: (v) => {
_internalPageData = v;
},
get: () => {
if (_internalPageData && _internalPageData.vipInfo) {
_internalPageData.vipInfo.global_svip_status = 1;
_internalPageData.vipInfo.isVip = 1;
}
return _internalPageData;
},
configurable: true
});
}
},
'kdocs.cn': {
regexp: /.*kdocs\.cn\/.*/,
init: function() {
let _APP = undefined;
if (unsafeWindow.APP) {
unsafeWindow.APP.canCopy = () => true;
} else {
Object.defineProperty(unsafeWindow, "APP", {
set: (v) => { _APP = v; if(v) v.canCopy = () => true; },
get: () => _APP,
configurable: true
});
}
}
}
};
// =================================================================================
// == SECTION 2: 通用解除限制功能 (白名单网站使用)
// =================================================================================
function applyUniversalMode() {
enhancerModule.log(`通用模式已为 ${currentHostname} 激活`, 'success');
const style = 'body, body *{-webkit-user-select:auto!important;-moz-user-select:auto!important;-ms-user-select:auto!important;user-select:auto!important}';
const styleNode = document.createElement('style');
styleNode.textContent = style;
document.head ? document.head.appendChild(styleNode) : document.addEventListener('DOMContentLoaded', () => document.head.appendChild(styleNode));
const events = ['copy', 'contextmenu', 'selectstart', 'dragstart', 'mousedown', 'keydown'];
const stopPropagation = e => e.stopPropagation();
const removeEventListeners = () => {
events.forEach(event => {
document.addEventListener(event, stopPropagation, true);
});
document.oncontextmenu = document.oncopy = document.onselectstart = null;
};
let attempts = 0;
const intervalId = setInterval(() => {
removeEventListeners();
if (++attempts >= 5) clearInterval(intervalId);
}, 500);
}
// =================================================================================
// == SECTION 3: 菜单命令与主逻辑
// =================================================================================
const enhancerModule = {
log(message, type = 'info') {
const style = { info: 'color: #03a9f4;', success: 'color: #28a745; font-weight: bold;', warn: 'color: #ffc107;', error: 'color: #dc3545; font-weight: bold;',} [type];
console.log(`%c[Copying Lifted] ${message}`, style);
},
async getWhitelist() {
return (await GM_getValue('whitelist', []));
},
async setWhitelist(list) {
await GM_setValue('whitelist', list);
},
async addToWhitelist() {
const list = await this.getWhitelist();
if (!list.includes(currentHostname)) {
list.push(currentHostname);
await this.setWhitelist(list);
this.log(`${currentHostname} 已加入白名单`, 'success');
global.location.reload();
}
},
async removeFromWhitelist() {
let list = await this.getWhitelist();
if (list.includes(currentHostname)) {
list = list.filter(item => item !== currentHostname);
await this.setWhitelist(list);
this.log(`${currentHostname} 已移出白名单`, 'warn');
global.location.reload();
}
},
async registerMenuCommands(isWhitelisted) {
if (global.menuIds) {
global.menuIds.forEach(id => GM_unregisterMenuCommand(id));
}
global.menuIds = [];
if (isWhitelisted) {
global.menuIds.push(GM_registerMenuCommand('❌ 移出解除名单', this.removeFromWhitelist.bind(this)));
} else {
global.menuIds.push(GM_registerMenuCommand('✅ 加入解除名单', this.addToWhitelist.bind(this)));
}
},
async run() {
// **【v1.1 核心修复】检查是否为特殊网站
for (const key in SPECIAL_SITES) {
if (currentHostname.includes(key)) {
this.log(`检测到特殊网站: ${key},执行专属方案`, 'success');
if (SPECIAL_SITES[key].init) {
try {
SPECIAL_SITES[key].init.call(this);
} catch (e) {
this.log(`在 ${key} 上执行专属方案时出错: ${e}`, 'error');
}
}
// **【v1.1 核心修复】执行完专属方案后,立即返回,不再执行通用逻辑
return;
}
}
// 如果不是特殊网站,则继续走白名单逻辑
const whitelist = await this.getWhitelist();
const isWhitelisted = whitelist.includes(currentHostname);
this.registerMenuCommands(isWhitelisted);
if (isWhitelisted) {
applyUniversalMode();
} else {
this.log(`当前网站 ${currentHostname} 未在白名单中,脚本待命中`, 'info');
}
}
};
enhancerModule.run();
}(window));