// ==UserScript==
// @name MEGA鏈接檢測器
// @name:zh-CN MEGA链接检测器
// @name:zh-TW MEGA鏈接檢測器
// @namespace http://tampermonkey.net/
// @version 0.6
// @description 檢測MEGA鏈接是否可用,並在旁邊顯示狀態
// @description:zh-CN 检测MEGA链接是否可用,并在旁边显示状态
// @description:zh-TW 檢測MEGA鏈接是否可用,並在旁邊顯示狀態
// @author Claude
// @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;
// 日誌函數
function log(message, data) {
if (!DEBUG) return;
if (data) {
console.log(`[MEGA檢測器] ${message}`, data);
} else {
console.log(`[MEGA檢測器] ${message}`);
}
}
// 主函數 - 檢查MEGA連結
function checkMEGALinks() {
executionCount++;
log(`開始檢查MEGA連結 (第${executionCount}次執行)`);
// 尋找頁面中的所有連結
const links = document.querySelectorAll('a');
let megaLinksCount = 0;
links.forEach(link => {
const href = link.href;
// 檢測是否為MEGA連結且尚未檢查過
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;
}
// 檢查MEGA連結狀態
function checkLinkStatus(linkElement, url) {
// 創建狀態指示器
const statusIndicator = document.createElement('span');
statusIndicator.style.marginLeft = '5px';
statusIndicator.style.padding = '2px 5px';
statusIndicator.style.borderRadius = '3px';
statusIndicator.style.fontSize = '12px';
statusIndicator.textContent = '檢查中...';
statusIndicator.style.backgroundColor = '#f0f0f0';
statusIndicator.style.color = '#666';
// 將狀態指示器添加到連結旁
linkElement.parentNode.insertBefore(statusIndicator, linkElement.nextSibling);
log(`正在檢查連結: ${url}`);
// 從URL提取文件ID和密鑰
const { fileID, fileKey } = extractMEGAInfo(url);
if (!fileID) {
log(`無法提取文件ID,URL格式可能不符合預期`);
updateStatusIndicator(statusIndicator, false);
return;
}
// 檢查是否有解密金鑰,如果沒有,標記為未知狀態
if (!fileKey) {
log(`未提供解密金鑰,無法確認文件狀態`);
updateStatusIndicator(statusIndicator, null, true);
return;
}
log(`提取到的文件ID: ${fileID}, 密鑰: ${fileKey ? '有' : '無'}`);
// 使用GM_xmlhttpRequest發送MEGA API請求
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, // 10秒超時
onload: function(response) {
log(`API回應狀態: ${response.status}`, response.responseText);
try {
// 嘗試解析JSON響應
const data = JSON.parse(response.responseText);
log(`解析API回應:`, data);
// 確定檔案狀態
if (data && Array.isArray(data)) {
// 檢查API錯誤代碼
if (data[0] === -9) {
// -9 表示資源不存在(通常是文件或文件夾已被刪除)
log(`文件不存在或已刪除 (錯誤碼: -9)`, data);
updateStatusIndicator(statusIndicator, false);
} else if (data[0] === -11) {
// -11 表示訪問被拒絕(可能是解密金鑰問題)
log(`訪問被拒絕 (錯誤碼: -11)`, data);
// 這裡我們將-11標記為未知,但添加特殊說明
updateStatusIndicator(statusIndicator, null, true);
} else if (typeof data[0] === 'object' && !data[0].e) {
// 成功獲取文件信息
log(`文件存在且可用`, data);
updateStatusIndicator(statusIndicator, true);
} else if (typeof data[0] === 'number' && data[0] < 0) {
// 其他錯誤代碼
log(`API返回錯誤代碼: ${data[0]}`, data);
updateStatusIndicator(statusIndicator, null);
} else {
log(`無法確認文件狀態`, data);
updateStatusIndicator(statusIndicator, null);
}
} else {
log(`API回應格式異常`, data);
updateStatusIndicator(statusIndicator, null);
}
} catch (e) {
log(`JSON解析錯誤`, e);
updateStatusIndicator(statusIndicator, null);
}
},
onerror: function(error) {
log(`API請求出錯`, error);
updateStatusIndicator(statusIndicator, null);
},
ontimeout: function() {
log(`API請求超時`);
updateStatusIndicator(statusIndicator, null);
}
});
}
// 從MEGA URL中提取文件ID和密鑰
function extractMEGAInfo(url) {
log(`正在從URL提取MEGA信息: ${url}`);
let fileID = null;
let fileKey = null;
// 處理新版格式: https://mega.nz/file/FILEID#FILEKEY
let match = url.match(/mega\.[a-z]+\/file\/([a-zA-Z0-9_-]+)(?:#([a-zA-Z0-9_-]+)|$|\?)/i);
if (!match) {
// 處理folder格式: https://mega.nz/folder/FOLDERID#FOLDERKEY
match = url.match(/mega\.[a-z]+\/folder\/([a-zA-Z0-9_-]+)(?:#([a-zA-Z0-9_-]+)|$|\?)/i);
}
if (!match) {
// 處理舊版格式: https://mega.nz/#!FILEID!FILEKEY 或 https://mega.nz/#F!FOLDERID!FOLDERKEY
match = url.match(/mega\.[a-z]+\/#(?:F|)!([a-zA-Z0-9_-]+)(?:!([a-zA-Z0-9_-]+)|$|\?)/i);
}
if (match) {
fileID = match[1];
fileKey = match[2];
}
return { fileID, fileKey };
}
// 更新狀態指示器
function updateStatusIndicator(indicator, isValid, needsDecryption = false) {
if (isValid === true) {
log(`設置狀態指示為可用`);
indicator.textContent = '可用';
indicator.style.backgroundColor = '#e6f7e6';
indicator.style.color = '#2e8b57';
} else if (isValid === false) {
log(`設置狀態指示為已失效`);
indicator.textContent = '已失效';
indicator.style.backgroundColor = '#ffebee';
indicator.style.color = '#d32f2f';
} else {
if (needsDecryption) {
log(`設置狀態指示為需要解密金鑰`);
indicator.textContent = '需要金鑰';
indicator.style.backgroundColor = '#e3f2fd';
indicator.style.color = '#1565c0';
} else {
log(`設置狀態指示為未知`);
indicator.textContent = '未知';
indicator.style.backgroundColor = '#fff9c4';
indicator.style.color = '#ff8f00';
}
}
// 添加懸停提示
if (needsDecryption) {
indicator.title = '此連結需要正確的解密金鑰才能訪問';
} else if (isValid === null) {
indicator.title = '無法確定連結狀態';
}
}
// 監視DOM變化,檢測新添加的MEGA連結
function setupMutationObserver() {
log('設置DOM變化監視器');
// 創建一個觀察器實例
const observer = new MutationObserver(function(mutations) {
let shouldCheck = false;
// 檢查是否有新增的節點
mutations.forEach(function(mutation) {
if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
shouldCheck = true;
}
});
// 如果有新增節點,檢查MEGA連結
if (shouldCheck) {
log('檢測到DOM變化,檢查新的MEGA連結');
checkMEGALinks();
}
});
// 配置觀察選項
const config = {
childList: true, // 觀察子節點的添加或刪除
subtree: true // 觀察所有後代節點
};
// 開始觀察document.body
observer.observe(document.body, config);
log('DOM變化監視器已設置');
return observer;
}
// 確保腳本在不同階段都能執行
function initialize() {
log('MEGA鏈接檢測器腳本初始化');
// 立即執行一次
if (document.readyState === 'loading') {
log('文檔仍在加載中,等待DOMContentLoaded事件');
document.addEventListener('DOMContentLoaded', function() {
log('DOMContentLoaded事件觸發');
setTimeout(function() {
checkMEGALinks();
setupMutationObserver();
}, 500);
});
} else {
log('文檔已加載完成,直接執行檢查');
setTimeout(function() {
checkMEGALinks();
setupMutationObserver();
}, 500);
}
// 頁面完全加載後再執行一次
window.addEventListener('load', function() {
log('頁面完全加載事件觸發');
setTimeout(function() {
checkMEGALinks();
}, 1000);
});
// 定期檢查,頻率降低
setInterval(function() {
log('定期檢查新的MEGA連結');
checkMEGALinks();
}, 30000); // 每30秒檢查一次
}
// 啟動腳本
initialize();
log('MEGA鏈接檢測器腳本已加載');
})();