// ==UserScript==
// @name 「网页复制限制解除」
// @namespace http://tampermonkey.net/
// @version 1.5.4
// @author Heavrnl
// @description 更新内容:增强复制解除功能,修复BUG
// @license MIT
// @match *://*/*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_registerMenuCommand
// @grant GM_addStyle
// ==/UserScript==
(function () {
'use strict';
// 检查是否在 iframe 中
const isInIframe = window !== window.top;
// 添加设置界面的样式
GM_addStyle(`
.watermark-settings {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0,0,0,0.3);
z-index: 10000;
width: 500px;
font-family: Arial, sans-serif;
}
.watermark-settings h2 {
margin: 0 0 15px 0;
color: #333;
}
.watermark-settings .buttons {
display: flex;
justify-content: flex-end;
gap: 10px;
}
.watermark-settings button {
padding: 8px 15px;
border: none;
border-radius: 4px;
cursor: pointer;
}
.watermark-settings .save {
background: #28a745;
color: white;
}
.watermark-settings .cancel {
background: #dc3545;
color: white;
}
.watermark-settings .overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.5);
z-index: 9999;
}
`);
// 初始化设置 - 只在主页面中执行
if (!isInIframe) {
console.log('初始化设置 - copySites:', GM_getValue('copySites', {}));
console.log('初始化设置 - watermarkSites:', GM_getValue('watermarkSites', {}));
if (GM_getValue('watermarkSites') === undefined) {
GM_setValue('watermarkSites', {});
}
if (GM_getValue('copySites') === undefined) {
GM_setValue('copySites', {});
}
// 在页面加载完成时检查并应用功能
document.addEventListener('DOMContentLoaded', () => {
console.log('页面加��完成,检查是否需要解除复制限制和去除水印');
const currentHost = window.location.hostname;
const copySites = GM_getValue('copySites', {});
const watermarkSites = GM_getValue('watermarkSites', {});
if (copySites[currentHost]) {
console.log('当前网站需要解除复制限制,正在应用...');
enableCopyAndRemoveOverlay();
}
if (watermarkSites[currentHost]) {
console.log('当前网站需要去除水印,正在应用...');
removeWatermark();
}
});
// 创建并添加按钮
const button = document.createElement("button");
// 使用 SVG 图标替代文字
const svgIcon = `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"></path>
<rect x="8" y="2" width="8" height="4" rx="1" ry="1"></rect>
</svg>`;
button.innerHTML = svgIcon;
// 根据存储的状态设置按钮样式
const currentHost = window.location.hostname;
const copySites = GM_getValue('copySites', {});
const isEnabled = copySites[currentHost] || false;
const getButtonStyle = (enabled) => `
position: fixed;
right: 10px;
bottom: 15%;
z-index: 9999;
width: 32px;
height: 32px;
padding: 6px;
background-color: ${enabled ? 'rgba(220, 53, 69, 0.3)' : 'rgba(40, 167, 69, 0.3)'};
color: white;
border: none;
border-radius: 50%;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
opacity: 0.3;
`;
button.style.cssText = getButtonStyle(isEnabled);
// 悬停效果
button.onmouseenter = () => {
button.style.opacity = "1";
const currentHost = window.location.hostname;
const copySites = GM_getValue('copySites', {});
const isEnabled = copySites[currentHost] || false;
button.style.backgroundColor = isEnabled ?
'rgba(220, 53, 69, 0.9)' :
'rgba(40, 167, 69, 0.9)';
};
button.onmouseleave = () => {
button.style.opacity = "0.3";
const currentHost = window.location.hostname;
const copySites = GM_getValue('copySites', {});
const isEnabled = copySites[currentHost] || false;
button.style.backgroundColor = isEnabled ?
'rgba(220, 53, 69, 0.3)' :
'rgba(40, 167, 69, 0.3)';
};
document.body.appendChild(button);
// 修改点击按钮时切换状态的代码
const handleButtonClick = () => {
const currentHost = window.location.hostname;
const copySites = GM_getValue('copySites', {});
const currentState = copySites[currentHost] || false;
console.log('按钮点 - 当前状态:', currentState);
if (!currentState) {
console.log('启用复制解除...');
copySites[currentHost] = true;
GM_setValue('copySites', copySites);
enableCopyAndRemoveOverlay();
button.style.backgroundColor = 'rgba(220, 53, 69, 0.3)';
console.log('复制解除已启用');
} else {
console.log('禁用复制解除...');
copySites[currentHost] = false;
GM_setValue('copySites', copySites);
location.reload(); // 刷新页面以恢复原始状态
}
};
// 绑定点击事件
button.addEventListener("click", handleButtonClick);
// 创建并添加去水印按钮
const watermarkButton = document.createElement("button");
const watermarkSvgIcon = `
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="1" y1="1" x2="23" y2="23"></line>
<path d="M21 21H3a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h18a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2z"></path>
</svg>`;
watermarkButton.innerHTML = watermarkSvgIcon;
// 获取去水印功能的状态
const isWatermarkEnabled = () => {
const currentHost = window.location.hostname;
const watermarkSites = GM_getValue('watermarkSites', {});
return watermarkSites[currentHost] || false;
};
// 设置去水印按钮样式
const getWatermarkButtonStyle = (enabled) => `
position: fixed;
right: 10px;
bottom: 10%;
z-index: 9999;
width: 32px;
height: 32px;
padding: 6px;
background-color: ${enabled ? 'rgba(220, 53, 69, 0.3)' : 'rgba(40, 167, 69, 0.3)'};
color: white;
border: none;
border-radius: 50%;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
opacity: 0.3;
`;
watermarkButton.style.cssText = getWatermarkButtonStyle(isWatermarkEnabled());
// 去水印按钮的悬停效果
watermarkButton.onmouseenter = () => {
watermarkButton.style.opacity = "1";
const currentHost = window.location.hostname;
const watermarkSites = GM_getValue('watermarkSites', {});
const isEnabled = watermarkSites[currentHost] || false;
watermarkButton.style.backgroundColor = isEnabled ?
'rgba(220, 53, 69, 0.9)' :
'rgba(40, 167, 69, 0.9)';
};
watermarkButton.onmouseleave = () => {
watermarkButton.style.opacity = "0.3";
const currentHost = window.location.hostname;
const watermarkSites = GM_getValue('watermarkSites', {});
const isEnabled = watermarkSites[currentHost] || false;
watermarkButton.style.backgroundColor = isEnabled ?
'rgba(220, 53, 69, 0.3)' :
'rgba(40, 167, 69, 0.3)';
};
// 去水印按钮点击事件
watermarkButton.addEventListener("click", () => {
const currentHost = window.location.hostname;
const watermarkSites = GM_getValue('watermarkSites', {});
const currentState = watermarkSites[currentHost] || false;
watermarkSites[currentHost] = !currentState;
GM_setValue('watermarkSites', watermarkSites);
// 如果启用去水印,立即执行一次
if (!currentState) {
removeWatermark();
} else {
location.reload(); // 如果是关闭状态,需要刷新页面
}
// 更新按钮样式
watermarkButton.style.cssText = getWatermarkButtonStyle(!currentState);
});
document.body.appendChild(watermarkButton);
}
// 移除复制限制及遮挡层的功能
const enableCopyAndRemoveOverlay = () => {
const currentHost = window.location.hostname;
const copySites = GM_getValue('copySites', {});
console.log('执行复制解除功能:', currentHost, copySites[currentHost]);
if (!copySites[currentHost]) {
console.log('当前网站未启用复制解除,退出函数');
return;
}
// 处理CSDN特定的复制限制
document.querySelectorAll('*').forEach(element => {
// 移除CSDN特定的user-select限制
if (element.classList.contains('htmledit_views') ||
element.classList.contains('markdown_views') ||
element.classList.contains('article_content')) {
element.style.cssText = `
-webkit-user-select: text !important;
-moz-user-select: text !important;
-ms-user-select: text !important;
user-select: text !important;
`;
}
// 移除CSDN的事件监听器
element.oncontextmenu = null;
element.onselectstart = null;
element.onselect = null;
element.oncopy = null;
element.onbeforecopy = null;
element.oncut = null;
element.onpaste = null;
element.ondrag = null;
element.ondragstart = null;
});
// 覆盖CSDN的复制事件处理
document.addEventListener('copy', function(e) {
e.stopPropagation();
const selection = window.getSelection();
e.clipboardData.setData('text/plain', selection.toString());
}, true);
// 移除CSDN的遮罩层和弹窗
const removeOverlays = () => {
const overlays = document.querySelectorAll('.login-mark, .login-box');
overlays.forEach(overlay => overlay.remove());
};
// 定期检查并移除遮罩
setInterval(removeOverlays, 100);
// 移除所有元素的复制限制
document.querySelectorAll('*').forEach(element => {
// 允许选择文本
element.style.userSelect = "text";
element.style.webkitUserSelect = "text";
element.style.msUserSelect = "text";
element.style.MozUserSelect = "text";
// 移除事件监听器
element.onselectstart = null;
element.oncontextmenu = null;
element.onmousedown = null;
element.onkeydown = null;
element.oncopy = null;
element.oncut = null;
element.ondrag = null;
element.ondragstart = null;
// 移除 unselectable 属性
element.removeAttribute('unselectable');
element.removeAttribute('oncontextmenu');
element.removeAttribute('oncopy');
element.removeAttribute('oncut');
element.removeAttribute('onselectstart');
});
// 移除遮层
document.querySelectorAll('*').forEach(element => {
const style = window.getComputedStyle(element);
if ((style.position === 'absolute' || style.position === 'fixed') &&
(style.opacity === '0' || parseFloat(style.opacity) < 0.1) &&
style.zIndex > 0) {
element.remove();
}
});
// 覆盖常见的禁用右键和复制的方法
document.oncontextmenu = null;
document.onselectstart = null;
document.oncopy = null;
document.oncut = null;
document.onpaste = null;
document.onkeydown = null;
document.onmousedown = null;
// 覆盖 window 对象上的限制方法
window.oncontextmenu = null;
window.onselectstart = null;
window.oncopy = null;
window.oncut = null;
window.onpaste = null;
window.onkeydown = null;
window.onmousedown = null;
// 阻止页面使用 addEventListener 添加新的限制
const originalAddEventListener = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function(type, listener, options) {
if (type === 'contextmenu' || type === 'selectstart' ||
type === 'copy' || type === 'cut' || type === 'paste' ||
type === 'keydown' || type === 'mousedown') {
return;
}
originalAddEventListener.call(this, type, listener, options);
};
// 移除 CSS 限制
const styleElement1 = document.createElement('style');
styleElement1.innerHTML = `
* {
-webkit-user-select: text !important;
-moz-user-select: text !important;
-ms-user-select: text !important;
user-select: text !important;
-webkit-touch-callout: default !important;
}
::selection {
background-color: #338FFF !important;
color: #fff !important;
}
`;
document.head.appendChild(styleElement1);
// 移除keydown事件监听器
document.removeEventListener('keydown', function(e) {
if (e.ctrlKey && (e.keyCode == 65 || e.keyCode == 67 || e.keyCode == 83 || e.keyCode == 85)) {
return false;
}
});
// 获取歌词容器
const lyricBody = document.querySelector('.lyricBody');
if(lyricBody){
// 移除禁止右键和选择的属性
lyricBody.removeAttribute('oncontextmenu');
lyricBody.removeAttribute('onselectstart');
// 移除可能存在的事件监听器
lyricBody.style.userSelect = 'text';
lyricBody.style.webkitUserSelect = 'text';
lyricBody.style.MozUserSelect = 'text';
// 允许复制
lyricBody.oncopy = null;
lyricBody.oncut = null;
lyricBody.onpaste = null;
// 移除所有子元素的复制限制
const elements = lyricBody.getElementsByTagName('*');
for(let el of elements) {
el.style.userSelect = 'text';
el.style.webkitUserSelect = 'text';
el.style.MozUserSelect = 'text';
el.oncopy = null;
el.oncut = null;
el.onpaste = null;
}
}
// 主要功能
function enableFeatures() {
// 重写原生方法
HTMLElement.prototype.addEventListener = (function(original) {
return function(type, listener, useCapture) {
if(type === 'selectstart' || type === 'contextmenu' || type === 'copy') {
return;
}
return original.apply(this, arguments);
};
})(HTMLElement.prototype.addEventListener);
// 添加事件处理
document.addEventListener('selectstart', allowSelection, true);
document.addEventListener('contextmenu', allowSelection, true);
document.addEventListener('copy', allowSelection, true);
document.addEventListener('mousedown', allowSelection, true);
document.addEventListener('mouseup', allowSelection, true);
// 移除所有可能的事件监听器
document.oncontextmenu = null;
document.onselectstart = null;
document.oncopy = null;
document.onmousedown = null;
document.onmouseup = null;
// 添加样式
if (!document.getElementById('enable-select-style')) {
const style = document.createElement('style');
style.id = 'enable-select-style';
style.textContent = `
* {
-webkit-user-select: text !important;
-moz-user-select: text !important;
-ms-user-select: text !important;
user-select: text !important;
}
.ne-content,
.article-content,
.portrait-page-box,
.J_Article,
.J_PortraitMoveBox,
.portrait-page-box,
p,
h1,
span,
div {
-webkit-user-select: text !important;
-moz-user-select: text !important;
-ms-user-select: text !important;
user-select: text !important;
cursor: text !important;
}
::selection {
background: #338fff !important;
color: #fff !important;
}
`;
document.head.appendChild(style);
}
// 立即执行
enableFeatures();
// 处理所有文本容器
const elements = document.querySelectorAll('p, h1, div, span, .ne-content, .article-content, .portrait-page-box, .J_Article, .J_PortraitMoveBox');
elements.forEach(el => {
if(el) {
// 移除所有可能的事件监听器
el.oncontextmenu = null;
el.onselectstart = null;
el.oncopy = null;
el.onmousedown = null;
el.onmouseup = null;
// 设置样式
el.style.setProperty('-webkit-user-select', 'text', 'important');
el.style.setProperty('-moz-user-select', 'text', 'important');
el.style.setProperty('-ms-user-select', 'text', 'important');
el.style.setProperty('user-select', 'text', 'important');
// 移除其他可能的限制
el.removeAttribute('unselectable');
}
});
}
// 移除文章阅读限制
const removeReadLimit = () => {
const contentBox = document.querySelector('.blog-content-box');
if (contentBox) {
const article = contentBox.querySelector('article');
if (article) {
article.style.height = 'auto';
article.style.overflow = 'visible';
}
// 移除登录(不可用)提示框
const loginBox = document.querySelector('.hide-article-box');
if (loginBox) {
loginBox.remove();
}
}
};
// 定期检查并移除限制
setInterval(removeReadLimit, 100);
// 在添加样式表之前添加日志
console.log('正在添加复制解除样式...');
const styleElement2 = document.createElement('style');
styleElement2.innerHTML = `
* {
-webkit-user-select: text !important;
-moz-user-select: text !important;
-ms-user-select: text !important;
user-select: text !important;
-webkit-touch-callout: default !important;
}
::selection {
background-color: #338FFF !important;
color: #fff !important;
}
`;
document.head.appendChild(styleElement2);
console.log('复制解除样式添加完成');
// 在 enableCopyAndRemoveOverlay 函数中添加
const removeSoilElements = () => {
document.querySelectorAll('.soil').forEach(el => {
el.remove();
});
};
// 定期执行清理
setInterval(removeSoilElements, 100);
if (window.location.hostname.includes('music.163.com')) {
// 移除歌曲标题的复制限制
document.querySelectorAll('.ttc b').forEach(el => {
el.style.userSelect = 'text';
el.style.webkitUserSelect = 'text';
});
// 允许复制歌曲标题的原始文本
document.addEventListener('copy', (e) => {
const selection = window.getSelection();
if(selection.toString().includes('soil')) {
e.preventDefault();
const cleanText = selection.toString().replace(/soil.*?soil/g, '');
e.clipboardData.setData('text/plain', cleanText);
}
}, true);
}
};
// 修改 MutationObserver 部分
const observer = new MutationObserver(() => {
const currentHost = window.location.hostname;
const copySites = GM_getValue('copySites', {});
// 只监听复制限制功能
if (copySites[currentHost]) {
enableCopyAndRemoveOverlay();
}
});
observer.observe(document.body, { childList: true, subtree: true });
// 修改页面加载完成时的检查逻辑
window.addEventListener('load', () => {
const currentHost = window.location.hostname;
const copySites = GM_getValue('copySites', {});
const watermarkSites = GM_getValue('watermarkSites', {});
// 检查并执行复制解除功能
if (copySites[currentHost]) {
enableCopyAndRemoveOverlay();
}
// 检查并执行去水印功能
if (watermarkSites[currentHost]) {
removeWatermark();
}
});
// 同时保留 DOMContentLoaded 的检查,以确保更早的响应
document.addEventListener('DOMContentLoaded', () => {
const currentHost = window.location.hostname;
const copySites = GM_getValue('copySites', {});
const watermarkSites = GM_getValue('watermarkSites', {});
if (copySites[currentHost]) {
enableCopyAndRemoveOverlay();
}
if (watermarkSites[currentHost]) {
removeWatermark();
}
});
// 将功能实现代码移出条件判断,这样在 iframe 中也能执行
function removeWatermark() {
const currentHost = window.location.hostname;
const watermarkSites = GM_getValue('watermarkSites', {});
console.log('执行去水印功能:', currentHost, watermarkSites[currentHost]);
if (!watermarkSites[currentHost]) {
console.log('当前网站未启用去水印,退出函数');
return;
}
// 添加去水印的具体实现
document.addEventListener('copy', function(e) {
e.stopPropagation();
const selection = window.getSelection();
e.clipboardData.setData('text/plain', selection.toString());
e.preventDefault();
}, true);
// 添加额外的水印移除代码
const style = document.createElement('style');
style.innerHTML = `
[class*="water"], [class*="Water"], [class*="WATER"],
[class*="copy"], [class*="Copy"], [class*="COPY"],
[id*="water"], [id*="Water"], [id*="WATER"],
[id*="copy"], [id*="Copy"], [id*="COPY"] {
display: none !important;
visibility: hidden !important;
opacity: 0 !important;
pointer-events: none !important;
}
`;
document.head.appendChild(style);
// 定期检查并移除水印元素
const removeWatermarkElements = () => {
const elements = document.querySelectorAll('[class*="water"], [class*="Water"], [class*="WATER"], [id*="water"], [id*="Water"], [id*="WATER"]');
elements.forEach(element => {
element.remove();
});
};
setInterval(removeWatermarkElements, 1000);
console.log('水印移除功能已启用');
}
})();