// ==UserScript== // @name 🎬 视频解析助手 - 稳定版 // @namespace https://github.com/video-helper // @version 3.0.0 // @description 专业视频解析工具 | 支持多平台 | 完全免费 | 仅供技术学习交流使用 // @author 智能解析助手 // @match *://*.iqiyi.com/* // @match *://v.qq.com/* // @match *://*.youku.com/* // @match *://*.mgtv.com/* // @match *://*.bilibili.com/* // @match *://*.le.com/* // @match *://*.sohu.com/* // @match *://*.pptv.com/* // @match *://*.1905.com/* // @grant GM_registerMenuCommand // @grant GM_addStyle // @grant GM_notification // @grant GM_getValue // @grant GM_setValue // @grant GM_openInTab // @require https://cdn.jsdelivr.net/npm/sweetalert2@11 // @run-at document-end // @icon https://cdn.jsdelivr.net/npm/simple-icons@v8/icons/vlc.svg // @license MIT // ==/UserScript== (function() { 'use strict'; // 调试开关 const DEBUG = true; // 支持的白名单域名 const SUPPORT_HOSTS = [ 'iqiyi.com', 'v.qq.com', 'youku.com', 'mgtv.com', 'bilibili.com', 'le.com', 'sohu.com', 'pptv.com', '1905.com' ]; // 内置解析接口 const parseApis = [ {name: "七哥解析", type: "1,3", url: "https://jx.nnxv.cn/tv.php?url=", recommended: true}, {name: "虾米解析", type: "1,3", url: "https://jx.xmflv.cc/?url=", recommended: true}, {name: "纯净解析", type: "1,2,3", url: "https://im1907.top/?jx="}, {name: "B站解析", type: "1,3", url: "https://jx.jsonplayer.com/player/?url="}, {name: "爱豆解析", type: "1,3", url: "https://jx.aidouer.net/?url="}, {name: "BL解析", type: "1,3", url: "https://vip.bljiex.com/?v="}, {name: "冰豆解析", type: "1,3", url: "https://api.qianqi.net/vip/?url="}, {name: "百域解析", type: "1,3", url: "https://jx.618g.com/?url="}, {name: "CK解析", type: "1,3", url: "https://www.ckplayer.vip/jiexi/?url="}, {name: "CHok解析", type: "1,3", url: "https://www.gai4.com/?url="}, {name: "ckmov解析", type: "1,3", url: "https://www.ckmov.vip/api.php?url="}, {name: "H8解析", type: "1,3", url: "https://www.h8jx.com/jiexi.php?url="}, {name: "JY解析", type: "1,3", url: "https://jx.playerjy.com/?url="}, {name: "解析接口", type: "1,3", url: "https://ckmov.ccyjjd.com/ckmov/?url="}, {name: "解析la", type: "1,3", url: "https://api.jiexi.la/?url="}, {name: "老板解析", type: "1,3", url: "https://vip.laobandq.com/jiexi.php?url="}, {name: "MAO解析", type: "1,3", url: "https://www.mtosz.com/m3u8.php?url="}, {name: "M3U8解析", type: "1,3", url: "https://jx.m3u8.tv/jiexi/?url="}, {name: "诺讯解析", type: "1,3", url: "https://www.nxflv.com/?url="}, {name: "OK解析", type: "1,3", url: "https://okjx.cc/?url="}, {name: "PM解析", type: "1,3", url: "https://www.playm3u8.cn/jiexi.php?url="}, {name: "盘古解析", type: "1,3", url: "https://www.pangujiexi.cc/jiexi.php?url="}, {name: "RDHK解析", type: "1,3", url: "https://jx.rdhk.net/?v="}, {name: "人人迷解析", type: "1,3", url: "https://jx.blbo.cc:4433/?url="}, {name: "思云解析", type: "1,3", url: "https://jx.ap2p.cn/?url="}, {name: "思古解析", type: "1,3", url: "https://jsap.attakids.com/?url="}, {name: "听乐解析", type: "1,3", url: "https://jx.dj6u.com/?url="}, {name: "维多解析", type: "1,3", url: "https://jx.ivito.cn/?url="}, {name: "YT解析", type: "1,3", url: "https://jx.yangtu.top/?url="}, {name: "云端解析", type: "1,3", url: "https://sb.5gseo.net/?url="}, {name: "0523解析", type: "1,3", url: "https://go.yh0523.cn/y.cy?url="}, {name: "17云解析", type: "1,3", url: "https://www.1717yun.com/jx/ty.php?url="}, {name: "180解析", type: "1,3", url: "https://jx.000180.top/jx/?url="}, {name: "4K解析", type: "1,3", url: "https://jx.4kdv.com/?url="}, {name: "8090解析", type: "1,3", url: "https://www.8090g.cn/?url="}, {name: "剖元解析", type: "1,3", url: "https://www.pouyun.com/?url="}, {name: "全民解析", type: "1,3", url: "https://43.240.74.102:4433?url="}, {name: "夜幕解析", type: "1,3", url: "https://www.yemu.xyz/?url="}, {name: "im1907(带选集)", type: "2", url: "https://im1907.top/?jx="}, {name: "云析(带选集)", type: "2", url: "https://jx.yparse.com/index.php?url="}, ]; // 去重处理 const uniqueApis = []; const seenUrls = new Set(); parseApis.forEach(api => { if (!seenUrls.has(api.url)) { seenUrls.add(api.url); uniqueApis.push(api); } }); // 获取自定义接口 function getCustomApis() { return GM_getValue('video_helper_custom_apis', []); } // 获取所有接口 function getAllApis() { return [...uniqueApis, ...getCustomApis()]; } // 检查是否支持当前网站 function isSupportSite() { const hostname = window.location.hostname; return SUPPORT_HOSTS.some(host => hostname.includes(host)); } // 调试日志 function log(...args) { if (DEBUG) { console.log('[视频解析助手]', ...args); } } // 主函数 function main() { log('脚本开始执行,当前网址:', window.location.href); // 检查是否支持当前网站 if (!isSupportSite()) { log('当前网站不在支持列表中'); return; } log('当前网站支持,继续初始化...'); // 注入CSS样式 injectStyles(); // 创建界面 createVipButton(); // 注册菜单 registerMenuCommands(); // 检查自动播放 checkAutoPlay(); log('脚本初始化完成'); } // 注入CSS样式 function injectStyles() { const css = ` #video-helper-container { position: fixed; top: 120px; left: 0; z-index: 2147483647; transition: left 0.3s ease; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; } .vh-main-icon { width: 40px; height: 40px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 8px 0 0 8px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: white; font-weight: bold; font-size: 14px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); user-select: none; } .vh-main-icon:hover { background: linear-gradient(135deg, #764ba2 0%, #667eea 100%); } .vh-panel { position: absolute; left: 40px; top: 0; width: 420px; background: white; border-radius: 0 8px 8px 8px; box-shadow: 0 8px 32px rgba(0,0,0,0.2); overflow: hidden; display: none; } .vh-panel.visible { display: block; } .vh-tabs { display: flex; background: #f8f9fa; border-bottom: 1px solid #e9ecef; } .vh-tab { flex: 1; padding: 12px; border: none; background: none; cursor: pointer; font-size: 12px; color: #6c757d; } .vh-tab.active { color: #667eea; font-weight: 600; border-bottom: 2px solid #667eea; background: white; } .vh-tab-content { padding: 16px; max-height: 400px; overflow-y: auto; } .vh-api-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; margin-bottom: 12px; } .vh-api-item { padding: 6px 4px; background: white; border: 1px solid #dee2e6; border-radius: 4px; font-size: 11px; text-align: center; cursor: pointer; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .vh-api-item:hover { border-color: #667eea; color: #667eea; } .vh-api-item.recommended { border-color: #28a745; } .vh-mode-toggle { color: #667eea; font-size: 10px; cursor: pointer; margin-left: 2px; } .vh-auto-switch { width: 40px; height: 40px; background: #28a745; border-radius: 8px 0 0 8px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: white; font-weight: bold; font-size: 12px; margin-top: 8px; } .vh-auto-switch.off { background: #dc3545; } `; GM_addStyle(css); } // 创建VIP按钮 function createVipButton() { log('创建VIP按钮...'); // 如果已存在,先移除 const existing = document.getElementById('video-helper-container'); if (existing) { existing.remove(); } const container = document.createElement('div'); container.id = 'video-helper-container'; container.innerHTML = `
VIP
内嵌/弹窗播放接口
${generateApiItems(getAllApis().filter(api => api.type.includes('1') || api.type.includes('3')))}
弹窗播放(带选集)
${generateApiItems(getAllApis().filter(api => api.type.includes('2')))}
${GM_getValue('video_helper_auto_play') ? '开' : '关'}
`; document.body.appendChild(container); bindEvents(container); // 立即显示面板(测试用) setTimeout(() => { const panel = container.querySelector('.vh-panel'); if (panel) { panel.classList.add('visible'); log('面板已显示(测试模式)'); } }, 1000); } // 生成接口项 function generateApiItems(apis) { return apis.map((api, index) => { const types = api.type.split(','); let modeText = ''; let modeAttr = ''; if (types.includes('1') && types.includes('3')) { modeText = '内嵌'; modeAttr = 'data-modes="1,3" data-current-mode="1"'; } else if (types.includes('1')) { modeText = '内嵌'; modeAttr = 'data-mode="1"'; } else if (types.includes('2')) { modeText = ''; modeAttr = 'data-mode="2"'; } else if (types.includes('3')) { modeText = '弹窗'; modeAttr = 'data-mode="3"'; } const modeHtml = modeText ? ` | ${modeText}` : ''; const recommendedClass = api.recommended ? 'recommended' : ''; return `
${api.name}${modeHtml}
`; }).join(''); } // 绑定事件 function bindEvents(container) { const mainIcon = container.querySelector('.vh-main-icon'); const panel = container.querySelector('.vh-panel'); // 点击主按钮切换面板 mainIcon.addEventListener('click', function() { panel.classList.toggle('visible'); }); // 选项卡切换 container.querySelectorAll('.vh-tab').forEach(tab => { tab.addEventListener('click', function() { const tabName = this.dataset.tab; // 更新激活状态 container.querySelectorAll('.vh-tab').forEach(t => t.classList.remove('active')); this.classList.add('active'); // 显示对应内容 container.querySelectorAll('.vh-tab-content').forEach(content => { content.style.display = content.dataset.content === tabName ? 'block' : 'none'; }); }); }); // 接口点击事件 const allApis = getAllApis(); container.querySelectorAll('.vh-api-item').forEach(item => { item.addEventListener('click', function(e) { if (e.target.classList.contains('vh-mode-toggle')) { toggleMode(this); return; } const index = parseInt(this.dataset.index); if (index >= 0 && index < allApis.length) { useApi(allApis[index], this); } }); }); // 自动解析开关 const autoSwitch = container.querySelector('.vh-auto-switch'); autoSwitch.addEventListener('click', function() { const isOn = this.classList.contains('on'); if (isOn) { this.classList.remove('on'); this.classList.add('off'); this.textContent = '关'; this.title = '自动解析已关闭'; GM_setValue('video_helper_auto_play', false); } else { this.classList.remove('off'); this.classList.add('on'); this.textContent = '开'; this.title = '自动解析已开启'; GM_setValue('video_helper_auto_play', true); } showNotification('设置已保存', `自动解析已${isOn ? '关闭' : '开启'}`); }); // 自定义接口表单 const saveBtn = container.querySelector('#save-custom-api'); if (saveBtn) { saveBtn.addEventListener('click', function() { const name = container.querySelector('#custom-api-name').value.trim(); const url = container.querySelector('#custom-api-url').value.trim(); const type = container.querySelector('#custom-api-type').value; if (!name || !url) { showNotification('输入不完整', '请填写接口名称和地址', 'error'); return; } if (!url.includes('?url=') && !url.includes('&url=')) { showNotification('格式错误', '接口地址必须包含 ?url= 或 &url= 参数', 'error'); return; } const newApi = { name, type, url }; const customApis = getCustomApis(); customApis.push(newApi); GM_setValue('video_helper_custom_apis', customApis); // 清空表单 container.querySelector('#custom-api-name').value = ''; container.querySelector('#custom-api-url').value = ''; showNotification('添加成功', '自定义接口已保存,刷新页面后生效'); }); } // 清空自定义接口 const clearBtn = container.querySelector('#clear-custom-apis'); if (clearBtn) { clearBtn.addEventListener('click', function() { if (confirm('确认清空所有自定义解析接口?')) { GM_setValue('video_helper_custom_apis', []); showNotification('已清空', '所有自定义接口已被删除'); } }); } // 拖拽功能 enableDragging(container); } // 切换模式 function toggleMode(element) { const modes = element.parentElement.getAttribute('data-modes').split(','); const currentMode = element.parentElement.getAttribute('data-current-mode'); let nextIndex = modes.indexOf(currentMode) + 1; if (nextIndex >= modes.length) nextIndex = 0; const nextMode = modes[nextIndex]; element.parentElement.setAttribute('data-current-mode', nextMode); let modeText = nextMode === '1' ? '内嵌' : '弹窗'; element.textContent = modeText; showNotification('模式切换', `已切换为${modeText}播放模式`); } // 使用接口 function useApi(api, element) { log(`使用解析接口: ${api.name}`); // 获取播放模式 let playMode = api.type.split(',')[0]; if (element.hasAttribute('data-modes')) { playMode = element.getAttribute('data-current-mode') || '1'; } else if (element.hasAttribute('data-mode')) { playMode = element.getAttribute('data-mode'); } // 保存选择的接口 const allApis = getAllApis(); const index = allApis.findIndex(a => a.url === api.url); if (index !== -1) { GM_setValue('video_helper_selected_api', index); } // 根据模式处理 if (playMode === '1') { embedPlay(api); } else { popupPlay(api); } // 更新选中状态 document.querySelectorAll('.vh-api-item').forEach(item => { item.classList.remove('selected'); }); if (element) { element.classList.add('selected'); } } // 内嵌播放 function embedPlay(api) { // 尝试查找播放器容器 const findTargetElement = () => { const selectors = ['#player', '.player', '.video-player', '.player-container', '.video-container']; for (const selector of selectors) { const element = document.querySelector(selector); if (element) { return element; } } return null; }; const container = findTargetElement(); if (!container) { showNotification('未找到播放器', '无法定位视频播放区域', 'warning'); return; } // 清空容器 while (container.firstChild) { container.removeChild(container.firstChild); } // 创建iframe const iframe = document.createElement('iframe'); iframe.src = api.url + encodeURIComponent(window.location.href); iframe.style.width = '100%'; iframe.style.height = '100%'; iframe.style.border = 'none'; iframe.allowFullscreen = true; container.appendChild(iframe); showNotification('解析成功', `正在使用 ${api.name} 播放`); } // 弹窗播放 function popupPlay(api) { const url = api.url + encodeURIComponent(window.location.href); GM_openInTab(url, { active: true }); showNotification('正在打开', `使用 ${api.name} 在新标签页播放`); } // 启用拖拽 function enableDragging(container) { let isDragging = false; let startX, startY, startLeft, startTop; container.querySelector('.vh-main-icon').addEventListener('mousedown', startDrag); container.querySelector('.vh-auto-switch').addEventListener('mousedown', startDrag); function startDrag(e) { isDragging = true; startX = e.clientX; startY = e.clientY; const rect = container.getBoundingClientRect(); startLeft = rect.left; startTop = rect.top; document.addEventListener('mousemove', drag); document.addEventListener('mouseup', stopDrag); } function drag(e) { if (!isDragging) return; const deltaX = e.clientX - startX; const deltaY = e.clientY - startY; let newLeft = startLeft + deltaX; let newTop = startTop + deltaY; newLeft = Math.max(0, Math.min(newLeft, window.innerWidth - 40)); newTop = Math.max(0, Math.min(newTop, window.innerHeight - 48)); container.style.left = newLeft + 'px'; container.style.top = newTop + 'px'; } function stopDrag() { isDragging = false; document.removeEventListener('mousemove', drag); document.removeEventListener('mouseup', stopDrag); } } // 检查自动播放 function checkAutoPlay() { if (!GM_getValue('video_helper_auto_play')) { return; } const selectedIndex = GM_getValue('video_helper_selected_api', 0); const allApis = getAllApis(); if (selectedIndex >= 0 && selectedIndex < allApis.length) { const api = allApis[selectedIndex]; if (api.type.includes('1')) { setTimeout(() => { useApi(api); log('自动播放已触发'); }, 2500); } } } // 注册菜单命令 function registerMenuCommands() { try { GM_registerMenuCommand('🎬 显示解析面板', () => { const container = document.getElementById('video-helper-container'); if (container) { const panel = container.querySelector('.vh-panel'); panel.classList.add('visible'); } }); GM_registerMenuCommand('⚙️ 工具设置', () => { Swal.fire({ title: '视频解析助手', html: `

版本:3.0.0

接口数量:${getAllApis().length}

自动解析:${GM_getValue('video_helper_auto_play') ? '已开启' : '已关闭'}

`, icon: 'info' }); }); GM_registerMenuCommand('📋 自定义接口', () => { const container = document.getElementById('video-helper-container'); if (container) { const panel = container.querySelector('.vh-panel'); panel.classList.add('visible'); container.querySelector('[data-tab="custom"]').click(); } }); } catch (error) { log('菜单命令注册失败:', error); } } // 显示通知 function showNotification(title, message, icon = 'success') { Swal.fire({ title: title, text: message, icon: icon, toast: true, position: 'top-end', showConfirmButton: false, timer: 2000 }); } // 启动脚本 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', main); } else { main(); } // 暴露到全局(调试用) if (DEBUG) { window.videoHelper = { getAllApis, isSupportSite, getCustomApis }; } })();