通過網頁操作, 達成屏蔽與解除屏蔽使用者
当前为
// ==UserScript==
// @name BanYouSb
// @namespace http://tampermonkey.net/
// @version 1.37
// @description 通過網頁操作, 達成屏蔽與解除屏蔽使用者
// @author RogerYeah
// @match *://jandan.net/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=jandan.net
// @grant none
// ==/UserScript==
(function () {
// 檢查 localStorage 中是否存在 banCode 鍵值對 , 若不存在則新增一個空物件
const BAN_CODE_KEY = 'banCode';
function initializeBanCode() {
try {
const banCode = localStorage.getItem(BAN_CODE_KEY);
if (!banCode) {
localStorage.setItem(BAN_CODE_KEY, '{}');
} else {
console.log('Here is who you ban: ' + banCode);
}
} catch (error) {
console.error('Error accessing localStorage:', error);
}
}
initializeBanCode();
// 將 localStorage 中的 banCode 鍵值對解析為 JSON 物件
var banCode = JSON.parse(localStorage.getItem(BAN_CODE_KEY))
// 獲取網頁中的所有評論列表
var comment = document.getElementsByClassName("commentlist")
var lis = comment[0].getElementsByTagName("li")
// 獲取網頁中的所有 .text 元素
var row = document.querySelectorAll('.text')
// 定義屏蔽按鈕
var voteElements = document.querySelectorAll(".jandan-vote")
// 定義吐槽按鈕
var tucao = document.querySelectorAll(".tucao-btn")
//定義 unban 函式
function unban(e) {
// 獲取 li 元素
var li = e.parentNode.parentNode.parentNode;
// 獲取作者姓名
var author = li.getElementsByClassName("author")[0].getElementsByTagName("strong")[0].textContent;
// 確認是否解除屏蔽
if (confirm("讓我看看 " + author + " 這傢夥有什麼長進")) {
// 從 banCode 物件中刪除 author 對應的鍵值對
delete banCode[author];
// 將更新後的 banCode 物件存入 localStorage
localStorage.setItem(BAN_CODE_KEY, JSON.stringify(banCode));
// 重新載入頁面
location.reload();
}
}
// 定義 ban 函式
function ban(e) {
// 獲取 li 元素
var li = e.parentNode.parentNode.parentNode;
// 獲取作者姓名
var author = li.getElementsByClassName("author")[0].children[0];
// 獲取作者防偽碼
var privCode = author.getAttribute('title').split('防伪码:').pop();
// 確認是否屏蔽
if (confirm("您確定要屏蔽 " + author.textContent + " 嗎?")) {
// 將作者姓名和防偽碼新增至 banCode 物件中
banCode[author.textContent] = privCode;
// 將更新後的 banCode 物件存入 localStorage
localStorage.setItem(BAN_CODE_KEY, JSON.stringify(banCode));
// 重新載入頁面
location.reload();
}
}
// 定義 unBanUser 函式
function unBanUser(e) {
// 確認是否解除屏蔽
if (confirm("讓我看看 " + e + " 這傢夥有什麼長進")) {
// 從 banCode 物件中刪除 author 對應的鍵值對
delete banCode[e];
// 將更新後的 banCode 物件存入 localStorage
localStorage.setItem(BAN_CODE_KEY, JSON.stringify(banCode));
// 重新載入頁面
location.reload();
}
}
// 定義吐槽屏蔽函式
function tucaoHandle(e) {
const bannedUsers = JSON.parse(localStorage.getItem("banCode"));
const bannedUsernames = Object.keys(bannedUsers);
const isFBan = localStorage.getItem('FBan') === 'true';
const tucaoList = e.querySelectorAll('.tucao-list .tucao-row');
const tucaoHotList = e.querySelectorAll('.tucao-hot .tucao-row');
let rowsToDelete = [];
if (!bannedUsers) return; // 如果 banCode 為空,則直接返回
bannedUsernames.forEach(bannedUser => {
rowsToDelete = [];
// 找到所有需要刪除的元素,並存儲到 rowsToDelete 陣列中
tucaoList.forEach(row => {
const tucaoAuthor = row.querySelector('.tucao-author');
if (tucaoAuthor && tucaoAuthor.textContent.includes(bannedUser)) {
rowsToDelete.push(row.id);
}
});
// 熱榜屏蔽
tucaoHotList.forEach(row => {
const tucaoAuthor = row.querySelector('.tucao-author');
if (tucaoAuthor && tucaoAuthor.textContent.includes(bannedUser)) {
rowsToDelete.push(row.id);
}
});
});
if (isFBan) {
rowsToDelete.forEach(row => {
document.getElementById(row).remove()
});
} else {
rowsToDelete.forEach(row => {
var rowItem = document.getElementById(row);
var contentBox = rowItem.querySelector(".tucao-content");
var content = contentBox.textContent;
document.getElementById(row).querySelector(".tucao-content").innerHTML = `
<del class="delete">
<span class="math-inline">已屏蔽</span>
</del>
<i class="peep" title="${content}">偷看一下(懸停)</i>
`;
});
}
}
// 屏蔽防偽碼標記用戶
for (let i = lis.length - 1; i >= 0; i--) {
// 獲取作者姓名
const author = lis[i].querySelector(".author strong");
const authorName = author ? author.innerText : '';
// 遍歷 banCode 物件中的所有鍵值對
for (const [bannedAuthor, _] of Object.entries(banCode)) {
// 若作者姓名與 banCode 物件中的鍵值對匹配 且 FBan Mode 為真
if (authorName === bannedAuthor && localStorage.getItem('FBan') === 'true') {
console.log(lis[i].remove());
} else if(authorName === bannedAuthor) {
// 獲取評論內容
const contentBox = lis[i].querySelector(".text");
const img = lis[i].querySelector("img");
const content = contentBox.querySelector('p:not(.bad_content)').textContent.replace(/<br>/g, ' ');
// 將評論內容替換為 "[已屏蔽]" 標記
contentBox.innerHTML = `
<del class="delete">
<span class="math-inline">${authorName} - 已屏蔽</span>
</del>
<i class="peep" title="${content}">偷看一下(懸停)
${img != null ? `<img style="opacity: 0;" src="${img.src}" alt="pic" />`: ''}
</i>
`;
break;
}
}
}
// 遍歷所有 .jandan-vote 元素
for (var x = 0; x < voteElements.length; x++) {
// 創建一個新的 a 元素
var button = document.createElement("a");
// 若評論內容包含 "[已屏蔽]" 標記
if (row[x].innerHTML.includes('del')) {
// 設定按鈕文字為 "[解除屏蔽]"
button.textContent = "[解除屏蔽]";
// 為按鈕添加點擊解除屏蔽函式
button.addEventListener("click", function () {
unban(this);
});
} else {
// 設定按鈕文字為 "[屏蔽]"
button.textContent = "[屏蔽]";
// 為按鈕添加點擊屏蔽函式
button.addEventListener("click", function () {
ban(this);
});
}
// 設定按鈕顏色為 "#c8c7cc"
button.style.color = "#c8c7cc";
// 將按鈕插入到 .jandan-vote 元素的開頭
voteElements[x].prepend(button);
}
// 生成list按鈕Dom
var counter = Object.keys(banCode).length
var listDom = `
<div class="banList">
<div class="toggleArea">
<div class="banModeSwitch" title="打開此開關完全屏蔽模式, 開啟後偷看功能關閉並完全屏蔽列表中的使用者(看不見任何與屏蔽使用者相關之項目)">
<div class="switch ${localStorage.getItem('FBan') === 'true' ? 'active' : ''}" id="switch"></div>
<span>FBan Mode</span>
</div>
屏蔽列表
<div class="toggleList">
<span class="toggleList-show">+</span>
<span class="toggleList-hide" style="display: none;">-</span>
</div>
</div>
<ul class="mainList" style="display: none;">
`
// 循環遍歷 banCode 對象中的已屏蔽用戶
for (var li = 0; li < counter; li++) {
listDom += `
<li class="mainList-item">${Object.keys(banCode)[li]} <a class="unban" href="javascript: void();">x</a></li>
`
}
listDom += `
</ul>
<form id="banForm">
<input class="ban-input" type="text" placeholder="手動屏蔽(鍵入ID後, 猛擊Enter)" />
</form>
</div>
`
// 獲取 DOM 元素
const wrapper = document.getElementById('wrapper');
const listDomElement = document.createElement('div');
listDomElement.innerHTML = listDom;
wrapper.appendChild(listDomElement);
// 添加點擊事件監聽器,用於處理刪除按鈕的點擊
wrapper.addEventListener('click', (event) => {
if (event.target.classList.contains('unban') && !event.target.classList.contains('clicked')) {
const username = event.target.parentNode.textContent.trim().replace(' x', '');
unBanUser(username);
event.target.classList.add('clicked')
}
if (event.target.classList.contains('tucao-btn') && !event.target.classList.contains('clicked')) {
var tucaoId = event.target.dataset.id;
var tucaoBox = document.getElementById(`jandan-tucao-${tucaoId}`)
var intervalBox = setInterval(() => {
if (tucaoBox.innerText !== "数据加载中....biubiubiu....") {
tucaoHandle(tucaoBox);
clearInterval(intervalBox);
event.target.classList.add('clicked')
}
}, 100);
}
});
// 獲取 DOM 元素
const switcher = document.getElementById('switch');
switcher.addEventListener('click', (event) => {
if(localStorage.getItem('FBan') !== null) {
const isFBan = localStorage.getItem('FBan') === 'true';
localStorage.setItem('FBan', !isFBan);
switcher.classList.toggle('active', !isFBan);
location.reload();
} else {
if(confirm('打開此開關完全屏蔽模式, 開啟後偷看功能關閉並完全屏蔽列表中的使用者(看不見任何與被屏蔽使用者相關之項目)')) {
const isFBan = localStorage.getItem('FBan') === 'true';
localStorage.setItem('FBan', !isFBan);
switcher.classList.toggle('active', !isFBan);
location.reload();
}
}
})
// 獲取並緩存屏蔽用戶列表 DOM 元素
const toggleList = document.querySelector('.toggleList');
if(toggleList != null) {
// 添加點擊事件監聽器,用於展開/收起屏蔽用戶列表
toggleList.addEventListener('click', function() {
const secondSpan = this.querySelector('span:nth-of-type(2)');
const ul = document.querySelector('.mainList');
secondSpan.style.display = secondSpan.style.display === 'none' ? 'block' : 'none';
ul.style.display = ul.style.display === 'none' ? 'block' : 'none';
});
}
// 手動屏蔽功能
const myForm = document.getElementById('banForm');
const myInput = document.querySelector('.ban-input');
myForm.addEventListener('submit', function() {
const inputValue = myInput.value;
if (confirm("此屏蔽無法正確辨識身分, 換個暱稱就屏蔽不了了, 您確定要屏蔽 " + inputValue + " 嗎?")) {
let banData = JSON.parse(localStorage.getItem("banCode")) || {}; // 初始化為空物件
if (banData[inputValue] == undefined) { // 避免重複添加
banData[inputValue] = null;
localStorage.setItem("banCode", JSON.stringify(banData));
setTimeout(() => {
location.reload();
}, 100)
} else {
alert("該用戶已經被屏蔽");
}
}
});
setTimeout(() => {
// 創建 style 元素
var style = document.createElement('style');
// 創建文本,包含 CSS 規則
style.innerHTML = `
.commentlist .row {
overflow: visible;
}
.delete {
display: inline-block;
margin-bottom: 20px;
margin-top: 7px;
margin-right: 5px;
}
.tucao-content {
.delete {
display: inline-block;
margin: 0;
}
}
.peep {
display: inline-block;
position: relative;
font-size: 10px;
img {
position: absolute;
left: calc(100% + 10px);
opacity: 0;
max-width: 250px !important;
pointer-events: none;
}
&:hover img {
opacity: 1 !important;
transition: .5s ease;
}
}
.banList {
display: flex;
flex-wrap: wrap;
justify-content: flex-end;
position: fixed;
top: 84px;
width: 1184px;
pointer-events: none;
width: calc((100vw - 984px - 60px) / 2);
max-height: calc(100% - 300px);
box-sizing: border-box;
left: calc(100% - (100vw - 984px - 30px) / 2);
}
.toggleArea {
padding: 5px;
position: relative;
text-align: center;
width: 100%;
border-radius: 5px;
background: #bababa;
color: #333;
font-weight: bold;
pointer-events: auto;
.toggleList {
display: inline-block;
position: absolute;
width: 20px;
height: 20px;
right: 5px;
}
.toggleList-show,
.toggleList-hide {
position: relative;
display: inline-block;
width: 20px;
height: 20px;
background: #bababa;
&:hover {
color: #666;
}
}
.toggleList-hide {
position: absolute;
top: 0;
}
}
.mainList {
margin-bottom: 3px;
position: relative;
width: 90px;
top: calc(100% + 10px);
display: none;
width: 100%;
color: gray;
overflow: auto;
height: calc(100vh - 196px);
}
.mainList-item {
margin-bottom: 4px;
padding-bottom: 4px;
width: 100%;
border-bottom: 1px solid gray;
font-size: 12px;
white-space:nowrap;
text-overflow:ellipsis;
-o-text-overflow:ellipsis;
overflow: hidden;
max-width: 100%;
padding-right: 20px;
box-sizing: border-box;
}
.unban {
pointer-events: auto;
cursor: pointer;
position: absolute;
right: 0;
}
#banForm {
position: absolute;
bottom: calc(100% + 5px);
left: 0;
width: 100%;
pointer-events: auto;
.ban-input {
position: relative;
width: 100%;
border-color: #d8d8d8;
border-width: 0px 00px 1px 0px;
}
.ban-input:focus {
outline: none;
}
}
#banForm .ban-input::placeholder {
color: #d8d8d8;
}
.banModeSwitch {
position: absolute;
top: 5px;
height: 20px;
.switch {
position: relative;
width: 20px;
height: 10px;;
border-radius: 10px;
background: rgb(255 255 255 / 40%);
&:after {
content: '';
display: block;
position: absolute;
top: 2px;
left: 2px;
height: 6px;
width: 6px;
border-radius: 10px;
background: rgb(0 0 0 / 20%);
}
&.active {
background: rgb(187 255 204 / 40%);
&:after {
left: auto;
right: 2px;
background: rgb(22 165 0 / 40%);
}
}
}
span {
padding-top: 2px;
display: block;
color: #333 !important;
font-size: 7px;
font-weight: 100;
}
}
`;
document.head.appendChild(style);
}, 1);
})();