// ==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 = `
📖 使用说明:
  1、「自定义设置」改样式 / 快捷键 / 接口(加错的接口可在里面的「管理自定义接口」删掉)
  2、解析视频:点击内嵌接口解析(优先试靠前的「TXNQ」「酥皮」「66网1」等;)
  3、播放模式:点击接口右侧「内嵌/弹窗」可切换
  4、解析切集后:换集后旧播放器会关闭,开自动解析则自动解析新集
  5、自动解析:先在「自动解析设置」选接口,再点发呆熊/跳熊浮标开关
  6、快捷键:Alt+V 呼出/隐藏,Alt+R 刷新接口,Alt+S 样式设置
  7、关闭解析:点击播放器右上角 × 刷新页面恢复原视频(手机端点浮标即可开关面板)
  8、404极阴岛 QQ 群:725752181
`; function updateAutoSwitchIcon(enabled, apiName) { const autoBtn = DOM_CACHE.vipBox && DOM_CACHE.vipBox.querySelector('#vip_auto'); const autoImg = autoBtn && autoBtn.querySelector('#vip_auto_img'); if (autoImg) { autoImg.src = enabled ? VIP_ICON_GIF.autoOn : VIP_ICON_GIF.autoOff; } if (autoBtn) { autoBtn.title = enabled ? (apiName ? `自动解析已开启:${apiName}(点击关闭)` : '自动解析已开启(点击关闭)') : '点击开启自动解析(需先在自动解析设置中选择接口)'; } } // 播放器容器配置 const PLAYER_CONTAINERS = [ { host: "v.qq.com", container: "#mod_player,#player-container,.container-player", displayNodes: ["#mask_layer", ".mod_vip_popup", "#mask_layer", ".panel-tip-pay"] }, { host: "m.v.qq.com", container: ".mod_player,#player", displayNodes: [".mod_vip_popup", "[class^=app_],[class^=app-],[class*=_app_],[class*=-app-],[class$=_app],[class$=-app]", "div[dt-eid=open_app_bottom]", "div.video_function.video_function_new", "a[open-app]", "section.mod_source", "section.mod_box.mod_sideslip_h.mod_multi_figures_h,section.mod_sideslip_privileges,section.mod_game_rec"] }, {host: "w.mgtv.com", container: "#mgtv-player-wrap", displayNodes: []}, {host: "www.mgtv.com", container: "#mgtv-player-wrap", displayNodes: []}, { host: "m.mgtv.com", container: ".video-area", displayNodes: ["div.adFixedContain,div.ad-banner,div.m-list-graphicxcy.fstp-mark", "div[class^=mg-app],div#comment-id.video-comment div.ft,div.bd.clearfix,div.v-follower-info", "div.ht.mgui-btn.mgui-btn-nowelt", "div.personal", "div[data-v-41c9a64e]"] }, {host: "www.bilibili.com", container: "#player_module,#bilibiliPlayer,#bilibili-player", displayNodes: []}, {host: "m.bilibili.com", container: ".player-wrapper,.player-container,.mplayer", displayNodes: []}, { host: "www.iqiyi.com", container: "#outlayer,.iqp-player-videolayer,.m-video-player-wrap", displayNodes: ["#playerPopup", "#vipCoversBox", "div.iqp-player-vipmask", "div.iqp-player-paymask", "div.iqp-player-loginmask", "div[class^=qy-header-login-pop]", ".covers_cloudCover__ILy8R", "#videoContent > div.loading_loading__vzq4j", ".iqp-player-guide", ".defaultController_playCtrl__Smes8", ".tips_textsBackImg__svIhR", "[class*='defaultController']", "[class*='player-buttons']", "[class*='tips_']", ".qy-player-controller", ".qy-player-tips", "[class*='danmu']", "[class*='Danmu']", ".iqp-danmu", ".qy-player-danmu", "[class*='barrage']", ".XPlayer_heatMapContainer__17MIj", ".progressBar_container__0x13u", ".XPlayer_bottom__xzRnb", "div.m-iqyGuide-layer", "a[down-app-android-url]", ".loading_loading__vzq4j", "[name=m-extendBar]", "[class*=ChannelHomeBanner]", "section.m-hotWords-bottom"] }, { host: "m.iqiyi.com", container: ".m-video-player-wrap, .iqp-player-videolayer", displayNodes: ["div.m-iqyGuide-layer", "a[down-app-android-url]", "div.iqp-player-vipmask", ".loading_loading__vzq4j", "[name=m-extendBar]", "[class*=ChannelHomeBanner]", "section.m-hotWords-bottom"] }, {host: "www.iq.com", container: ".intl-video-wrap", displayNodes: []}, {host: "www.youku.com", container: "#ykPlayer,#playerMouseWheel,.h5-detail-player", displayNodes: []}, { host: "v.youku.com", container: "#ykPlayer,#playerMouseWheel,.h5-detail-player", displayNodes: ["#iframaWrapper", "#video_side_cashier", ".secondary-container.video_side_cashier_wrapper", ".advertise-layer", ".youku-advertise-layer", "#youku-advertise", "#player-advertise", ".advertise-youku-tips", ".preloading-layer", ".preplay-layer", ".kui-preloading-layer-0", ".kui-layer-0", ".kui-preloadinglayer-preloading-animation", ".kui-preplaylayer-preplay-background", ".kui-dashboard-timer-container", ".kui-dashboard-bar-container", ".kui-dashboard-dashboard-panel", "#youku-dashboard > div.kui-dashboard-dashboard-panel", "#youku-dashboard > div.kui-dashboard-dashboard-background", "#youku-dashboard > div.kui-dashboard-bar-container", "#youku-dashboard > div.kui-dashboard-timer-container"] }, {host: "m.youku.com", container: "#playerMouseWheel,.h5-detail-player", displayNodes: []}, {host: "tv.sohu.com", container: "#player", displayNodes: []}, {host: "film.sohu.com", container: "#playerWrap", displayNodes: []}, {host: "www.le.com", container: "#le_playbox", displayNodes: []}, {host: "video.tudou.com", container: ".td-playbox", displayNodes: []}, {host: "v.pptv.com", container: "#pptv_playpage_box", displayNodes: []}, {host: "vip.pptv.com", container: ".w-video", displayNodes: []}, {host: "www.wasu.cn", container: "#flashContent", displayNodes: []}, {host: "www.acfun.cn", container: "#player", displayNodes: []}, {host: "www.1905.com", container: "#player,#vodPlayer", displayNodes: []}, {host: "vip.1905.com", container: "#player,#vodPlayer", displayNodes: []}, ]; const DEFAULT_STYLE = { bgColor: '#3f4149', fontColor: '#DCDCDC', opacity: 0.95, width: '380px' }; const DEFAULT_SHORTCUT = { toggle: 'v', refresh: 'r', style: 's' }; // 样式/快捷键/面板位置/自动解析等全网共用同一套 GM 键;手动解析标记仍按站点隔离,避免多标签页互相干扰 const VIP_STORAGE_GLOBAL = "404vip_jx_global"; const shortcutStorageKey = "vip_custom_shortcut_" + VIP_STORAGE_GLOBAL; const CONFIG = { vipBoxId: vipBoxId, autoPlayerKey: "auto_player_key_" + VIP_STORAGE_GLOBAL, autoPlayerVal: "auto_player_value_" + VIP_STORAGE_GLOBAL, flag: "flag_vip_" + window.location.host.replace(/[^a-z0-9.-]/gi, "_"), panelPosKey: "vip_panel_pos_" + VIP_STORAGE_GLOBAL, customStyleKey: "vip_custom_style_" + VIP_STORAGE_GLOBAL, customShortcutKey: shortcutStorageKey, shortcut: GM_getValue(shortcutStorageKey, DEFAULT_SHORTCUT) }; (function migratePerHostPrefsToGlobal() { const h = window.location.host; const tryCopy = (newKey, oldPrefix) => { const oldKey = oldPrefix + h; if (GM_getValue(newKey) === undefined && GM_getValue(oldKey) !== undefined) { GM_setValue(newKey, GM_getValue(oldKey)); } }; tryCopy(CONFIG.customStyleKey, "vip_custom_style_"); tryCopy(CONFIG.customShortcutKey, "vip_custom_shortcut_"); tryCopy(CONFIG.panelPosKey, "vip_panel_pos_"); tryCopy(CONFIG.autoPlayerKey, "auto_player_key_"); tryCopy(CONFIG.autoPlayerVal, "auto_player_value_"); })(); // ===== 轻量提示条 ===== // 自绘的居中提示:白底卡片,带图标与出入场动画;样式全部内联,不受站点 CSS 影响。 // 关键帧只注入一次(单独一个 ' + '
' + '