// ==UserScript== // @name 🫧404小站 — 🎬VIP追剧神器 | 完全免费 | 支持多平台 | (电脑/手机/平板...自适应) // @namespace https://scriptcat.org/zh-CN/users/162063 // @version 3.5.4 // @description ▶在线VIP视频解析工具 (电脑/手机/平板...自适应) | free | 支持多平台【爱奇艺】【腾讯视频】【优酷土豆】【芒果TV】【乐视视频】【哔哩哔哩】【搜狐视频】等常见平台。✨9条解析接口实测可用 ✨内嵌播放无广告 ✨智能切集追剧 ✨内嵌铺满原播放区 ✨一键自动解析 制作不易,有问题可加微信咨询:Why15236444193 [如果加微信未能及时回复,请多多包涵哈!] // @author yyy404 // @match *://*/* // @grant GM_registerMenuCommand // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @grant GM_openInTab // @grant GM_xmlhttpRequest // @resource hlsJs https://cdn.jsdelivr.net/npm/hls.js@1.7.3/dist/hls.min.js // @resource artPlayerJs https://cdn.jsdelivr.net/npm/artplayer@5.4.0/dist/artplayer.js // @grant GM_getResourceText // @connect * // @run-at document-start // @icon https://cdn.jsdmirror.com/gh/whyyy-404/icon@main/Collection/Cartoon/bear-yes.gif // ==/UserScript== // =========================================================================== // 【致谢与来源】 // // 本项目非常感谢来自「屏幕前的你」大佬(https://github.com/963540817) // 的 Hub 以及各种强势功能,特此致谢。(引用前提:拒绝商业化) // // 「采集源」标签页(含其中的「搜索跳转」分组)所收录的第三方采集接口清单, // 参考自「屏幕前的你」大佬分享的自用脚本: // // https://github.com/963540817/dashu // // 本脚本在该清单基础上所做的工作是:逐条实测、剔除已失效的条目、按可用性重新分组, // 并补充了搜索 / 代理兜底 / 两步型等取数逻辑。 // 但清单的来源是 dashu —— 再次感谢来自「屏幕前的你」大佬的 Hub。 // // 如果「屏幕前的你」大佬本人认为当前的收录或署名方式仍有不妥, // 欢迎提 Issue 或直接联系,我会立即调整或移除相关内容。 // =========================================================================== /* ┏┓ ┏┓ ┏┛┻━━━━━━┛ ┻┓ ┃ ┃ ┃ ━ ┃ ┃ ┳┛ ┗┳ ┃ ┃ ┃ ┃ ┻ ┃ ┃ ┃ ┗━━━┓ ┏━┛Codes are far away from bugs with the animal protecting ┃ ┃ 神兽保佑,代码无bug ┃ ┃ ┃ ┗━━━┓ ┃ ┣┓ ┃ ┏┛ ┗┓┓┏━┳┓┏┛ ┃┫┫ ┃┫┫ ┗┻┛ ┗┻┛ */ (function() { 'use strict'; // ===== 防止在iframe中重复执行 ===== if (window.self !== window.top) { console.log('VIP解析脚本:检测到iframe环境,跳过执行'); return; } // ===== 66dpw 跳板页接管 ===== // https://www.66dpw.vip/?url=<视频页> 不是解析接口,单独打开是没用的: // · 服务端忽略 ?url=(带 / 不带 / 编码过的 ?url= 返回完全相同的首页 HTML) // · 首页自身没有播放能力(HTML 与 12 个外部 JS 里没有任何播放器库的痕迹) // 它的唯一用途是当「授权宿主页」:真播放接口只有当「自己嵌在这个已授权域名下」才放行, // 顶层直接打开同一个接口会被拒(实测提示「您的域名未授权播放」)。 // 授权判定读的是祖先域、不是 Referer 头,所以这里不伪造来源。 // 做法:点击时把「宿主页地址 / 真播放接口 / 要解析的视频页地址」三个值记进 GM 存储; // 宿主页读到后整体替换 body,只留一个容器 + 一个 iframe, // 并用常驻 CSS 把它的其余元素移出屏幕。 // ⚠️ iframe 上这几组属性都要带,少一个都会出问题(都是实测对比出来的): // · sandbox="allow-scripts allow-same-origin" // 缺了它,内层页面(它自己会加载统计脚本和 Cast SDK)能弹窗、能跳顶层; // 带上之后这些都被禁掉。allow-same-origin 必须留,否则内层拿不到 localStorage。 // · loading="eager" importance="high" fetchpriority="high" // 加载优先级。不标的话这个 iframe 是默认优先级, // 会和宿主页那 1 MB 脚本 + 几百张封面图抢带宽,起播明显变慢。 // · allow="autoplay;encrypted-media;picture-in-picture;…" + allowfullscreen // 不给她方权限,起播和全屏都会被挡。 // ⚠️ 不能在这里调 window.stop():它会连「新的 frame」一起停掉, // 会导致新建的 iframe 永远不出画面(表现:整页纯黑,连它自己的 loading 图都看不到)。 const GATE_HOST = 'www.66dpw.vip'; const GATE_PLAY_API = 'https://svip.qlplayer.cyou/?url='; // 宿主页的窗口名。 // ⚠️ 必须是【具名窗口】,不能再用 '_blank': // 具名窗口同名只有一个,第二次点会复用它并导航过去,而不是再开一个新标签。 // 用 _blank 的话每点一次就多留一个宿主页标签,而每个宿主页都在往真播放接口加载 iframe, // 十几个标签同时抢同一个域名的连接 → 新开那个的请求一直排不到 → iframe 永远不出画面。 const GATE_WIN_NAME = 'vip_jx_gate'; // 宿主页的完整前缀。判断「当前这页是不是跳板页」必须用它整串比对: // ⚠️ 只查 hostname + 有没有 ?url= 是不够的 —— 那样 jiexi.html?url=…(66网2)也会被吃掉, // 66网2 就变成 66网1 了。路径必须是 /,参数必须紧跟在 ? 后面。 const GATE_PREFIX = 'https://' + GATE_HOST + '/?url='; // 要解析的目标地址【直接读地址栏的 ?url=】,不经过 GM 存储: // 目标就明明白白写在地址栏上,手动打开或刷新那一页也能用,不存在跨页隐藏状态。 // (原先还写了一份到 GM 存储做兜底,但地址栏永远带着目标 ⇒ 那份兜底从来没被读到过,已删) function gateInfo() { try { if (!String(window.location.href).startsWith(GATE_PREFIX)) return null; // 取「url=」之后的全部内容,不按 & 截断(视频页地址自带 & 也不会被切掉) const m = /[?&]url=(.+)$/.exec(window.location.search); if (!m) return null; let v = m[1]; try { v = decodeURIComponent(v); } catch (e) { } return /^https?:\/\//i.test(v) ? { api: GATE_PLAY_API, target: v } : null; } catch (e) { return null; } } const GATE = gateInfo(); if (GATE) { let gateWrap = null; const buildGate = () => { if (gateWrap) return true; const body = document.body; if (!body) return false; // 常驻规则:把它的元素移出屏幕并压成零尺寸。 // 只写 display:none 不够 —— 它自己的懒加载仍可能把首屏那几 MB 封面图拉下来。 const st = document.createElement('style'); st.textContent = 'html,body{margin:0;padding:0;height:100%;overflow:hidden;}' + 'body>:not(#vip_gate_wrap){display:none !important;max-width:0 !important;max-height:0 !important;' + 'overflow:hidden !important;position:absolute;left:-102030px;}'; (document.head || document.documentElement).appendChild(st); // 建容器 + iframe。 // ⚠️ 顺序很关键:必须【先挂 load 监听 → 再进 DOM → 最后才设 src】。 // 之前用 body.innerHTML 插入,iframe 一进 DOM 就开始导航, // 等我们再回头找它挂监听时已经错过 load,表现就是「永远加载不出来」。 // 容器用 fixed + 视口单位,不吃 body 的高度(宿主页自己有 360 KB 的 CSS,body 高度不可靠) gateWrap = document.createElement('div'); gateWrap.id = 'vip_gate_wrap'; gateWrap.style.cssText = 'visibility:visible!important;opacity:1!important;overflow:visible!important;' + 'position:fixed;top:0;left:0;width:100vw;height:100vh;margin:0;padding:0;' + 'z-index:1;background:#000;display:flex;justify-content:center;align-items:center;flex-direction:column;'; const ifrEl = document.createElement('iframe'); ifrEl.setAttribute('frameborder', '0'); ifrEl.setAttribute('allow', 'autoplay; fullscreen; encrypted-media; picture-in-picture'); ifrEl.setAttribute('allowfullscreen', 'true'); ifrEl.style.cssText = 'display:block;position:absolute;top:0;left:0;width:100%;height:100%;' + 'border:0;margin:0;padding:0;'; const gateSrc = GATE.api + GATE.target; gateWrap.appendChild(ifrEl); body.innerHTML = ''; body.appendChild(gateWrap); // 最后一步才开始加载:容器和样式都就位了,免得加载时布局还没稳 ifrEl.src = gateSrc; if (document.title === '') document.title = 'VIP追剧神器 · 播放'; return true; }; // 后到的元素靠常驻 CSS 挡;这里再移一次,避免它们留在 DOM 里参与布局 // (容器必须保留:把它一起删掉会卸载 iframe,播放得重来) const dropOthers = () => { const body = document.body; if (!body || !gateWrap) return; Array.prototype.slice.call(body.children).forEach((el) => { if (el !== gateWrap) { try { el.remove(); } catch (e) { } } }); }; if (!buildGate()) { const waitBody = setInterval(() => { if (buildGate()) clearInterval(waitBody); }, 1); } document.addEventListener('DOMContentLoaded', dropOthers, { once: true }); window.addEventListener('load', dropOthers, { once: true }); } // 接口 / 条目的底色标记(想换颜色只改这里) // 规律:同一家的条目,不管在哪个标签页,都用同一个 mark —— 这样一眼能认出是同一家。 // special = 邦宁(红):解析结果特殊 // qilin = 66网 / 麒麟(绿):同一家的全部入口 —— // 解析接口 66网1·66网2·麒麟1 + 搜索跳转 66网1片库搜索 + 导航 66大片网 // wsyzy = 无损云(蓝):主站 wsyzy.cc / 采集接口 api.wsyzy.net —— 采集源 + 搜索跳转 + 导航 三处同色 // txnp = txnp.cn 一家(紫):解析接口 TXNQ(bfq.) / 酥皮(art.) + 搜索跳转 cms.txnp.cn + 导航 cms.txnp.cn // lxyy = 洛雪TV(橙):导航页(目前只有这一条) // zip0 = ZIP0(青柠黄绿):导航页第一条(作者的邀请链接) // ⚠️ 这是【文字颜色】,不是底色 —— 只给名字上色,不铺背景(铺背景会"顶眼睛",看久了不舒服)。 // 所以用实色 hex(不要带透明度):文字色一旦半透明就会发灰、看不清。 // 底色是深灰 #2c2e34,所以这些颜色都偏亮 —— 亮色在深底上才读得清。 // ⚠️ 排列规则:同一家(同色)必须挨在一起,而且【三个分区的家族顺序必须一致】—— // 下面这个声明顺序就是家族顺序:导航页 / 搜索跳转 / 解析接口 都按它排。 // 各家的顺序在三个分区里完全相同,看熟一个分区就够了。 // ⚠️ 配色尽量照顾色觉障碍(红绿色弱最常见): // ① 不用纯红+纯绿这一对(红绿色弱下会混成相近的黄褐色)⇒ 66网一家改用【蓝绿 teal】 // ② 靠色相之余也拉开明度(黄最亮、粉次之、朱红/橙居中) // ③ 但要说实话:8 家颜色不可能两两都被所有色觉类型分辨。颜色在这里只是【辅助分组】—— // 名字就写在旁边,不靠颜色也能用,所以不影响功能。 const API_MARK_COLOR = { zip0: '#c6f36b', // ① 青柠黄绿 —— ZIP0(取自它官网「找到就直接播放」那句的颜色,就是站点主色) txnp: '#c9a0f0', // ② 紫红 —— txnp.cn 一家(TXNQ / 酥皮 / txnp搜索 / cms.txnp.cn) qilin: '#3fd9b8', // ③ 蓝绿 —— 66大片网 / 麒麟 一家(原纯绿,色弱考虑换掉) wsyzy: '#5cb8ff', // ④ 天蓝 —— 无水印资源网 / 无损云 eco: '#ffa64d', // ⑤ 橙 —— EcoHub 一家 ikanbot: '#9db8d1', // ⑥ 钢蓝灰 —— 爱看机器人(名字带「机器人」,配金属冷色;也是唯一低饱和色,最好认) lxyy: '#ff8fb0', // ⑦ 粉 —— 洛雪TV special: '#ff6b4a' // ⑧ 朱红 —— 邦宁(原来跟纯绿挨着,现在绿已改蓝绿) }; const parseApis = [ // ===== 解析接口【只保留已实测可用的 10 条】===== // 这 10 条都是逐条实测确认可用的;历史上删掉的失效条目不再收录。 // ⚠️ 排列规则:同一家的(同色)挨在一起,且【家族顺序跟导航页 / 搜索跳转一致】 // (见 API_MARK_COLOR 的声明顺序)。TXNQ 那家排最前,因为它是实测里最好用的。 {"name": "TXNQ", "type": "1,3", "url": "https://bfq.txnp.cn/player?url=", "mark": "txnp"}, {"name": "酥皮", "type": "1,3", "url": "https://art.txnp.cn/?url=", "mark": "txnp"}, // ===== 66大片网 / 麒麟 这一家的三个解析入口(同色 = 同一家)===== // 命名:66网1/2 = 走 66大片网 的两个入口;麒麟1 = 麒麟自己的接口域名。 // 66网1:站内跳转入口(= 授权宿主页)。需要"剥 query + 不编码"的形态,所以打 clean 标记 {"name": "66网1", "type": "3", "url": "https://www.66dpw.vip/?url=", "mark": "qilin", "clean": true, "windowOpen": true}, // 66网2:独立解析页(内部再嵌真正的接口)。内嵌会被域名授权挡住 {"name": "66网2", "type": "3", "url": "https://www.66dpw.vip/88888888/jiexi.html?url=", "mark": "qilin"}, // 麒麟1:麒麟的另一个接口域名。实测 title 是「麒麟视频播放器」。 // ⚠️ type 用 "1,3" 是故意的:66网2 内嵌被域名授权挡所以只敢写 "3";这条静态检查没发现拦截, // 但静态查不出运行时的域名授权 ⇒ 写 "1,3" 让界面上能【一键切内嵌/弹窗】自己试。 {"name": "麒麟1", "type": "1,3", "url": "https://free.maccms.xyz/?url=", "mark": "qilin"}, // LX解析:lxyy 家族(和导航页「洛雪TV」同域同色)。 // ⚠️ 只给 "3"(弹窗):直接打开或内嵌都会报「您的域名未授权播放」—— // 实测入口本身 200,被挡的是它内部播放器的二次请求;必须让它自己的页面打开才正常。 {"name": "LX解析", "type": "3", "url": "https://jx.lxyy.club/index.php?url=", "mark": "lxyy", "windowOpen": true}, // 邦宁:解析结果特殊,所以单独一个颜色。放在最后 —— 原来紧跟 66网那组(蓝绿)之后、 // 那时 66网还是纯绿,红绿相邻对红绿色弱不友好;现在绿已换蓝绿,而且它排在家族顺序的末位。 {"name": "邦宁", "type": "1,3", "url": "https://video.isyour.love/player/getplayer?url=", "mark": "special"}, // ===== 以下 3 条没有颜色(不属于上面任何一家)===== {"name": "七哥", "type": "1,3", "url": "https://jx.202617.xyz/tv.php?url="}, {"name": "M1907", "type": "1,2,3", "url": "https://im1907.top/?jx="}, {"name": "Node", "type": "1,3", "url": "https://jx.nodenode.dpdns.org/?url="}, ]; const uniqueApis = []; const seenUrls = new Set(); parseApis.forEach(api => { if (!seenUrls.has(api.url)) { seenUrls.add(api.url); uniqueApis.push(api); } }); let customApis = GM_getValue("custom_parse_apis", []); let allApis = [...uniqueApis, ...customApis]; const vipBoxId = 'vip_jx_box_' + Math.ceil(Math.random() * 100000000); const VIP_ICON_CDN = 'https://cdn.jsdmirror.com/gh/whyyy-404/icon@main/Collection/Cartoon'; const VIP_ICON_GIF = { idle: `${VIP_ICON_CDN}/bear-idle.gif`, drag: `${VIP_ICON_CDN}/bear-drag.gif`, autoOff: `${VIP_ICON_CDN}/bear-auto-off.gif`, autoOn: `${VIP_ICON_CDN}/bear-auto-on.gif`, notice: `${VIP_ICON_CDN}/notice.gif` }; const VIP_MAIN_ICON_SIZE = 72; const VIP_FLOAT_ICON_SIZE = 56; const VIP_USAGE_HTML = `