// ==UserScript==
// @name 哔哩哔哩触控板滚动反转
// @namespace http://zhangmaimai.com/
// @version 2.0.4
// @author MaxChang3
// @description 优化 b 站视频音量调节在触控板上的体验。使用此脚本后, 在 b 站视频全屏界面中,使用触控板向下滚动将减少音量。(未安装时为增大)
// @license MIT
// @icon https://www.bilibili.com/favicon.ico
// @match https://www.bilibili.com/bangumi/play/*
// @match https://www.bilibili.com/video/*
// @grant GM_getValue
// @grant GM_setValue
// @run-at document-start
// @downloadURL none
// ==/UserScript==
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
(function() {
"use strict";
class ChainableDOM {
constructor(tagName, options) {
__publicField(this, "element");
this.element = document.createElement(tagName, options);
}
setAttribute(...args) {
this.element.setAttribute(...args);
return this;
}
setInnerText(text) {
this.element.innerText = text;
return this;
}
setInnerHTML(html) {
this.element.innerHTML = html;
return this;
}
setTextContent(text) {
this.element.textContent = text;
return this;
}
insert(element, position = "beforeend") {
if (element instanceof HTMLElement)
this.element.insertAdjacentElement(position, element);
else if (element instanceof ChainableDOM)
this.element.insertAdjacentElement(position, element.element);
else
this.element.insertAdjacentHTML(position, element);
return this;
}
on(type, listener, options) {
this.element.addEventListener(type, listener, options);
return this;
}
}
const $$ = (tagName, options) => new ChainableDOM(tagName, options);
var monkeyWindow = window;
var GM_setValue = /* @__PURE__ */ (() => monkeyWindow.GM_setValue)();
var GM_getValue = /* @__PURE__ */ (() => monkeyWindow.GM_getValue)();
const getMouseMinDelta = () => GM_getValue("MOUSE_MIN", void 0);
const setMouseMinDelta = (number) => GM_setValue("MOUSE_MIN", number);
class Popup extends HTMLElement {
constructor() {
super();
__publicField(this, "dialog");
const shadow = this.attachShadow({ mode: "open" });
const style = $$("style").setTextContent(
/* css */
`
dialog {
padding: 0;
border: 0;
height: 80%;
width: 80%;
overflow: hidden;
position:fixed;
user-select: none;
}
dialog::backdrop {
background-color: hsla(0,0%,7%,.65);
}
.inner {
padding: 25px;
}
.inner:focus{
outline: none;
}
.default-btn {
box-sizing: border-box;
padding: 0;
line-height: 30px;
height: 30px;
border-radius: 6px;
font-size: 14px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
background: #C9CCD0;
position: relative;
}`
);
const dialog = $$("dialog").setInnerHTML(
/* html */
`
`
).element;
this.dialog = dialog;
shadow.appendChild(dialog);
shadow.appendChild(style.element);
}
showModal() {
this.dialog.showModal();
}
closeModal() {
this.dialog.close();
}
closeWhenClickOuter() {
this.dialog.addEventListener("click", (e) => {
if (!e || !e.target)
return;
if (!e.target.closest("div"))
e.target.close();
});
}
}
const setMinDelta = (popup, delta) => {
setMouseMinDelta(delta);
alert(`已经设置为【${getMouseMinDelta()}】`);
popup.closeModal();
location.reload();
};
const setupInitPopup = () => {
if (getMouseMinDelta() !== void 0)
return;
customElements.define("my-popup", Popup);
const popup = $$("my-popup");
const easy = $$("button").setInnerText("简单").setAttribute("class", "default-btn").on("click", () => {
setMinDelta(popup.element, 100);
});
const easyBox = $$("h3").setInnerText("(直接使用,默认 deltaY 100 以下为触控板)").insert(easy, "afterbegin");
const calibrate = $$("button").setInnerText("校准").setAttribute("class", "default-btn").on("click", () => {
let MOUSE_MIN2 = Infinity;
const minDelta = $$("u");
const minDeltaInfo = $$("h1").setInnerText("最小 |deltaY| ").insert(minDelta);
const reset = $$("button").setInnerText("重置").on("click", () => {
MOUSE_MIN2 = Infinity;
});
const submit = $$("button").setInnerText("确定").on("click", () => {
setMinDelta(popup.element, MOUSE_MIN2);
});
popup.insert(
/*html*/
`请使用最小刻度滚动鼠标滚轮!(优先整数)
`
).insert(minDeltaInfo).on("wheel", (e) => {
e.preventDefault();
e.stopPropagation();
const evt = e;
if (evt.deltaY !== 0 && Math.abs(evt.deltaY) < MOUSE_MIN2)
MOUSE_MIN2 = Math.abs(evt.deltaY);
minDelta.setInnerText(`${MOUSE_MIN2} 【当前:${evt.deltaY}】`);
}).insert(reset).insert(submit);
});
const calibrateBox = $$("h3").setInnerText("(根据提示移动鼠标和触控板)").insert(calibrate, "afterbegin");
popup.insert(
/*html*/
`
Bilibili Trackpad Scroll Reverser
初始化,请选择你的反转策略:
`
).insert(easyBox).insert(" ").insert(calibrateBox);
document.body.insertAdjacentElement("afterbegin", popup.element);
popup.element.showModal();
window.onload = () => {
window.player.pause();
document.body.style.overflow = "hidden";
};
};
const MOUSE_MIN = getMouseMinDelta() || 100;
console.log(`[BILIBILI-TRACKPAD-SCROLL-REVERSER] MOUSE_MIN: ${MOUSE_MIN}`);
const isFullScreen = () => !!document.fullscreenElement;
const isTrackpad = (wheelEvent) => {
return Math.abs(wheelEvent.deltaY) < MOUSE_MIN || Math.abs(wheelEvent.deltaY) > MOUSE_MIN && Number.isInteger(wheelEvent.deltaY * 2);
};
const orgin = EventTarget.prototype.addEventListener;
const applyHandler = (target, thisArg, args) => {
const [type, evt, ...rest] = args;
if (thisArg instanceof HTMLElement || !(evt instanceof Function) || type !== "mousewheel" && type !== "wheel")
return Reflect.apply(target, thisArg, args);
const evtWrapper = (e) => {
if (!isFullScreen() || !isTrackpad(e))
return Reflect.apply(evt, thisArg, [e]);
const proxy = new Proxy(e, {
get: (obj, prop) => typeof prop === "symbol" || prop !== "wheelDelta" ? Reflect.get(obj, prop) : Reflect.get(obj, "deltaY") * 10
// Considering that `wheelDelta` is deprecated
});
return Reflect.apply(evt, thisArg, [proxy]);
};
return Reflect.apply(target, thisArg, [type, evtWrapper, ...rest]);
};
EventTarget.prototype.addEventListener = new Proxy(orgin, { apply: applyHandler });
setupInitPopup();
})();