// ==UserScript==
// @name 抖音优化
// @namespace https://github.com/WhiteSevs/TamperMonkeyScript
// @version 2024.11.5.22
// @author WhiteSevs
// @description 视频过滤,包括广告、直播或自定义规则,伪装登录、屏蔽登录弹窗、自定义清晰度选择、未登录解锁画质选择、禁止自动播放、自动进入全屏、双击进入全屏、屏蔽弹幕和礼物特效、手机模式、修复进度条拖拽、自定义视频和评论区背景色等
// @license GPL-3.0-only
// @icon data:image/png;base64,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
// @supportURL https://github.com/WhiteSevs/TamperMonkeyScript/issues
// @match *://*.douyin.com/*
// @match *://*.iesdouyin.com/*
// @require https://update.greasyfork.icu/scripts/494167/1413255/CoverUMD.js
// @require https://fastly.jsdelivr.net/npm/@whitesev/utils@2.4.5/dist/index.umd.js
// @require https://fastly.jsdelivr.net/npm/@whitesev/domutils@1.3.8/dist/index.umd.js
// @require https://fastly.jsdelivr.net/npm/@whitesev/pops@1.8.8/dist/index.umd.js
// @require https://fastly.jsdelivr.net/npm/qmsg@1.2.5/dist/index.umd.js
// @connect *
// @grant GM_deleteValue
// @grant GM_getResourceText
// @grant GM_getValue
// @grant GM_info
// @grant GM_registerMenuCommand
// @grant GM_setValue
// @grant GM_unregisterMenuCommand
// @grant GM_xmlhttpRequest
// @grant unsafeWindow
// @run-at document-start
// @downloadURL none
// ==/UserScript==
(function (Qmsg, Utils, DOMUtils, pops) {
'use strict';
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);
var _a;
var _GM_deleteValue = /* @__PURE__ */ (() => typeof GM_deleteValue != "undefined" ? GM_deleteValue : void 0)();
var _GM_getResourceText = /* @__PURE__ */ (() => typeof GM_getResourceText != "undefined" ? GM_getResourceText : void 0)();
var _GM_getValue = /* @__PURE__ */ (() => typeof GM_getValue != "undefined" ? GM_getValue : void 0)();
var _GM_info = /* @__PURE__ */ (() => typeof GM_info != "undefined" ? GM_info : void 0)();
var _GM_registerMenuCommand = /* @__PURE__ */ (() => typeof GM_registerMenuCommand != "undefined" ? GM_registerMenuCommand : void 0)();
var _GM_setValue = /* @__PURE__ */ (() => typeof GM_setValue != "undefined" ? GM_setValue : void 0)();
var _GM_unregisterMenuCommand = /* @__PURE__ */ (() => typeof GM_unregisterMenuCommand != "undefined" ? GM_unregisterMenuCommand : void 0)();
var _GM_xmlhttpRequest = /* @__PURE__ */ (() => typeof GM_xmlhttpRequest != "undefined" ? GM_xmlhttpRequest : void 0)();
var _unsafeWindow = /* @__PURE__ */ (() => typeof unsafeWindow != "undefined" ? unsafeWindow : void 0)();
var _monkeyWindow = /* @__PURE__ */ (() => window)();
const KEY = "GM_Panel";
const ATTRIBUTE_INIT = "data-init";
const ATTRIBUTE_KEY = "data-key";
const ATTRIBUTE_DEFAULT_VALUE = "data-default-value";
const ATTRIBUTE_INIT_MORE_VALUE = "data-init-more-value";
const UISelect = function(text, key, defaultValue, data, callback, description) {
let selectData = [];
if (typeof data === "function") {
selectData = data();
} else {
selectData = data;
}
let result = {
text,
type: "select",
description,
attributes: {},
getValue() {
return PopsPanel.getValue(key, defaultValue);
},
callback(event, isSelectedValue, isSelectedText) {
PopsPanel.setValue(key, isSelectedValue);
if (typeof callback === "function") {
callback(event, isSelectedValue, isSelectedText);
}
},
data: selectData
};
if (result.attributes) {
result.attributes[ATTRIBUTE_KEY] = key;
result.attributes[ATTRIBUTE_DEFAULT_VALUE] = defaultValue;
}
return result;
};
const UISwitch = function(text, key, defaultValue, clickCallBack, description) {
let result = {
text,
type: "switch",
description,
attributes: {},
getValue() {
return Boolean(PopsPanel.getValue(key, defaultValue));
},
callback(event, value) {
log.success(`${value ? "开启" : "关闭"} ${text}`);
PopsPanel.setValue(key, Boolean(value));
},
afterAddToUListCallBack: void 0
};
if (result.attributes) {
result.attributes[ATTRIBUTE_KEY] = key;
result.attributes[ATTRIBUTE_DEFAULT_VALUE] = Boolean(defaultValue);
}
return result;
};
const afterEnterDeepMenuCallBack = (formConfig, container) => {
let $oneClickOpen = container.sectionBodyContainer.querySelector(
".keyboard-oneClickOpen"
);
let $oneClickClose = container.sectionBodyContainer.querySelector(
".keyboard-oneClickClose"
);
let clickCallBack = (isOpen) => {
var _a2;
(_a2 = container.sectionBodyContainer) == null ? void 0 : _a2.querySelectorAll(".pops-panel-switch").forEach(($ele) => {
let $input = $ele.querySelector(
".pops-panel-switch__input"
);
let $checkbox = $ele.querySelector(
".pops-panel-switch__core"
);
if (isOpen) {
if (!$input.checked) {
$checkbox.click();
}
} else {
if ($input.checked) {
$checkbox.click();
}
}
});
};
domUtils.on($oneClickOpen, "click", (event) => {
utils.preventEvent(event);
clickCallBack(true);
});
domUtils.on($oneClickClose, "click", (event) => {
utils.preventEvent(event);
clickCallBack(false);
});
};
const AutoOpenOrClose = {
text: (
/*html*/
`
一键开启
一键关闭
`
),
afterEnterDeepMenuCallBack
};
const PanelCommonConfig = {
id: "panel-config-common",
title: "通用",
forms: [
{
text: "",
type: "forms",
forms: [
{
text: "Toast配置",
type: "deepMenu",
forms: [
{
text: "",
type: "forms",
forms: [
UISelect(
"Toast位置",
"qmsg-config-position",
"bottom",
[
{
value: "topleft",
text: "左上角"
},
{
value: "top",
text: "顶部"
},
{
value: "topright",
text: "右上角"
},
{
value: "left",
text: "左边"
},
{
value: "center",
text: "中间"
},
{
value: "right",
text: "右边"
},
{
value: "bottomleft",
text: "左下角"
},
{
value: "bottom",
text: "底部"
},
{
value: "bottomright",
text: "右下角"
}
],
(event, isSelectValue, isSelectText) => {
log.info("设置当前Qmsg弹出位置" + isSelectText);
},
"Toast显示在页面九宫格的位置"
),
UISelect(
"最多显示的数量",
"qmsg-config-maxnums",
3,
[
{
value: 1,
text: "1"
},
{
value: 2,
text: "2"
},
{
value: 3,
text: "3"
},
{
value: 4,
text: "4"
},
{
value: 5,
text: "5"
}
],
void 0,
"限制Toast显示的数量"
),
UISwitch(
"逆序弹出",
"qmsg-config-showreverse",
false,
void 0,
"修改Toast弹出的顺序"
)
]
}
]
}
]
},
{
type: "forms",
text: "",
forms: [
{
text: "功能",
type: "deepMenu",
forms: [
{
text: "",
type: "forms",
forms: [
UISwitch(
"伪装登录",
"disguiseLogin",
false,
void 0,
"使用随机UID进行伪装"
),
UISwitch(
"initial-scale=1",
"dy-initialScale",
false,
void 0,
"可配合手机模式放大页面"
),
UISwitch(
"移除 apple-itunes-app",
"dy-apple-removeMetaAppleItunesApp",
true,
void 0,
"Safari使用,移除顶部横幅【Open in the 抖音 app】"
),
UISwitch(
"移除某些Cookie",
"dy-cookie-remove__ac__",
false,
void 0,
""
)
]
}
]
},
{
text: "Url重定向",
type: "deepMenu",
forms: [
{
text: "",
type: "forms",
forms: [
UISwitch(
"重定向/home",
"douyin-redirect-url-home-to-root",
false,
void 0,
"/home => /"
)
]
}
]
},
{
type: "deepMenu",
text: "快捷键禁用",
afterEnterDeepMenuCallBack: AutoOpenOrClose.afterEnterDeepMenuCallBack,
forms: [
{
type: "forms",
text: AutoOpenOrClose.text,
forms: [
UISwitch(
"赞|取消赞",
"dy-keyboard-hook-likeOrDislike",
false,
void 0,
"Z"
),
UISwitch(
"评论",
"dy-keyboard-hook-comment",
false,
void 0,
"X"
),
UISwitch(
"开启/关闭弹幕",
"dy-keyboard-hook-danmaku-enable",
false,
void 0,
"B"
),
UISwitch(
"收藏/取消收藏",
"dy-keyboard-hook-collect-enable",
false,
void 0,
"C"
),
UISwitch(
"复制分享口令",
"dy-keyboard-hook-copyShareLink",
false,
void 0,
"V"
),
UISwitch(
"清屏",
"dy-keyboard-hook-clearScreen",
false,
void 0,
"J"
),
UISwitch(
"自动连播",
"dy-keyboard-hook-automaticBroadcast",
false,
void 0,
"K"
),
UISwitch(
"视频信息",
"dy-keyboard-hook-videoInfo",
false,
void 0,
"I"
),
UISwitch(
"不感兴趣",
"dy-keyboard-hook-notInterested",
false,
void 0,
"R"
),
UISwitch(
"进入作者主页",
"dy-keyboard-hook-enterAuthorHomePage",
false,
void 0,
"F"
),
UISwitch(
"关注/取消关注",
"dy-keyboard-hook-follow",
false,
void 0,
"G"
),
UISwitch(
"抖音搜索",
"dy-keyboard-hook-search",
false,
void 0,
"Shift+F"
),
UISwitch(
"一键关闭当前页",
"dy-keyboard-hook-closeTheCurrentPageWithOneClick",
false,
void 0,
"Shift+Q"
),
UISwitch(
"上下翻页",
"dy-keyboard-hook-pageUpAndDown",
false,
void 0,
"↑↓"
),
UISwitch(
"快进快退",
"dy-keyboard-hook-fastForwardAndFastBack",
false,
void 0,
"← →"
),
UISwitch(
"暂停",
"dy-keyboard-hook-pause",
false,
void 0,
"空格"
),
UISwitch(
"网页内全屏",
"dy-keyboard-hook-fullScreenInsideThePage",
false,
void 0,
"Y"
),
UISwitch(
"全屏",
"dy-keyboard-hook-fullScreen",
false,
void 0,
"H"
),
UISwitch(
"稍后再看",
"dy-keyboard-hook-watchItOutLater",
false,
void 0,
"L"
),
UISwitch(
"音量调整",
"dy-keyboard-hook-volumeAdjustment",
false,
void 0,
"Shift + / Shift -"
),
UISwitch(
"呼出快捷键列表",
"dy-keyboard-hook-listOfCallShortcutKeys",
false,
void 0,
"?"
),
UISwitch(
"关闭快捷键列表",
"dy-keyboard-hook-closeTheShortcutKeyList",
false,
void 0,
"ESC"
),
UISwitch(
"相关推荐",
"dy-keyboard-hook-relevantRecommendation",
false,
void 0,
"N"
)
]
}
]
}
]
},
{
text: "",
type: "forms",
forms: [
{
text: "屏蔽-通用",
type: "deepMenu",
afterEnterDeepMenuCallBack: AutoOpenOrClose.afterEnterDeepMenuCallBack,
forms: [
{
type: "forms",
text: AutoOpenOrClose.text,
forms: [
UISwitch(
"【屏蔽】登录弹窗",
"watchLoginDialogToClose",
true,
void 0,
"屏蔽元素且自动等待元素出现并关闭登录弹窗"
),
UISwitch(
"【屏蔽】底部?按钮",
"shieldBottomQuestionButton",
true,
void 0,
"屏蔽元素"
)
]
}
]
},
{
text: "屏蔽-左侧导航栏",
type: "deepMenu",
afterEnterDeepMenuCallBack: AutoOpenOrClose.afterEnterDeepMenuCallBack,
forms: [
{
type: "forms",
text: AutoOpenOrClose.text,
forms: [
UISwitch(
"【屏蔽】左侧导航栏",
"shieldLeftNavigator",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】首页",
"shieldLeftNavigator-tab-home",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】推荐",
"shieldLeftNavigator-tab-recommend",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】关注",
"shieldLeftNavigator-tab-follow",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】朋友",
"shieldLeftNavigator-tab-friend",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】我的",
"shieldLeftNavigator-tab-user_self",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】喜欢",
"shieldLeftNavigator-tab-user_self_like",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】收藏",
"shieldLeftNavigator-tab-user_self_collection",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】观看历史",
"shieldLeftNavigator-tab-user_self_record",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】看奥运",
"shieldLeftNavigator-tab-olympics",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】直播",
"shieldLeftNavigator-tab-live",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】放映厅",
"shieldLeftNavigator-tab-vs",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】知识",
"shieldLeftNavigator-tab-channel_300203",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】游戏",
"shieldLeftNavigator-tab-channel_300205",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】二次元",
"shieldLeftNavigator-tab-channel_300206",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】音乐",
"shieldLeftNavigator-tab-channel_300209",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】美食",
"shieldLeftNavigator-tab-channel_300204",
false,
void 0,
"屏蔽元素"
)
]
}
]
},
{
text: "屏蔽-顶部导航栏",
type: "deepMenu",
afterEnterDeepMenuCallBack: AutoOpenOrClose.afterEnterDeepMenuCallBack,
forms: [
{
text: AutoOpenOrClose.text,
type: "forms",
forms: [
UISwitch(
"【屏蔽】顶部导航栏",
"shieldTopNavigator",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】客户端提示",
"shieldClientTip",
true,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】充钻石",
"shieldFillingBricksAndStones",
true,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】客户端",
"shieldClient",
true,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】快捷访问",
"shieldQuickAccess",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】通知",
"shieldNotifitation",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】私信",
"shieldPrivateMessage",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】投稿",
"shieldSubmission",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】壁纸",
"shieldWallpaper",
false,
void 0,
"屏蔽元素"
)
]
}
]
},
{
text: "屏蔽-搜索",
type: "deepMenu",
afterEnterDeepMenuCallBack: AutoOpenOrClose.afterEnterDeepMenuCallBack,
forms: [
{
text: AutoOpenOrClose.text,
type: "forms",
forms: [
UISwitch(
"【屏蔽】搜索框",
"shieldSearch",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】搜索框的提示",
"shieldSearchPlaceholder",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】猜你想搜",
"shieldSearchGuessYouWantToSearch",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】抖音热点",
"shieldSearchTiktokHotspot",
false,
void 0,
"屏蔽元素"
)
]
}
]
},
{
type: "deepMenu",
text: "屏蔽-鼠标悬浮提示",
afterEnterDeepMenuCallBack: AutoOpenOrClose.afterEnterDeepMenuCallBack,
forms: [
{
type: "forms",
text: AutoOpenOrClose.text + "
视频区域-右侧工具栏",
forms: [
UISwitch(
"进入作者主页",
"dy-video-mouseHoverTip-rightToolBar-enterUserHome",
false
),
UISwitch(
"关注",
"dy-video-mouseHoverTip-rightToolBar-follow",
false
),
UISwitch(
"点赞",
"dy-video-mouseHoverTip-rightToolBar-addLike",
false
),
UISwitch(
"评论",
"dy-video-mouseHoverTip-rightToolBar-comment",
false
),
UISwitch(
"收藏",
"dy-video-mouseHoverTip-rightToolBar-collect",
false
),
UISwitch(
"分享",
"dy-video-mouseHoverTip-rightToolBar-share",
false
),
UISwitch(
"看相关",
"dy-video-mouseHoverTip-rightToolBar-seeCorrelation",
false
)
]
},
{
type: "forms",
text: "视频区域-底部工具栏",
forms: [
UISwitch(
"自动连播",
"dy-video-mouseHoverTip-bottomToolBar-automaticBroadcast",
false
),
UISwitch(
"清屏",
"dy-video-mouseHoverTip-bottomToolBar-clearScreen",
false
),
UISwitch(
"稍后再看",
"dy-video-mouseHoverTip-bottomToolBar-watchLater",
false
),
UISwitch(
"网页全屏",
"dy-video-mouseHoverTip-bottomToolBar-pageFullScreen",
false
),
UISwitch(
"全屏",
"dy-video-mouseHoverTip-bottomToolBar-fullScreen",
false
)
]
}
]
}
]
}
]
};
const DouYinDanmuFilter = {
key: "douyin-live-danmu-rule",
$data: {
rule: [],
isFilterAttrName: "data-is-filter"
},
init() {
this.parseRule();
},
/**
* 解析规则
*/
parseRule() {
let localRule = this.get().trim();
let localRuleSplit = localRule.split("\n");
localRuleSplit.forEach((item) => {
if (item.trim() == "") return;
item = item.trim();
let itemRegExp = new RegExp(item.trim());
this.$data.rule.push(itemRegExp);
});
},
/**
* 通知弹幕改变(可能是新增)
*/
change() {
var _a2, _b, _c, _d, _e, _f, _g;
let danmakuQueue = Array.from(
document.querySelectorAll("xg-danmu.xgplayer-danmu > div > div")
);
if (!danmakuQueue.length) {
return;
}
for (let messageIndex = 0; messageIndex < danmakuQueue.length; messageIndex++) {
let $danmuItem = danmakuQueue[messageIndex];
if ($danmuItem.hasAttribute(this.$data.isFilterAttrName)) {
continue;
}
let $messageObj = (_d = (_c = (_b = (_a2 = utils.getReactObj($danmuItem)) == null ? void 0 : _a2.reactFiber) == null ? void 0 : _b.return) == null ? void 0 : _c.memoizedProps) == null ? void 0 : _d.message;
let message = ((_e = $messageObj == null ? void 0 : $messageObj.payload) == null ? void 0 : _e.content) || ((_g = (_f = $messageObj == null ? void 0 : $messageObj.payload) == null ? void 0 : _f.common) == null ? void 0 : _g.describe);
for (let index = 0; index < this.$data.rule.length; index++) {
const ruleRegExp = this.$data.rule[index];
if (typeof message === "string") {
if (ruleRegExp.test(message)) {
log.info("过滤弹幕: " + message);
$danmuItem.setAttribute(this.$data.isFilterAttrName, "true");
domUtils.hide($danmuItem);
break;
}
}
}
}
},
set(value) {
_GM_setValue(this.key, value);
},
get() {
return _GM_getValue(this.key, "");
}
};
const DouYinLiveDanmuku = {
/**
* 弹幕过滤
*/
filterDanmu() {
utils.waitNode("xg-danmu.xgplayer-danmu", 1e5).then(($danmu) => {
if (!$danmu) {
log.error("xg-danmu.xgplayer-danmu获取失败");
return;
}
log.success("弹幕过滤");
DouYinDanmuFilter.init();
utils.mutationObserver($danmu, {
config: {
childList: true,
subtree: true
},
callback: () => {
DouYinDanmuFilter.change();
}
});
});
}
};
const DouYinUtils = {
/**
* 判断是否是竖屏
*
* window.screen.orientation.type
* + landscape-primary 横屏
* + portrait-primary 竖屏
*/
isVerticalScreen() {
return !window.screen.orientation.type.includes("landscape");
},
/**
* 添加屏蔽CSS
* @param args
* @example
* addBlockCSS("")
* addBlockCSS("","")
* addBlockCSS(["",""])
*/
addBlockCSS(...args) {
let selectorList = [];
if (args.length === 0) {
return;
}
if (args.length === 1 && typeof args[0] === "string" && args[0].trim() === "") {
return;
}
args.forEach((selector) => {
if (Array.isArray(selector)) {
selectorList = selectorList.concat(selector);
} else {
selectorList.push(selector);
}
});
return utils.addStyle(
`${selectorList.join(",\n")}{display: none !important;}`
);
},
/**
* 深度获取对象属性
* @param obj 待获取的对象
* @param getPropertiesCallBack 获取属性的回调
*/
getObjectPropertiesInDepth(obj, getPropertiesCallBack) {
if (obj == null) {
return;
}
let value = getPropertiesCallBack(obj);
if (typeof (value == null ? void 0 : value.isFind) === "boolean" && value.isFind) {
return value == null ? void 0 : value.data;
}
return this.getObjectPropertiesInDepth(value.data, getPropertiesCallBack);
}
};
const ReactUtils = {
/**
* 等待react某个属性并进行设置
*/
async waitReactPropsToSet($target, propName, needSetList) {
function getTarget() {
let __target__ = null;
if (typeof $target === "string") {
__target__ = document.querySelector($target);
} else if (typeof $target === "function") {
__target__ = $target();
} else if ($target instanceof HTMLElement) {
__target__ = $target;
}
return __target__;
}
if (typeof $target === "string") {
let $ele = await utils.waitNode($target, 1e4);
if (!$ele) {
return;
}
}
needSetList.forEach((needSetOption) => {
if (typeof needSetOption.msg === "string") {
log.info(needSetOption.msg);
}
function checkObj() {
let target = getTarget();
if (target == null) {
return false;
}
let targetObj = utils.getReactObj(target);
if (targetObj == null) {
return false;
}
let targetObjProp = targetObj[propName];
if (targetObjProp == null) {
return false;
}
let needOwnCheck = needSetOption.check(targetObjProp);
return Boolean(needOwnCheck);
}
utils.waitPropertyByInterval(
() => {
return getTarget();
},
checkObj,
250,
1e4
).then(() => {
let target = getTarget();
if (target == null) {
return;
}
let targetObj = utils.getReactObj(target);
if (targetObj == null) {
return;
}
let targetObjProp = targetObj[propName];
if (targetObjProp == null) {
return;
}
needSetOption.set(targetObjProp);
});
});
}
};
const DouYinLiveChatRoomHideElement = {
init() {
PopsPanel.execMenuOnce("live-shieldChatRoom", () => {
return this.shieldChatRoom();
});
PopsPanel.execMenuOnce("live-shielChatRoomVipSeats", () => {
return this.shielChatRoomVipSeats();
});
PopsPanel.execMenuOnce("dy-live-shieldUserLevelIcon", () => {
return this.shieldUserLevelIcon();
});
PopsPanel.execMenuOnce("dy-live-shieldUserVIPIcon", () => {
return this.shieldUserVIPIcon();
});
PopsPanel.execMenuOnce("dy-live-shieldUserFansIcon", () => {
return this.shieldUserFansIcon();
});
PopsPanel.execMenuOnce("dy-live-shieldMessage", () => {
return this.shieldMessage();
});
},
/**
* 【屏蔽】评论区(聊天室)
*/
shieldChatRoom() {
log.info("【屏蔽】评论区(聊天室)");
return [
DouYinUtils.addBlockCSS("#chatroom"),
addStyle(`
div[data-e2e="living-container"],
div[data-e2e="living-container"] > div{
margin-bottom: 0px !important;
}`)
];
},
/**
* 【屏蔽】评论区的贵宾席
*/
shielChatRoomVipSeats() {
log.info("【屏蔽】评论区的贵宾席");
return [
DouYinUtils.addBlockCSS(
"#chatroom > div > div:has(#audiencePanelScrollId)"
)
];
},
/**
* 【屏蔽】用户等级图标
*/
shieldUserLevelIcon() {
log.info("【屏蔽】用户等级图标");
return [
DouYinUtils.addBlockCSS(
'.webcast-chatroom___item span:has(>img[src*="level"])'
)
];
},
/**
* 【屏蔽】VIP图标
*/
shieldUserVIPIcon() {
log.info("【屏蔽】VIP图标");
return [
DouYinUtils.addBlockCSS(
'.webcast-chatroom___item span:has(>img[src*="subscribe"])'
)
];
},
/**
* 【屏蔽】粉丝牌
*/
shieldUserFansIcon() {
log.info("【屏蔽】粉丝牌");
return [
DouYinUtils.addBlockCSS(
'.webcast-chatroom___item span:has(>div[style*="fansclub"])'
)
];
},
/**
* 【屏蔽】信息播报
*/
shieldMessage() {
log.info("【屏蔽】信息播报");
return [
DouYinUtils.addBlockCSS(
".webcast-chatroom___bottom-message",
// 上面的滚动播报,xxx加入了直播间
'#chatroom >div>div>div:has(>div[elementtiming="element-timing"])'
)
];
}
};
const DouYinLiveDanmuHideElement = {
init() {
PopsPanel.execMenuOnce("live-shieldDanmuku", () => {
return this.shieldDanmu();
});
},
/**
* 屏蔽弹幕
*/
shieldDanmu() {
log.info("屏蔽弹幕");
return [DouYinUtils.addBlockCSS("xg-danmu.xgplayer-danmu")];
}
};
const DouYinLiveHideElement = {
init() {
PopsPanel.execMenuOnce("live-shieldGiftColumn", () => {
return this.shieldGiftColumn();
});
PopsPanel.execMenuOnce("live-shieldTopToolBarInfo", () => {
return this.shieldTopToolBarInfo();
});
PopsPanel.execMenuOnce("live-shieldGiftEffects", () => {
return this.shieldGiftEffects();
});
PopsPanel.execMenuOnce("live-shielYellowCar", () => {
return this.shieldYellowCar();
});
DouYinLiveChatRoomHideElement.init();
DouYinLiveDanmuHideElement.init();
},
/**
* 【屏蔽】底部的礼物栏
*/
shieldGiftColumn() {
log.info("屏蔽底部的礼物栏");
return [
DouYinUtils.addBlockCSS(
'div[data-e2e="living-container"] >div> :last-child',
/* 全屏状态下的礼物栏 */
'div[data-e2e="living-container"] xg-controls > div:has(div[data-e2e="gifts-container"])'
),
addStyle(`
/* 去除全屏状态下的礼物栏后,上面的工具栏bottom也去除 */
div[data-e2e="living-container"] xg-controls xg-inner-controls:has(+div div[data-e2e="gifts-container"]){
bottom: 0 !important;
}`)
];
},
/**
* 【屏蔽】顶栏信息
* 包括直播作者、右侧的礼物展馆
*/
shieldTopToolBarInfo() {
log.info("【屏蔽】顶栏信息");
return [
DouYinUtils.addBlockCSS(
'div[data-e2e="living-container"] > div > pace-island[id^="island_"]'
)
];
},
/**
* 【屏蔽】礼物特效
*/
shieldGiftEffects() {
log.info("【屏蔽】礼物特效");
return [
DouYinUtils.addBlockCSS(
// ↓该屏蔽会把连麦的用户也屏蔽了
// '.basicPlayer[data-e2e="basicPlayer"] pace-island[id^="island_"]:has(>div>div>div)'
'.basicPlayer[data-e2e="basicPlayer"] pace-island[id^="island_"]:has(>div>div:not([class*="video_layout_container"])>div)'
)
];
},
/**
* 【屏蔽】小黄车
*/
shieldYellowCar() {
log.info("【屏蔽】小黄车");
return [
DouYinUtils.addBlockCSS(
'div[id^="living_room_player_container"] .basicPlayer > div:has(div[data-e2e="yellowCart-container"])'
)
];
}
};
const DouYinLivePlayerInstance = {
$data: {
playerInstance: null
},
$el: {
$playerIns: null
},
/**
* 添加油猴菜单
*/
initMenu() {
GM_Menu.add({
key: "live-parsePlayerInstance",
text: "⚙ PlayerInstance",
autoReload: false,
showText(text, enable) {
return text;
},
callback: () => {
let $playerIns = document.querySelector(
`[id^="living_room_player_container"]`
);
if (!$playerIns) {
log.error("获取playerInstance所在的元素失败");
Qmsg.error("获取playerInstance所在的元素失败");
return;
}
this.$el.$playerIns = $playerIns;
let playerInstance = this.parseElementPlayerIns(this.$el.$playerIns);
if (playerInstance == null) {
log.error("获取playerInstance失败");
log.error("获取playerInstance失败");
return;
}
this.$data.playerInstance = playerInstance;
this.showParseDialog();
}
});
},
/**
* 解析元素上的播放器实例
*/
parseElementPlayerIns($ele) {
var _a2, _b, _c, _d;
let react = utils.getReactObj($ele);
return (_d = (_c = (_b = (_a2 = react == null ? void 0 : react.reactFiber) == null ? void 0 : _a2.child) == null ? void 0 : _b.child) == null ? void 0 : _c.memoizedProps) == null ? void 0 : _d.playerInstance;
},
/**
* 显示解析的信息弹窗
*/
showParseDialog() {
var _a2, _b, _c, _d;
log.info(["解析的信息:", this.$data.playerInstance]);
let blobSrc = ((_a2 = this.$data.playerInstance) == null ? void 0 : _a2.url) || ((_b = this.$data.playerInstance) == null ? void 0 : _b.src);
let pushSrc = (_c = this.$data.playerInstance) == null ? void 0 : _c.config.url;
__pops.alert({
title: {
text: "解析信息",
position: "center"
},
content: {
text: (
/*html*/
`
播放器版本:
${(_d = this.$data.playerInstance) == null ? void 0 : _d.version}
`
),
html: true
},
mask: {
enable: false
},
width: window.innerWidth > 550 ? "550px" : "88wv",
height: window.innerHeight > 550 ? "550px" : "70vh",
style: (
/*css*/
`
.live-dy-parse-container{
display: flex;
flex-direction: column;
gap: 10px;
}
.live-dy-parse-item{
display: flex;
flex-wrap: wrap;
border: 1px solid #919191;
border-left: 0px;
border-right: 0px;
width: 100%;
background: #0af9ee;
padding: 5px 5px;
}
`
)
});
}
};
class ShortCut {
constructor(key) {
/** 存储的键 */
__publicField(this, "key", "short-cut");
/** 是否存在等待按下的按键 */
__publicField(this, "isWaitPress", false);
if (typeof key === "string") {
this.key = key;
}
}
/**
* 初始化配置默认值
*/
initConfig(key, option) {
if (this.hasOption(key)) ;
else {
this.setOption(key, option);
}
}
/** 获取存储的键 */
getStorageKey() {
return this.key;
}
/**
* 获取本地存储的所有值
*/
getLocalAllOptions() {
return _GM_getValue(this.key, []);
}
/**
* 判断是否存在该配置
* @param key 键
*/
hasOption(key) {
let localOptions = this.getLocalAllOptions();
let findOption = localOptions.find((item) => item.key === key);
return !!findOption;
}
/**
* 判断是否存在该配置的value值
* @param key 键
*/
hasOptionValue(key) {
if (this.hasOption(key)) {
let option = this.getOption(key);
return !((option == null ? void 0 : option.value) == null);
} else {
return false;
}
}
/**
* 获取配置
* @param key 键
* @param defaultValue 默认值
*/
getOption(key, defaultValue) {
let localOptions = this.getLocalAllOptions();
let findOption = localOptions.find((item) => item.key === key);
return findOption ?? defaultValue;
}
/**
* 设置配置
* @param key 键
* @param value 配置
*/
setOption(key, value) {
let localOptions = this.getLocalAllOptions();
let findIndex = localOptions.findIndex((item) => item.key === key);
if (findIndex == -1) {
localOptions.push({
key,
value
});
} else {
Reflect.set(localOptions[findIndex], "value", value);
}
_GM_setValue(this.key, localOptions);
}
/**
* 清空当前已有配置录入的值
* @param key
*/
emptyOption(key) {
let result = false;
let localOptions = this.getLocalAllOptions();
let findIndex = localOptions.findIndex((item) => item.key === key);
if (findIndex !== -1) {
localOptions[findIndex].value = null;
result = true;
}
_GM_setValue(this.key, localOptions);
return result;
}
/**
* 删除配置
* @param key 键
*/
deleteOption(key) {
let result = false;
let localValue = this.getLocalAllOptions();
let findValueIndex = localValue.findIndex((item) => item.key === key);
if (findValueIndex !== -1) {
localValue.splice(findValueIndex, 1);
result = true;
}
_GM_setValue(this.key, localValue);
return result;
}
/**
* 把配置的快捷键转成文字
* @param keyboardValue
* @returns
*/
translateKeyboardValueToButtonText(keyboardValue) {
let result = "";
keyboardValue.ohterCodeList.forEach((ohterCodeKey) => {
result += utils.stringTitleToUpperCase(ohterCodeKey, true) + " + ";
});
result += utils.stringTitleToUpperCase(keyboardValue.keyName);
return result;
}
/**
* 获取快捷键显示的文字
* @param key 本地存储的快捷键键名
* @param defaultShowText 默认显示的文字
*/
getShowText(key, defaultShowText) {
if (this.hasOption(key)) {
let localOption = this.getOption(key);
if (localOption.value == null) {
return defaultShowText;
} else {
return this.translateKeyboardValueToButtonText(localOption.value);
}
} else {
return defaultShowText;
}
}
/**
* 录入快捷键
* @param key 本地存储的快捷键键名
*/
async enterShortcutKeys(key) {
return new Promise((resolve) => {
this.isWaitPress = true;
let keyboardListener = domUtils.listenKeyboard(
window,
"keyup",
(keyName, keyValue, ohterCodeList) => {
const currentOption = {
keyName,
keyValue,
ohterCodeList
};
const shortcutJSONString = JSON.stringify(currentOption);
const allOptions = this.getLocalAllOptions();
for (let index = 0; index < allOptions.length; index++) {
let localValue = allOptions[index];
if (localValue.key === key) {
continue;
}
const localShortCutJSONString = JSON.stringify(localValue.value);
let isUsedByOtherOption = false;
if (localValue.value != null && shortcutJSONString === localShortCutJSONString) {
isUsedByOtherOption = true;
}
if (isUsedByOtherOption) {
this.isWaitPress = false;
keyboardListener.removeListen();
resolve({
status: false,
key: localValue.key,
option: currentOption
});
return;
}
}
this.setOption(key, currentOption);
this.isWaitPress = false;
keyboardListener.removeListen();
resolve({
status: true,
key,
option: currentOption
});
}
);
});
}
/**
* 初始化全局键盘监听
* @param shortCutOption 快捷键配置 一般是{ "键名": { callback: ()=>{}}},键名是本地存储的自定义快捷键的键名
*/
initGlobalKeyboardListener(shortCutOption) {
let localOptions = this.getLocalAllOptions();
if (!localOptions.length) {
log.warn("没有设置快捷键");
return;
}
let that = this;
function setListenKeyboard($ele, option) {
domUtils.listenKeyboard(
$ele,
"keydown",
(keyName, keyValue, ohterCodeList) => {
if (that.isWaitPress) {
return;
}
localOptions = that.getLocalAllOptions();
let findShortcutIndex = localOptions.findIndex((item) => {
let option2 = item.value;
let tempOption = {
keyName,
keyValue,
ohterCodeList
};
if (JSON.stringify(option2) === JSON.stringify(tempOption)) {
return item;
}
});
if (findShortcutIndex != -1) {
let findShortcut = localOptions[findShortcutIndex];
log.info(["调用快捷键", findShortcut]);
if (findShortcut.key in option) {
option[findShortcut.key].callback();
}
}
}
);
}
let WindowShortCutOption = {};
let ElementShortCutOption = {};
Object.keys(shortCutOption).forEach((localKey) => {
let option = shortCutOption[localKey];
if (option.target == null || typeof option.target === "string" && option.target === "") {
option.target = "window";
}
if (option.target === "window") {
Reflect.set(WindowShortCutOption, localKey, option);
} else {
Reflect.set(ElementShortCutOption, localKey, option);
}
});
setListenKeyboard(window, WindowShortCutOption);
domUtils.ready(() => {
Object.keys(ElementShortCutOption).forEach(async (localKey) => {
let option = ElementShortCutOption[localKey];
if (typeof option.target === "string") {
utils.waitNode(option.target, 1e4).then(($ele) => {
if (!$ele) {
return;
}
let __option = {};
Reflect.set(__option, localKey, option);
setListenKeyboard($ele, __option);
});
} else if (typeof option.target === "function") {
let target = await option.target();
if (target == null) {
return;
}
let __option = {};
Reflect.set(__option, localKey, option);
setListenKeyboard(target, __option);
} else {
let __option = {};
Reflect.set(__option, localKey, option);
setListenKeyboard(option.target, __option);
}
});
});
}
}
const DouYinLiveShortCut = {
shortCut: new ShortCut("live-short-cut"),
$data: {
blockChatRoom: false
},
init() {
this.shortCut.initGlobalKeyboardListener(this.getShortCutMap());
},
getShortCutMap() {
return {
"dy-live-block-chatroom": {
target: "window",
callback() {
log.info("快捷键 ==> 【屏蔽】聊天室");
let flag = PopsPanel.getValue("live-shieldChatRoom");
PopsPanel.setValue("live-shieldChatRoom", !flag);
}
},
"dy-live-shieldGiftEffects": {
target: "window",
callback: () => {
log.info("快捷键 ==> 【屏蔽】礼物特效");
let flag = PopsPanel.getValue("live-shieldGiftEffects");
PopsPanel.setValue("live-shieldGiftEffects", !flag);
}
}
};
}
};
const VideoQualityMap = {
auto: {
label: "自动",
sign: 0
},
ld: {
label: "标清",
sign: 1
},
sd: {
label: "高清",
sign: 2
},
hd: {
label: "超清",
sign: 3
},
uhd: {
label: "蓝光",
sign: 4
},
origin: {
label: "潮汐海灵",
sign: 5
}
};
const DouYinLive = {
init() {
DouYinLiveHideElement.init();
DouYinLiveShortCut.init();
PopsPanel.execMenu("live-autoEnterElementFullScreen", () => {
this.autoEnterElementFullScreen();
});
PopsPanel.execMenu("live-danmu-shield-rule-enable", () => {
DouYinLiveDanmuku.filterDanmu();
});
PopsPanel.execMenu("live-chooseQuality", (quality) => {
if (quality === "auto") {
return;
}
this.chooseQuality(quality);
});
PopsPanel.execMenu("live-unlockImageQuality", () => {
this.unlockImageQuality();
});
PopsPanel.execMenuOnce("live-waitToRemovePauseDialog", () => {
this.waitToRemovePauseDialog();
});
PopsPanel.execMenu("live-pauseVideo", () => {
this.pauseVideo();
});
PopsPanel.execMenu("live-bgColor-enable", () => {
PopsPanel.execMenuOnce("live-changeBackgroundColor", (value) => {
return this.changeBackgroundColor(value);
});
});
PopsPanel.execMenuOnce("live-parsePlayerInstance", () => {
DouYinLivePlayerInstance.initMenu();
});
},
/**
* 自动进入网页全屏
*/
autoEnterElementFullScreen() {
log.info("自动进入网页全屏");
utils.waitNode(
'xg-icon[classname] > div > div:has(path[d="M9.75 8.5a2 2 0 00-2 2v11a2 2 0 002 2h12.5a2 2 0 002-2v-11a2 2 0 00-2-2H9.75zM15 11.25h-3.75a1 1 0 00-1 1V16h2v-2.75H15v-2zm5.75 9.5H17v-2h2.75V16h2v3.75a1 1 0 01-1 1z"])'
).then((element) => {
element.click();
});
},
/**
* 选择画质
* @param [quality="origin"] 选择的画质
*/
chooseQuality(quality = "origin") {
ReactUtils.waitReactPropsToSet(
'xg-inner-controls xg-right-grid >div:has([data-e2e="quality-selector"])',
"reactProps",
[
{
check(reactObj) {
var _a2, _b, _c, _d, _e, _f, _g, _h, _i;
return typeof ((_d = (_c = (_b = (_a2 = reactObj == null ? void 0 : reactObj.children) == null ? void 0 : _a2.props) == null ? void 0 : _b.children) == null ? void 0 : _c.props) == null ? void 0 : _d.qualityHandler) === "object" && typeof ((_i = (_h = (_g = (_f = (_e = reactObj == null ? void 0 : reactObj.children) == null ? void 0 : _e.props) == null ? void 0 : _f.children) == null ? void 0 : _g.props) == null ? void 0 : _h.qualityHandler) == null ? void 0 : _i.getCurrentQualityList) === "function";
},
set(reactObj) {
let qualityHandler = reactObj.children.props.children.props.qualityHandler;
let currentQualityList = qualityHandler.getCurrentQualityList();
if (currentQualityList.includes(quality)) {
qualityHandler.setCurrentQuality(quality);
log.success("成功设置画质为【" + quality + "】");
} else {
let __quality = quality;
Qmsg.error(
"当前直播没有【" + __quality + "】画质,自动选择最高画质"
);
currentQualityList.sort((a, b) => {
if (!VideoQualityMap[a]) {
log.error("画质【" + a + "】不存在");
return 0;
}
if (!VideoQualityMap[b]) {
log.error("画质【" + b + "】不存在");
return 0;
}
return VideoQualityMap[a].sign - VideoQualityMap[b].sign;
});
__quality = currentQualityList[currentQualityList.length - 1];
qualityHandler.setCurrentQuality(quality);
log.success("成功设置画质为【" + quality + "】");
}
}
}
]
);
},
/**
* 解锁画质选择
*
* 未登录情况下最高选择【高清】画质
*/
unlockImageQuality() {
log.info("解锁画质选择");
domUtils.on(
document,
"click",
'div[data-e2e="quality-selector"] > div',
function(event) {
var _a2, _b;
utils.preventEvent(event);
let clickNode = event.target;
try {
let reactObj = utils.getReactObj(clickNode);
let key = (_a2 = reactObj == null ? void 0 : reactObj.reactFiber) == null ? void 0 : _a2["key"];
let parent = clickNode.closest("div[data-index]");
let parentReactObj = utils.getReactObj(parent);
let current = (_b = parentReactObj == null ? void 0 : parentReactObj.reactProps) == null ? void 0 : _b["children"]["ref"]["current"];
log.info("当前选择的画质: " + key);
log.info(["所有的画质: ", current.getCurrentQualityList()]);
current.setCurrentQuality(key);
} catch (error) {
log.error(error);
Qmsg.error("切换画质失败");
}
},
{
capture: true
}
);
},
/**
* 长时间无操作,已暂停播放
* 累计节能xx分钟
*/
waitToRemovePauseDialog() {
log.info("监听【长时间无操作,已暂停播放】弹窗");
function checkDialogToClose($ele, from) {
var _a2, _b, _c, _d, _e, _f;
let eleText = $ele.textContent || $ele.innerText;
if (eleText.includes("长时间无操作") && eleText.includes("暂停播放")) {
log.info(`检测${from}:出现【长时间无操作,已暂停播放】弹窗`);
Qmsg.info(`检测${from}:出现【长时间无操作,已暂停播放】弹窗`);
let $rect = utils.getReactObj($ele);
if (typeof $rect.reactContainer === "object") {
let closeDialogFn = DouYinUtils.getObjectPropertiesInDepth(
$rect.reactContainer,
(obj) => {
var _a3, _b2;
if (typeof obj["onClose"] === "function") {
return {
isFind: true,
data: obj["onClose"]
};
} else if (typeof ((_a3 = obj == null ? void 0 : obj["memoizedProps"]) == null ? void 0 : _a3["onClose"]) === "function") {
return {
isFind: true,
data: (_b2 = obj == null ? void 0 : obj["memoizedProps"]) == null ? void 0 : _b2["onClose"]
};
} else {
return {
isFind: false,
data: obj["child"]
};
}
}
) || ((_f = (_e = (_d = (_c = (_b = (_a2 = $rect == null ? void 0 : $rect.reactContainer) == null ? void 0 : _a2.memoizedState) == null ? void 0 : _b.element) == null ? void 0 : _c.props) == null ? void 0 : _d.children) == null ? void 0 : _e.props) == null ? void 0 : _f.onClose);
if (typeof closeDialogFn === "function") {
log.success(`检测${from}:调用函数关闭弹窗`);
Qmsg.success(`检测${from}:调用函数关闭弹窗`);
closeDialogFn();
}
}
}
}
domUtils.ready(() => {
utils.mutationObserver(document.body, {
config: {
subtree: true,
childList: true
},
callback() {
document.querySelectorAll(
"body > div[elementtiming='element-timing']"
).forEach(($elementTiming) => {
checkDialogToClose($elementTiming, "1");
});
document.querySelectorAll('body > div:not([id="root"])').forEach(($ele) => {
checkDialogToClose($ele, "2");
});
}
});
});
},
/**
* 暂停视频
*/
pauseVideo() {
log.info("禁止自动播放视频(直播)");
utils.waitNode('.basicPlayer[data-e2e="basicPlayer"] video').then(($video) => {
domUtils.on(
$video,
"play",
() => {
$video.pause();
},
{
capture: true,
once: true
}
);
$video.autoplay = false;
$video.pause();
});
},
/**
* 修改视频背景颜色
* @param color 颜色
*/
changeBackgroundColor(color) {
log.info("修改视频背景颜色");
return addStyle(
/*css*/
`
div[id^="living_room_player_container"] > div,
#chatroom > div{
background: ${color};
}
`
);
}
};
const UIButton = function(text, description, buttonText, buttonIcon, buttonIsRightIcon, buttonIconIsLoading, buttonType, clickCallBack, afterAddToUListCallBack) {
let result = {
text,
type: "button",
description,
buttonIcon,
buttonIsRightIcon,
buttonIconIsLoading,
buttonType,
buttonText,
callback(event) {
if (typeof clickCallBack === "function") {
clickCallBack(event);
}
},
afterAddToUListCallBack
};
return result;
};
const UIButtonShortCut = function(text, description, key, defaultValue, defaultButtonText, buttonType = "default", shortCut) {
let __defaultButtonText = defaultButtonText;
let getButtonText = () => {
return shortCut.getShowText(key, __defaultButtonText);
};
let result = UIButton(
text,
description,
getButtonText,
"keyboard",
false,
false,
buttonType,
async (event) => {
var _a2;
let $click = event.target;
let $btn = (_a2 = $click.closest(".pops-panel-button")) == null ? void 0 : _a2.querySelector("span");
if (shortCut.isWaitPress) {
Qmsg.warning("请先执行当前的录入操作");
return;
}
if (shortCut.hasOptionValue(key)) {
shortCut.emptyOption(key);
Qmsg.success("清空快捷键");
} else {
let loadingQmsg = Qmsg.loading("请按下快捷键...", {
showClose: true
});
let {
status,
option,
key: isUsedKey
} = await shortCut.enterShortcutKeys(key);
loadingQmsg.close();
if (status) {
log.success(["成功录入快捷键", option]);
Qmsg.success("成功录入");
} else {
Qmsg.error(
`快捷键 ${shortCut.translateKeyboardValueToButtonText(
option
)} 已被 ${isUsedKey} 占用`
);
}
}
$btn.innerHTML = getButtonText();
}
);
result.attributes = {};
Reflect.set(result.attributes, ATTRIBUTE_INIT, () => {
return false;
});
return result;
};
const PanelLiveConfig = {
id: "panel-config-live",
title: "直播",
forms: [
{
text: "",
type: "forms",
forms: [
{
text: "功能",
type: "deepMenu",
forms: [
{
text: "功能",
type: "forms",
forms: [
UISelect(
"清晰度",
"live-chooseQuality",
"auto",
(() => {
return Object.keys(VideoQualityMap).map((key) => {
let item = VideoQualityMap[key];
return {
value: key,
text: item.label
};
});
})(),
void 0,
"自行选择清晰度"
),
UISwitch(
"解锁画质选择",
"live-unlockImageQuality",
true,
void 0,
"未登录的情况下选择原画实际上是未登录的情况下最高选择的画质"
),
UISwitch(
"自动进入网页全屏",
"live-autoEnterElementFullScreen",
false,
void 0,
"网页加载完毕后自动点击网页全屏按钮进入全屏"
),
UISwitch(
"监听并关闭【长时间无操作,已暂停播放】弹窗",
"live-waitToRemovePauseDialog",
true,
void 0,
"自动监听并检测弹窗"
),
UISwitch(
"禁止自动播放",
"live-pauseVideo",
false,
void 0,
"暂停直播播放"
),
UISwitch(
"解析直播信息",
"live-parsePlayerInstance",
false,
void 0,
"开启后将在油猴菜单中新增菜单【⚙ PlayerInstance】,可解析当前的直播信息"
),
UISwitch(
"禁用双击点赞",
"dy-live-disableDoubleClickLike",
false,
void 0,
"禁止直播视频区域双击点赞"
)
]
},
{
text: "视频区域背景色",
type: "forms",
forms: [
UISwitch(
"启用",
"live-bgColor-enable",
false,
void 0,
"自定义视频背景色"
),
{
type: "own",
attributes: {
"data-key": "live-changeBackgroundColor",
"data-default-value": "#000000"
},
getLiElementCallBack(liElement) {
let $left = domUtils.createElement("div", {
className: "pops-panel-item-left-text",
innerHTML: `
视频背景颜色
自定义视频背景颜色,包括评论区
`
});
let $right = domUtils.createElement("div", {
className: "pops-panel-item-right",
innerHTML: `
`
});
let $color = $right.querySelector(
".pops-color-choose"
);
$color.value = PopsPanel.getValue(
"live-changeBackgroundColor"
);
let $style = domUtils.createElement("style");
domUtils.append(document.head, $style);
domUtils.on(
$color,
["input", "propertychange"],
(event) => {
log.info("选择颜色:" + $color.value);
$style.innerHTML = `
div[id^="living_room_player_container"] > div,
#chatroom > div{
background: ${$color.value};
}
`;
PopsPanel.setValue(
"live-changeBackgroundColor",
$color.value
);
}
);
liElement.appendChild($left);
liElement.appendChild($right);
return liElement;
}
}
]
}
]
},
{
text: "过滤-弹幕",
type: "deepMenu",
forms: [
{
text: "",
type: "forms",
forms: [
UISwitch(
"启用",
"live-danmu-shield-rule-enable",
false,
void 0,
"启用自定义的弹幕过滤规则"
),
{
type: "own",
getLiElementCallBack(liElement) {
let textareaDiv = domUtils.createElement(
"div",
{
className: "pops-panel-textarea",
innerHTML: ``
},
{
style: "width: 100%;"
}
);
let textarea = textareaDiv.querySelector(
"textarea"
);
textarea.value = DouYinDanmuFilter.get();
domUtils.on(
textarea,
["input", "propertychange"],
utils.debounce(function() {
DouYinDanmuFilter.set(textarea.value);
}, 200)
);
liElement.appendChild(textareaDiv);
return liElement;
}
}
]
}
]
},
{
text: "自定义快捷键",
type: "deepMenu",
forms: [
{
text: "",
type: "forms",
forms: [
UIButtonShortCut(
"【屏蔽】聊天室",
"",
"dy-live-block-chatroom",
void 0,
"点击录入快捷键",
void 0,
DouYinLiveShortCut.shortCut
),
UIButtonShortCut(
"【屏蔽】礼物特效",
"",
"dy-live-shieldGiftEffects",
void 0,
"点击录入快捷键",
void 0,
DouYinLiveShortCut.shortCut
)
]
}
]
},
{
type: "deepMenu",
text: "快捷键禁用",
afterEnterDeepMenuCallBack: AutoOpenOrClose.afterEnterDeepMenuCallBack,
forms: [
{
type: "forms",
text: AutoOpenOrClose.text,
forms: [
UISwitch("刷新", "dy-live-refresh", false, void 0, "E"),
UISwitch(
"屏幕旋转",
"dy-live-screenRotation",
false,
void 0,
"D"
),
UISwitch(
"开启小窗模式",
"dy-live-enableSmallWindowMode",
false,
void 0,
"U"
)
]
}
]
}
]
},
{
text: "",
type: "forms",
forms: [
{
text: "屏蔽-视频区域内",
type: "deepMenu",
afterEnterDeepMenuCallBack: AutoOpenOrClose.afterEnterDeepMenuCallBack,
forms: [
{
text: AutoOpenOrClose.text,
type: "forms",
forms: [
UISwitch(
"【屏蔽】顶栏信息",
"live-shieldTopToolBarInfo",
false,
void 0,
"屏蔽元素,包括直播作者、右侧的礼物展馆"
),
UISwitch(
"【屏蔽】底部的礼物栏",
"live-shieldGiftColumn",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】礼物特效",
"live-shieldGiftEffects",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】弹幕",
"live-shieldDanmuku",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】小黄车",
"live-shielYellowCar",
false,
void 0,
"屏蔽元素"
)
]
}
]
},
{
text: "屏蔽-聊天室",
type: "deepMenu",
afterEnterDeepMenuCallBack: AutoOpenOrClose.afterEnterDeepMenuCallBack,
forms: [
{
text: AutoOpenOrClose.text,
type: "forms",
forms: [
UISwitch(
"【屏蔽】聊天室",
"live-shieldChatRoom",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】贵宾席",
"live-shielChatRoomVipSeats",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】用户等级图标",
"dy-live-shieldUserLevelIcon",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】VIP图标",
"dy-live-shieldUserVIPIcon",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】粉丝牌",
"dy-live-shieldUserFansIcon",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】信息播报",
"dy-live-shieldMessage",
false,
void 0,
"底部滚动播报的的xxx来了,xxx给主播点赞"
)
]
}
]
}
]
}
]
};
const MobileCSS$1 = '/* 去除顶部的padding距离 */\r\n#douyin-right-container {\r\n padding-top: 0;\r\n}\r\n/* 放大放大顶部的综合、视频、用户等header的宽度 */\r\n#search-content-area > div > div:nth-child(1) > div:nth-child(1) {\r\n width: 100vw;\r\n}\r\n/* 放大顶部的综合、视频、用户等header */\r\n#search-content-area > div > div:nth-child(1) > div:nth-child(1) > div {\r\n transform: scale(0.8);\r\n}\r\n/* 视频宽度 */\r\nul[data-e2e="scroll-list"] {\r\n padding: 0px 10px;\r\n}\r\n#sliderVideo {\r\n width: -webkit-fill-available;\r\n}\r\n/* 距离是顶部导航栏的高度 */\r\n#search-content-area {\r\n margin-top: 65px;\r\n}\r\n/* 调整视频列表的宽度 */\r\n@media screen and (max-width: 550px) {\r\n #sliderVideo {\r\n width: 100%;\r\n }\r\n /* 调整顶部搜索框的宽度 */\r\n #component-header\r\n div[data-click="doubleClick"]\r\n > div[data-click="doubleClick"]\r\n > div:has(input[data-e2e="searchbar-input"]) {\r\n width: -webkit-fill-available;\r\n padding-right: 0;\r\n }\r\n}\r\n';
const DouYinSearchHideElement = {
init() {
PopsPanel.execMenuOnce("douyin-search-shieldReleatedSearches", () => {
return this.shieldReleatedSearches();
});
},
/**
* 【屏蔽】相关搜索
*/
shieldReleatedSearches() {
log.info("【屏蔽】相关搜索");
return [
DouYinUtils.addBlockCSS("#search-content-area > div > div:nth-child(2)"),
addStyle(
/*css*/
`
#search-content-area > div > div:nth-child(1) > div:nth-child(1){
width: 100vw;
}`
)
];
}
};
const DouYinElement = {
/**
* 观察 #slidelist的加载每条视频
* @param callback
*/
watchVideDataListChange(callback) {
let $os = null;
domUtils.ready(() => {
utils.waitAnyNode([
"#slidelist",
// 搜索页面的↓搜索结果列表
'#search-content-area ul[data-e2e="scroll-list"]'
]).then(($ele) => {
log.info(`启用观察器观察加载的视频`);
utils.mutationObserver($ele, {
config: {
childList: true,
subtree: true
},
callback: (mutations, observer) => {
if (!$os) {
$os = this.getOSElement();
}
if (!$os) {
log.error("watchVideDataListChange:获取osElement失败");
return;
}
callback($os, observer);
},
immediate: true
});
});
});
},
getOSElement() {
return document.querySelector("#root div[class*='-os']") || document.querySelector("#douyin-right-container");
}
};
class DouYinVideoFilter {
constructor(config) {
/** 存储的键 */
__publicField(this, "key");
__publicField(this, "$data", {
__rule: null,
/**
* 解析出的规则
*/
get rule() {
if (this.__rule == null) {
this.__rule = new utils.Dictionary();
}
return this.__rule;
},
/**
* 多组规则
*/
moreRule: []
});
__publicField(this, "$flag", {
/** 是否屏蔽在直播 */
isBlockLiveVideo: false,
/** 是否屏蔽广告 */
isBlockAdsVideo: false
});
this.key = config.key;
this.$flag.isBlockLiveVideo = Boolean(config.isBlockLiveVideo);
this.$flag.isBlockAdsVideo = Boolean(config.isBlockAdsVideo);
this.initLocalRule();
}
/**
* 根据视频信息,判断是否需要屏蔽
*/
checkFilterWithRule(details) {
if (details.videoInfoValue == null) {
return false;
}
if (details.ruleValue == null) {
return false;
}
if (typeof details.videoInfoValue === "string") {
if (Boolean(details.videoInfoValue.match(details.ruleValue))) {
return true;
}
} else if (typeof details.videoInfoValue === "object" && Array.isArray(details.videoInfoValue)) {
let findValue = details.videoInfoValue.find(
(awemeInfoDictValue) => Boolean(awemeInfoDictValue.match(details.ruleValue))
);
if (findValue) {
return true;
}
} else if (typeof details.videoInfoValue === "number" && typeof details.ruleValue === "string") {
let compareNumberMatch = details.ruleValue.match(/(\d+)/);
if (!compareNumberMatch) {
log.warn(["过滤器-解析比较大小的数字失败: ", details]);
return false;
}
let compareNumber = Number(compareNumberMatch[1]);
if (details.ruleValue.startsWith(">")) {
if (details.ruleValue.startsWith(">=") && details.videoInfoValue >= compareNumber) {
return true;
} else if (details.videoInfoValue > compareNumber) {
return true;
}
} else if (details.ruleValue.startsWith("<")) {
if (details.ruleValue.startsWith("<=") && details.videoInfoValue <= compareNumber) {
return true;
} else if (details.videoInfoValue < compareNumber) {
return true;
}
} else if (details.ruleKey.startsWith("=")) {
if (details.videoInfoValue === compareNumber) {
return true;
}
} else {
log.warn(["过滤器-自定义屏蔽-未经允许的比较符号: ", details]);
return false;
}
}
return false;
}
/**
* 检测视频是否可以屏蔽,可以屏蔽返回true
* @param awemeInfo 视频信息结构
*/
checkAwemeInfoIsFilter(awemeInfo) {
let awemeInfoTagDict = this.getAwemeInfoDictData(awemeInfo, true);
let flag = false;
if (!flag) {
if (this.$flag.isBlockLiveVideo && awemeInfoTagDict.isLive) {
log.success("过滤器-屏蔽直播");
flag = true;
}
}
if (!flag) {
if (this.$flag.isBlockAdsVideo && awemeInfoTagDict.isAds) {
log.success("过滤器-屏蔽广告");
flag = true;
}
}
if (!flag) {
for (const [ruleKey, ruleValue] of this.$data.rule.entries()) {
if (!Reflect.has(awemeInfoTagDict, ruleKey)) {
continue;
}
let tagKey = ruleKey;
let tagValue = awemeInfoTagDict[tagKey];
let details = {
videoInfoKey: tagKey,
videoInfoValue: tagValue,
ruleKey,
ruleValue
};
let checkFlag = this.checkFilterWithRule(details);
if (checkFlag) {
flag = true;
log.success(["过滤器-自定义屏蔽: ", details]);
break;
}
}
}
if (!flag) {
for (const rule of this.$data.moreRule) {
let moreRuleFlag = true;
for (const [ruleKey, ruleValue] of Object.entries(rule)) {
if (!Reflect.has(awemeInfoTagDict, ruleKey)) {
moreRuleFlag = false;
break;
}
let tagKey = ruleKey;
let tagValue = awemeInfoTagDict[tagKey];
let details = {
videoInfoKey: tagKey,
videoInfoValue: tagValue,
ruleKey,
ruleValue
};
let checkFlag = this.checkFilterWithRule(details);
if (!checkFlag) {
moreRuleFlag = false;
break;
}
}
if (moreRuleFlag) {
flag = true;
log.success([
"多组过滤器-自定义屏蔽: ",
rule,
this.getAwemeInfoDictData(awemeInfo)
]);
break;
}
}
}
return flag;
}
/**
* 解析awemeInfo转为规则过滤的字典
* @param awemeInfo
* @param showLog 是否显示日志输出
*/
getAwemeInfoDictData(awemeInfo, showLog = false) {
var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
let nickname = (_b = (_a2 = awemeInfo == null ? void 0 : awemeInfo["authorInfo"]) == null ? void 0 : _a2["nickname"]) == null ? void 0 : _b.toString();
let uid = (_d = (_c = awemeInfo == null ? void 0 : awemeInfo["authorInfo"]) == null ? void 0 : _c["uid"]) == null ? void 0 : _d.toString();
let desc = (_e = awemeInfo == null ? void 0 : awemeInfo["desc"]) == null ? void 0 : _e.toString();
let collectCount = (_f = awemeInfo == null ? void 0 : awemeInfo["stats"]) == null ? void 0 : _f["collectCount"];
let commentCount = (_g = awemeInfo == null ? void 0 : awemeInfo["stats"]) == null ? void 0 : _g["commentCount"];
let diggCount = (_h = awemeInfo == null ? void 0 : awemeInfo["stats"]) == null ? void 0 : _h["diggCount"];
let shareCount = (_i = awemeInfo == null ? void 0 : awemeInfo["stats"]) == null ? void 0 : _i["shareCount"];
let textExtra = [];
let isLive = false;
let isAds = false;
if (typeof (awemeInfo == null ? void 0 : awemeInfo["textExtra"]) === "object" && Array.isArray(awemeInfo == null ? void 0 : awemeInfo["textExtra"])) {
(_j = awemeInfo == null ? void 0 : awemeInfo["textExtra"]) == null ? void 0 : _j.forEach((item) => {
textExtra.push(item["hashtagName"]);
});
}
let videoTag = [];
if (typeof (awemeInfo == null ? void 0 : awemeInfo["videoTag"]) === "object" && Array.isArray(awemeInfo == null ? void 0 : awemeInfo["videoTag"])) {
awemeInfo == null ? void 0 : awemeInfo["videoTag"].forEach((item) => {
videoTag.push(item["tagName"]);
});
}
if (typeof awemeInfo["cellRoom"] === "object") {
isLive = true;
if (showLog) {
log.success("直播间:cellRoom is not null");
}
}
if (awemeInfo["isAds"]) {
isAds = true;
if (showLog) {
log.success("广告:isAds is true");
}
} else if (typeof awemeInfo["rawAdData"] === "string" && utils.isNotNull(awemeInfo["rawAdData"])) {
isAds = true;
if (showLog) {
log.success("广告:rawAdData is not null");
}
} else if ((_l = (_k = awemeInfo["webRawData"]) == null ? void 0 : _k["brandAd"]) == null ? void 0 : _l["is_ad"]) {
isAds = true;
if (showLog) {
log.success("广告:webRawData.brandAd.is_ad is true");
}
} else if ((_n = (_m = awemeInfo["webRawData"]) == null ? void 0 : _m["insertInfo"]) == null ? void 0 : _n["is_ad"]) {
isAds = true;
if (showLog) {
log.success("广告:webRawData.insertInfo.is_ad is true");
}
}
return {
nickname,
uid,
desc,
textExtra,
videoTag,
collectCount,
commentCount,
diggCount,
shareCount,
isLive,
isAds
};
}
/**
* 解析并初始化自定义规则
*/
initLocalRule() {
let localRule = this.get().trim();
let localRuleSplit = localRule.split("\n");
this.$data.rule.clear();
this.$data.moreRule = [];
localRuleSplit.forEach((item) => {
if (utils.isNull(item)) {
return;
}
let trimItem = item.trim();
let itemSplit = trimItem.split("##");
if (itemSplit.length < 2) {
return;
}
let keyName = itemSplit[0];
itemSplit.shift();
if (keyName === "more") {
let keyValue = itemSplit.join("##");
let moreItemSplit = keyValue.split("##");
let moreRule = {};
for (let index = 0; index < moreItemSplit.length; index += 2) {
let ruleKey = moreItemSplit[index];
let ruleValue = moreItemSplit[index + 1];
try {
if (ruleValue.match(/^>|<|=/g)) {
Reflect.set(moreRule, ruleKey, ruleValue.trim());
} else {
let regExpKeyValue = new RegExp(ruleValue, "g");
Reflect.set(moreRule, ruleKey, regExpKeyValue);
}
} catch (error) {
log.error(["多组-自定义视频过滤规则-正则解析错误:" + error]);
log.error("多组-错误的规则:" + item);
}
}
this.$data.moreRule.push(moreRule);
} else {
let keyValue = itemSplit.join("");
try {
if (keyValue.match(/^>|<|=/g)) {
this.$data.rule.set(keyName, keyValue.trim());
} else {
let regExpKeyValue = new RegExp(keyValue, "g");
this.$data.rule.set(keyName, regExpKeyValue);
}
} catch (error) {
log.error(["自定义视频过滤规则-正则解析错误:" + error]);
log.error("错误的规则:" + item);
}
}
});
}
/**
* 更新规则
*/
updateRule(ruleText) {
ruleText = ruleText.trim();
if (ruleText == "") {
return;
}
let localRule = this.get().trim();
localRule = localRule + "\n" + ruleText;
this.set(localRule);
this.initLocalRule();
}
set(value) {
_GM_setValue(this.key, value);
}
get() {
return _GM_getValue(this.key, "");
}
/**
* 清空存储的值
*/
clear() {
this.set("");
}
/**
* 销毁存储的值
*/
destory() {
_GM_deleteValue(this.key);
}
}
const DouYinSearchFilter = {
__videoFilter: null,
get videoFilter() {
if (this.__videoFilter == null) {
const KEY2 = "douyin-search-shield-rule";
const isBlockLiveVideo = PopsPanel.getValue(
"search-shieldVideo-live"
);
const isBlockAdsVideo = PopsPanel.getValue(
"search-shieldVideo-ads"
);
this.__videoFilter = new DouYinVideoFilter({
key: KEY2,
isBlockLiveVideo,
isBlockAdsVideo
});
}
return this.__videoFilter;
},
init() {
DouYinElement.watchVideDataListChange(
utils.debounce((osElement) => {
var _a2, _b, _c, _d;
let $searchContentAreaScrollList = Array.from(
document.querySelectorAll(
'#search-content-area ul[data-e2e="scroll-list"] li'
)
);
if (!$searchContentAreaScrollList.length) {
log.error("未获取到搜索视频列表元素");
return;
}
for (let index = 0; index < $searchContentAreaScrollList.length; index++) {
const $searchContentAreaScrollItem = $searchContentAreaScrollList[index];
let reactProps = (_a2 = utils.getReactObj(
$searchContentAreaScrollItem
)) == null ? void 0 : _a2.reactProps;
if (reactProps == null) {
log.error([
"元素上不存在reactProps属性",
$searchContentAreaScrollItem
]);
return;
}
let awemeInfo = (_d = (_c = (_b = reactProps == null ? void 0 : reactProps.children) == null ? void 0 : _b.props) == null ? void 0 : _c.data) == null ? void 0 : _d.awemeInfo;
if (awemeInfo == null) {
log.error([
"元素上不存在awemeInfo属性",
$searchContentAreaScrollItem
]);
return;
}
let flag = this.videoFilter.checkAwemeInfoIsFilter(awemeInfo);
if (flag) {
$searchContentAreaScrollItem.remove();
index--;
}
}
}, 50)
);
},
get() {
return this.videoFilter.get();
},
set(value) {
this.videoFilter.set(value);
}
};
const DouYinSearch = {
init() {
DouYinSearchHideElement.init();
PopsPanel.execMenuOnce("search-shieldVideo", () => {
DouYinSearchFilter.init();
});
PopsPanel.execMenuOnce("dy-search-disableClickToEnterFullScreen", () => {
this.disableClickToEnterFullScreen();
});
PopsPanel.execMenuOnce(
"live-setSearchResultFilterWithVideoStyle",
(value) => {
return this.setSearchResultFilterWithVideoStyle(value);
}
);
},
/**
* 手机模式
* (由通用统一调用,勿放在本函数的init内)
*/
mobileMode() {
log.info("搜索-手机模式");
let result = [];
result.push(addStyle(MobileCSS$1));
result.push(
addStyle(
/*css*/
`
@media screen and (max-width: 550px){
div#search-body-container {
display: flex;
}
div#search-body-container #component-Navigation {
flex: 0;
}
div#search-body-container #douyin-right-container {
flex: 1 auto;
}
div#search-body-container #douyin-right-container #search-content-area > div {
width: 100% !important;
}
div#search-body-container #douyin-right-container #search-content-area > div > div > div {
width: 100% !important;
margin-left: 0px;
margin-right: 0px;
padding-left: 0px;
padding-right: 0px;
}
/* 上面的搜索结果筛选 */
#search-content-area > div >div> div:first-child > div:first-child > div:last-child{
overflow: auto;
text-wrap: nowrap;
height: auto;
}
/* 视频右侧的TA的作品↓ */
#searchSideCard{
width: unset !important;
}
#searchSideCard > div{
padding: 0px !important;
}
#searchSideCard > div:has(>div+svg),
#searchSideCard ul[data-e2e="scroll-list"]{
padding: 0px 10px !important;
}
#searchSideCard ul[data-e2e="scroll-list"] .video-playing-item > div{
width: auto;
}
/* 视频右侧的TA的作品↑ */
/* 悬浮的筛选 */
#douyin-right-container #douyin-header{
background-color: var(--color-bg-b0);
}
xg-right-grid{
margin: auto !important;
}
}
`
)
);
utils.waitNode("#relatedVideoCard").then(($relatedVideoCard) => {
log.info("评论区展开的className:" + $relatedVideoCard.className);
result.push(
addStyle(
/*css*/
`
html[data-vertical-screen]
#sliderVideo[data-e2e="feed-active-video"]
#videoSideBar:has(#relatedVideoCard[class="${$relatedVideoCard.className}"]) {
width: 100vw !important;
}`
)
);
});
},
/**
* 禁止点击视频区域进入全屏
*/
disableClickToEnterFullScreen() {
log.info("搜索-禁止点击视频区域进入全屏");
domUtils.on(
document,
"click",
".focusPanel",
(event) => {
var _a2;
utils.preventEvent(event);
let $click = event.target;
let $parent = (_a2 = $click.parentElement) == null ? void 0 : _a2.parentElement;
let $video = $parent.querySelector("video");
if ($video) {
if ($video.paused) {
log.info(".focusPanel:播放视频");
$video.play();
} else {
log.info(".focusPanel:视频暂停");
$video.pause();
}
} else {
log.error(".focusPanel未找到