您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Provides a better modding interface for the cam girls site of chaturbate.com. This script makes modding faster and easier. Check out the details.
当前为
// ==UserScript== // @name Chaturbate - Better Modding // @namespace http://www.vpycha.com/gmscripts // @description Provides a better modding interface for the cam girls site of chaturbate.com. This script makes modding faster and easier. Check out the details. // @include http://chaturbate.com/* // @include https://chaturbate.com/* // @include http://*.chaturbate.com/* // @include https://*.chaturbate.com/* // @exclude http://serve.ads.chaturbate.com/* // @exclude https://serve.ads.chaturbate.com/* // @grant none // @license GPL version 3 or any later version; http://www.gnu.org/copyleft/gpl.html // @version 2.8 // ==/UserScript== // Author: Vladimir Pycha [email protected] // Website: vladpride.cz // Nickname on chaturbate.com: vlad88x (banned permanently), vlad88z // Nickname on greasyfork.org: vlad88 // First revision created and released on: July 2013 // The home page of this script is: https://greasyfork.org/scripts/3819-chaturbate-better-modding // There is also a detailed description of this script there. function doBetterModdingChanges() { var messagesCountMax = 200; var mostRecentMessagesCount = 4; var doRealDeleteWhenCollapsingMessages = false; var cookieExpirePeriod = 1 * 365; var pixelsToScrollOffChatBottom = 5; var expandChar = '+'; var collapseChar = '-'; var output = document.getElementById('ChaturbateBetterModding'); output.innerHTML = 'ChaturbateBetterModding user script is active<br /><span title="In simulation mode you can excersize modding without having to be a mod"><label for="ChaturbateBetterModding_SimulationMode">Simulation mode: </label><input id="ChaturbateBetterModding_SimulationMode" type="checkbox" /></span>'; var $ = jQuery; $.error = console.error; function strStartsWith(str, prefix) { return str.substring(0, prefix.length) === prefix; } function strEndsWith(str, suffix) { return str.substring(str.length - suffix.length) === suffix; } var oldConfirm = window.confirm; var silenceMsgTemplateLocalized = gettext("Silence %(username)s?"); window.confirm = function(msg) { var parts = silenceMsgTemplateLocalized.split('%(username)s'); if (strStartsWith(msg, parts[0]) && strEndsWith(msg, parts[1])) { var userToSilence = msg.substring(parts[0].length, msg.length - parts[1].length); var usernameValidationRegExp = /^\S+$/; if (userToSilence.replace(usernameValidationRegExp, '') === '') { return true; } } return oldConfirm(msg); } var theElement = document.body; var simulationModeCookieName = 'btmd_sim_mode'; var deletedMessagesShouldBeExpandedCookieName = 'btmd_expand'; var simulationMode = $.cookie(simulationModeCookieName) == '1'; var deletedMessagesShouldBeExpanded = $.cookie(deletedMessagesShouldBeExpandedCookieName) == '1'; setSimulationModeCookie(); setDeletedMessagesShouldBeExpandedCookie(); function setSimulationModeCookie() { $.cookie(simulationModeCookieName, simulationMode ? '1' : '0', { expires: cookieExpirePeriod, path: '/' }); } function setDeletedMessagesShouldBeExpandedCookie() { $.cookie(deletedMessagesShouldBeExpandedCookieName, deletedMessagesShouldBeExpanded ? '1' : '0', { expires: cookieExpirePeriod, path: '/' }); } var simulationModeCheckbox = document.getElementById('ChaturbateBetterModding_SimulationMode'); simulationModeCheckbox.checked = simulationMode; simulationModeCheckbox.onclick = function(evt) { simulationMode = this.checked; this.blur(); document.body.focus(); setSimulationModeCookie(); } var domele = $(theElement.getElementsByClassName('chat-list')[0]); var chat = domele.get(0); var messagesCount = 0; var previousChatOuterWidth = 0; var pathArray = window.location.pathname.split('/'); var broadcaster; if (pathArray.length == 3 && pathArray[0] == "" && pathArray[1] != "" && pathArray[2] == "") { broadcaster = pathArray[1]; } else if (pathArray.length == 4 && pathArray[0] == "" && pathArray[1] == "b" && pathArray[2] != "" && pathArray[3] == "") { broadcaster = pathArray[2]; } else { return; } var controlsContainer = document.createElement('div'); controlsContainer.innerHTML = '<input type="button" id="ChaturbateBetterModding_ChatLength" value="' + messagesCount + '" title="Click to delete all messages except the\nlast page, or except the last ' + mostRecentMessagesCount + ' messages\nif clicked with Shift key down" /><br />' + '<input type="button" id="ChaturbateBetterModding_ToggleExpand" value="' + (deletedMessagesShouldBeExpanded ? collapseChar : expandChar) + '" title="Click to toggle the automatic expanding or collapsing of\ndeleted messages and to expand or collapse all of them\n(keyboard shortcut is <), or click it with Shift key down to\ndo it without the toggling (shortcut is >)" />'; controlsContainer.style.textAlign = 'center'; document.body.appendChild(controlsContainer); var chatLengthButton = document.getElementById('ChaturbateBetterModding_ChatLength'); var toggleExpandButton = document.getElementById('ChaturbateBetterModding_ToggleExpand'); chatLengthButton.style.paddingLeft = '1px'; chatLengthButton.style.paddingRight = '1px'; toggleExpandButton.style.paddingLeft = '1px'; toggleExpandButton.style.paddingRight = '1px'; var origValue = chatLengthButton.value; chatLengthButton.value = 266; var chatLengthButtonMinWidth = $(chatLengthButton).outerWidth(); // really outer width is correct here, I do not know why not inner width chatLengthButton.value = origValue; chatLengthButton.style.minWidth = chatLengthButtonMinWidth + 'px'; toggleExpandButton.style.minWidth = chatLengthButtonMinWidth + 'px'; setControlsContainerPosition(); window.ChaturbateBetterModding_updateControlsContainerPosition = setControlsContainerPosition; function setControlsContainerPosition() { var chatPosition = domele.offset(); controlsContainer.style.position = 'absolute'; var chatOuterWidth = domele.outerWidth(); if (previousChatOuterWidth && previousChatOuterWidth - chatOuterWidth == 1) { // this is a work-aroud chatOuterWidth = previousChatOuterWidth; } else { previousChatOuterWidth = chatOuterWidth; } var left = chatPosition.left + chatOuterWidth + 10; var top = chatPosition.top; if (left + controlsContainer.clientWidth > document.body.scrollWidth) { left = chatPosition.left + chatOuterWidth - controlsContainer.clientWidth - 20; top -= 9; } controlsContainer.style.left = left + 'px'; controlsContainer.style.top = top + 'px'; } var updateChatLength = function() { //var length = chat.childNodes.length; var length = messagesCount; chatLengthButton.value = length.toString(); if (length >= messagesCountMax) { chatLengthButton.style.color = 'rgb(255,0,0)'; } else { chatLengthButton.style.color = ''; } } chatLengthButton.onclick = function(evt) { if (document.activeElement == chatLengthButton) { chatLengthButton.blur(); document.body.focus(); } var bigDelete = evt.shiftKey; var recentMessagesCount; if (bigDelete) { recentMessagesCount = mostRecentMessagesCount; } else { recentMessagesCount = 0; var totalHeight = 0; var node = chat.lastChild; do { while (node && node.nodeName != 'DIV') { node = node.previousSibling; } if (!node) { break; } totalHeight += $(node).outerHeight(true); recentMessagesCount++; node = node.previousSibling; } while (totalHeight < chat.clientHeight + pixelsToScrollOffChatBottom); } while (messagesCount > recentMessagesCount) { while (chat.firstChild.nodeName != 'DIV') { chat.removeChild(chat.firstChild); } chat.removeChild(chat.firstChild); messagesCount--; } chat.scrollTop = chat.scrollHeight; updateChatLength(); } var messagesToRemove = []; chat.addEventListener('scroll', onChatScroll, false); var silencedNickAttr = 'data-silenced-nick'; var silencerNickAttr = 'data-silencer-nick'; var deletedMessageHeight = '10px'; function is_at_bottom() { return chat.scrollTop >= chat.scrollHeight - chat.clientHeight; } function onChatScroll(evt) { if (messagesToRemove.length > 0 && is_at_bottom()) { for (var i = messagesToRemove.length - 1; i >= 0; i--) { var msgDiv = messagesToRemove[i]; messagesToRemove[i] = null; if (!deletedMessagesShouldBeExpanded && msgDiv && msgDiv.parentNode) { //msgDiv.parentNode.removeChild(msgDiv); if (!msgDiv.msgDeleted) { deleteMessage(msgDiv); } } messagesToRemove.length = i; } } } var bannedNickAttr = 'data-banned-nick'; function getSilencedByTitle(silencer_nick) { return 'silenced by ' + silencer_nick; } var deletedMessageBgColor = 'rgb(225,225,225)'; var on_user_silenced = function (silenced_nick, silencer_nick) { $(".chat-list > div.text > [data-nick='" + silenced_nick + "']").each(function (index, value) { //$(this).parent("div.text").remove(); var msgDiv = this.parentNode; if (!msgDiv.getAttribute(silencedNickAttr) && !msgDiv.getAttribute(bannedNickAttr)) { msgDiv.setAttribute(silencedNickAttr, silenced_nick); msgDiv.setAttribute(silencerNickAttr, silencer_nick); msgDiv.setAttribute('title', getSilencedByTitle(silencer_nick)); msgDiv.style.background = ''; msgDiv.style.backgroundColor = deletedMessageBgColor; messagesToRemove[messagesToRemove.length] = msgDiv; } onChatScroll(null); }); /*var text = interpolate(gettext("User %(username)s was silenced by %(silencer)s and his/her messages have been removed"), { username: silenced_nick, silencer: silencer_nick }, true);*/ var text = 'User ' + silenced_nick + ' was silenced by ' + silencer_nick; $.add_system_message(text, domele); }; var kickedOutTitle = 'kicked out'; var on_user_banned = function (username) { $(".chat-list > div.text > [data-nick='" + username + "']").each(function (index, value) { //$(this).parent("div.text").remove(); var msgDiv = this.parentNode; if (!msgDiv.getAttribute(bannedNickAttr)) { if (msgDiv.getAttribute(silencedNickAttr)) { msgDiv.removeAttribute(silencedNickAttr); msgDiv.removeAttribute(silencerNickAttr); } msgDiv.setAttribute(bannedNickAttr, username); msgDiv.setAttribute('title', kickedOutTitle); msgDiv.style.background = ''; msgDiv.style.backgroundColor = deletedMessageBgColor; messagesToRemove[messagesToRemove.length] = msgDiv; msgDiv.style.outlineColor = 'rgb(40,40,40)'; msgDiv.style.outlineWidth = '2px'; msgDiv.style.outlineStyle = 'solid'; } onChatScroll(null); }); /*var text = interpolate(gettext("User %(username)s was silenced by %(silencer)s and his/her messages have been removed"), { username: silenced_nick, silencer: silencer_nick }, true);*/ var text = 'User ' + username + ' was kicked out of the room'; $.add_system_message(text, domele); }; var old_add_message; var message_outbound = null; setTimeout(function() { var handler = defchat_settings.handler; var message_receiver = handler.defchat_message_receiver; message_receiver.on_user_silenced = on_user_silenced; message_receiver.on_user_banned = on_user_banned; old_add_message = message_receiver.add_message; messagesCount = domele.find('> div').length; message_receiver.add_message = add_message; message_outbound = handler.message_outbound; setControlsContainerPosition(); }, 1); function undeleteMessage(msgDiv) { msgDiv.style.height = ''; msgDiv.childNodes[0].style.display = ''; for (var i = 1; i < msgDiv.childNodes.length; i++) { var childNode = msgDiv.childNodes[i]; if (childNode.nodeType == 3) { // TextNode childNode.nodeValue = childNode.htmlBeforeDeleting; childNode.htmlBeforeDeleting = ''; } else { if (doRealDeleteWhenCollapsingMessages) { childNode.innerHTML = childNode.htmlBeforeDeleting; childNode.htmlBeforeDeleting = ''; } else { childNode.style.display = ''; } } } if (msgDiv.hasAttribute(silencedNickAttr)) { var silencer_nick = msgDiv.getAttribute(silencerNickAttr); msgDiv.setAttribute('title', getSilencedByTitle(silencer_nick)); } else if (msgDiv.hasAttribute(bannedNickAttr)) { msgDiv.setAttribute('title', kickedOutTitle); } msgDiv.msgDeleted = false; } function deleteMessage(msgDiv) { for (var i = msgDiv.childNodes.length - 1; i >= 1; i--) { var childNode = msgDiv.childNodes[i]; if (childNode.nodeType == 3) { // TextNode childNode.htmlBeforeDeleting = childNode.nodeValue; childNode.nodeValue = ''; } else { if (doRealDeleteWhenCollapsingMessages) { childNode.htmlBeforeDeleting = childNode.innerHTML; childNode.innerHTML = ''; } else { childNode.style.display = 'none'; } } } msgDiv.childNodes[0].style.display = 'none'; msgDiv.style.height = deletedMessageHeight; if (msgDiv.hasAttribute(silencedNickAttr)) { var silenced_nick = msgDiv.getAttribute(silencedNickAttr); var silencer_nick = msgDiv.getAttribute(silencerNickAttr); msgDiv.setAttribute('title', '' + silenced_nick + ', silenced by ' + silencer_nick); } else if (msgDiv.hasAttribute(bannedNickAttr)) { var username = msgDiv.getAttribute(bannedNickAttr); msgDiv.setAttribute('title', '' + username + ', kicked out'); } msgDiv.msgDeleted = true; } function add_message(message, domeleParam) { if (!domeleParam) { domeleParam = domele; } if (domeleParam.get(0) != chat) { return old_add_message.call(this, message, domeleParam); } var oldFind = domeleParam.find; domeleParam.find = function(selector) { if (selector == 'div.text') { return []; } return oldFind.call(this, selector); }; var originalScrollTop = chat.scrollTop; var at_bottom = is_at_bottom(); var result; try { result = old_add_message.call(this, message, domeleParam); } finally { domeleParam.find = oldFind; } messagesCount++; var totalHeight = 0; while (messagesCount > messagesCountMax) { var element = chat.firstChild; if (!at_bottom) { var outerHeight = $(element).outerHeight(true); totalHeight += outerHeight; } chat.removeChild(element); messagesCount--; } if (at_bottom) { chat.scrollTop = chat.scrollHeight; } else { chat.scrollTop = originalScrollTop - totalHeight; } updateChatLength(); return result; } chat.addEventListener('dblclick', onChatClick, false); chat.addEventListener('click', onChatClick, false); function onChatClick(evt) { if (evt.button != 0 || evt.shiftKey || evt.altKey || evt.metaKey) { return; } var ban = evt.ctrlKey; var nick; var par = evt.target; // par means paragraph if (par.nodeName == 'IMG') { par = par.parentNode; } var msgDiv; if (par.nodeName == 'P') { msgDiv = par.parentNode; } else { msgDiv = par; par = null; } var s = msgDiv.firstChild; // s means span if (msgDiv.nodeName == 'DIV' && msgDiv.getAttribute('class') == 'text' && s && s.nodeName == 'SPAN' && strStartsWith(s.className, 'username messagelabel')) { var nick; var banned = msgDiv.hasAttribute(bannedNickAttr); var isDeletedMessage = msgDiv.hasAttribute(silencedNickAttr) || banned; var isDoubleClick = evt.type == 'dblclick' && evt.detail == 2; var togglingExpanded = isDeletedMessage && evt.type == 'click' && !ban; var modding = !isDeletedMessage && isDoubleClick || isDeletedMessage && isDoubleClick && ban && !banned; if (togglingExpanded || modding) { if (!isDeletedMessage) { nick = s.getAttribute('data-nick'); } else { nick = msgDiv.getAttribute(silencedNickAttr); if (!nick) { nick = msgDiv.getAttribute(bannedNickAttr); } } if (nick) { if (modding) { window.getSelection().removeAllRanges(); evt.stopImmediatePropagation(); evt.stopPropagation(); evt.preventDefault(); if (messagesCount >= messagesCountMax && chat.scrollTop <= 0) { alert('The chat box is scrolled to the top and there is also the maximum mumber of messages in it, which is ' + messagesCountMax + '. First, either scroll it a little bit down, or delete some of the messages by clicking on that floating button with the number of messages.'); return; } if (is_at_bottom() && chat.scrollHeight > chat.clientHeight) { alert('The chat list is scrolled to the bottom. First, scroll it up by pressing SPACE.'); return; } } if (togglingExpanded) { if (msgDiv.msgDeleted) { undeleteMessage(msgDiv); } else { deleteMessage(msgDiv); } } else { if (!simulationMode) { if (ban) { message_outbound.send_kickban_user(nick); } var url = '/' + (ban ? 'roomban' : 'roomsilence') + '/' + nick + '/' + broadcaster + '/'; $.post(url, { 'foo': 'bar' }, function(data, textStatus, jqXHR) { //alert('data: ' + data + ', textStatus: ' + textStatus); if (data == 'OK' && textStatus == 'success') { } else { if (ban) { alert('A ban request has failed.'); } else { alert('A silence request has failed.'); } } }); } else { window.setTimeout(function() { //msgDiv.innerHTML = '<p>It was ' + nick + '</p>'; if (ban) { on_user_banned(nick); } else { on_user_silenced(nick, 'nobody'); } }, 700); } msgDiv.style.outlineColor = ban ? 'rgb(40,40,40)' : 'rgb(150,150,150)'; msgDiv.style.outlineWidth = '2px'; msgDiv.style.outlineStyle = ban ? 'dashed' : 'solid'; } } } } } function toggleExpand(noStateChange) { var expand = !deletedMessagesShouldBeExpanded; if (!noStateChange) { toggleExpandButton.value = expand ? collapseChar : expandChar; deletedMessagesShouldBeExpanded = expand; setDeletedMessagesShouldBeExpandedCookie(); } var at_bottom = is_at_bottom(); domele.find('> div').each(function(index, value) { var msgDiv = value; if (!msgDiv.getAttribute) { alert(msgDiv); } if (msgDiv.getAttribute(silencedNickAttr) || msgDiv.getAttribute(bannedNickAttr)) { if (expand) { if (msgDiv.msgDeleted) { undeleteMessage(msgDiv); } } else { if (!msgDiv.msgDeleted) { deleteMessage(msgDiv); } } } msgDiv = msgDiv.nextSibling; }); if (at_bottom) { chat.scrollTop = chat.scrollHeight; } } theElement.addEventListener('keypress', function(evt) { var nodeName = evt.target.nodeName; if (nodeName != "INPUT" && nodeName != "TEXTAREA" && nodeName != "BUTTON") { var character = String.fromCharCode(evt.charCode); if (character == ' ') { if (is_at_bottom()) { chat.scrollTop = chat.scrollHeight - chat.clientHeight - pixelsToScrollOffChatBottom; } else { chat.scrollTop = chat.scrollHeight; } evt.stopImmediatePropagation(); evt.stopPropagation(); evt.preventDefault(); } else if (character == '<' || character == '>') { var noStateChange = character == '>'; toggleExpand(noStateChange); } } }, false); toggleExpandButton.onclick = function(evt) { var noStateChange = evt.shiftKey; toggleExpand(noStateChange); if (document.activeElement == toggleExpandButton) { toggleExpandButton.blur(); document.body.focus(); } } } var output = document.createElement('div'); output.setAttribute('id', 'ChaturbateBetterModding'); output.setAttribute('style', 'padding: 0px 8px 10px 8px'); document.body.appendChild(output); contentEval(doBetterModdingChanges.toString()); if (document.forms.chat_form) { contentEval('doBetterModdingChanges();'); } else { output.innerHTML = 'ChaturbateBetterModding user script is on'; } function contentEval(source) { // Check for function input. if ('function' == typeof source) { // Execute this function with no arguments, by adding parentheses. // One set around the function, required for valid syntax, and a // second empty set calls the surrounded function. source = '(' + source + ')();' } // Create a script node holding this source code. var script = document.createElement('script'); script.setAttribute("type", "application/javascript"); script.textContent = source; // Insert the script node into the page, so it will run, and immediately // remove it to clean up. document.body.appendChild(script); document.body.removeChild(script); }