// ==UserScript==
// @name 通用下载助手
// @namespace http://tampermonkey.net/
// @version 0.9
// @description 快速实现下载功能
// @author niweizhuan
// @match *://*/*
// @grant GM_xmlhttpRequest
// @grant GM_registerMenuCommand
// @grant GM_addStyle
// @license MIT
// @downloadURL https://update.greasyfork.icu/scripts/525497/%E9%80%9A%E7%94%A8%E4%B8%8B%E8%BD%BD%E5%8A%A9%E6%89%8B.user.js
// @updateURL https://update.greasyfork.icu/scripts/525497/%E9%80%9A%E7%94%A8%E4%B8%8B%E8%BD%BD%E5%8A%A9%E6%89%8B.meta.js
// ==/UserScript==
(function() {
'use strict';
// 添加悬浮窗样式
GM_addStyle(`
#downloaderOverlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 9999;
display: none;
}
#downloaderPopup {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
padding: 20px;
border: 1px solid #ccc;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
z-index: 10000;
width: 90%; /* 悬浮窗宽度占屏幕宽度的 90% */
max-width: 400px; /* 最大宽度限制 */
font-family: Arial, sans-serif;
}
#downloaderPopup h3 {
margin: 0 0 15px;
font-size: 18px;
color: #333;
text-align: center;
}
#downloaderPopup input[type="text"] {
width: 100%;
padding: 10px;
margin-bottom: 15px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
font-size: 14px;
}
#downloaderPopup label {
display: block;
margin-bottom: 15px;
font-size: 14px;
color: #555;
}
#downloaderPopup button {
width: 100%;
padding: 10px;
background-color: #007BFF;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
#downloaderPopup button:hover {
background-color: #0056b3;
}
#loading {
display: none;
margin-top: 15px;
text-align: center;
font-size: 14px;
color: #555;
}
#closePopup {
position: absolute;
top: 10px;
right: 10px;
background: none;
border: none;
font-size: 5vw; /* 按钮大小占屏幕宽度的 5% */
color: #999;
cursor: pointer;
padding: 0;
width: 5vw; /* 按钮宽度占屏幕宽度的 5% */
height: 5vw; /* 按钮高度占屏幕宽度的 5% */
max-width: 24px; /* 最大宽度限制 */
max-height: 24px; /* 最大高度限制 */
display: flex;
align-items: center;
justify-content: center;
}
#closePopup:hover {
color: #333;
}
.custom-notification {
position: fixed;
top: 20px;
right: 20px;
background: #f0f0f0; /* 浅灰色背景 */
color: #333; /* 深灰色文字 */
padding: 10px 20px;
border-radius: 4px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
z-index: 10001;
display: none;
animation: slideIn 0.5s ease-out, fadeOut 0.5s 2.5s ease-out forwards;
}
@keyframes slideIn {
from {
transform: translateX(100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes fadeOut {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
`);
// 创建悬浮窗和遮罩层
const overlay = document.createElement('div');
overlay.id = 'downloaderOverlay';
document.body.appendChild(overlay);
const popup = document.createElement('div');
popup.id = 'downloaderPopup';
popup.innerHTML = `
下载器
正在处理...
`;
document.body.appendChild(popup);
// 创建自定义通知
const customNotification = document.createElement('div');
customNotification.className = 'custom-notification';
document.body.appendChild(customNotification);
// 显示自定义通知
function showNotification(message, duration = 3000) {
customNotification.textContent = message;
customNotification.style.display = 'block';
setTimeout(() => {
customNotification.style.display = 'none';
}, duration);
}
// 默认隐藏悬浮窗和遮罩层
popup.style.display = 'none';
overlay.style.display = 'none';
// 关闭悬浮窗
const closePopup = document.getElementById('closePopup');
const closePopupAndOverlay = () => {
popup.style.display = 'none';
overlay.style.display = 'none';
};
closePopup.addEventListener('click', closePopupAndOverlay);
// 点击遮罩层关闭悬浮窗
overlay.addEventListener('click', closePopupAndOverlay);
// 注册油猴菜单项
GM_registerMenuCommand('打开下载器', () => {
popup.style.display = 'block';
overlay.style.display = 'block';
});
// 下载功能
const downloadButton = document.getElementById('downloadButton');
const loadingDiv = document.getElementById('loading');
downloadButton.addEventListener('click', () => {
const linkInput = document.getElementById('downloadLink');
const forceTxtCheckbox = document.getElementById('forceTxt');
const url = linkInput.value;
// 验证输入的链接是否为空
if (!url) {
alert('内容不能为空');
return;
}
// 判断链接类型(HTTP/HTTPS 或磁力链接)
const isHttpLink = /^(https?|ftp):\/\/[^\s/$.?#].[^\s]*$/.test(url);
const isMagnetLink = /^magnet:\?xt=urn:btih:[^\s&]+/.test(url);
if (!isHttpLink && !isMagnetLink) {
alert('请输入有效的下载链接');
return;
}
// 显示加载状态
loadingDiv.style.display = 'block';
if (isHttpLink) {
// 处理 HTTP/HTTPS 链接
GM_xmlhttpRequest({
method: 'GET',
url: url,
responseType: 'blob',
onload: function(response) {
loadingDiv.style.display = 'none';
if (response.status === 200) {
const blob = response.response;
let fileName;
// 处理响应头大小写问题
const headers = response.responseHeaders.toLowerCase();
const dispositionIndex = headers.indexOf('content-disposition');
if (dispositionIndex !== -1) {
const disposition = headers.substring(dispositionIndex + 'content-disposition'.length).split('\n')[0].trim();
const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
const matches = filenameRegex.exec(disposition);
if (matches != null && matches[1]) {
fileName = matches[1].replace(/['"]/g, '');
}
}
if (!fileName) {
// 如果没有从响应头中获取到文件名,使用 URL 的最后一部分
fileName = url.substring(url.lastIndexOf('/') + 1);
}
if (forceTxtCheckbox.checked) {
// 去掉原文件扩展名并添加 .txt
fileName = fileName.replace(/\.[^/.]+$/, '') + '.txt';
}
const link = document.createElement('a');
let objectUrl;
try {
objectUrl = window.URL.createObjectURL(blob);
link.href = objectUrl;
link.download = fileName;
link.click();
} finally {
if (objectUrl) {
window.URL.revokeObjectURL(objectUrl);
}
}
} else {
alert('下载失败,请检查链接是否有效,状态码: ' + response.status);
}
},
onerror: function(error) {
loadingDiv.style.display = 'none';
alert(`下载过程中出现错误,请稍后重试,状态码: ${error.status},错误信息: ${error.statusText}`);
}
});
} else if (isMagnetLink) {
// 处理磁力链接
try {
const magnetLink = document.createElement('a');
magnetLink.href = url;
magnetLink.click();
// 设置超时检测(5 秒)
const timeout = 5000; // 5 秒
const startTime = Date.now();
// 监听窗口是否失去焦点(表示客户端可能已打开)
const onBlur = () => {
showNotification('正在通过默认客户端打开磁力链接...');
loadingDiv.style.display = 'none'; // 隐藏加载状态
window.removeEventListener('blur', onBlur);
};
window.addEventListener('blur', onBlur);
// 超时检测
setTimeout(() => {
window.removeEventListener('blur', onBlur);
if (Date.now() - startTime >= timeout) {
loadingDiv.style.display = 'none'; // 隐藏加载状态
showNotification('打开客户端失败,请手动复制链接到 BT 客户端。');
navigator.clipboard.writeText(url).catch((err) => {
console.error('复制磁力链接失败:', err);
});
}
}, timeout);
} catch (error) {
// 如果无法直接打开,复制到剪贴板并提示用户
loadingDiv.style.display = 'none'; // 隐藏加载状态
navigator.clipboard.writeText(url).then(() => {
alert('打开客户端失败,请手动粘贴链接到 BT 客户端。');
}).catch((err) => {
console.error('复制磁力链接失败:', err);
});
}
}
});
})();