Greasy Fork is available in English.
自动检测视频播放页并解析替换播放框,支持多接口切换,实时监听URL变化,针对爱奇艺/腾讯/芒果TV优化
当前为
// ==UserScript==
// @name 2025/10月最新VIP视频自动4K解析(针对爱奇艺/腾讯/芒果TV优化)
// @namespace https://baidu.com/
// @version 1.0.0
// @description 自动检测视频播放页并解析替换播放框,支持多接口切换,实时监听URL变化,针对爱奇艺/腾讯/芒果TV优化
// @author User
// @match *://*.iqiyi.com/*
// @match *://v.qq.com/*
// @match *://*.mgtv.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=isyour.love
// @run-at document-idle
// @grant GM_setValue
// @grant GM_getValue
// @noframes
// ==/UserScript==
(function () {
'use strict';
const IFRAME_ID = 'tm-vip-parser-iframe';
const CONTAINER_DATA_FLAG = 'tmVipParserContainer';
const CONFIG_KEY = 'vip_parser_config';
const PARSE_INTERFACES = [
{"name": "789解析", "url": "https://jiexi.789jiexi.icu:4433/?url="},
{"name": "聚合解析", "url": "https://video.isyour.love/player/getplayer?url="},
{"name": "冰豆解析", "url": "https://bd.jx.cn/?url="},
{"name": "973解析", "url": "https://jx.973973.xyz/?url="},
{"name": "Player-JY", "url": "https://jx.playerjy.com/?url="},
{"name": "虾米视频解析", "url": "https://jx.xmflv.com/?url="},
{"name": "CK", "url": "https://www.ckplayer.vip/jiexi/?url="},
{"name": "七哥解析", "url": "https://jx.nnxv.cn/tv.php?url="},
{"name": "夜幕", "url": "https://www.yemu.xyz/?url="},
{"name": "盘古", "url": "https://www.pangujiexi.com/jiexi/?url="},
{"name": "playm3u8", "url": "https://www.playm3u8.cn/jiexi.php?url="},
{"name": "七七云解析", "url": "https://jx.77flv.cc/?url="},
{"name": "芒果TV2", "url": "https://im1907.top/?jx="},
{"name": "HLS解析", "url": "https://jx.hls.one/?url="}
];
const DEFAULT_CONFIG = {
enabled: true,
selectedInterface: 0,
sites: {
iqiyi: true,
qq: true,
mgtv: true
}
};
let parseActive = false;
let currentContainer = null;
let lastUrl = location.href;
let urlCheckTimer = null;
let currentSite = getSiteType();
function getConfig() {
try {
const saved = GM_getValue(CONFIG_KEY);
if (saved) {
const config = JSON.parse(saved);
return { ...DEFAULT_CONFIG, ...config, sites: { ...DEFAULT_CONFIG.sites, ...config.sites } };
}
} catch (e) {
console.error('[解析] 获取配置失败:', e);
}
return DEFAULT_CONFIG;
}
function saveConfig(config) {
try {
GM_setValue(CONFIG_KEY, JSON.stringify(config));
} catch (e) {
console.error('[解析] 保存配置失败:', e);
}
}
function getCurrentParsePrefix() {
const config = getConfig();
const index = config.selectedInterface || 0;
return PARSE_INTERFACES[index].url;
}
function getSiteType() {
const host = location.hostname;
if (/iqiyi\.com$/i.test(host)) return 'iqiyi';
if (/v\.qq\.com$/i.test(host)) return 'qq';
if (/mgtv\.com$/i.test(host)) return 'mgtv';
return null;
}
function isVideoPage() {
const url = location.href;
const host = location.hostname;
const hasHtmlInUrl = /\.html?/i.test(url);
let hasPlayer = false;
if (/iqiyi\.com$/i.test(host)) {
hasPlayer = !!(
document.querySelector('video[src^="blob:"]') ||
document.querySelector('[data-player-hook="videolayer"]') ||
document.querySelector('.iqp-player-videolayer') ||
document.querySelector('#videoContent')
);
} else if (/v\.qq\.com$/i.test(host)) {
hasPlayer = !!(
document.querySelector('#player-container') ||
document.querySelector('.txp_videos_container video') ||
document.querySelector('[data-mvp-dom="player"]')
);
} else if (/mgtv\.com$/i.test(host)) {
hasPlayer = !!(
document.querySelector('video[src^="blob:"]') ||
document.querySelector('#mgtv-player-wrap') ||
document.querySelector('.mango-player')
);
}
return hasHtmlInUrl && hasPlayer;
}
function extractCanonicalHtmlUrl(href) {
try {
const u = new URL(href);
let path = u.pathname || '/';
const lower = path.toLowerCase();
let cutIdx = lower.indexOf('.html');
if (cutIdx >= 0) {
cutIdx += 5;
} else {
const htmIdx = lower.indexOf('.htm');
if (htmIdx >= 0) cutIdx = htmIdx + 4;
}
if (cutIdx && cutIdx > 0) {
path = path.slice(0, cutIdx);
} else {
if (path.length > 1 && path.endsWith('/')) path = path.slice(0, -1);
}
return u.origin + path;
} catch (e) {
return href.split('#')[0].split('?')[0];
}
}
function isElementVisible(el) {
if (!el) return false;
const s = window.getComputedStyle(el);
if (s.display === 'none' || s.visibility === 'hidden' || s.opacity === '0') return false;
const r = el.getBoundingClientRect();
return r.width > 50 && r.height > 50;
}
function getSiteSpecificSelectors() {
const host = location.hostname;
const generic = [
'video',
'#mod_player', '.mod_player', '.txp_player', '#tenvideo_player', '.tenvideo_player', '#player_container', '#player', '.player',
'#flashbox', '.iqp-player', '#iqp-iframe',
'#mgtv-player-wrap', '#mgtv-player', '.mgtv-player-wrap', '#player-box',
'[class*="player"]', '[id*="player"]', '[class*="video"]', '[id*="video"]',
'iframe[src*="iqiyi" i]', 'iframe[src*="v.qq.com" i]', 'iframe[src*="mgtv" i]'
];
if (/iqiyi\.com$/i.test(host)) {
return [
'#videoContent', '#video',
'[data-player-hook="videolayer"], .iqp-player-videolayer',
'[data-player-hook="container"]', '[data-player-hook="outlayer"]',
'#player', '.iqp-player', '#iqp-iframe',
'#flashbox',
...generic
];
}
if (/v\.qq\.com$/i.test(host)) {
return [
'#player-container', '.player__container',
'#player', '[data-mvp-dom="player"]',
'.txp_videos_container', '._mod_thumbplayer_container_',
'.mod_player', '#mod_player',
...generic
];
}
if (/mgtv\.com$/i.test(host)) {
return [
'#mgtv-player', '#player-box',
'#mgtv-player-wrap', '.mgtv-player-wrap',
...generic
];
}
return generic;
}
function findBestPlayerElement() {
const selectors = getSiteSpecificSelectors();
const candidates = [];
for (const sel of selectors) {
const els = document.querySelectorAll(sel);
for (const el of els) {
if (el && isElementVisible(el) && !el.dataset[CONTAINER_DATA_FLAG]) {
const rect = el.getBoundingClientRect();
const area = rect.width * rect.height;
const ratio = rect.width / (rect.height || 1);
candidates.push({ el, area, ratio });
}
}
if (candidates.length > 0) break;
}
if (candidates.length === 0) return null;
candidates.sort((a, b) => {
const scoreA = a.area * (a.ratio >= 1.3 && a.ratio <= 2.0 ? 1.2 : 1.0);
const scoreB = b.area * (b.ratio >= 1.3 && b.ratio <= 2.0 ? 1.2 : 1.0);
return scoreB - scoreA;
});
return candidates[0].el;
}
function getSiteContainer(preferredEl) {
const host = location.hostname;
if (/iqiyi\.com$/i.test(host)) {
const videoLayer = document.querySelector('[data-player-hook="videolayer"], .iqp-player-videolayer');
if (videoLayer && isElementVisible(videoLayer)) return videoLayer;
const out = document.querySelector('[data-player-hook="outlayer"], .iqp-player');
if (out && isElementVisible(out)) return out;
const vc = document.querySelector('#videoContent');
if (vc && isElementVisible(vc)) return vc;
if (preferredEl && preferredEl !== document.body && preferredEl !== document.documentElement) return preferredEl;
return null;
}
if (/v\.qq\.com$/i.test(host)) {
const playerContainer = document.querySelector('#player-container, .player__container');
if (playerContainer && isElementVisible(playerContainer)) return playerContainer;
const player = document.querySelector('#player[data-mvp-dom="player"]');
if (player && isElementVisible(player)) return player;
const txpContainer = document.querySelector('._mod_thumbplayer_container_');
if (txpContainer && isElementVisible(txpContainer)) return txpContainer;
if (preferredEl && preferredEl !== document.body && preferredEl !== document.documentElement) return preferredEl;
return null;
}
if (/mgtv\.com$/i.test(host)) {
const mgtvPlayer = document.querySelector('#mgtv-player-wrap');
if (mgtvPlayer && isElementVisible(mgtvPlayer)) return mgtvPlayer;
const playerBox = document.querySelector('#player-box');
if (playerBox && isElementVisible(playerBox)) return playerBox;
if (preferredEl && preferredEl !== document.body && preferredEl !== document.documentElement) return preferredEl;
return null;
}
return preferredEl;
}
function pauseVideos() {
document.querySelectorAll('video').forEach(v => {
try {
v.pause();
v.muted = true;
v.volume = 0;
if (v.src && v.src.startsWith('blob:')) {
v.removeAttribute('src');
v.load();
}
} catch (e) {}
});
document.querySelectorAll('audio').forEach(a => {
try {
a.pause();
a.muted = true;
a.volume = 0;
} catch (e) {}
});
if (/iqiyi\.com$/i.test(location.hostname)) {
try {
if (window.Q && window.Q.player) {
window.Q.player.pause();
}
document.querySelectorAll('iframe').forEach(iframe => {
try {
const iframeDoc = iframe.contentDocument || iframe.contentWindow?.document;
if (iframeDoc) {
iframeDoc.querySelectorAll('video, audio').forEach(media => {
media.pause();
media.muted = true;
media.volume = 0;
});
}
} catch (e) {}
});
} catch (e) {}
}
if (/v\.qq\.com$/i.test(location.hostname)) {
try {
if (window.player && typeof window.player.pause === 'function') {
window.player.pause();
}
if (window.PLAYER && typeof window.PLAYER.pause === 'function') {
window.PLAYER.pause();
}
} catch (e) {}
}
if (/mgtv\.com$/i.test(location.hostname)) {
try {
if (window.player && typeof window.player.pause === 'function') {
window.player.pause();
}
} catch (e) {}
}
}
let pauseInterval = null;
function startPauseMonitor() {
if (pauseInterval) clearInterval(pauseInterval);
pauseVideos();
pauseInterval = setInterval(() => {
pauseVideos();
}, 500);
}
function stopPauseMonitor() {
if (pauseInterval) {
clearInterval(pauseInterval);
pauseInterval = null;
}
}
function ensureIframeIn(container, targetUrl) {
if (!container) return false;
if (container === document.body || container === document.documentElement) return false;
container.dataset[CONTAINER_DATA_FLAG] = '1';
let iframe = document.getElementById(IFRAME_ID);
if (!iframe) {
iframe = document.createElement('iframe');
iframe.id = IFRAME_ID;
iframe.setAttribute('allowfullscreen', 'true');
iframe.setAttribute('allow', 'autoplay; fullscreen; picture-in-picture');
iframe.setAttribute('sandbox', 'allow-same-origin allow-scripts allow-forms allow-popups allow-modals allow-top-navigation');
iframe.setAttribute('referrerpolicy', 'no-referrer');
iframe.style.cssText = `
position: fixed !important;
top: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100% !important;
border: none !important;
z-index: 2147483647 !important;
background: #000 !important;
opacity: 1 !important;
visibility: visible !important;
pointer-events: auto !important;
`;
document.body.appendChild(iframe);
console.log('[解析] iframe 已插入 body');
}
if (iframe.src !== targetUrl) {
iframe.src = targetUrl;
console.log('[解析] iframe src 已更新:', targetUrl);
}
function updateIframePosition() {
if (!container || !iframe) return;
const rect = container.getBoundingClientRect();
iframe.style.top = rect.top + 'px';
iframe.style.left = rect.left + 'px';
iframe.style.width = rect.width + 'px';
iframe.style.height = rect.height + 'px';
}
updateIframePosition();
window.addEventListener('resize', updateIframePosition);
window.addEventListener('scroll', updateIframePosition);
setInterval(() => {
if (iframe && iframe.style.zIndex !== '2147483647') {
iframe.style.zIndex = '2147483647';
}
}, 500);
startPauseMonitor();
return true;
}
function removeEmbed() {
const iframe = document.getElementById(IFRAME_ID);
if (iframe) {
iframe.remove();
console.log('[解析] iframe 已移除');
}
const marked = document.querySelectorAll(`[data-${CONTAINER_DATA_FLAG}]`);
marked.forEach(el => {
delete el.dataset[CONTAINER_DATA_FLAG];
});
stopPauseMonitor();
parseActive = false;
currentContainer = null;
}
function startParse() {
if (parseActive) {
console.log('[解析] 已在解析状态');
return;
}
const canonical = extractCanonicalHtmlUrl(location.href);
const parsePrefix = getCurrentParsePrefix();
const targetUrl = parsePrefix + encodeURIComponent(canonical);
console.log('[解析] 目标 URL:', targetUrl);
const el = findBestPlayerElement();
if (!el) {
console.warn('[解析] 未找到合适的播放器元素');
return;
}
const container = getSiteContainer(el);
if (!container) {
console.warn('[解析] 未找到有效容器');
return;
}
currentContainer = container;
if (ensureIframeIn(container, targetUrl)) {
parseActive = true;
console.log('[解析] 解析已启动');
updateUI();
}
}
function stopParse() {
removeEmbed();
console.log('[解析] 解析已停止');
updateUI();
}
function toggleAutoParseSwitch() {
const config = getConfig();
config.enabled = !config.enabled;
saveConfig(config);
console.log('[解析] 自动解析开关:', config.enabled ? '开启' : '关闭');
if (!config.enabled && parseActive) {
stopParse();
}
if (config.enabled && isVideoPage() && !parseActive) {
setTimeout(() => {
startParse();
}, 500);
}
updateUI();
}
function showInterfaceModal() {
let panel = document.getElementById('vip-parser-interface-panel');
if (panel) {
panel.style.display = panel.style.display === 'none' ? 'flex' : 'none';
return;
}
const uiContainer = document.getElementById('vip-parser-ui');
const rect = uiContainer.getBoundingClientRect();
panel = document.createElement('div');
panel.id = 'vip-parser-interface-panel';
panel.style.cssText = `
position: fixed !important;
top: ${rect.top}px !important;
left: ${rect.right + 20}px !important;
z-index: 2147483649 !important;
display: flex !important;
align-items: center !important;
gap: 10px !important;
background: rgba(255, 255, 255, 0.85) !important;
backdrop-filter: blur(20px) !important;
padding: 8px 16px !important;
border-radius: 8px !important;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3) !important;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
max-width: calc(100vw - ${rect.right + 40}px) !important;
overflow-x: auto !important;
`;
const title = document.createElement('span');
title.textContent = '选择接口:';
title.style.cssText = `
font-size: 14px !important;
font-weight: 600 !important;
color: #333 !important;
white-space: nowrap !important;
`;
panel.appendChild(title);
const config = getConfig();
const currentIndex = config.selectedInterface || 0;
const interfaceButtons = [];
PARSE_INTERFACES.forEach((iface, index) => {
const item = document.createElement('button');
item.textContent = iface.name;
item.dataset.interfaceIndex = index;
item.style.cssText = `
padding: 6px 14px !important;
background: ${index === currentIndex ? '#1e90ff' : 'rgba(128, 128, 128, 0.2)'} !important;
color: ${index === currentIndex ? '#fff' : '#333'} !important;
border: none !important;
border-radius: 6px !important;
cursor: pointer !important;
font-size: 13px !important;
font-weight: 600 !important;
transition: all 0.3s !important;
white-space: nowrap !important;
`;
item.onmouseover = () => {
const currentCfg = getConfig();
const current = currentCfg.selectedInterface || 0;
if (index !== current) {
item.style.background = 'rgba(128, 128, 128, 0.3) !important';
}
};
item.onmouseout = () => {
const currentCfg = getConfig();
const current = currentCfg.selectedInterface || 0;
if (index !== current) {
item.style.background = 'rgba(128, 128, 128, 0.2) !important';
}
};
item.onclick = () => {
const cfg = getConfig();
cfg.selectedInterface = index;
saveConfig(cfg);
console.log('[解析] 切换接口:', iface.name);
interfaceButtons.forEach((btn, i) => {
if (i === index) {
btn.style.cssText = `
padding: 6px 14px !important;
background: #1e90ff !important;
color: #fff !important;
border: none !important;
border-radius: 6px !important;
cursor: pointer !important;
font-size: 13px !important;
font-weight: 600 !important;
transition: all 0.3s !important;
white-space: nowrap !important;
`;
} else {
btn.style.cssText = `
padding: 6px 14px !important;
background: rgba(128, 128, 128, 0.2) !important;
color: #333 !important;
border: none !important;
border-radius: 6px !important;
cursor: pointer !important;
font-size: 13px !important;
font-weight: 600 !important;
transition: all 0.3s !important;
white-space: nowrap !important;
`;
}
});
if (parseActive) {
stopParse();
setTimeout(() => {
startParse();
}, 300);
}
};
interfaceButtons.push(item);
panel.appendChild(item);
});
const closeBtn = document.createElement('button');
closeBtn.textContent = '✕';
closeBtn.style.cssText = `
padding: 4px 10px !important;
background: rgba(255, 0, 0, 0.1) !important;
color: #f44336 !important;
border: none !important;
border-radius: 6px !important;
cursor: pointer !important;
font-size: 14px !important;
font-weight: 700 !important;
transition: all 0.3s !important;
margin-left: 8px !important;
white-space: nowrap !important;
`;
closeBtn.onmouseover = () => {
closeBtn.style.background = 'rgba(255, 0, 0, 0.2) !important';
};
closeBtn.onmouseout = () => {
closeBtn.style.background = 'rgba(255, 0, 0, 0.1) !important';
};
closeBtn.onclick = () => {
panel.style.display = 'none';
};
panel.appendChild(closeBtn);
document.body.appendChild(panel);
document.addEventListener('click', function closePanelOutside(e) {
const interfaceBtn = document.getElementById('vip-parser-interface');
if (panel && !panel.contains(e.target) && !interfaceBtn.contains(e.target)) {
panel.style.display = 'none';
}
});
}
function createUI() {
const container = document.createElement('div');
container.id = 'vip-parser-ui';
container.style.cssText = `
position: fixed !important;
top: 10px !important;
left: 10px !important;
z-index: 2147483648 !important;
display: flex !important;
gap: 10px !important;
align-items: center !important;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
`;
const toggleBtn = document.createElement('button');
toggleBtn.id = 'vip-parser-toggle';
const config = getConfig();
toggleBtn.textContent = config.enabled ? '已开启' : '已关闭';
toggleBtn.style.cssText = `
padding: 10px 20px !important;
background: rgba(128, 128, 128, 0.3) !important;
border: none !important;
border-radius: 6px !important;
cursor: pointer !important;
font-size: 14px !important;
font-weight: 600 !important;
color: #1e90ff !important;
transition: all 0.3s ease !important;
box-shadow: 0 2px 8px rgba(0,0,0,0.15) !important;
user-select: none !important;
backdrop-filter: blur(10px) !important;
`;
toggleBtn.onmouseover = () => {
toggleBtn.style.background = 'rgba(128, 128, 128, 0.4) !important';
toggleBtn.style.boxShadow = '0 4px 12px rgba(30,144,255,0.3) !important';
};
toggleBtn.onmouseout = () => {
toggleBtn.style.background = 'rgba(128, 128, 128, 0.3) !important';
toggleBtn.style.boxShadow = '0 2px 8px rgba(0,0,0,0.15) !important';
};
toggleBtn.onclick = () => {
toggleAutoParseSwitch();
};
const interfaceBtn = document.createElement('button');
interfaceBtn.id = 'vip-parser-interface';
interfaceBtn.textContent = '选择接口';
interfaceBtn.style.cssText = `
padding: 10px 20px !important;
background: rgba(128, 128, 128, 0.3) !important;
border: none !important;
border-radius: 6px !important;
cursor: pointer !important;
font-size: 14px !important;
font-weight: 600 !important;
color: #1e90ff !important;
transition: all 0.3s ease !important;
box-shadow: 0 2px 8px rgba(0,0,0,0.15) !important;
user-select: none !important;
backdrop-filter: blur(10px) !important;
`;
interfaceBtn.onmouseover = () => {
interfaceBtn.style.background = 'rgba(128, 128, 128, 0.4) !important';
interfaceBtn.style.boxShadow = '0 4px 12px rgba(30,144,255,0.3) !important';
};
interfaceBtn.onmouseout = () => {
interfaceBtn.style.background = 'rgba(128, 128, 128, 0.3) !important';
interfaceBtn.style.boxShadow = '0 2px 8px rgba(0,0,0,0.15) !important';
};
interfaceBtn.onclick = () => {
showInterfaceModal();
};
container.appendChild(toggleBtn);
container.appendChild(interfaceBtn);
document.body.appendChild(container);
console.log('[解析] UI 已创建');
}
function updateUI() {
const toggleBtn = document.getElementById('vip-parser-toggle');
if (toggleBtn) {
const config = getConfig();
toggleBtn.textContent = config.enabled ? '已开启' : '已关闭';
}
}
function watchUrlChange() {
urlCheckTimer = setInterval(() => {
const currentUrl = location.href;
if (currentUrl !== lastUrl) {
console.log('[解析] URL 已变化:', currentUrl);
lastUrl = currentUrl;
if (parseActive) {
removeEmbed();
}
setTimeout(() => {
if (isVideoPage()) {
console.log('[解析] 检测到播放页,准备自动解析');
const config = getConfig();
if (config.enabled) {
startParse();
}
}
}, 500);
}
}, 300);
}
function init() {
console.log('[解析] 脚本启动, 当前站点:', currentSite);
createUI();
if (isVideoPage()) {
console.log('[解析] 检测到播放页');
const config = getConfig();
if (config.enabled) {
setTimeout(() => {
startParse();
}, 1000);
}
}
watchUrlChange();
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
setTimeout(init, 500);
}
})();