// ==UserScript==
// @name MEGA鏈接檢測器
// @name:zh-CN MEGA链接检测器
// @name:zh-TW MEGA鏈接檢測器
// @namespace http://tampermonkey.net/
// @version 0.8
// @description 檢測MEGA鏈接是否可用,並在旁邊顯示狀態
// @description:zh-CN 检测MEGA链接是否可用,并在旁边显示状态
// @description:zh-TW 檢測MEGA鏈接是否可用,並在旁邊顯示狀態
// @author Mark
// @license MIT
// @match *://*/*
// @grant GM_xmlhttpRequest
// @connect mega.nz
// @connect mega.io
// @connect g.api.mega.co.nz
// @connect *
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
const DEBUG = true;
const checkedLinks = new Set();
let executionCount = 0;
let observer = null;
function log(message, data) {
if (!DEBUG) return;
console.log(`[MEGA檢測器] ${message}`, data || '');
}
function checkMEGALinks() {
executionCount++;
log(`開始檢查MEGA連結 (第${executionCount}次執行)`);
const links = document.querySelectorAll('a');
let megaLinksCount = 0;
links.forEach(link => {
const href = link.href;
if (href && (href.includes('mega.nz') || href.includes('mega.io')) && !checkedLinks.has(href)) {
checkedLinks.add(href);
megaLinksCount++;
log(`發現MEGA連結: ${href}`);
checkLinkStatus(link, href);
}
});
log(`本次檢查發現 ${megaLinksCount} 個新MEGA連結`);
return megaLinksCount;
}
function checkLinkStatus(linkElement, url) {
let statusIndicator = linkElement.nextElementSibling;
if (!statusIndicator || !statusIndicator.classList.contains('mega-status-indicator')) {
statusIndicator = document.createElement('span');
statusIndicator.classList.add('mega-status-indicator');
statusIndicator.style.marginLeft = '5px';
statusIndicator.style.padding = '2px 5px';
statusIndicator.style.borderRadius = '3px';
statusIndicator.style.fontSize = '12px';
linkElement.parentNode.insertBefore(statusIndicator, linkElement.nextSibling);
}
statusIndicator.textContent = '檢查中...';
statusIndicator.style.backgroundColor = '#f0f0f0';
statusIndicator.style.color = '#666';
const { fileID, fileKey } = extractMEGAInfo(url);
if (!fileID) {
updateStatusIndicator(statusIndicator, false);
return;
}
if (!fileKey) {
updateStatusIndicator(statusIndicator, null, true);
return;
}
GM_xmlhttpRequest({
method: 'POST',
url: 'https://g.api.mega.co.nz/cs',
data: JSON.stringify([{"a": "g", "g": 1, "p": fileID, "ssl": 0}]),
headers: {
'Content-Type': 'application/json'
},
timeout: 10000,
onload: function(response) {
try {
const data = JSON.parse(response.responseText);
if (data && Array.isArray(data)) {
if (data[0] === -9) {
updateStatusIndicator(statusIndicator, false);
} else if (data[0] === -11) {
updateStatusIndicator(statusIndicator, null, true);
} else if (typeof data[0] === 'object' && !data[0].e) {
updateStatusIndicator(statusIndicator, true);
} else {
updateStatusIndicator(statusIndicator, null);
}
} else {
updateStatusIndicator(statusIndicator, null);
}
} catch (e) {
updateStatusIndicator(statusIndicator, null);
}
},
onerror: function() {
updateStatusIndicator(statusIndicator, null);
},
ontimeout: function() {
updateStatusIndicator(statusIndicator, null);
}
});
}
function extractMEGAInfo(url) {
let match = url.match(/mega\.[a-z]+\/(?:file|folder)\/([a-zA-Z0-9_-]+)(?:#([a-zA-Z0-9_-]+)|$|\?)/i) ||
url.match(/mega\.[a-z]+\/#(?:F|)!([a-zA-Z0-9_-]+)(?:!([a-zA-Z0-9_-]+)|$|\?)/i);
return match ? { fileID: match[1], fileKey: match[2] } : { fileID: null, fileKey: null };
}
function updateStatusIndicator(indicator, isValid, needsDecryption = false) {
if (isValid === true) {
indicator.textContent = '可用';
indicator.style.backgroundColor = '#e6f7e6';
indicator.style.color = '#2e8b57';
} else if (isValid === false) {
indicator.textContent = '已失效';
indicator.style.backgroundColor = '#ffebee';
indicator.style.color = '#d32f2f';
} else if (needsDecryption) {
indicator.textContent = '需要金鑰';
indicator.style.backgroundColor = '#e3f2fd';
indicator.style.color = '#1565c0';
} else {
indicator.textContent = '未知';
indicator.style.backgroundColor = '#fff9c4';
indicator.style.color = '#ff8f00';
}
indicator.title = needsDecryption ? '此連結需要正確的解密金鑰才能訪問' :
(isValid === null ? '無法確定連結狀態' : '');
}
function setupMutationObserver() {
if (observer) {
observer.disconnect();
}
observer = new MutationObserver(function(mutations) {
let shouldCheck = false;
for (let mutation of mutations) {
if (mutation.type === 'childList' || mutation.type === 'subtree') {
shouldCheck = true;
break;
}
}
if (shouldCheck) {
log('檢測到DOM變化,檢查新的MEGA連結');
checkMEGALinks();
}
});
observer.observe(document.body, {
childList: true,
subtree: true,
attributes: false,
characterData: false
});
log('DOM變化監視器已設置');
}
function initialize() {
log('MEGA鏈接檢測器腳本初始化');
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', onReady);
} else {
onReady();
}
window.addEventListener('load', onLoad);
window.addEventListener('popstate', onPageChange);
window.addEventListener('pushstate', onPageChange);
window.addEventListener('replacestate', onPageChange);
}
function onReady() {
log('DOMContentLoaded 或文檔已準備就緒');
setTimeout(function() {
checkMEGALinks();
setupMutationObserver();
}, 500);
}
function onLoad() {
log('頁面完全加載');
setTimeout(checkMEGALinks, 1000);
}
function onPageChange() {
log('檢測到頁面變化');
setTimeout(function() {
checkMEGALinks();
setupMutationObserver();
}, 500);
}
// 模擬 pushState 和 replaceState 事件
function setupHistoryWatcher() {
const pushState = history.pushState;
const replaceState = history.replaceState;
history.pushState = function() {
pushState.apply(history, arguments);
window.dispatchEvent(new Event('pushstate'));
};
history.replaceState = function() {
replaceState.apply(history, arguments);
window.dispatchEvent(new Event('replacestate'));
};
}
setupHistoryWatcher();
initialize();
// 定期檢查
setInterval(checkMEGALinks, 30000);
log('MEGA鏈接檢測器腳本已加載');
})();