Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ==UserScript==
- // @name DH2 mod bot
- // @namespace FileFace
- // @description A moderator bot to assist mod team for Diamond Hunt online
- // @version 0.13
- // @author you, and ktnn
- // @include *.diamondhunt.co/*
- // @match dh2.diamondhunt.co
- // @grant none
- // ==/UserScript==
- /*
- CHANGELOG 0.13:
- - Fixed typo in new mute command
- - Added a list of words that instantly mute
- CHANGELOG 0.12a:
- - Added Fireblade as mod
- - Updated to new smute command
- - Fixed a couple of minor syntax errors
- CHANGELOG 0.12:
- - Added an option to enable/disable the autoMute feature. It is disabled by default and can be found in the customizable section.
- You should only enable it when chat really needs strictly moderation.
- CHANGELOG 0.11a:
- - small fixed syntax
- CHANGELOG 0.11:
- - Move down some important paremeters that have been tested carefully, from customizable to non-customizable section
- - Min pts of excessive cursing words is from 7 to 8
- - Added an insult directly word into heavy list
- - Raise the trigger lines of flooding to 1 line of each.
- - Added level and flooding lines of flooder to the console log, for QA moderation
- END of Changelog
- */
- // INSTRUCTION: using the script with tampermonkey. Turn on your browser's console to see the detector's log.
- (function (){
- 'use strict';
- console.info('DH2 Mod bot is up and running');
- // Customizable parameters section
- var modList = ['smitty', 'eegos', 'ted120', 'martlands', 'mattyboy', 'luxferre', 'ktnn', 'zack', 'morgan91']; // mods are unaffected by the script
- var lightWords = ['dick', 'asshole', 'arsehole', 'arse', 'ass', 'bitch', 'twat', 'fuck', 'fucked', 'fucking', 'fuckers', 'fucker',
- 'wanker', 'goddamn', 'bastard', 'choad', 'kys']; // add 1 pts
- var heavyWords = ['fuck you', 'niger', 'anal', 'cunt', 'whore', 'motherfucker',
- 'slut', 'douch', 'cocksucker']; // add 2 pts
- var instaWords = ['nigger', 'nigga', 'fag', 'faggot', 'nibba', 'fags', 'niggers', 'faggots'];
- var autoMute = true; // WARNING: this feature is disabled by default, change it as true to enable
- // It will inform/alert about the situation instead of automatically mute.
- // DO NOT turn it on unless the chat needs to be moderated strictly
- var minLevelAlt = 30; // min global level to detect an alt, the detector will be more sensisitve
- var muteTimeSpam = 1; // mute duration for spamming/flooding
- var muteTimeSwear = 1; // mute duration for excessive swearing/cursing
- var notifKeywords = ['#mods', '#mod', 'morgan', 'morgan91', '@mods', '@morgan'];
- // Not customizable anymore!! DO NOT change it if you have no idea how they work, or without carefully testing
- var check = (autoMute == false) ? 'disabled' : 'enabled';
- console.info('Automute feature is '+check);
- var minSpamWords = 6; // min duplicate words in a single chat line, to be considered as a spam
- var resetTime = 15000; // time to reset a check phase of spamming and swearing, the bigger it is, the more sensitive to trigger
- var minPoints = 8; // min points of excessive cursing/swearing to be triggered
- var badWordsList = lightWords.concat(heavyWords).concat(instaWords);
- var swearUserObj = {name:'', msg:[], pts:0};
- var spamUserObj = {name:'', number:0};
- var floodCount = {};
- var countDupWords = {};
- var notifSpam = ' just got muted for spamming. Go review it.'; // need to review to see if the mute was justified by the bot. If not, unmute manually
- var notifFlood = ' just got muted for flooding. Go review it.';
- var notifSwear = ' just got muted for cursing. Go review it.';
- var notifGeneral = ' is calling out the mod team. Or there may be issues in chat.';
- var notifAlertSpam = ' seems to be spamming. Go check it';
- var notifAlertFlood = ' seems to be flooding. Go check it';
- var notifAlertSwear = ' seems to be swearing. Go check it';
- //var resultDup = [];
- //var allMsgArray = [];
- var target = document.getElementById('div-chat-area');
- var textBox = document.getElementById("chat-input-text");
- var chatSendButton = document.getElementById("chat-send-button");
- // Utility functions
- // check if messageAuthor is in mod list, if yes return true
- function checkModsException(username, list){
- var result = false;
- if (username.length <= 20){
- for (var i = 0; i < list.length; i++){
- if (username != list[i]){
- continue;
- } else if (username == list[i]){
- result = true;
- }
- }
- } else{
- result = undefined;
- }
- return result;
- }
- function resetFlood(){
- floodCount = {};
- //countDupWords = {};
- }
- setInterval(resetFlood, 2000); // time to reset a flooding check
- function resetCheck(){
- countDupWords = {};
- spamUserObj.name = '';
- spamUserObj.number = 0;
- swearUserObj.pts = 0;
- swearUserObj.name = '';
- }
- var timer = setInterval(resetCheck, resetTime);
- /*
- function findDuplicates(data) {
- data.forEach(function(element, index) {
- // Find if there is a duplicate or not
- if (data.indexOf(element, index + 1) > -1) {
- // Find if the element is already in the result array or not
- if (resultDup.indexOf(element) === -1) {
- resultDup.push(element);
- }
- }
- });
- return resultDup;
- }
- function random(num1, num2){
- return Math.floor(Math.random() * (num2-num1 + 1) + num1);
- }
- function swearWarning (username){
- var rdm = random(1, 3);
- var warning = '';
- var text = textBox.value = '/pm ' + username + ' ';
- var text1 = 'You could use nicer words';
- var text2 = 'Excuse me, would you please keep the language G rated?';
- var text3 = 'You are going to violate the chat rule by excessive swearings';
- if (rdm === 1){
- warning = text.concat(text1);
- } else if (rdm === 2){
- warning = text.concat(text2);
- } else if (rdm === 3){
- warning = text.concat(text3);
- }
- return warning;
- }
- function spamWarning (username){
- var rdm = random(1, 3);
- var warning = '';
- var text = textBox.value = '/pm ' + username + ' ';
- var text1 = 'Hey, do not spam';
- var text2 = 'Would you please stop spamming?';
- var text3 = 'You are going to violate the chat rule by spamming';
- if (rdm === 1){
- warning = text.concat(text1);
- } else if (rdm === 2){
- warning = text.concat(text2);
- } else if (rdm === 3){
- warning = text.concat(text3);
- }
- return warning;
- }
- */
- // check if a string contains certain words, e.g.: 'lovely' or 'aslove' can match 'love'
- function checkWords(string, array){
- for (var i = 0; i < array.length; i++){
- if (string.includes(array[i])){
- return true;
- }
- }
- }
- // compare two arrays, strict word to word, e.g.: only 'love' can match 'love'
- function scanWords(array, words) {
- for (var i =0; i< array.length; i++){
- for (var u =0; u< words.length;u++){
- if (array[i] === words[u]){
- return true;
- }
- }
- }
- }
- // compare bad words list to msg content, light words add 1 pts, heavy words add 2 pts, insta words add 8 pts
- function countWords(array, words) {
- var count = 0;
- for(var i = 0; i < array.length; i++)
- {
- for (var u = 0; u < words.length; u++){
- if (array[i] == lightWords[u]) {
- count++;
- }else if (array[i] == heavyWords[u]) {
- count +=2;
- }else if (array[i] == instaWords[u]) {
- count +=8;}
- }
- }
- return count;
- }
- // remove link from message, unless the link length is too long
- function removeLink(array){
- for (var i = 0; i < array.length;i++){
- if (array[i].indexOf('https://') !== -1 && array[i].length < 150){
- array.splice(i, 1);
- }else if (array[i].indexOf('www.') !== -1 && array[i].length < 150){
- array.splice(i, 1);
- }else if (array[i].indexOf('.com') !== -1 && array[i].length < 150){
- array.splice(i, 1);
- }
- }
- return array;
- }
- function getLongestCharacters(array){
- var longest = 0;
- for (var i = 0; i < array.length;i++){
- if (longest < array[i].length){
- longest = array[i].length;
- }
- }
- return longest;
- }
- function getKeyByValue(object, value) {
- return Object.keys(object).find(key => object[key] === value);
- }
- function sendChat(text){
- cBytes('CHAT='+text);
- }
- function mutePlayer(name, duration, reason){ // reason: 0 = other, 1 = flood/spam, 4 = excessively swear/curse
- if (reason==1) {
- cBytes('SMUTE='+name+'~'+duration+'~'+'Modbot: Flood/Spam'+'~'+0);}
- else if (reason==4) {
- cBytes('SMUTE='+name+'~'+duration+'~'+'Modbot: Excessive offensive language'+'~'+0);}
- else {
- cBytes('SMUTE='+name+'~'+duration+'~'+'Modbot: Other'+'~'+0);}
- }
- // notification
- function notif(username, message){
- if (!window.Notification) {
- alert("Sorry, Notification is not supported in this Browser!");
- } else {
- if (Notification.permission === 'default') {
- Notification.requestPermission(function(p) {
- if (p === 'denied') {
- alert('You have denied Notification'); }
- else {
- var notify = new Notification('Beep Boop, Beep Bop', {
- body: username + message,
- requireInteraction: true,
- icon: 'images/lumberjack.png'
- });
- }
- });
- } else {
- var notify = new Notification('Beep Boop, Beep Bop', {
- body: username + message,
- icon: 'images/lumberjack.png',
- requireInteraction: true
- });
- }
- }
- }
- function analyzeMutation(mutation){
- //console.log(mutation.addedNodes.length);
- if(mutation.addedNodes.length == 2){
- var isPM = false;
- var messageAuthor = "";
- var messageText = "";
- var messageContent = "";
- var globalLevel = -1;
- messageText = mutation.addedNodes[1].innerText; //Retrieve the contents of the message. This is everything included the name and level
- messageContent = messageText.slice(messageText.indexOf(":")+2); // getting the string after the colon and space
- messageContent = messageContent.toLowerCase(); // all msg content to lower
- if(messageText.startsWith("[")){ // All PMs start with an opening square bracket
- isPM = true;
- }
- if(isPM){ //Retrieve the username based on if it's a PM or not, since they are structured differently.
- messageAuthor = messageText.slice(9, messageText.indexOf("]")); // [PM from username <= index 9 at username
- }else{
- messageAuthor = messageText.slice(0, messageText.indexOf("(")-1); // getting the string before the opening bracket and the space that appears before it
- }
- if(!isPM){ //Global level is only shown in normal chat
- globalLevel = parseInt(messageText.slice(messageText.indexOf("(")+1, messageText.indexOf(")")));
- }
- return {
- isPM: isPM,
- messageAuthor: messageAuthor,
- messageContent: messageContent,
- globalLevel: globalLevel,
- }; // return an object to make it easy to access the variable
- }else{
- return false;
- }
- }
- var observer = new MutationObserver(function(mutations) {
- mutations.forEach(function(mutation){
- var messageInfo = analyzeMutation(mutation); // each msg, including name, lvl, content, is pm or not
- if (!messageInfo){
- return;
- }
- //var sendMessage = true;
- if (websocketReady === true && !checkModsException(username, modList)){
- observer.disconnect();
- console.info('DH2 Mod bot is disabled. Current user is not a moderator');
- }
- var msg = messageInfo.messageContent;
- var messageArray = msg.split(" "); // split into each word in a msg content, by a space between
- var user = messageInfo.messageAuthor;
- var isPM = messageInfo.isPM;
- var level = messageInfo.globalLevel;
- //checkModsException(user, modList);
- //console.log(spamUserObj);
- //console.log(floodCount[user]);
- //console.log(swearUserObj);
- //console.log(countDupWords);
- // MODERATING SECTION
- if(!isPM && !checkModsException(user, modList)){ //not a pm and user is not a mod
- if (scanWords(messageArray, notifKeywords)){
- notif(user, notifGeneral);
- }
- // SPAM DETECTOR:
- messageArray.forEach(function(i) {
- countDupWords[i] = (countDupWords[i] || 0) + 1; // count words of msg and store the duplicate times in countDupWords
- });
- var countValueObj = Object.values(countDupWords);
- var max = Math.max(...countValueObj); // most repetitive word
- var getWord = getKeyByValue(countDupWords, max);
- var spamTrigger = (getLongestCharacters(removeLink(messageArray)) > 30 || // word has more than 30 chars and not an URL is spam
- (max >= minSpamWords) || // repeat word more than minSpamWords
- (max >= 3 && max < minSpamWords && getWord.length >= 6)); // lesser repeat word but the length is longer than usual
- countDupWords = {};
- if (spamTrigger){// can always view timestamp in console: SETTING > SHOW TIMESTAMPS
- //console.log('spam '+user);
- if(spamUserObj.name == ''){
- spamUserObj.name = user;
- }
- if(spamUserObj.name === user){
- ++spamUserObj.number;
- clearInterval(timer); // reset timer between the check whenever the marked user fouls
- timer = setInterval(resetCheck, resetTime);
- }
- if(spamUserObj.number >= 3 || ((spamUserObj.number === 2) && (level < minLevelAlt))){
- //if(spamUserObj.number >= 3){
- if (autoMute == false){
- console.log(user + ' was spamming. Last msg is "'+msg+'"');
- notif(user, notifAlertSpam);
- resetCheck();
- } else if (autoMute == true){
- mutePlayer(user, muteTimeSpam, 1);
- console.log(user + ' has been muted for spamming for '+muteTimeSpam+' hrs. Last msg is "'+msg+'"');
- notif(user, notifSpam);
- resetCheck();
- }
- }
- }
- // FLOODING DETECTOR: check if one is typing too many lines in short period of time
- if(floodCount[user]){
- //console.log('flood user is '+user+', line is ' +floodCount[user]);
- if(++floodCount[user] >= 4 || (++floodCount[user] === 3 && level < minLevelAlt)){
- //if(++floodCount[user] >= 4){
- if (autoMute == false){
- console.log(user + ' was flooding. Last msg is "'+msg+'"');
- notif(user, notifAlertFlood);
- floodCount = {};
- } else if (autoMute == true){
- mutePlayer(user, muteTimeSpam, 1);
- console.log(user + ' has been muted for flooding for '+muteTimeSpam+' hrs (level '+level+', lines '+floodCount[user]+'). Last msg is "'+msg+'"');
- notif(user, notifFlood);
- floodCount = {};
- }
- }
- } else {
- floodCount[user] = 1;
- }
- // CURSING/SWEARING DETECTOR: check if one is swearing too much
- if(scanWords(messageArray, badWordsList)){
- //console.log('swear '+user);
- clearInterval(timer);
- timer = setInterval(resetCheck, resetTime);
- if(swearUserObj.name == ''){
- swearUserObj.name = user;
- }
- if(user === swearUserObj.name){
- swearUserObj.msg.push(msg);
- var swearArray = swearUserObj.msg[0].split(" ");
- swearUserObj.pts += countWords(swearArray, badWordsList);
- //console.log(swearUserObj.pts + ' ' + user);
- swearArray = [];
- swearUserObj.msg = [];
- clearInterval(timer);
- timer = setInterval(resetCheck, resetTime);
- }
- //if (swearUserObj.pts >= minPoints){
- if (swearUserObj.pts >= minPoints || ((swearUserObj.pts >= (minPoints - 5)) && (level < minLevelAlt))){
- if (autoMute == false){
- console.log(user + ' was cursing excessively. Last msg is "'+msg+'"');
- notif(user, notifAlertSwear);
- resetCheck();
- } else if (autoMute == true){
- mutePlayer(user, muteTimeSwear, 4);
- console.log(user + ' has been muted for excessive swearing for '+muteTimeSwear+' hrs ('+swearUserObj.pts+' pts). Last msg is "'+msg+'"');
- notif(user, notifSwear);
- resetCheck();
- }
- }
- }
- }
- });
- });
- // configuration of the observer:
- var config = { attributes: true, childList: true, characterData: true };
- // pass in the target node, as well as the observer options
- observer.observe(target, config);
- //Stop observing
- //observer.disconnect();
- })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement