// ==UserScript==
// @name 斗鱼自动发送弹幕、自定义清爽模式
// @namespace http://tampermonkey.net/
// @version 0.0.4
// @icon http://www.douyutv.com/favicon.ico
// @description 循环弹幕、自定义清爽模式
// @author H2P
// @compatible chrome
// @match *://*.douyu.com/0*
// @match *://*.douyu.com/1*
// @match *://*.douyu.com/2*
// @match *://*.douyu.com/3*
// @match *://*.douyu.com/4*
// @match *://*.douyu.com/5*
// @match *://*.douyu.com/6*
// @match *://*.douyu.com/7*
// @match *://*.douyu.com/8*
// @match *://*.douyu.com/9*
// @note 2020.04.26-V0.0.01 发送循环弹幕,设定自动保存
// @note 2020.04.26-V0.0.02 自定义清爽模式,目前只支持主播信息
// @note 2020.04.27-V0.0.03 优化清爽模式,支持导航栏
// @note 2020.04.27-V0.0.04 修复清爽模式自动保存 BUG
// @downloadURL https://update.greasyfork.icu/scripts/401994/%E6%96%97%E9%B1%BC%E8%87%AA%E5%8A%A8%E5%8F%91%E9%80%81%E5%BC%B9%E5%B9%95%E3%80%81%E8%87%AA%E5%AE%9A%E4%B9%89%E6%B8%85%E7%88%BD%E6%A8%A1%E5%BC%8F.user.js
// @updateURL https://update.greasyfork.icu/scripts/401994/%E6%96%97%E9%B1%BC%E8%87%AA%E5%8A%A8%E5%8F%91%E9%80%81%E5%BC%B9%E5%B9%95%E3%80%81%E8%87%AA%E5%AE%9A%E4%B9%89%E6%B8%85%E7%88%BD%E6%A8%A1%E5%BC%8F.meta.js
// ==/UserScript==
(() => {
// 抽奖倒计时:document.querySelector('div.LotteryDrawEnter div.LotteryDrawEnter-desc').textContent
const $H2P = function (xpath, one = true) {
if (one) { return document.querySelector(xpath); }
else { return document.querySelectorAll(xpath); }
}
window.onload = function () {
new Promise((resolve, reject) => {
// 先添加样式
let eleStyle = document.createElement('style');
eleStyle.innerHTML = `
button {
font-family: WeibeiSC-Bold, STKaiti;
outline: none;
cursor: pointer;
transition: all 0.8s ease;
}
button:active {
opacity: 0;
}
.h2p-div-borad {
position: fixed;
z-index: 9999;
bottom: 60%;
right: -322px;
width: 300px;
min-height: 100px;
height: auto;
padding: 10px;
border: 1px solid rgb(255, 145, 26);
border-right: 0;
border-radius: 10px 0 0 10px;
display: flex;
flex-flow: row wrap;
font-size: 14px;
font-family: WeibeiSC-Bold, STKaiti;
line-height: 15px;
background: #f8f8f8;
transition: all 1s ease;
}
.h2p-div-borad:hover {
right: 0px;
}
.h2p-left-out {
position: absolute;
top: 40%;
left: -16px;
width: 15px;
height: 80px;
border: 1px solid #ff9019;
border-right: 0;
border-radius: 15px 0 0 15px;
background-color: #f8f8f8;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
opacity: 1;
transition: opacity 1s ease-in;
}
.h2p-div-borad:hover .h2p-left-out{
opacity: 0;
transition: opacity 0s;
}
.h2p-nav-bottom {
width: 320px;
height: 27px;
margin: 10px -10px -10px;
border-top: 1px solid #d0d0d0;
border-radius: 0 0 0 15px;
}
.h2p-nav-bottom button {
width: 33.33%;
height: 100%;
border: none;
background: #f8f8f8;
transition: opacity 0.5s;
}
.h2p-nav-bottom button:nth-child(1) {
border-right: 1px solid #d0d0d0;
border-radius: 0 0 0 9px;
}
.h2p-nav-bottom button:nth-child(2) {
border-right: 1px solid #d0d0d0;
}
.h2p-nav-item-btn-selected {
background: #ffbb77!important;
}
.h2p-div-ceil {
width: 300px;
}
.h2p-flex-main-center {
display: flex;
flex-flow: row wrap;
justify-content: center;
}
.h2p-flex-main-start {
display: flex;
justify-content: flex-start;
}
.h2p-flex-main-end {
display: flex;
justify-content: flex-end;
}
.h2p-flex-cross-center {
display: flex;
align-items: center;
}
.h2p-item-100p {
width: 100%;
margin: 5px 0;
}
.h2p-item-50p {
width: 50%;
margin: 5px 0;
}
.h2p-item-33p {
width: 33.33%;
margin: 5px 0;
}
.h2p-item-25p {
width: 25%;
margin: 5px 0;
}
.h2p-item-hover {
background: #2299ff!important;
}
.h2p-item-selected {
background: #77bbff;
}
`;
document.head.append(eleStyle);
resolve();
})
.then(() => {
// 添加发送弹幕界面元素
let eleBoard = document.createElement('div');
eleBoard.id = 'h2p-div-borad';
eleBoard.className = 'h2p-div-borad';
eleBoard.innerHTML = `
<
`;
document.body.append(eleBoard);
})
.then(() => {
// 开始在界面上添加元素
initView_Chat();
initView_Clear();
})
.then(() => {
let nav = $H2P('div#div-nav-bottom');
nav.addEventListener('click', (event) => {
let target = event.target;
$H2P('div#h2p-div-borad > div.h2p-div-ceil', false).forEach(ele => { ele.style.display = 'none'; });
$H2P('div#div-nav-bottom button', false).forEach(ele => ele.classList.remove('h2p-nav-item-btn-selected'));
if (target.id === 'btn-chat') {
$H2P('button#btn-chat').classList.add('h2p-nav-item-btn-selected');
$H2P('div#h2p-div-chat').style.display = '';
} else if (target.id === 'btn-clear') {
$H2P('button#btn-clear').classList.add('h2p-nav-item-btn-selected');
$H2P('div#h2p-div-clear').style.display = '';
} else if (target.id === 'btn-config') {
$H2P('button#btn-config').classList.add('h2p-nav-item-btn-selected');
$H2P('div#h2p-div-config').style.display = '';
}
}, false);
})
.catch((error) => { console.log(error); })
}
// ========== ========== ========== ========== ========== ========== ==========
//
//
//
// 初始化弹幕模块
//
//
//
// ========== ========== ========== ========== ========== ========== ==========
const LSChat = 'h2p-DY-config-chat';
let config_chat = undefined;
let [Chat, INVL_SendMsg, INVL_ShowCD] = [undefined, undefined, undefined];
function initView_Chat () {
new Promise((resolve, reject) => {
// 先添加样式
let eleStyle = document.createElement('style');
eleStyle.innerHTML = `
.h2p-input-invl {
width: 23px;
min-height: 17px;
padding: 0 3px;
border: 1px solid #d0d0d0;
border-radius: 3px;
}
.h2p-ta-chat-loop {
width: 100%;
height: 60px;
padding: 0 4px;
border: 1px solid #d0d0d0;
border-radius: 5px;
resize: none;
}
.h2p-btn-send-chat {
width: 100%;
padding: 4px 0;
border: none;
border-radius: 5px;
background: #66ddcc;
cursor: pointer;
transition: all 0.5s
}
.h2p-btn-send-chat:hover {
background: #55ccaa;
}
.h2p-btn-send-chat span {
display: inline-block;
position: relative;
transition: all 0.5s
}
.h2p-btn-send-chat span:after {
content: '🔥';
position: absolute;
opacity: 0;
top: -2px;
right: -20px;
transition: 0.5s;
}
.h2p-btn-send-chat:hover span {
padding-right: 20px;
}
.h2p-btn-send-chat:hover span:after {
opacity: 1;
right: 0;
}
.h2p-btn-active {
background: #ffbb77!important;
}
`;
document.head.append(eleStyle);
resolve();
})
.then(() => {
// 添加发送弹幕界面元素
let eleChat = document.createElement('div');
eleChat.id = 'h2p-div-chat';
eleChat.className = 'h2p-flex-main-center h2p-div-ceil';
eleChat.style = 'order: 0;';
eleChat.innerHTML = `
间隔:
~
秒
`;
$H2P('div#h2p-div-borad').append(eleChat);
})
.then(() => {
// 给元素添加监听
let eleChat = $H2P('div#h2p-div-chat');
eleChat.addEventListener('click', (event) => {
let target = event.target;
if (target.id === 'input-chat-loop') {
config_chat.isLoop = target.checked;
}
localStorage.setItem(LSChat, JSON.stringify(config_chat));
}, false)
// 间隔最小值
let eleInvlStart = $H2P('input#input-invl-start');
eleInvlStart.addEventListener('input', () => { eleInvlStart.value = eleInvlStart.value.slice(0, 3); });
eleInvlStart.addEventListener('keyup', () => { eleInvlStart.value = eleInvlStart.value.replace(/[^\d]/g, ''); });
eleInvlStart.addEventListener('focusout', () => {
eleInvlStart.value = Math.max(eleInvlStart.value, 3);
config_chat.invlStart = eleInvlStart.value;
localStorage.setItem(LSChat, JSON.stringify(config_chat));
});
// 间隔最大值
let eleInvlEnd = $H2P('input#input-invl-end');
eleInvlEnd.addEventListener('input', () => { eleInvlEnd.value = eleInvlEnd.value.slice(0, 3); });
eleInvlEnd.addEventListener('keyup', () => { eleInvlEnd.value = eleInvlEnd.value.replace(/[^\d]/g, ''); });
eleInvlEnd.addEventListener('focusout', () => {
eleInvlEnd.value = Math.max(eleInvlEnd.value, Number(eleInvlStart.value) + 1, 4);
config_chat.invlEnd = eleInvlEnd.value;
localStorage.setItem(LSChat, JSON.stringify(config_chat));
});
let eleLoop = $H2P('textarea.h2p-ta-chat-loop');
eleLoop.addEventListener('focusout', () => {
if (eleLoop.value && eleLoop.value.replace(/\s/g, '')) {
config_chat.loopChat = eleLoop.value.split('\n');
localStorage.setItem(LSChat, JSON.stringify(config_chat));
}
});
let eleSend = $H2P('button#btn-chat-send');
eleSend.addEventListener('click', () => {
config_chat.isSend = !config_chat.isSend;
if (config_chat.isSend) {
setINVL_SendMsg();
eleSend.classList.add('h2p-btn-active');
eleSend.firstElementChild.textContent = "发送中";
}
else {
window.clearTimeout(INVL_SendMsg);
INVL_SendMsg = undefined;
window.clearInterval(INVL_ShowCD);
$H2P('input#input-invl').value = '';
INVL_ShowCD = undefined;
eleSend.classList.remove('h2p-btn-active');
eleSend.firstElementChild.textContent = "发送";
}
localStorage.setItem(LSChat, JSON.stringify(config_chat));
}, false)
})
.catch((error) => { console.log(error); })
.then(() => {
if (!config_chat) { config_chat = JSON.parse(localStorage.getItem(LSChat)) || {}; }
$H2P('input#input-invl-start').value = config_chat.invlStart || '';
$H2P('input#input-invl-end').value = config_chat.invlEnd || '';
$H2P('input#input-chat-loop').checked = config_chat.isLoop || false;
$H2P('textarea.h2p-ta-chat-loop').value = config_chat.loopChat ? config_chat.loopChat.join('\n') : '';
if (config_chat.isSend) {
config_chat.isSend = false;
$H2P('button#btn-chat-send').click();
}
if (!Chat) { Chat = setChat(); }
})
.catch((error) => {
// 判断 localStorage 是否能够读取 h2p-DY-config-chat
console.log(error);
config_chat = config_chat || {};
localStorage.removeItem(LSChat);
localStorage.setItem(LSChat, JSON.stringify(config_chat));
})
function getMsg () {
let msg = undefined;
if (!msg && config_chat.isLoop && Array.isArray(config_chat.loopChat)) {
let index = Math.floor(Math.random() * (config_chat.loopChat.length));
msg = config_chat.loopChat[index];
}
return msg;
}
function setINVL_SendMsg () {
let {invlStart = 2, invlEnd = 2} = config_chat;
let [start, end] = [Number(invlStart), Number(invlEnd)];
let invl = Math.floor(Math.random() * (end - start)) + start;
setINVL_ShowCD(invl);
INVL_SendMsg = setTimeout(() => {
Chat.setMsg(getMsg());
Chat.sendMsg();
setINVL_SendMsg();
}, invl * 1000);
}
function setINVL_ShowCD (invl) {
new Promise((resolve, reject) => {
window.clearInterval(INVL_ShowCD);
resolve(invl);
}).then((invl)=> {
let cd = invl + 0.3;
INVL_ShowCD = setInterval(() => {
cd = Math.max(Math.floor((cd - 0.1) * 10) / 10.0, 0);
$H2P('input#input-invl').value = cd;
}, 100);
})
}
function setChat () {
let [eleSetMsg, eleSendMsg] = [undefined, undefined];
return {
setMsg : (msg)=>{
if (!eleSetMsg && $H2P('.ChatSend-txt')) { eleSetMsg = $H2P('.ChatSend-txt'); }
if (eleSetMsg) { eleSetMsg.value = msg; }
},
sendMsg : ()=>{
if (!eleSendMsg && $H2P('.ChatSend-button')) { eleSendMsg = $H2P('.ChatSend-button'); }
if (eleSendMsg) { eleSendMsg.click(); }
}
}
}
}
// ========== ========== ========== ========== ========== ========== ==========
//
//
//
// 初始化清爽模块
//
//
//
// ========== ========== ========== ========== ========== ========== ==========
const LSClear = 'h2p-DY-config-clear';
let config_clear = undefined;
function initView_Clear () {
let isSelectingEle = false;
new Promise((resolve, reject) => {
// 先添加样式
let eleStyle = document.createElement('style');
eleStyle.innerHTML = `
.h2p-btn-clear {
width: 95%;
padding: 4px 0;
border: none;
border-radius: 5px;
background: #66ddcc;
transition: 0.5s;
}
.h2p-btn-clear:hover {
background: #55ccaa;
}
`;
document.head.append(eleStyle);
resolve();
})
.then(() => {
// 添加清爽模式界面元素
let eleClear = document.createElement('div');
eleClear.id = 'h2p-div-clear';
eleClear.className = 'h2p-flex-main-center h2p-div-ceil';
eleClear.style = 'display: none; order: 0';
eleClear.innerHTML = `
`;
$H2P('div#h2p-div-borad').append(eleClear);
})
.then(() => {
let eleClear = $H2P('div#h2p-div-clear');
eleClear.addEventListener('click', (event) => {
let target = event.target;
if (target.tagName.toLowerCase() === 'button') { target.classList.toggle('h2p-btn-active'); }
// 自定义清爽模式
if (target.id === 'btn-clear-DIY') {
config_clear.isClearDIY = !config_clear.isClearDIY;
localStorage.setItem(LSClear, JSON.stringify(config_clear));
// $H2P('div#js-player-title').style.display = 'none';
config_clear.clearInfo.forEach(xpath => { $H2P(xpath).style.display = config_clear.isClearDIY ? 'none' : ''; });
// $H2P('div#js-player-title').style.display = '';
}
// 选择自定义清爽的元素
else if (target.id === 'btn-clear-selectEle') {
isSelectingEle = target.classList.contains('h2p-btn-active');
if (!isSelectingEle) {
$H2P('.h2p-item-selected', false).forEach(ele => {
if (config_clear.isClearDIY) { ele.style.display = 'none'; }
ele.classList.remove('h2p-item-selected')
});
} else if (!config_clear.isClearDIY) {
config_clear.clearInfo.forEach(xpath => $H2P(xpath).classList.add('h2p-item-selected'));
}
}
}, false)
})
.then(() => {
// 导航栏、主播信息面板
let areas = [$H2P('header#js-header'), $H2P('div#js-player-title')];
for (area of areas) {
if (area) {
let curele = undefined;
area.addEventListener('mouseover', (event) => {
if (isSelectingEle) {
curele = event.target;
event.target.classList.add('h2p-item-hover');
}
}, false);
area.addEventListener('mouseout', (event) => {
if (isSelectingEle) {
curele = undefined;
event.target.classList.remove('h2p-item-hover');
}
}, false);
area.addEventListener('click', (event) => {
if (curele === event.target && curele !== event.currentTarget) {
clearClickSelect(event.target, `${area.tagName.toLowerCase()}#${area.id}`);
}
}, false)
}
}
})
.catch((error) => { console.log(error); })
.then(() => {
if (!config_clear) { config_clear = JSON.parse(localStorage.getItem(LSClear)) || {}; }
if (config_clear.isClearDIY) {
$H2P('button#btn-clear-DIY').classList.add('h2p-btn-active');
let wait = setInterval(() => {
let notReady = config_clear.clearInfo.filter(xpath => !$H2P(xpath));
let eles = config_clear.clearInfo.filter(xpath => $H2P(xpath) && $H2P(xpath).style.display !== 'none');
eles.forEach(xpath => { $H2P(xpath).style.display = 'none'; });
if (notReady.length === 0) {
window.clearInterval(wait);
wait = undefined;
}
}, 500);
}
})
function findXPath (current, root) {
if (root.tagName.toLowerCase() === 'header' && root.id === 'js-header' && current.tagName.toLowerCase() === 'div' && current.parentNode.tagName.toLowerCase() === 'li') {
current = current.parentNode;
}
let index = Array.from(current.parentNode.children).filter(ele => ele.tagName === current.tagName).indexOf(current);
let xpath = index === 0 ? ` > ${current.tagName.toLowerCase()}` : ` > ${current.tagName.toLowerCase()}:nth-child(${index+1})`;
current = current.parentNode;
while (current !== root && !current.id) {
index = Array.from(current.parentNode.children).filter(ele => ele.tagName === current.tagName).indexOf(current);
if (index === 0) { xpath = ` > ${current.tagName.toLowerCase()}` + xpath; }
else { xpath = ` > ${current.tagName.toLowerCase()}:nth-child(${index+1})` + xpath; }
current = current.parentNode;
}
return `${current.tagName.toLowerCase()}#${current.id}${xpath}`;
}
function clearClickSelect (target, xpathPre) {
let xpath = '';
if (target.id) { xpath = `${xpathPre} ${target.tagName.toLowerCase()}#${target.id}`; }
else { xpath = findXPath(target, event.currentTarget); }
// console.log(xpath);
$H2P(xpath).classList.toggle('h2p-item-selected');
if ($H2P(xpath).classList.contains('h2p-item-selected')) {
if (!config_clear.clearInfo) { config_clear.clearInfo = []; }
if (config_clear.clearInfo.indexOf(xpath) < 0) {
config_clear.clearInfo.push(xpath);
localStorage.setItem(LSClear, JSON.stringify(config_clear));
}
} else {
let index = config_clear.clearInfo.indexOf(xpath);
if (index > -1) {
config_clear.clearInfo.splice(index, 1);
localStorage.setItem(LSClear, JSON.stringify(config_clear));
}
}
}
}
})();