1.购买服务器阿里云:服务器购买地址https://t.aliyun.com/U/E8o0aM若失效,可用地址
阿里云:
服务器购买地址
https://t.aliyun.com/U/E8o0aM若失效,可用地址
https://www.aliyun.com/daily-act/ecs/activity_selection?source=5176.29345612&userCode=49hts92d腾讯云:
https://curl.qcloud.com/wJpWmSfU若失效,可用地址
https://cloud.tencent.com/act/cps/redirect?redirect=2446&cps_key=ad201ee2ef3b771157f72ee5464b1fea&from=console华为云
https://activity.huaweicloud.com/cps.html?fromacct=64b5cf7cc11b4840bb4ed2ea0b2f4468&utm_source=V1g3MDY4NTY=&utm_medium=cps&utm_campaign=2019052.部署教程
3.代码如下
// 目前脚本在vm和tm中均测试通过,且unsafeWindow都指向页面window,而window都是包装过的Proxy,无法获取页面window的三方属性如window.jQuery、window.HUYA_*等// 此时要么使用unsafeWindow.jQuery,要么直接访问全局属性(如脚本中直接使用 $ )window.addEventListener('DOMContentLoaded', () => {'use strict';// 禁止篡改console// Object.freeze(console);if (GM_getValue('autoBestRESDelay') !== undefined) GM_deleteValue('autoBestRESDelay'); // 在vm上与GM_setValue(key)作用相同const getById = (id) => document.getElementById(id);if (!getById('liveRoomObj')) return;// 更改菜单选项function changeMenuItem(id, onCaption, offCaption, onClick) {const inplace = id === GM_registerMenuCommand(offCaption, null, { id });if (inplace) {// 插件如VM2.15.9起支持根据id注册选项GM_registerMenuCommand(onCaption, onClick, { id });} else {// 不支持需先卸载原选项,再注册新选项GM_unregisterMenuCommand(offCaption);GM_registerMenuCommand(onCaption, onClick);}}// 注册可变菜单项function registerToggle(id, onCaption, offCaption, onClick) {changeMenuItem(id, onCaption, offCaption, () => {onClick();registerToggle(id, offCaption, onCaption, onClick);});}// 注册常规菜单项/* function addMenuItem(item) {if (item.id !== GM_registerMenuCommand(item.title, () => item.click(), { id: item.id })) {GM_unregisterMenuCommand(item.title);GM_registerMenuCommand(item.title, () => item.click());}} *//* function addModal(title, body, persist) {const dialog = document.createElement('dialog');dialog.innerHTML = `<div><p>${title}</p>${body}<div style='text-align:right'><button>确定</button> <button>取消</button></div></div>`;const btns = dialog.querySelectorAll('button');dialog.children[0].onclick = (e) => e.stopPropagation();dialog.onclick = btns[1].onclick = () => {dialog.oncancel?.();dialog.close();};btns[0].onclick = () => {dialog.onconfirm?.();dialog.close();};Object.defineProperty(dialog, 'title', {get() {return this.children[0].children[0].textContent;},set(text) {this.children[0].children[0].innerText = text;}});if (!persist) {dialog.onclose = () => dialog.remove();}document.body.append(dialog);return dialog;} *//* const Modal = addModal('', '<input type=number min=0 step=.5 />', true);Modal.onclose = () => {Modal.querySelector('input').value = '';}; */// 待注册const toggles = [{id: 1,title: '自动最高画质',gmKey: 'autoBestRES',gmValue: GM_getValue('autoBestRES')},{id: 2,title: '单击/空格控制播放/暂停',gmKey: 'clickToPlay',gmValue: GM_getValue('clickToPlay', true)},{id: 3,title: '中键/回车切换全屏(火狐限制左键触发全屏',gmKey: 'midClickToFullscreen',gmValue: GM_getValue('midClickToFullscreen', true)},{id: 4,title: '自动剧场模式',gmKey: 'autoFullPage',gmValue: GM_getValue('autoFullPage')},{id: 5,title: '屏蔽视频下方礼物栏',gmKey: 'hideGiftBar',gmValue: GM_getValue('hideGiftBar'),click() {if (this.gmValue) {this.css = GM_addStyle('#player-ctrl-wrap:not(.showup){opacity:0}#player-gift-wrap{visibility:hidden;}#player-wrap{min-height:100%}#player-ctrl-wrap{bottom:0!important}');getById('player-ctrl-wrap').classList.add('showup');return;}getById('player-ctrl-wrap').classList.remove('showup');this.css?.remove();}}];toggles.forEach((e) => {registerToggle(e.id,(e.gmValue ? '✔️' : '✖️') + e.title,(!e.gmValue ? '✔️' : '✖️') + e.title,() => {e.gmValue = !e.gmValue;e.click?.(e.gmValue);GM_setValue(e.gmKey, e.gmValue);});});/* const menu = [// {// id: 6,// title: '自动切换画质延迟',// gmKey: 'autoBestRESDelay',// gmValue: GM_getValue('autoBestRESDelay', 0),// click() {// Modal.title = '调整自动切换画质的延迟,单位:秒(s),留空无延迟\n当前延迟:' + this.gmValue;// Modal.showModal();// Modal.onconfirm = () => {// const delay = +Modal.querySelector('input').value;// this.gmValue = isNaN(delay) ? 0 : delay;// GM_setValue(this.gmKey, this.gmValue);// };// }// }];menu.forEach((e) => {addMenuItem(e);}); */if (toggles[3].gmValue) {document.body.classList.add('mode-page-theater');}// 隐藏进入页面后的登录弹窗。 ← 貌似不需要了,虎牙不会立马显示登录框了new MutationObserver((mutations, ob) => {// const mask = getById('HUYA-UDBSdkLgn');// if (!mask) return;const video = getById('hy-video');if (!video) return;if (toggles[4].gmValue) {toggles[4].click();}const $vtList = $('#player-ctrl-wrap .player-videotype-list'),unlockRES = () => {const $highRes = $vtList.children(':has(.bitrate-right-btn.common-enjoy-btn)');$highRes.length? $highRes.each((i, e) => {$(e).data('data').status = 0;// autoBestRESi === 0 && toggles[0].gmValue && e.click(); // setTimeout(() => e.click(), menu[0].gmValue * 1000);}): toggles[0].gmValue && $vtList.children().length > 1 && $vtList.children()[0].click();};// 插入登录框后则只监听该元素的变更。/* new MutationObserver((records, mob) => {if (mask?.style.display !== 'none') {mask.style.display = 'none';mob.disconnect();}}).observe(mask, {attributes: true}); */// 无限制播放,避免严格模式下对getter属性赋值导致异常中断// try {if (toggles[3].gmValue) {const pfBtn = getById('player-fullpage-btn');const tid = setInterval(() => {pfBtn.classList.contains('player-narrowpage') ? clearInterval(tid) : pfBtn.click();}, 500);// getById('player-fullpage-btn').className="player-narrowpage"// getById('player-fullpage-btn').title="退出剧场"}// getById('hy-video').srcObject.active = false;// } catch (e) {// // alert('尝试无限制播放失败,可能需要刷新页面或切换线路。异常:\n' + e)// }ob.disconnect();// unlock resnew MutationObserver(unlockRES).observe($vtList[0], {attributes: false,childList: true,subtree: false});unlockRES();// 添加部分播放器事件setTimeout(() => {const vid = mutations[0].target; // 此处观察的节点即getById('hy-video')let flag = null,tid = null;getById('player-mouse-event-wrap').onmousemove = function () {if (flag) return;flag = true;clearTimeout(tid);this.style.cursor = '';if (toggles[4].gmValue) {getById('player-ctrl-wrap').classList.add('showup');}tid = setTimeout(() => {this.style.cursor = 'none';if (toggles[4].gmValue) {getById('player-ctrl-wrap').classList.remove('showup');}}, 5000);setTimeout(() => {flag = null;}, 1000);};// 单击/空格控制播放/暂停if (toggles[1].gmValue) {let isOneClick, tmp, tid;// 判断是否触发虎牙播放器单击模拟的双击vid.addEventListener('click', () => {isOneClick = !tmp;if (isOneClick) {tmp = setTimeout(() => {tmp = null;}, 301);}});vid.onclick = () => {clearTimeout(tid);const arr = ['smartMenu_videoMenu', 'player-danmu-report'];if (arr.every((e) => !(getById(e)?.style.display === 'block'))) {tid = setTimeout(() => {isOneClick && getById('player-btn').click();}, 300);}};document.addEventListener('keyup', (e) => {if (e.code === 'Space' && !'INPUT TEXTAREA'.includes(e.target.nodeName)) {e.preventDefault();getById('player-btn').click();}});}// 中键/回车切换全屏if (toggles[2].gmValue) {vid.onmousedown = (e) => e.preventDefault();vid.onauxclick = (e) => {e.button === 1 && getById('player-fullscreen-btn').click();};document.addEventListener('keyup', (e) => {e.key === 'Enter' &&!'INPUT TEXTAREA'.includes(e.target.nodeName) &&getById('player-fullscreen-btn').click();});}});}).observe(getById('player-video'), {attributes: false,childList: true,subtree: false});// 观察节点自动点击播放模式// function autoPlay() {// GM_addStyle("div#UDBSdkLgn{z-index: -1;}");// const targetNode =// getById("player-ctrl-wrap").querySelector(".player-play-big");// new MutationObserver((mutationsList, ob) => {// // console.log(mutationsList)// if (// mutationsList[0].type !== "attributes" ||// targetNode.style.display === "none"// )// return;// const mask = getById("UDBSdkLgn");// if (mask.style.display === "block") {// targetNode.click();// mask.style.display = "none";// // console.log('自动续播成功')// }// }).observe(targetNode, {// attributes: true,// childList: false,// subtree: false,// });// }});
解析
这是一款面向虎牙直播页面(huya.com/*)的脚本,用来在未登录情况下改善观看体验。核心改动包括:
自动切换最高画质(尽量解锁被登录限制的清晰度选项)。
支持单击/空格控制播放暂停、中键/回车切换全屏(兼容火狐限制)。
自动剧场模式(页面内大屏)。
隐藏礼物栏/控制条自动显隐以提升观感。
提供油猴菜单里的开关项,可随时启用/停用以上功能,状态持久化到
GM_*存储。
注意:脚本专门优化"未登录观看"。如果你需要登录互动,不建议使用。
主要方法
环境/注入说明(顶部注释)
解释@grant/ sandbox /unsafeWindow在不同管理器(VM/TM)下的差异;本脚本依赖直接访问页面全局对象(如$、HUYA 变量)时的注意事项。入口:
window.addEventListener('DOMContentLoaded', …)
DOM 就绪后开始执行;若未找到播放器容器#liveRoomObj则直接返回。菜单注册工具
autoBestRES:自动最高画质。clickToPlay:单击/空格 控制播放暂停(默认开)。midClickToFullscreen:中键/回车 全屏(默认开)。autoFullPage:自动剧场模式。hideGiftBar:隐藏视频下方礼物栏(附带插入 CSS/恢复逻辑)。changeMenuItem(id, onCaption, offCaption, onClick)/registerToggle(...)
动态创建"可切换"的菜单项(✔/✖ 图标切换),并在点击时反转开关值、调用回调、写入GM_setValue。toggles数组(功能开关清单):初始化时为每个开关调用
registerToggle,把当前状态展示到油猴菜单。剧场模式初始化
若
autoFullPage为真,给body添加mode-page-theater,进入剧场布局。主 MutationObserver(监听播放器装载)
观察#player-video子节点变化,等#hy-video(video 标签)出现后:控制条显隐与鼠标指针自动隐藏(5s 无操作隐藏,移动时显示)。
clickToPlay:midClickToFullscreen:处理虎牙自身的单击/双击识别冲突(300ms 内判定);
单击空白(无菜单/举报框显示时)触发
#player-btn播放/暂停;监听键盘
Space(非输入框下)触发播放/暂停。禁止默认中键行为,
auxclick中键触发#player-fullscreen-btn;键盘
Enter(非输入框下)也触发全屏。若有"享受按钮"项,优先点击第一项;
若列表长度>1 且找不到标记项,退化为点击第一项。
该函数既在初次执行,也通过新的MutationObserver持续监听清晰度列表变化自动执行。若启用"隐藏礼物栏",注入/移除对应 CSS 并控制底部条显隐。
解锁画质
unlockRES():
寻找清晰度列表#player-ctrl-wrap .player-videotype-list,把高码率项的状态改为可选;自动剧场模式点击:循环点击"剧场模式"按钮
#player-fullpage-btn直到生效。播放器交互事件:
样式注入(可选)
GM_addStyle(...)在开启"隐藏礼物栏"时注入:隐藏礼物区、控制条透明、播放器高度等。
总结:
脚本通过 DOM 观察 + 菜单化开关,把虎牙未登录的观看障碍(画质、控制方式、弹条干扰)"一网打尽",默认就能用。
注意:
本文部分变量已做脱敏处理,仅用于测试和学习研究,禁止用于商业用途,不能保证其合法性,准确性,完整性和有效性,请根据情况自行判断。技术层面需要提供帮助,可以通过打赏的方式进行探讨。
没有评论:
发表评论