// ==UserScript==
// @name 抖音优化
// @namespace https://github.com/WhiteSevs/TamperMonkeyScript
// @version 2024.7.16
// @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/*
// @require https://update.greasyfork.icu/scripts/494167/1376186/CoverUMD.js
// @require https://fastly.jsdelivr.net/npm/qmsg@1.2.1/dist/index.umd.js
// @require https://fastly.jsdelivr.net/npm/@whitesev/utils@1.6.1/dist/index.umd.js
// @require https://fastly.jsdelivr.net/npm/@whitesev/domutils@1.1.2/dist/index.umd.js
// @require https://fastly.jsdelivr.net/npm/@whitesev/pops@1.2.4/dist/index.umd.js
// @grant GM_addStyle
// @grant GM_deleteValue
// @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 __typeError = (msg) => {
throw TypeError(msg);
};
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value);
var _key, _isWaitPress, _a;
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_KEY = "data-key";
const ATTRIBUTE_DEFAULT_VALUE = "data-default-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 PanelCommonConfig = {
id: "panel-config-common",
title: "通用",
forms: [
{
text: "",
type: "forms",
forms: [
{
text: "功能",
type: "deepMenu",
forms: [
{
text: "",
type: "forms",
forms: [
UISwitch(
"debug模式",
"debug",
true,
void 0,
"移除抖音的开发者模式检测"
),
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】"
)
]
}
]
},
{
text: "Url重定向",
type: "deepMenu",
forms: [
{
text: "",
type: "forms",
forms: [
UISwitch(
"重定向/home",
"douyin-redirect-url-home-to-root",
false,
void 0,
"/home => /"
)
]
}
]
},
{
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弹出的顺序"
)
]
}
]
}
]
},
{
text: "",
type: "forms",
forms: [
{
text: "屏蔽-通用",
type: "deepMenu",
forms: [
{
text: "",
type: "forms",
forms: [
UISwitch(
"【屏蔽】登录弹窗",
"watchLoginDialogToClose",
true,
void 0,
"屏蔽元素且自动等待元素出现并关闭登录弹窗"
),
UISwitch(
"【屏蔽】底部?按钮",
"shieldBottomQuestionButton",
true,
void 0,
"屏蔽元素"
)
]
}
]
},
{
text: "屏蔽-主框架",
type: "deepMenu",
forms: [
{
text: "",
type: "forms",
forms: [
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,
"屏蔽元素"
),
UISwitch(
"【屏蔽】左侧导航栏",
"shieldLeftNavigator",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】顶部导航栏",
"shieldTopNavigator",
false,
void 0,
"屏蔽元素"
)
]
}
]
},
{
text: "屏蔽-搜索",
type: "deepMenu",
forms: [
{
text: "",
type: "forms",
forms: [
UISwitch(
"【屏蔽】搜索框",
"shieldSearch",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】搜索框的提示",
"shieldSearchPlaceholder",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】猜你想搜",
"shieldSearchGuessYouWantToSearch",
false,
void 0,
"屏蔽元素"
),
UISwitch(
"【屏蔽】抖音热点",
"shieldSearchTiktokHotspot",
false,
void 0,
"屏蔽元素"
)
]
}
]
}
]
}
]
};
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 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 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;}`
);
}
};
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(
'#living_room_player_container .basicPlayer > div:has(div[data-e2e="yellowCart-container"])'
)
];
}
};
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();
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) => {
this.changeBackgroundColor(value);
});
});
},
/**
* 自动进入网页全屏
*/
autoEnterElementFullScreen() {
log.info("自动进入网页全屏");
utils.waitNode(
'xg-icon[classname] > div > div:has(path[d="M9.75 8.5a2 2 0 0 0-2 2v11a2 2 0 0 0 2 2h12.5a2 2 0 0 0 2-2v-11a2 2 0 0 0-2-2H9.75zM15 11.25h-3.75a1 1 0 0 0-1 1V16h2v-2.75H15v-2zm5.75 9.5H17v-2h2.75V16h2v3.75a1 1 0 0 1-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;
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";
},
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 deepFindFunction(target, propName, funcName) {
let targetValue = target[propName];
if (typeof targetValue === "object") {
if (typeof targetValue[funcName] === "function") {
return targetValue[funcName];
} else {
return deepFindFunction(targetValue, propName, funcName);
}
}
}
function checkDialogToClose($ele, from) {
var _a2, _b, _c, _d, _e, _f;
if ($ele.innerText.includes("长时间无操作") && $ele.innerText.includes("暂停播放")) {
log.info(`检测${from}:出现【长时间无操作,已暂停播放】弹窗`);
Qmsg.info(`检测${from}:出现【长时间无操作,已暂停播放】弹窗`);
let $rect = utils.getReactObj($ele);
if (typeof $rect.reactContainer === "object") {
let onClose = deepFindFunction($rect.reactContainer, "child", "onClose") || ((_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 onClose === "function") {
log.success(`检测${from}:调用onClose关闭弹窗`);
Qmsg.success("调用onClose关闭弹窗");
onClose();
}
}
}
}
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("修改视频背景颜色");
addStyle(`
#living_room_player_container > div,
#chatroom > div{
background: ${color};
}
`);
}
};
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,
"暂停直播播放"
)
]
},
{
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 = `
#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: "forms",
forms: [
{
text: "屏蔽-视频区域内",
type: "deepMenu",
forms: [
{
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",
forms: [
{
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 DouYinElement = {
/**
* 观察 #slidelist的加载每条视频
* @param callback
*/
watchVideDataListChange(callback) {
let $os = null;
domUtils.ready(() => {
utils.waitNode("#slidelist").then(($slidelist) => {
utils.mutationObserver($slidelist, {
config: {
childList: true,
subtree: true
},
callback: () => {
if (!$os) {
$os = this.getOSElement();
}
if (!$os) {
log.error("watchVideDataListChange:获取osElement失败");
return;
}
callback($os);
}
});
});
});
},
getOSElement() {
return document.querySelector("#root div[class*='-os']") || document.querySelector("#douyin-right-container");
}
};
const DouYinVideoFilter = {
key: "douyin-shield-rule",
$data: {
__rule: null,
/**
* 解析出的规则
*/
get rule() {
if (DouYinVideoFilter.$data.__rule == null) {
DouYinVideoFilter.$data.__rule = new utils.Dictionary();
}
return DouYinVideoFilter.$data.__rule;
},
/** 是否是首次加载视频 */
isFirstLoad: true
},
/**
* authorInfo.nickname:string 作者
* authorInfo.uid:string 作者id
* desc:string 视频描述
* shareInfo.shareLinkDesc:string xxx复制链接到抖音App的识别码
* shareInfo.shareUrl:string 网页直接看的视频链接
* textExtra[{hashtagName: ""},...] 话题
* videoTag[{tagName: ""},...] 视频标签
*/
init() {
this.parseRule();
log.info(["当前自定义视频拦截规则: ", this.$data.rule.getItems()]);
let firstLoadEndVideoId = null;
DouYinElement.watchVideDataListChange(
utils.debounce((osElement) => {
var _a2, _b, _c, _d, _e;
let $videoList = document.querySelector(
'#slidelist div[data-e2e="slideList"]'
);
if (!$videoList) {
log.error("未获取到视频列表元素");
return;
}
let reactFiber = (_a2 = utils.getReactObj($videoList)) == null ? void 0 : _a2.reactFiber;
if (reactFiber == null) {
log.error(["元素上不存在reactFiber属性", $videoList]);
return;
}
let videoDataList = reactFiber == null ? void 0 : reactFiber.return.memoizedProps.data;
if (!videoDataList.length) {
return;
}
if (this.$data.isFirstLoad) {
let endVideo = videoDataList[videoDataList.length - 1];
if (firstLoadEndVideoId == null) {
firstLoadEndVideoId = endVideo.awemeId;
}
if (firstLoadEndVideoId === endVideo.awemeId) {
return;
}
this.$data.isFirstLoad = false;
}
for (let index = 0; index < videoDataList.length; index++) {
let videoData = videoDataList[index];
let videoInfoTag = this.getVideoInfoTagMap(videoData);
let flag = false;
if (!flag) {
if (typeof videoData["cellRoom"] === "object" && PopsPanel.getValue("shieldVideo-live")) {
log.success("屏蔽直播: because cellRoom is not null");
flag = true;
}
}
if (!flag) {
if (PopsPanel.getValue("shieldVideo-ads")) {
if (videoData["isAds"]) {
flag = true;
log.success("屏蔽广告: because isAds is true");
} else if (typeof videoData["rawAdData"] === "string" && utils.isNotNull(videoData["rawAdData"])) {
flag = true;
log.success("屏蔽广告: because rawAdData is not null");
} else if ((_c = (_b = videoData["webRawData"]) == null ? void 0 : _b["brandAd"]) == null ? void 0 : _c["is_ad"]) {
flag = true;
log.success(
"屏蔽广告: because webRawData.brandAd.is_ad is true"
);
} else if ((_e = (_d = videoData["webRawData"]) == null ? void 0 : _d["insertInfo"]) == null ? void 0 : _e["is_ad"]) {
flag = true;
log.success(
"屏蔽广告: because webRawData.insertInfo.is_ad is true"
);
}
}
}
if (!flag) {
for (const [ruleKey, ruleValue] of this.$data.rule.entries()) {
if (!(ruleKey in videoInfoTag)) {
continue;
}
let tagValue = videoInfoTag[ruleKey];
if (tagValue != null) {
if (typeof tagValue === "string") {
flag = Boolean(tagValue.match(ruleValue));
if (flag) {
log.success([
"自定义屏蔽: " + ruleKey + " " + ruleValue,
videoInfoTag
]);
break;
}
} else if (typeof tagValue === "object" && Array.isArray(tagValue)) {
let findValue = tagValue.find(
(tagValueItem) => Boolean(tagValueItem.match(ruleValue))
);
if (findValue) {
flag = true;
log.success([
"自定义屏蔽: " + ruleKey + " " + ruleValue,
videoInfoTag
]);
break;
}
}
}
}
}
if (flag) {
videoDataList.splice(index, 1);
index--;
}
}
}, 50)
);
},
/**
* 获取视频各个信息的字典
*/
getVideoInfoTagMap(data) {
var _a2, _b, _c, _d, _e, _f;
let nickname = (_b = (_a2 = data == null ? void 0 : data["authorInfo"]) == null ? void 0 : _a2["nickname"]) == null ? void 0 : _b.toString();
let uid = (_d = (_c = data == null ? void 0 : data["authorInfo"]) == null ? void 0 : _c["uid"]) == null ? void 0 : _d.toString();
let desc = (_e = data == null ? void 0 : data["desc"]) == null ? void 0 : _e.toString();
let textExtra = [];
if (typeof (data == null ? void 0 : data["textExtra"]) === "object" && Array.isArray(data == null ? void 0 : data["textExtra"])) {
(_f = data == null ? void 0 : data["textExtra"]) == null ? void 0 : _f.forEach((item) => {
textExtra.push(item["hashtagName"]);
});
}
let videoTag = [];
if (typeof (data == null ? void 0 : data["videoTag"]) === "object" && Array.isArray(data == null ? void 0 : data["videoTag"])) {
data == null ? void 0 : data["videoTag"].forEach((item) => {
videoTag.push(item["tagName"]);
});
}
return {
nickname,
uid,
desc,
textExtra,
videoTag
};
},
/**
* 解析规则
*/
parseRule() {
let localRule = this.get().trim();
let localRuleSplit = localRule.split("\n");
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();
let keyValue = itemSplit.join("");
try {
let regExpKeyValue = new RegExp(keyValue, "g");
this.$data.rule.set(keyName, regExpKeyValue);
} catch (error) {
log.error(["自定义视频过滤规则-正则解析错误:" + error]);
log.error("错误的规则:" + item);
}
});
},
set(value) {
_GM_setValue(this.key, value);
},
get() {
return _GM_getValue(this.key, "");
}
};
const UIButton = function(text, description, buttonText, buttonIcon, buttonIsRightIcon, buttonIconIsLoading, buttonType, clickCallBack) {
let result = {
text,
type: "button",
description,
buttonIcon,
buttonIsRightIcon,
buttonIconIsLoading,
buttonType,
buttonText,
callback(event) {
if (typeof clickCallBack === "function") {
clickCallBack(event);
}
},
afterAddToUListCallBack: void 0
};
return result;
};
class ShortCut {
constructor(key) {
__privateAdd(this, _key, "short-cut");
__privateAdd(this, _isWaitPress, false);
if (typeof key === "string") {
__privateSet(this, _key, key);
}
}
getValue(key, defaultValue) {
let localValue = _GM_getValue(__privateGet(this, _key), []);
if (key) {
let findValue = localValue.find((item) => item.key === key);
return findValue ?? defaultValue;
} else {
return localValue;
}
}
/**
* 设置值
* @param key 键
*/
setValue(key, keyName, keyValue, ohterCodeList) {
let localValue = _GM_getValue(__privateGet(this, _key), []);
localValue.push({
key,
value: {
keyName,
keyValue,
ohterCodeList
}
});
_GM_setValue(__privateGet(this, _key), localValue);
}
/**
* 删除值
* @param key 键
*/
deleteValue(key) {
let result = false;
let localValue = _GM_getValue(__privateGet(this, _key), []);
let findValueIndex = localValue.findIndex((item) => item["key"] === key);
if (findValueIndex !== -1) {
localValue.splice(findValueIndex, 1);
result = true;
}
_GM_setValue(__privateGet(this, _key), localValue);
return result;
}
/**
* 获取快捷键显示的文字
* @param key
* @param defaultValue
*/
getShowText(key, defaultValue) {
let localValue = this.getValue(key);
if (localValue) {
let result = "";
localValue.value.ohterCodeList.forEach((ohterCodeKey) => {
if (localValue.key === key) {
result += utils.stringTitleToUpperCase(ohterCodeKey, true) + " + ";
}
});
result += localValue.value.keyName;
return result;
} else {
return defaultValue;
}
}
/**
* 录入快捷键
*/
inputShortCut(key, defaultValue, callback) {
let localValue = this.getValue(key) ?? defaultValue;
if (localValue === defaultValue) {
let loadingQmsg = Qmsg.loading("请按下快捷键...", {
showClose: true,
onClose() {
keyboardListener.removeListen();
}
});
__privateSet(this, _isWaitPress, true);
let keyboardListener = utils.listenKeyboard(
window,
"keyup",
(keyName, keyValue, ohterCodeList) => {
let shortcutJSONString = JSON.stringify({
keyName,
keyValue,
ohterCodeList
});
let allDetails = this.getValue();
for (let index = 0; index < allDetails.length; index++) {
if (shortcutJSONString === JSON.stringify(allDetails[index]["value"])) {
Qmsg.error(
`快捷键 ${this.getShowText(
allDetails[index]["key"],
keyName
)} 已被占用`
);
__privateSet(this, _isWaitPress, false);
loadingQmsg.close();
return;
}
}
this.setValue(key, keyName, keyValue, ohterCodeList);
if (typeof callback === "function") {
callback(this.getShowText(key, defaultValue));
}
__privateSet(this, _isWaitPress, false);
loadingQmsg.close();
}
);
} else {
this.deleteValue(key);
}
if (typeof callback === "function") {
callback(this.getShowText(key, defaultValue));
}
}
/**
* 初始化全局键盘监听
*/
initGlobalKeyboardListener(shortCutMap) {
let localValue = this.getValue();
if (!localValue.length) {
return;
}
utils.listenKeyboard(
window,
"keydown",
(keyName, keyValue, ohterCodeList) => {
if (__privateGet(this, _isWaitPress)) {
return;
}
localValue = this.getValue();
let findShortcutIndex = localValue.findIndex((item) => {
let itemValue = item["value"];
let tempValue = {
keyName,
keyValue,
ohterCodeList
};
if (JSON.stringify(itemValue) === JSON.stringify(tempValue)) {
return item;
}
});
if (findShortcutIndex != -1) {
let findShortcut = localValue[findShortcutIndex];
log.info(["调用快捷键", findShortcut]);
if (findShortcut.key in shortCutMap) {
shortCutMap[findShortcut.key].callback();
}
}
}
);
}
}
_key = new WeakMap();
_isWaitPress = new WeakMap();
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: 100dvw;\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: 100dvw;\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\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(`
#search-content-area > div > div:nth-child(1) > div:nth-child(1){
width: 100dvw;
}`)
];
}
};
const DouYinSearch = {
init() {
DouYinSearchHideElement.init();
PopsPanel.execMenuOnce("dy-search-disableClickToEnterFullScreen", () => {
this.disableClickToEnterFullScreen();
});
},
/**
* 手机模式
* (由通用统一调用,勿放在本函数的init内)
*/
mobileMode() {
log.info("搜索-手机模式");
addStyle(MobileCSS$1);
utils.waitNode("#relatedVideoCard").then(($relatedVideoCard) => {
log.info("评论区展开的className:" + $relatedVideoCard.className);
addStyle(`
html[data-vertical-screen]
#sliderVideo[data-e2e="feed-active-video"]
#videoSideBar:has(#relatedVideoCard[class="${$relatedVideoCard.className}"]) {
width: 100dvw !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未找到