// ==UserScript== // @name 2025/10月最新VIP视频自动解析4K原画(针对爱奇艺/腾讯/芒果TV优化) // @namespace https://baidu.com/ // @version 1.1.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 // @downloadURL none // ==/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); } })();