// ==UserScript== // @name vip视频解析工具 // @namespace xyz_xyz-abcd // @version 1.0.0 // @description 提供优酷、爱奇艺、腾讯、B站(bilibili)、乐视、芒果、搜狐、PPTV等各大视频网站(PC+移动端)视频解析服务整合,免去vip的烦恼,点击相应视频解析接口就可以跳转到对应的解析页面,感谢使用!!! // @author xyz_xyz // @match *://*.youku.com/* // @match *://*.iqiyi.com/* // @match *://*.iq.com/* // @match *://*.le.com/* // @match *://v.qq.com/* // @match *://m.v.qq.com/* // @match *://*.tudou.com/* // @match *://*.mgtv.com/* // @match *://tv.sohu.com/* // @match *://film.sohu.com/* // @match *://*.1905.com/* // @match *://*.bilibili.com/* // @match *://*.pptv.com/* // @connect 8.138.189.217 // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @grant GM_xmlhttpRequest // ==/UserScript== (function() { 'use strict'; // 1. 配置项 const defaultURLs = [ { name: "虾米", url: "https://jx.xmflv.com/?url=" }, { name: "虾米2", url: "https://jx.xmflv.cc/?url=" }, { name: "纯净1", url: "https://im1907.top/?jx=" }, { name: "B站1", url: "https://jx.jsonplayer.com/player/?url=" }, { name: "咸鱼云解析", url: "https://jx.xymp4.cc/?url=" }, { name: "爱豆", url: "https://jx.aidouer.net/?url=" }, { name: "CHok", url: "https://www.gai4.com/?url=" }, { name: "OK", url: "https://okjx.cc/?url=" }, { name: "RDHK", url: "https://jx.rdhk.net/?v=" }, { name: "人人迷", url: "https://jx.blbo.cc:4433/?url=" }, { name: "思古3", url: "https://jsap.attakids.com/?url=" }, { name: "听乐", url: "https://jx.dj6u.com/?url=" }, { name: "YT", url: "https://jx.yangtu.top/?url=" } ]; const CONFIG = { unlockPassword: "abcdefg", helpImageUrl: "http://8.138.189.217:31415/static/qrcode.png", panelBaseWidthPercent: "28%", panelMinWidth: "320px", panelMaxWidth: "600px", isRememberUnlock: true, apiListMaxRows: 5, apiItemHeight: "50px", collapsedBtnSize: "40px" }; // 2. 样式注入(保留所有优化样式) GM_addStyle(` #videoParserPanel { position: fixed; top: 20px; right: 20px; width: ${CONFIG.panelBaseWidthPercent}; min-width: ${CONFIG.panelMinWidth}; max-width: ${CONFIG.maxWidth}; background: #fff; border-radius: 12px; box-shadow: 0 4px 20px rgba(0,0,0,0.15); padding: 20px; z-index: 99999999; font-family: "Microsoft YaHei", sans-serif; box-sizing: border-box; transition: all 0.3s ease-in-out; overflow: hidden; } #videoParserPanel.collapsed { width: ${CONFIG.collapsedBtnSize}; height: ${CONFIG.collapsedBtnSize}; min-width: ${CONFIG.collapsedBtnSize}; max-width: ${CONFIG.collapsedBtnSize}; padding: 0; display: flex; align-items: center; justify-content: center; } #videoParserPanel .panel-header { font-size: 18px; font-weight: bold; color: #333; margin-bottom: 16px; padding-bottom: 8px; border-bottom: 1px solid #f0f0f0; position: relative; } #videoParserPanel .control-group { position: absolute; top: 0; right: 0; display: flex; align-items: center; gap: 12px; } #videoParserPanel .toggle-collapse { width: 24px; height: 24px; border-radius: 4px; border: 1px solid #e9ecef; background: #f8f9fa; color: #666; font-size: 12px; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: all 0.2s ease; } #videoParserPanel .toggle-collapse:hover { background: #e7f5ff; border-color: #4dabf7; color: #1976d2; } #videoParserPanel .close-panel { width: 24px; height: 24px; font-size: 16px; color: #999; cursor: pointer; border: none; background: none; border-radius: 4px; display: flex; align-items: center; justify-content: center; } #videoParserPanel .close-panel:hover { color: #ff4d4f; background: #fff5f5; } #videoParserPanel .panel-content { transition: opacity 0.2s ease; } #videoParserPanel.collapsed .panel-content { display: none; opacity: 0; } #videoParserPanel .collapse-btn { width: 100%; height: 100%; border: none; background: #4dabf7; color: #fff; font-size: 16px; border-radius: 12px; cursor: pointer; display: none; align-items: center; justify-content: center; } #videoParserPanel.collapsed .collapse-btn { display: flex; } #videoParserPanel .help-area { margin-bottom: 20px; width: 100%; } #videoParserPanel .help-title { font-size: 14px; color: #666; margin-bottom: 8px; } #videoParserPanel .help-image { width: 30%; height: auto; border-radius: 8px; object-fit: cover; margin-bottom: 12px; background: #f8f9fa; padding: 10px; box-sizing: border-box; min-height: 150px; } #videoParserPanel .help-desc { font-size: 12px; color: #999; line-height: 1.5; width: 100%; } #videoParserPanel .api-list { margin-bottom: 20px; width: 100%; max-height: calc(${CONFIG.apiListMaxRows} * ${CONFIG.apiItemHeight} + (${CONFIG.apiListMaxRows} - 1) * 10px); overflow-y: auto; overflow-x: hidden; scrollbar-width: thin; scrollbar-color: #4dabf7 #f0f0f0; } #videoParserPanel .api-list::-webkit-scrollbar { width: 6px; } #videoParserPanel .api-list::-webkit-scrollbar-track { background: #f0f0f0; border-radius: 3px; } #videoParserPanel .api-list::-webkit-scrollbar-thumb { background: #4dabf7; border-radius: 3px; } #videoParserPanel .api-item { display: block; width: 100%; height: ${CONFIG.apiItemHeight}; line-height: ${CONFIG.apiItemHeight}; padding: 0 16px; background: #f8f9fa; border-radius: 8px; margin-bottom: 10px; text-align: center; font-size: 14px; color: #333; text-decoration: none; border: 1px solid #e9ecef; transition: all 0.3s ease; cursor: pointer; box-sizing: border-box; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } #videoParserPanel .api-item:hover { background: #e7f5ff; border-color: #4dabf7; color: #1976d2; } #videoParserPanel .unlock-area { padding-top: 16px; border-top: 1px dashed #f0f0f0; width: 100%; transition: all 0.3s ease; } #videoParserPanel .unlock-area.hidden { display: none; height: 0; padding: 0; border: none; } #videoParserPanel .unlock-input { width: calc(100% - 100px); padding: 10px 12px; border: 1px solid #e9ecef; border-radius: 8px 0 0 8px; font-size: 14px; outline: none; box-sizing: border-box; } #videoParserPanel .unlock-input:focus { border-color: #4dabf7; } #videoParserPanel .unlock-btn { width: 100px; padding: 10px 0; background: #4dabf7; color: #fff; border: none; border-radius: 0 8px 8px 0; font-size: 14px; cursor: pointer; transition: background 0.3s ease; box-sizing: border-box; } #videoParserPanel .unlock-btn:hover { background: #1976d2; } #videoParserPanel .unlock-success { font-size: 12px; color: #52c41a; text-align: center; margin-top: 8px; padding-bottom: 8px; } #videoParserPanel .image-loading { font-size: 12px; color: #999; text-align: center; padding: 60px 0; } `); // 3. 核心工具函数 function getCurrentPageUrl() { const { href } = window.location; const anchorIndex = href.indexOf('#'); return anchorIndex > -1 ? href.substring(0, anchorIndex) : href; } function jumpToParser(apiBaseUrl) { const currentUrl = encodeURIComponent(getCurrentPageUrl()); const fullParserUrl = apiBaseUrl + currentUrl; window.open(fullParserUrl, '_blank'); } function isUnlocked() { return CONFIG.isRememberUnlock ? GM_getValue('videoParserUnlocked', false) : false; } function markAsUnlocked() { if (CONFIG.isRememberUnlock) { GM_setValue('videoParserUnlocked', true); } } /** * 核心优化:使用 GM_xmlhttpRequest 获取图片并转 Base64(绕过混合内容限制) * @param {string} imageUrl 图片网络地址(HTTP/IP 形式) * @returns {Promise} Base64格式图片字符串 */ function convertImageToBase64WithGM(imageUrl) { return new Promise((resolve, reject) => { // 使用油猴专属 GM_xmlhttpRequest(沙箱环境运行,不受混合内容限制) GM_xmlhttpRequest({ method: 'GET', url: imageUrl, responseType: 'blob', // 响应类型为 Blob(二进制数据) timeout: 10000, // 10秒超时 onload: function(response) { // 响应成功(状态码 200) if (response.status === 200) { const blob = response.response; // 将 Blob 转为 Base64 const fileReader = new FileReader(); fileReader.onload = function(e) { resolve(e.target.result); // 返回 Base64 字符串 }; fileReader.onerror = function() { reject(new Error('FileReader 读取 Blob 失败')); }; fileReader.readAsDataURL(blob); } else { reject(new Error(`图片请求失败,状态码:${response.status}`)); } }, onerror: function() { reject(new Error('GM_xmlhttpRequest 网络请求失败,无法获取图片')); }, ontimeout: function() { reject(new Error('GM_xmlhttpRequest 图片请求超时(10秒)')); } }); }); } // 4. 折叠/展开功能 let isPanelCollapsed = false; const panelDom = { panel: null, unlockArea: null, unlockInput: null, unlockBtn: null, helpImage: null }; function togglePanelCollapse() { if (!panelDom.panel) return; isPanelCollapsed = !isPanelCollapsed; panelDom.panel.classList.toggle('collapsed', isPanelCollapsed); const collapseBtn = panelDom.panel.querySelector('.collapse-btn'); const toggleBtn = panelDom.panel.querySelector('.toggle-collapse'); if (collapseBtn && toggleBtn) { collapseBtn.textContent = isPanelCollapsed ? '🔍' : '−'; toggleBtn.textContent = isPanelCollapsed ? '+' : '−'; } } // 5. 初始化图片(使用 GM 方法转 Base64) async function initHelpImage() { const helpImage = panelDom.helpImage; if (!helpImage) return; // 显示加载提示 helpImage.style.display = 'none'; const loadingTip = document.createElement('div'); loadingTip.className = 'image-loading'; loadingTip.textContent = '图片加载中...'; helpImage.parentNode.insertBefore(loadingTip, helpImage); try { // 调用 GM 专属方法转换图片 const base64Image = await convertImageToBase64WithGM(CONFIG.helpImageUrl); // 插入 Base64 图片 helpImage.src = base64Image; helpImage.alt = '二维码使用说明(GM 方法加载)'; // 隐藏加载提示,显示图片 loadingTip.remove(); helpImage.style.display = 'block'; } catch (error) { console.error('图片转 Base64 失败:', error); // 降级使用备用图 loadingTip.remove(); helpImage.src = 'https://picsum.photos/800/300'; helpImage.alt = '图片加载失败(备用图)'; helpImage.style.display = 'block'; } } // 6. UI 构建函数 function buildPanel() { const panel = document.createElement('div'); panel.id = 'videoParserPanel'; panelDom.panel = panel; const collapseBtn = document.createElement('button'); collapseBtn.className = 'collapse-btn'; collapseBtn.textContent = '🔍'; collapseBtn.onclick = togglePanelCollapse; const panelContent = document.createElement('div'); panelContent.className = 'panel-content'; const header = document.createElement('div'); header.className = 'panel-header'; header.innerHTML = '视频解析接口工具'; const controlGroup = document.createElement('div'); controlGroup.className = 'control-group'; const toggleCollapseBtn = document.createElement('button'); toggleCollapseBtn.className = 'toggle-collapse'; toggleCollapseBtn.textContent = '−'; toggleCollapseBtn.onclick = togglePanelCollapse; const closeBtn = document.createElement('button'); closeBtn.className = 'close-panel'; closeBtn.innerHTML = '×'; closeBtn.onclick = () => panel.style.display = 'none'; controlGroup.appendChild(toggleCollapseBtn); controlGroup.appendChild(closeBtn); header.appendChild(controlGroup); const helpArea = document.createElement('div'); helpArea.className = 'help-area'; helpArea.innerHTML = `
使用说明
二维码使用说明
1. 扫描二维码,关注公众号,解锁更多接口;
2. 直接点击下方接口按钮,自动携带当前页面URL跳转解析;
3. 前3个接口为公开接口,全部接口需输入密码解锁;
4. 解析结果取决于接口有效性,与本工具无关;
5. 点击右上角「−/+」可折叠/展开面板,节省屏幕空间。
`; panelDom.helpImage = helpArea.querySelector('.help-image'); const apiList = document.createElement('div'); apiList.className = 'api-list'; const renderApiItems = (isFull = false) => { apiList.innerHTML = ''; const displayURLs = isFull ? defaultURLs : defaultURLs.slice(0, 3); displayURLs.forEach(item => { const apiItem = document.createElement('a'); apiItem.className = 'api-item'; apiItem.innerHTML = `🔗 ${item.name} 解析接口`; apiItem.onclick = (e) => { e.preventDefault(); jumpToParser(item.url); }; apiList.appendChild(apiItem); }); }; renderApiItems(isUnlocked()); const unlockArea = document.createElement('div'); unlockArea.className = 'unlock-area'; unlockArea.innerHTML = ` `; panelDom.unlockArea = unlockArea; panelDom.unlockInput = unlockArea.querySelector('.unlock-input'); panelDom.unlockBtn = unlockArea.querySelector('.unlock-btn'); panelDom.unlockBtn.onclick = () => { const inputPwd = panelDom.unlockInput.value.trim(); if (!inputPwd) { alert('请输入解锁密码!'); return; } if (inputPwd === CONFIG.unlockPassword) { markAsUnlocked(); renderApiItems(true); unlockArea.innerHTML = '
✅ 已解锁全部接口!
'; setTimeout(() => { unlockArea.classList.add('hidden'); }, 1500); alert('解锁成功,已展示全部解析接口!'); } else { alert('密码错误,请重新输入!'); panelDom.unlockInput.value = ''; panelDom.unlockInput.focus(); } }; panelDom.unlockInput.onkeydown = (e) => { if (e.key === 'Enter') { panelDom.unlockBtn.click(); } }; if (isUnlocked()) { renderApiItems(true); unlockArea.innerHTML = '
✅ 已解锁全部接口!
'; setTimeout(() => { unlockArea.classList.add('hidden'); }, 1000); } panelContent.appendChild(header); panelContent.appendChild(helpArea); panelContent.appendChild(apiList); panelContent.appendChild(unlockArea); panel.appendChild(collapseBtn); panel.appendChild(panelContent); return panel; } // 7. 初始化脚本 function initScript() { if (document.getElementById('videoParserPanel')) return; const panel = buildPanel(); document.body.appendChild(panel); initHelpImage(); } // 页面加载完成后初始化 if (document.readyState === 'complete' || document.readyState === 'interactive') { initScript(); } else { document.addEventListener('DOMContentLoaded', initScript); } })();