// ==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
};
}
})();