// ==UserScript==
// @name 百度网盘文件直链解析助手尊享版
// @namespace https://www.qyccc.com/
// @version 0.13
// @description 百度网盘免会员文件直链解析满速下载
// @author 清语尘
// @match *://pan.baidu.com/*
// @icon https://android-artworks.25pp.com/fs08/2025/09/05/3/110_a434d925c0416fd0188b2d7fea68d7fb_con.png
// @grant GM_addStyle
// @run-at document-idle
// @license MIT
// @tag 百度网盘,直链解析
// ==/UserScript==
(function () {
'use strict';
const TARGET_IFRAME_ORIGIN = 'https://p.pupp.top';
const TARGET_IFRAME_URL = `${TARGET_IFRAME_ORIGIN}/user/parse`;
GM_addStyle(`
#tm_proxy_overlay { position:fixed;inset:0;background:rgba(0,0,0,0.45);z-index:2147483646;display:flex;align-items:center;justify-content:center; }
#tm_proxy_modal { width:92%;max-width:1100px;height:90vh;background:#fff;border-radius:8px;display:flex;flex-direction:column; }
#tm_modal_header { height:44px; display:flex; align-items:center; justify-content:space-between; padding:0 12px; background:#f6f6f6; border-bottom:1px solid #eee; }
#tm_modal_iframe { flex:1; border:0;width:100%;height:100%; }
#tm_modal_footer { height:40px; display:flex; align-items:center; justify-content:flex-end; padding:6px 10px; border-top:1px solid #eee; background:#fafafa; font-size:12px; color:#666; }
#tm_proxy_btn, #tm_close_btn { padding:6px 10px; border-radius:6px; cursor:pointer; }
#tm_proxy_btn { background:#2d8cf0; color:#fff; border:none; margin-left:6px; }
#tm_close_btn { background:#fff; border:1px solid #ddd; }
`);
function looksLikePanShare(text) {
return text && /https?:\/\/pan\.baidu\.com\/s\/[A-Za-z0-9_-]+/.test(text);
}
function showModalWithIframe(link) {
document.getElementById('tm_proxy_overlay')?.remove();
const overlay = document.createElement('div');
overlay.id = 'tm_proxy_overlay';
const modal = document.createElement('div');
modal.id = 'tm_proxy_modal';
const header = document.createElement('div');
header.id = 'tm_modal_header';
header.innerHTML = `
文件直链解析助手尊享版
`;
const iframe = document.createElement('iframe');
iframe.id = 'tm_modal_iframe';
iframe.src = TARGET_IFRAME_URL;
iframe.sandbox = 'allow-scripts allow-forms allow-same-origin allow-popups';
iframe.style.height = '100%';
iframe.style.flex = '1';
const footer = document.createElement('div');
footer.id = 'tm_modal_footer';
footer.textContent = '等待发送链接…';
const sendBtn = document.createElement('button');
sendBtn.id = 'tm_proxy_btn';
sendBtn.textContent = '重发链接';
footer.appendChild(sendBtn);
modal.appendChild(header);
modal.appendChild(iframe);
modal.appendChild(footer);
overlay.appendChild(modal);
document.body.appendChild(overlay);
document.getElementById('tm_close_btn').onclick = () => overlay.remove();
function postLink(times = 8, interval = 600) {
const indicator = footer;
let count = 0;
const timer = setInterval(() => {
count++;
try { iframe.contentWindow.postMessage({ cmd: 'fill_link', link }, TARGET_IFRAME_ORIGIN); } catch (e) {}
indicator.textContent = `已发送 ${count} 次`;
if (count >= times) clearInterval(timer);
}, interval);
try { iframe.contentWindow.postMessage({ cmd: 'fill_link', link }, TARGET_IFRAME_ORIGIN); indicator.textContent = '已发送 1 次'; } catch(e){}
}
iframe.addEventListener('load', () => postLink());
sendBtn.onclick = () => postLink();
}
function handleShareLink(rawText) {
const shareLink = rawText.trim();
if (!looksLikePanShare(shareLink)) return;
showModalWithIframe(shareLink);
}
document.addEventListener('copy', e => {
const copied = e.clipboardData?.getData('text/plain') || window.getSelection()?.toString() || '';
if (looksLikePanShare(copied)) handleShareLink(copied);
}, true);
window.addEventListener('message', e=>{
if(e.data?.cmd==='code_verified'){
const iframe=document.getElementById('tm_modal_iframe');
if(iframe) iframe.src=iframe.src;
}
});
let triggered = false;
const observer = new MutationObserver(muts => {
if (triggered) return;
for (const m of muts) {
if (!m.addedNodes) continue;
for (const node of m.addedNodes) {
if (node.nodeType !== 1) continue;
const text = (node.textContent || '').trim();
if (looksLikePanShare(text)) { triggered = true; handleShareLink(text); return; }
const inputs = node.querySelectorAll ? node.querySelectorAll('input,textarea,div,span') : [];
for (const el of inputs) {
const v = (el.value || el.textContent || '').trim();
if (looksLikePanShare(v)) { triggered = true; handleShareLink(v); return; }
}
}
}
});
observer.observe(document, { childList: true, subtree: true });
})();