Created
May 4, 2016 20:10
-
-
Save Stjerneklar/b26d4366a9691a81eb8321437b34f6fc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name RLC | |
// @version 3.8.12 | |
// @description Chat-like functionality for Reddit Live | |
// @author FatherDerp | |
// @contributor Stjerneklar, thybag, mofosyne, jhon, 741456963789852123, MrSpicyWeiner, Concerned Hobbit (TheVarmari), Kretenkobr2 | |
// @website https://github.com/BNolet/RLC/ | |
// @namespace http://tampermonkey.net/ | |
// @updateURL https://github.com/BNolet/RLC/blob/master/rlcs.user.js | |
// @downloadURL https://github.com/BNolet/RLC/blob/master/rlcs.user.js | |
// @include https://www.reddit.com/live/* | |
// @exclude https://www.reddit.com/live/ | |
// @exclude https://www.reddit.com/live | |
// @exclude https://www.reddit.com/live/*/edit* | |
// @exclude https://www.reddit.com/live/*/contributors* | |
// @exclude https://*.reddit.com/live/create* | |
// @require https://code.jquery.com/jquery-2.2.3.min.js | |
// @grant GM_addStyle | |
// @grant GM_setValue | |
// @grant GM_getValue | |
// @grant GM_getResourceText | |
// @grant GM_setClipboard | |
// @run-at document-idle | |
// @noframes | |
// ==/UserScript== | |
(function() { | |
/*¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ | |
RLC GLOBAL VARIABLES SECTION BELOW | |
010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101 | |
101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010 | |
____________________________________________________________________________________________________________________________________________________________________________*/ | |
// Settings Keys (used in /sharesettings) | |
var optionsArray = []; | |
//Check and store browser details | |
var nVer = navigator.appVersion; | |
var nAgt = navigator.userAgent; | |
var browserName = navigator.appName; | |
var fullVersion = ''+parseFloat(navigator.appVersion); | |
var majorVersion = parseInt(navigator.appVersion,10); | |
var nameOffset,verOffset,ix; | |
// set default states(on first load of RLC, otherwise presists via GM/TM local variables) for options ( ONLY NEEEDED FOR DEFAULT TRUE ) | |
if (!GM_getValue("rlc-ChannelColors")) { GM_setValue("rlc-ChannelColors", true);} | |
if (!GM_getValue("rlc-AutoScroll")) { GM_setValue("rlc-AutoScroll", true);} | |
// Grab users username + play nice with RES | |
var robinUser = $("#header-bottom-right .user a").first().text().toLowerCase(); | |
// Channel Colours | |
var colors = ["rgba(255,0,0,0.1)", "rgba(0,255,0,0.1)", "rgba(0,0,255,0.1)", "rgba(0,255,255,0.1)", "rgba(255,0,255,0.1)", "rgba(255,255,0,0.1)", "rgba(211,211,211, .1)", "rgba(0,100,0, .1)", "rgba(255,20,147, .1)", "rgba(184,134,11, .1)"]; | |
// Notification sound in base64 encoding | |
var base64sound ="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QECBtFxREzTNkMyfLLVlM9UgS6aQnkPEo3DJRYkUyVQacP6j+5rqMc4TaCiVCxzSEDIKUTvMec6D7tk0aS4CEYQqahfEu6jh/We1NrVrQzhbTKZBgYbi8YbecRuLTMpTvUoAIIlynCMCimNNtBMWwDOcZIMABFMmDZPSCQgzPrLBYvUyQFMUd6UR1kbzgIGfWKw/SrqKgg5coZaKgUBQzOtyEaucSrOTBlGOqpGMNYXtGwYFhwTdfZ/nmjb0QUrCKicsj8alcPp0y7KmpuOEVAQSvUg25SKDofWuZEBtKidNLZhQJ0oGpdfVeGhJgUUEjARAINH4cGP3olbJAcdDR4gdl/onWtSmuw1xa2WVPSOy6CJ4qHBgSoO8r9UmcZiT4P+YkAhcKf+BJTTY44/cYFV5vLKV2XeYQShgODRoQoL8Kv/7ksTXgBhp4TbVygAE2sIlAzuwAJ5JQRVudDXlr7DoQRA6LbSquF6tu7RZb5t9nGr1bOOvx+64QknJBvtR///////////////6R48LQFE////////////////2AwDFdBkACAVhVSstnYaa015ymstdiCPRbJK5R0zROkwvcAhgeoNiRyAwEGJhpENIsbJLJknUCBC5jw5QzRuQEc0uCEwauFwjqEFhBYXEVxjQyKGKSXFmigRmTxeLx0mUjEumrUkklJJLLpqogQ5x4mhziLGyJdRatHrRLrooskk6Jq6Jqj1o/qSSqS/60UZkXmUkk9FFGtFH/9aPRRZRkXmSLyT0W/0UaLKSSWYl1zFMQU1FMy45OC4yqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpMQU1FMy45OC4yqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqr/+5LEoQPVgaL0XYiAAAAANIAAAASqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"; | |
var snd = new Audio("data:audio/wav;base64, " + base64sound); | |
// Chrome notice image in bass64 | |
var chromeNotificationImage = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAIAAABuYg/PAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAEnQAABJ0Ad5mH3gAAADgSURBVFhH7ZdRbsMwDENzgt7/Sj2VG0eEKxGUmgJOUKR5eMNgiRH3u6U5lgPA6Q08sHg+povL1mJNlJiu9Z1bdkKT2Zv+rAyL7/8OfFbcFKOID2QiGhEBMYr4QCaiERHgt2JkpAgpOMNvxchIEVJwht+KkZEipODMeL9HER/IRDQiAmIU8YFMRCMi4EcmFvtqvPisuEnTg7zLpniXTfGXyopVZn2tQ9Nhscqsr3VoOixWmfW1Dk299Zb8eKpDUxKhHdCH5K7QLK9ddt3/YtYf6zuoEpetxX4ZtpgLTq+09gIQTX1K/dS/IgAAAABJRU5ErkJggg=="; | |
// HTML for injection, inserted at doc.ready | |
var htmlPayload = `<div id="rlc-wrapper"> | |
<div id="rlc-header"> | |
<div id="rlc-titlebar"> | |
<div id="rlc-togglebar"> | |
<div id="togglebarTTS">TextToSpeech</div> | |
<div id="togglebarLoadHist">Load History</div> | |
<div id="togglebarAutoscroll">Autoscroll</div> | |
</div> | |
</div> | |
<div id="rlc-statusbar"></div> | |
</div> | |
<div id="rlc-leftpanel"> </div> | |
<div id="rlc-main"> | |
<div id="rlc-chat"></div> | |
<div id="rlc-messagebox"> | |
<select id="rlc-channel-dropdown"> | |
<option></option> | |
<option>%general</option> | |
<option>%offtopic</option> | |
<option>%dev</option> | |
</select> | |
<div id="rlc-sendmessage">Send Message</div> | |
</div> | |
</div> | |
<div id="rlc-sidebar"> | |
<div id="rlc-settingsbar"> | |
<div id="rlc-toggleoptions" title="Show Options" class="noselect">Options</div> | |
<div id="rlc-update" class="noselect"><a target="_blank" href="https://github.com/BNolet/RLC/raw/master/rlcs.user.js" rel="nofollow">Update RLC</a></div> | |
<div id="rlc-toggleguide" title="Show Guide" class="noselect">Readme</div> | |
</div> | |
<div id="rlc-main-sidebar"></div> | |
<div id="rlc-readmebar"><div class="md"></div> | |
</div> | |
<div id="rlc-guidebar"><div class="md"></div> | |
</div> | |
<div id="rlc-settings"> | |
</div> | |
</div> | |
<div id="myContextMenu"> | |
<ul> | |
<li id="mute"><a>Mute User</a></li> | |
<li id="PMUser"><a>PM User</a></li> | |
<li id="deleteCom"><a>Delete Comment</a></li> | |
<li id="copyMessage"><a>Copy Message</a></li> | |
<li id="speakMessage"><a>Speak Message</a></li> | |
</ul> | |
</div> | |
</div>`; | |
/*¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ | |
RLC INIT LOGIC SECTION BELOW | |
010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101 | |
101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010 | |
____________________________________________________________________________________________________________________________________________________________________________*/ | |
// In Opera 15+, the true version is after "OPR/" | |
if ((verOffset=nAgt.indexOf("OPR/"))!=-1) { | |
browserName = "Opera"; | |
fullVersion = nAgt.substring(verOffset+4); | |
} | |
// In older Opera, the true version is after "Opera" or after "Version" | |
else if ((verOffset=nAgt.indexOf("Opera"))!=-1) { | |
browserName = "Opera"; | |
fullVersion = nAgt.substring(verOffset+6); | |
if ((verOffset=nAgt.indexOf("Version"))!=-1) | |
fullVersion = nAgt.substring(verOffset+8); | |
} | |
// In MSIE, the true version is after "MSIE" in userAgent | |
else if ((verOffset=nAgt.indexOf("MSIE"))!=-1) { | |
browserName = "Microsoft Internet Explorer"; | |
fullVersion = nAgt.substring(verOffset+5); | |
} | |
// In Chrome, the true version is after "Chrome" | |
else if ((verOffset=nAgt.indexOf("Chrome"))!=-1) { | |
browserName = "Chrome"; | |
fullVersion = nAgt.substring(verOffset+7); | |
} | |
// In Safari, the true version is after "Safari" or after "Version" | |
else if ((verOffset=nAgt.indexOf("Safari"))!=-1) { | |
browserName = "Safari"; | |
fullVersion = nAgt.substring(verOffset+7); | |
if ((verOffset=nAgt.indexOf("Version"))!=-1) | |
fullVersion = nAgt.substring(verOffset+8); | |
} | |
// In Firefox, the true version is after "Firefox" | |
else if ((verOffset=nAgt.indexOf("Firefox"))!=-1) { | |
browserName = "Firefox"; | |
fullVersion = nAgt.substring(verOffset+8); | |
} | |
// In most other browsers, "name/version" is at the end of userAgent | |
else if ( (nameOffset=nAgt.lastIndexOf(' ')+1) < | |
(verOffset=nAgt.lastIndexOf('/')) ) | |
{ | |
browserName = nAgt.substring(nameOffset,verOffset); | |
fullVersion = nAgt.substring(verOffset+1); | |
if (browserName.toLowerCase()==browserName.toUpperCase()) { | |
browserName = navigator.appName; | |
} | |
} | |
// trim the fullVersion string at semicolon/space if present | |
if ((ix=fullVersion.indexOf(";"))!=-1) | |
fullVersion=fullVersion.substring(0,ix); | |
if ((ix=fullVersion.indexOf(" "))!=-1) | |
fullVersion=fullVersion.substring(0,ix); | |
majorVersion = parseInt(''+fullVersion,10); | |
if (isNaN(majorVersion)) { | |
fullVersion = ''+parseFloat(navigator.appVersion); | |
majorVersion = parseInt(navigator.appVersion,10); | |
} | |
/*¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ | |
RLC VARIOUS FUNCTIONS SECTION BELOW | |
010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101 | |
101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010 | |
____________________________________________________________________________________________________________________________________________________________________________*/ | |
// Scroll chat back to bottom | |
var scrollToBottom = function(){ | |
$("#rlc-chat").scrollTop($("#rlc-chat")[0].scrollHeight); | |
}; | |
// Manipulate native reddit live into loading old messages | |
function loadHistory() { | |
if (GM_getValue("rlc-TextToSpeechTTS")) { | |
// TODO: Switch to something more user-friendly. Message in the chat? | |
alert("You have TextToSpeech enabled, please disable to load old messages."); | |
} else { | |
loadingInitialMessages = 1; | |
$("body").toggleClass("allowHistoryScroll"); | |
$("body").scrollTop($("body")[0].scrollHeight); | |
scrollToBottom(); | |
$("body").toggleClass("allowHistoryScroll"); | |
} | |
} | |
// Time converter for active user list | |
function convertTo24Hour(time) { | |
var hours = parseInt(time.substr(0, 2)); | |
if (time.indexOf("am") !== -1 && hours === 12) time = time.replace("12", "0"); | |
if (time.indexOf("pm") !== -1 && hours < 12) time = time.replace(hours, (hours + 12)); | |
return time.replace(/(am|pm)/, ""); | |
} | |
var b = GM_getValue("mutedUsers"); | |
if(b!=undefined){ | |
var mutedUsers = b; | |
}else{ | |
var mutedUsers = []; | |
} | |
function updateMutedUsers() { | |
// Reset by removing CSS and userlist | |
$("#mystyle").remove(); | |
$("#bannedlist").empty(); | |
// Iterate over the muted users | |
var selectors = []; | |
for(let i = 0; i <= mutedUsers.length; i++){ | |
if (mutedUsers[i] !== undefined) { // Avoid the undefined one I cant figure out why I'm puttin in | |
selectors.push(`.u_${mutedUsers[i]}{display:none;}`); // Generate CSS display none rule for user in list | |
$('.u_'+mutedUsers[i]).addClass('muted'); | |
$("#bannedlist").append(`<p>${mutedUsers[i]}</p>`); // Generate interface element for disabling muting | |
reAlternate(); | |
} | |
} | |
$("body").append(`<style id='mystyle'>${selectors.join(" ")}</style>`); // Inject style tag with user rules | |
// Handle clicking in muted user list (needs to be here for scope reasons) | |
$("#bannedlist p").click(function(){ | |
let target = $(this).text(); | |
let targetPosition = mutedUsers.indexOf(target); | |
$('.u_'+mutedUsers[targetPosition]).removeClass('muted'); | |
reAlternate(); | |
$(this).remove(); // Remove this element from the muted list | |
mutedUsers.splice(targetPosition, 1); // Remove target from the muted array | |
updateMutedUsers(); // Update | |
scrollToBottom(); | |
}); | |
GM_setValue("mutedUsers", mutedUsers); | |
} | |
var activeUserArray = [], | |
activeUserTimes = [], | |
updateArray = []; | |
// Update active user list | |
function processActiveUsersList() { | |
$("#rlc-activeusers ul").empty(); | |
updateArray = []; | |
for(let i = 0; i <= activeUserArray.length; i++){ | |
if (updateArray.indexOf(activeUserArray[i]) === -1 && activeUserArray[i] !== undefined) { | |
updateArray.push(activeUserArray[i]); | |
$("#rlc-activeusers ul").append(`<li><span class='activeusersUser'>${activeUserArray[i]}</span> @ <span class='activeusersTime'>${activeUserTimes[i]}</span></li>`); | |
} else if (updateArray.indexOf(activeUserArray[i]) > -1) { | |
/* TODO: Add things. | |
Add message counter value | |
Check if timestamp is recent enough? */ | |
} | |
} | |
} | |
// Create persistant option | |
function createOption(name, clickAction, defaultState, description){ | |
var checkedMarkup; | |
var key = "rlc-" + name.replace(/\W/g, ""); | |
var state = (typeof defaultState !== "undefined") ? defaultState : false; | |
// Add if not exist in optionsArray | |
if ( !(key in optionsArray) ){ | |
optionsArray.push(key); | |
} | |
// Try and state if setting is defined | |
if (GM_getValue(key)){ | |
state = GM_getValue(key); | |
} | |
// Markup for state | |
checkedMarkup = state ? "checked='checked'" : ""; | |
// sorry, im nub | |
if (description === undefined) { | |
description = ""; | |
} | |
// Render option | |
var $option = $(`<label id='option-${key}'><input type='checkbox' ${checkedMarkup}>${name}<span>${description}</span></label>`).click(function(){ | |
let checked = $(this).find("input").is(":checked"); | |
// Persist state | |
if (checked !== state){ | |
GM_setValue(key, checked); | |
state = checked; | |
} | |
clickAction(checked, $(this)); | |
}); | |
// Add to DOM | |
$("#rlc-settings").append($option); | |
clickAction(state, $option); | |
/*uncomment below to output option key/value */ | |
//console.log(key+" = "+state); | |
} | |
/*¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ | |
RLC MESSAGE HANDLING FUNCTIONS SECTION BELOW | |
01010101010101010101010101010101010101010101penis0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101 | |
101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010 | |
____________________________________________________________________________________________________________________________________________________________________________*/ | |
// Channel prefix removal | |
var removeChannelKeyFromMessage = function(message){ | |
if ($("#rlc-chat").attr("data-channel-key")){ | |
var offset = $("#rlc-chat").attr("data-channel-key").length; | |
if (offset === 0) return message; | |
if (message.indexOf("/me") === 0) return "/me "+ message.slice(offset+5); | |
return message.slice(offset+1); | |
} | |
return message; | |
}; | |
// Convert string to hex (for user colors) | |
function toHex(str) { | |
var result = ""; | |
for (var i=0; i<str.length; i++) { | |
result += str.charCodeAt(i).toString(16); | |
} | |
return result; | |
} | |
// Generate random value based on seed, max and minimum (for user colors) | |
Math.seededRandom = function(seed, max = 1, min = 0) { | |
// In order to work 'seed' must NOT be undefined, | |
// So in any case, you HAVE to provide a Math.seed | |
seed = (seed * 9301 + 49297) % 233280; | |
var rnd = seed / 233280; | |
return parseInt(min + rnd * (max - min)); | |
}; | |
// Message background alternation via js | |
var rowAlternator = false; | |
// Modify color by amount | |
function LightenDarkenColor(col, amt) { | |
var r = col.slice(0,2); | |
var g = col.slice(2,4); | |
var b = col.slice(4,6); | |
if (rowAlternator) amt+=10; // TODO: Might want to rethink this | |
var randR = (Math.seededRandom(r*100,120,175)); | |
var randG = (Math.seededRandom(g*100,120,175)); | |
var randB = (Math.seededRandom(b*100,120,175)); | |
// TODO-SUGGESTION: Code readability | |
var suppress = (Math.seededRandom(col*r*10,0,6)); | |
var modAmt =2 ; | |
switch(suppress) { | |
case 0: | |
randR/=modAmt; | |
break; | |
case 1: | |
randG/=modAmt; | |
break; | |
case 2: | |
randB/=modAmt; | |
break; | |
case 4: | |
randR/=modAmt; | |
randG/=modAmt; | |
break; | |
case 5: | |
randR/=modAmt; | |
randB/=modAmt; | |
break; | |
case 6: | |
randG/=modAmt; | |
randB/=modAmt; | |
break; | |
default: | |
//console.log("This shouldn't happen! (LightenDarkenColor switch case)"); | |
break; | |
} | |
var hexR = (parseInt(randR) + parseInt(amt)).toString(16); | |
var hexG = (parseInt(randG) + parseInt(amt)).toString(16); | |
var hexB = (parseInt(randB) + parseInt(amt)).toString(16); | |
return hexR + hexG + hexB; | |
} | |
function messageMentionHandler(line, $usr, $el) { | |
if (line.indexOf(robinUser) !== -1){ | |
// Add bold highlighting | |
$el.addClass("user-mention"); | |
} | |
} | |
function alternateMsgBackground($el) { | |
if (!GM_getValue("rlc-CSSBackgroundAlternation")) { | |
if (loadingInitialMessages === 0) { | |
var $child = $('.liveupdate-listing:not(.muted)').children()[1]; | |
rowAlternator=($($child).hasClass('alt-bgcolor')); | |
}else{ | |
rowAlternator=!rowAlternator; | |
} | |
if(rowAlternator === false){ | |
$el.addClass("alt-bgcolor"); | |
} | |
} | |
} | |
// emoji trigger list. supports multiple triggers for one emote(eg meh) and automaticly matches both upper and lower case letters(eg :o/:O) | |
var emojiList={ ":)": "smile", | |
":((": "angry", | |
":(": "frown", | |
":s": "silly", | |
":I": "meh", | |
":|": "meh", | |
":/": "meh", | |
":o": "shocked", | |
":D": "happy", | |
"D:": "sad", | |
";_;": "crying", | |
"T_T": "crying", | |
";)": "wink", | |
"-_-": "zen", | |
"X|": "annoyed", | |
"X)": "xsmile", | |
"X(": "xsad", | |
"XD": "xhappy", | |
":P": "tongue"}; | |
function emoteSupport(line, $msg, firstLine) { | |
if (!GM_getValue("rlc-NoEmotes")){ | |
$.each(emojiList, function(emoji,replace){ | |
if (line.toLowerCase().indexOf(emoji.toLowerCase()) !== -1 && line.indexOf("http") === -1){ | |
if ($msg.has("h1").length === 0 && $msg.has("li").length === 0 && $msg.has("code").length === 0 && $msg.has("table").length === 0){ | |
firstLine.html(firstLine.html().split(emoji.toUpperCase()).join(emoji.toLowerCase())); | |
firstLine.html(firstLine.html().split(emoji.toLowerCase()).join(`<span class='mrPumpkin mp_${replace}'></span>`)); | |
} | |
} | |
}); | |
} | |
} | |
// User color | |
function messageUserColor($usr) { | |
if (!GM_getValue("rlc-RobinColors")) { | |
var hexName = toHex($usr.text()).split(""); | |
var adder = 1; | |
$.each(hexName, function(ind,num){ | |
num = (parseInt(num) + 1); | |
if (num !== 0 && !isNaN(num)){ | |
adder = adder * num; | |
} | |
}); | |
adder = adder.toString().replace(".", "").split("0").join(""); | |
let start = adder.length-10; | |
let end = adder.length-4; | |
var firstThree = adder.toString().substring(start, end); | |
// Variable brigtening of colors based on dark mode setting | |
if (GM_getValue("rlc-DarkMode")){ | |
var lighterColor = LightenDarkenColor(firstThree, 60); | |
$usr.css("color", "#"+lighterColor); | |
} | |
else { | |
var darkerColor = LightenDarkenColor(firstThree, -40); | |
$usr.css("color", "#"+darkerColor); | |
} | |
} else { | |
$usr.css("color", getColor($usr.text())); //ROBIN COLORS!!!!! | |
} | |
} | |
// Timestamp modification & user activity tracking | |
function timeAndUserTracking($el, $usr) { | |
var shortTime = $el.find(".body time").attr("title").split(" "); | |
var amPm = shortTime[4].toLowerCase(); | |
if (!(amPm === "am" || amPm === "pm")) { amPm = " "; } | |
var militarytime = convertTo24Hour(shortTime[3] + " " + amPm); | |
if ($("body").hasClass("rlc-24hrTimeStamps")) { | |
shortTime = convertTo24Hour(shortTime[3] + " " + amPm); | |
} else { | |
shortTime = shortTime[3]+" "+amPm; | |
} | |
// Add simplified timestamps | |
if ($el.find(".body .simpletime").length <= 0) { | |
$el.find(".body time").before(`<div class='simpletime'>${shortTime}</div>`); | |
} | |
// Add info to activeuserarray | |
activeUserArray.push($usr.text()); | |
activeUserTimes.push(militarytime); | |
// Moved here to add user activity from any time rather than only once each 10 secs. (Was in tab tick function, place it back there if performance suffers) | |
processActiveUsersList(); | |
} | |
// I'm not even going to try to clear this up. | |
function messageClickHandler($usr, $msg, $el) { | |
var $menu = $("#myContextMenu"); | |
$(".hasEmbed").click(function(){ | |
$("#rlc-leftpanel").empty(); | |
$("#rlc-leftpanel").append(" "); | |
$("#rlc-leftpanel").append($msg.find("iframe")); | |
//$(this).hide(); | |
}); | |
$usr.click(function(event){ | |
event.preventDefault(); | |
if ($menu.css("display") === "none" && !isNaN(divPos["left"]) && !isNaN(divPos["top"]) ) { | |
if (window.innerHeight-100 > divPos["top"]){ | |
$menu.css({"left":divPos["left"], "top":divPos["top"], "display": "initial"}); //menu down | |
} else { | |
$menu.css({"left":divPos["left"], "top":divPos["top"]-70, "display": "initial"}); //menu up | |
} | |
var $button = $(this).parent().siblings().find(".delete").find("button"); | |
if ($button.length>0){ | |
$menu.find("#deleteCom").removeClass("disabled"); | |
} else { | |
$menu.find("#deleteCom").addClass("disabled"); | |
} | |
$menu.find("ul li").unbind("click"); | |
$menu.find("ul li").bind("click", function(){ | |
var $id = $(this).attr("id"); | |
if ($id === "deleteCom" && $(this).has(".disabled").length === 0){ | |
deleteComment($el); | |
} | |
if ($id === "PMUser"){ | |
OpenUserPM($usr.text()); | |
} | |
if ($id === "mute"){ | |
var banusername = String($usr.text()).trim(); | |
mutedUsers.push(banusername); | |
updateMutedUsers(); | |
} | |
if ($id === "copyMessage"){ | |
var copystring = String($usr.text()).trim() + " : " + String($msg.text()).trim(); | |
$(".usertext-edit.md-container textarea").focus().val(copystring); | |
} | |
if ($id === "speakMessage"){ | |
messageTextToSpeechHandler($msg, $usr); | |
} | |
$menu.css({"left":0, "top":0, "display": "none"}); //close menu | |
}); | |
$("body").unbind("click"); | |
$("body").bind("click", function(e) { | |
if ($(e.target).closest($usr).length === 0) { | |
$menu.css({"left":0, "top":0, "display": "none"}); | |
} | |
}); | |
} else { | |
$menu.css({"left":0, "top":0, "display": "none"}); //close menu | |
} | |
}); | |
} | |
// Used differentiate initial and subsequent messages | |
var loadingInitialMessages = 1; | |
// Track if username has been mentioned | |
var meMentioned = 0; | |
// Message display handling for new and old (rescan) messages | |
// Add any proccessing for new messages in here | |
var handleNewMessage = function($el, rescan){ | |
//console.log(rescan); | |
var $msg = $el.find(".body .md"); | |
var $usr = $el.find(".body .author"); | |
var line = $msg.text().toLowerCase(); | |
var firstLine = $msg.find("p").first(); | |
meMentioned = 0; | |
// /me support | |
if (line.indexOf("/me") === 0){ | |
$el.addClass("user-narration"); | |
firstLine.html(firstLine.html().replace("/me", " " + $usr.text().replace("/u/", ""))); | |
meMentioned = 1; | |
} | |
if($msg.text().length>250){ | |
$msg.addClass("longMessageClosed"); | |
firstLine.prepend("<input type='button' value='+' class='extendButton' style='width:18px;height:18px;padding:0px;font-size:0.8em'>"); | |
$msg.on('click', '.extendButton', function () { | |
if($msg.hasClass("longMessageClosed")){ | |
$msg.removeClass("longMessageClosed"); | |
$msg.find('.extendButton').val('-'); | |
}else{ | |
$msg.addClass("longMessageClosed"); | |
$msg.find('.extendButton').val('+'); | |
} | |
scrollToBottom(); | |
}); | |
} | |
// Target blank all message links | |
$msg.find("a").attr("target", "_blank"); | |
if (loadingInitialMessages === 0) { | |
if (GM_getValue("rlc-LeftPanel")) { | |
/* embedded content detection - removes links and their contents to see if that was the only content, if so, treat as embed */ | |
/* need to check like this since the iframes dont exist when our code is run */ | |
var $messageNoLink = $msg; | |
$messageNoLink.find("a").contents().remove(); | |
$messageNoLink.remove("a"); | |
//console.log($messageNoLink.text().length); | |
//console.log($messageNoLink.text()); | |
if ($messageNoLink.text().length === 1) { | |
$msg.addClass("hasEmbed"); | |
} | |
} | |
else { | |
firstLine.html(firstLine.html()+" "); | |
// Prevent embedly iframe link handling | |
} | |
} | |
// Insert time | |
$usr.before($el.find("time")); | |
// Remove the /u/ in author name | |
$usr.text($usr.text().replace("/u/", "")); | |
// Tag message with user identifier for muting | |
$el.addClass("u_"+$usr.text()); | |
// Alternating background color | |
alternateMsgBackground($el); | |
// Current User name mentioned | |
messageMentionHandler(line, $usr, $el); | |
// Emote support | |
emoteSupport(line, $msg, firstLine); | |
// Easy (and hacky) multiline | |
$msg.html($msg.html().split("\n").join("<br>")); | |
$msg.html($msg.html().replace("<br><br>","<br>")); | |
$msg.html($msg.html().replace("</p><br>", "")); | |
// Track channels | |
tabbedChannels.proccessLine(line, $el, rescan); | |
// Remove separator | |
$(".liveupdate-listing .separator").remove(); | |
// Timestamp modification & user activity tracking | |
timeAndUserTracking($el, $usr); | |
messageUserColor($usr); // User color | |
messageClickHandler($usr, $msg, $el); // Message click handling | |
if(mutedUsers.indexOf($usr.text())!=-1){ //deal with muting | |
$msg.parent().addClass('muted'); | |
} | |
if (loadingInitialMessages === 0) { | |
reAlternate(); | |
// Stuff that should not be done to messages loaded on init, like TTS handling | |
if (rescan) { | |
//console.log("This is the rescan. Do you copy? Not sure why we're reporting. Over and out."); | |
// This is rescan, do nothing. rescans happen when channel tabs are changed | |
} | |
else { | |
// Not rescan, read aloud if TTS enabled | |
if (line.indexOf(robinUser) !== -1){ | |
if ($("body").hasClass("rlc-notificationsound")) { | |
snd.play(); | |
} | |
if ($("body").hasClass("rlc-notificationchrome")) { | |
new Notification("Robin Live Chat",{ | |
icon: chromeNotificationImage, | |
body: $usr.text() + ": " + line | |
}); | |
} | |
} | |
if(!$msg.parent().hasClass('muted')){ | |
messageTextToSpeechHandler($msg, $usr); | |
} | |
} | |
} | |
}; | |
function getColor(username) { | |
var colors = ["#e50000", "#db8e00", "#ccc100", "#02be01", "#0083c7", "#820080"]; | |
var e = username.toLowerCase(), | |
t = e.replace(/[^a-z0-9]/g, ""), | |
n = parseInt(t, 36) % 6; | |
return colors[n]; | |
} | |
function OpenUserPM(name) { | |
var $url = "https://www.reddit.com/message/compose/?to="; | |
var win = window.open($url+name, "_blank"); | |
win.focus(); | |
} | |
function reAlternate($objComment){ | |
if($objComment===undefined){ | |
var alt=false; | |
for(i=$('.liveupdate-listing').children().length;i>=0;i--){ | |
var obj=$('.liveupdate-listing').children()[i]; | |
if(!$(obj).hasClass('muted')){ | |
$(obj).removeClass('alt-bgcolor'); | |
if(alt){ | |
$(obj).addClass('alt-bgcolor'); | |
} | |
alt=!alt; | |
} | |
} | |
}else{ | |
var found; | |
var alt; | |
for(i=$('.liveupdate-listing').children().length;i>=0;i--){ | |
var obj=$('.liveupdate-listing').children()[i]; | |
if(obj == $objComment.context) { | |
found=true; | |
alt = $($('.liveupdate-listing').children()[i+1]).hasClass("alt-bgcolor"); | |
} | |
if(found){ | |
$($('.liveupdate-listing').children()[i]).removeClass('alt-bgcolor'); | |
if(alt){ | |
$($('.liveupdate-listing').children()[i]).addClass('alt-bgcolor'); | |
} | |
alt=!alt; | |
} | |
} | |
} | |
} | |
function deleteComment($objComment){ | |
if ($objComment.has(".buttonrow").length>0){ | |
reAlternate($objComment); | |
var $button = $objComment.find(".delete").find("button"); | |
$button.click(); | |
$button = $objComment.find(".delete").find(".yes"); | |
$button.click(); | |
} | |
} | |
var divPos = {}; | |
$(document).mousemove(function(e){ | |
divPos = { | |
left: e.pageX, | |
top: e.pageY | |
}; | |
}); | |
/*¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ | |
RLC TEXT TO SPEECH FUNCTIONS SECTION BELOW | |
010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101 | |
101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010 | |
____________________________________________________________________________________________________________________________________________________________________________*/ | |
// Numbers to english words for TTS | |
var digits = ["", "one ", "two ", "three ", "four ", "five ", "six ", "seven ", "eight ", "nine ", "ten ", "eleven ", "twelve ", "thirteen ", "fourteen ", "fifteen ", "sixteen ", "seventeen ", "eighteen ", "nineteen "], | |
tens = ["", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"]; | |
function numberToEnglish (num) { | |
if ((num = num.toString()).length > 9) return "Overflow in numberToEnglish function."; | |
let n = ("000000000" + num).substr(-9).match(/^(\d{2})(\d{2})(\d{2})(\d{1})(\d{2})$/); | |
/* NOTE: IF YOU REPLACE != with !== below, the numbers are read wrong */ | |
if (!n) return; var str = ""; | |
str += (n[1] != 0) ? (digits[Number(n[1])] || tens[n[1][0]] + " " + digits[n[1][1]]) + "crore " : ""; | |
str += (n[2] != 0) ? (digits[Number(n[2])] || tens[n[2][0]] + " " + digits[n[2][1]]) + "lakh " : ""; | |
str += (n[3] != 0) ? (digits[Number(n[3])] || tens[n[3][0]] + " " + digits[n[3][1]]) + "thousand " : ""; | |
str += (n[4] != 0) ? (digits[Number(n[4])] || tens[n[4][0]] + " " + digits[n[4][1]]) + "hundred " : ""; | |
str += (n[5] != 0) ? ((str != "") ? "and " : "") + (digits[Number(n[5])] || tens[n[5][0]] + " " + digits[n[5][1]]) + " " : ""; | |
return str.trim(); | |
} | |
function getNumbers(input) { | |
return input.match(/[0-9]+/g); | |
} | |
// Select Emoji to narration tone | |
var toneList = {"smile": "smiling", | |
"angry": "angrily", | |
"frown": "while frowning", | |
"silly": "pulling a silly face", | |
"meh": "in a disinterested manner", | |
"shocked": "in shock", | |
"happy": "happily", | |
"sad": "looking sad", | |
"crying": "with tears in his eyes", | |
"wink": "while winking", | |
"zen": "in zen mode", | |
"annoyed": "expressing annoyance", | |
"xsmile": "with a grinning broadly", | |
"xsad": "very sadly", | |
"xhappy": "very happily", | |
"tongue": "while sticking out a tongue"}; | |
// Abbreviation Expansion (All keys must be in uppercase) | |
var replaceStrList = { | |
"AFAIK": "As Far As I Know", | |
"AFK": "Away From Keyboard", | |
"AKA": "Also Known As", | |
"ASAP": "As Soon As Possible", | |
"BRB": "Be right back", | |
"B8": "Bait", | |
"BTW": "By The Way", | |
"CYA": "See Ya", | |
"DIY": "Do it yourself", | |
"FTW": "For The Win", | |
"FK": "Fuck", | |
"FTFY": "Fixed that for you", | |
"FFS": "For Fucks Sake", | |
"G2G": "got to go", | |
"GR8": "Great", | |
"GL": "Good luck", | |
"GTFO": "Get The Fuck Out", | |
"IRL": "In real life", | |
"IIRC": "If I recall correctly", | |
"IKR": "I Know Right", | |
"IMO": "In My Opinion", | |
"JK": "Just Kidding", | |
"MATE": "M8", | |
"NVM": "Nevermind", | |
"N1": "Nice One", | |
"NP": "No problem", | |
"OFC": "Of Course", | |
"OMG": "Oh My God", | |
"RTFM": "Read The Fucking Manual", | |
"R8": "Rate", | |
"RLC": "Reddit Live Chat", | |
"TLDR": "Too Long, Didn't Read", | |
"TTS": "Text to speech", | |
"TIL": "Today I learned", | |
"TY": "Thanks", | |
"YW": "You're welcome", | |
"TBH": "To be honest", | |
"WTF": "What The Fuck", | |
"KRETENKOBR2": "KretenkobrTwo", | |
"<": "Kleinerdong", | |
"stfu": "Shut The Front Door" | |
}; | |
var langSupport = ["el","fr","da","en","en-GB", "en-US", "sv", "es-US", "hi-IN", "it-IT", "nl-NL", "pl-PL", "ru-RU"]; | |
function strSeededRandInt (str, min = 0, max = 256, code = 0){ | |
for(let i = 0; i < str.length; i++){ | |
code += str.charCodeAt(i); | |
} | |
return code % (1 + max - min) + min; | |
} | |
function messageTextToSpeechHandler($msg, $usr) { | |
if (GM_getValue("rlc-TextToSpeechTTS")) { | |
if($msg.text().length<250){ | |
var linetoread = $msg.text(); // Load in message string | |
var hasTripple = /([^. ])\1\1/.test(linetoread); // Check for single character spamming | |
if (!hasTripple) { | |
// Abbrev Conversion (Btw: http://www.regexpal.com/ is useful for regex testing) | |
var checkingStr = linetoread.trim(); // Trim spaces to make recognition easier | |
linetoread = linetoread.split(" ").map(function(token){ | |
if ( token.toUpperCase() in replaceStrList ){return replaceStrList[token.toUpperCase()];} else {return token;} | |
}).join(" "); | |
// Number To Words Conversion (Moved under abbrev conversion to avoid interfering with Abbrev detection ) | |
var numbermatches = getNumbers(linetoread); | |
$.each(numbermatches, function(i) { | |
linetoread = linetoread.split(numbermatches[i]).join(numberToEnglish(numbermatches[i])); | |
}); | |
// Emoji Detection (Btw: I am a little unconfortable with this function, since its relying on the second class of that span to always be the same ) | |
var msgemotes = $msg.find(".mrPumpkin"); // find all emotes in message | |
var domEmoji = ""; | |
if (msgemotes.length) { | |
var finalemote; | |
$.each(msgemotes, function() { | |
finalemote = $(this).attr("class"); | |
}); | |
var lastEmote = finalemote.split(" ")[1].split("mp_")[1]; // Btw `.split("mp_")[1]` means to get rid of the `mp_` bit in example `mp_happy` to get just `happy` (Note: This can be fragile if "mp_" is changed to something else) | |
domEmoji = lastEmote; | |
} | |
var toneStr=""; | |
if ( domEmoji in toneList ){ | |
toneStr = " " + toneList[domEmoji]; | |
} | |
// Narration Style | |
var msg; | |
var usr = $usr.text(); | |
if (usr == "741456963789852123") { usr = "7 4 1"; } /* idea: if username is a lot of numbers, call them by the first 3 numbers seperated */ | |
if (usr == "Kretenkobr2") { usr = "KretenkobrTwo"; } | |
if (!GM_getValue("rlc-TTSUsernameNarration")) { | |
msg = new SpeechSynthesisUtterance(linetoread + toneStr); | |
} else { | |
switch (true) { //These are causing AutoScroll not to work..? (FF) | |
case /.+\?$/.test(checkingStr): // Questioned | |
msg = new SpeechSynthesisUtterance(linetoread + " questioned " + usr + toneStr ); | |
break; | |
case /.+\!$/.test(checkingStr): // Exclaimed | |
msg = new SpeechSynthesisUtterance(linetoread + " exclaimed " + usr + toneStr ); | |
break; | |
case /.+[\\\/]s$/.test(checkingStr): // Sarcasm switch checks for /s or \s at the end of a sentence | |
linetoread = linetoread.trim().slice(0, -2); | |
msg = new SpeechSynthesisUtterance(linetoread + " stated " + usr + "sarcastically"); | |
break; | |
case checkingStr === checkingStr.toUpperCase(): //Check for screaming | |
msg = new SpeechSynthesisUtterance(linetoread + " shouted " + usr + toneStr ); | |
break; | |
case meMentioned === 1: //Check for /me | |
msg = new SpeechSynthesisUtterance( linetoread + toneStr ); | |
break; | |
default: // said | |
msg = new SpeechSynthesisUtterance(linetoread + " said " + usr + toneStr ); | |
break; | |
} | |
} | |
// Console Logging | |
// console.log("TTS | " + linetoread + " by " + usr + " with tone "+ toneStr ); | |
// Now speak the sentence | |
msg.voiceURI = 'native'; | |
// Set variable voice type | |
if (!$("body").hasClass("rlc-NoUserVoices")){ // You want to be able to disable this in options. | |
// Select voices that english users can use, even if its not for english exactly... | |
var voiceList = speechSynthesis.getVoices().filter(function(voice) { | |
for (var key in langSupport) { | |
if ( voice.lang.indexOf(langSupport[key]) > -1 ){ return true; } | |
} | |
}); | |
// Cheap String Seeded Psudo Random Int Hash (Author: mofosyne) | |
msg.voice = voiceList[strSeededRandInt($usr.text(),0,voiceList.length-1)]; | |
msg.pitch = 0.0 + (1.6-0.0)*strSeededRandInt($usr.text()+" pitch salt ",0,10)/10; // random range: 0.5 to 1.5 | |
msg.rate = 0.8 + (1.2-0.8)*strSeededRandInt($usr.text()+" rate salt ",0,10)/10; // random range: 0.5 to 1.5 | |
console.log(msg.voice); | |
// pitch alteration is known to break firefox TTS, rate is reset for suspicion of the same behavior | |
if (navigator.userAgent.toLowerCase().indexOf("firefox") > -1) | |
{ | |
msg.pitch = 1; | |
msg.rate = 1; | |
} | |
} | |
msg.volume = 1; // 0 to 1 | |
//msg.rate = 1; // 0.1 to 10 | |
//msg.pitch = 1; //0 to 2 | |
window.speechSynthesis.speak(msg); | |
// get supported voices | |
/*speechSynthesis.getVoices().forEach(function(voice) { | |
console.log(voice.lang, voice.name); | |
});*/ | |
} | |
} | |
} | |
} | |
/*¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ | |
RLC TABBED CHANNELS FUNCTION SECTION BELOW | |
010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101 | |
101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010 | |
____________________________________________________________________________________________________________________________________________________________________________*/ | |
// rate limiter for prevention of message send withn 1 sec on previous user message, see Tick and Event Handlers | |
var rateLimit = 0; | |
// badmanfix tts (see channel Tick) | |
//var badmanfixtts = 1; | |
// channel tabs megafunction | |
var tabbedChannels = new function(){ | |
/* Basic usage - tabbedChannels.init( dom_node_to_add_tabs_to ); | |
* and hook up tabbedChannels.proccessLine(lower_case_text, jquery_of_line_container); to each line detected by the system */ | |
var _self = this; | |
// Default options | |
this.channels = ["%general", "%offtopic"]; | |
this.mode = "single"; | |
// internals | |
this.unreadCounts = {}; | |
this.$el = null; | |
this.$opt = null; | |
this.defaultRoomClasses = ""; | |
this.channelMatchingCache = []; | |
//channels user is in currently | |
this.currentRooms = 0; | |
// When channel is clicked, toggle it on or off | |
this.toggleChannel = function(e){ | |
var channel = $(e.target).data("filter"); | |
if (channel===null)return; // no a channel | |
if (!$("#rlc-chat").hasClass("rlc-filter-" + channel)){ | |
_self.enableChannel(channel); | |
$(e.target).addClass("selected"); | |
// clear unread counter | |
$(e.target).find("span").text(0); | |
_self.unreadCounts[channel] = 0; | |
} else { | |
_self.disableChannel(channel); | |
$(e.target).removeClass("selected"); | |
} | |
// scroll everything correctly | |
scrollToBottom(); | |
}; | |
// Enable a channel | |
this.enableChannel = function(channelID){ | |
// if using room type "single", deslect other rooms on change | |
if (this.mode === "single"){ | |
this.disableAllChannels(); | |
} | |
$("#rlc-chat").addClass("rlc-filter rlc-filter-" + channelID); | |
$("#rlc-chat").attr("data-channel-key", this.channels[channelID]); | |
this.currentRooms++; | |
// unselect show all | |
_self.$el.find("span.all").removeClass("selected"); | |
}; | |
// disable a channel | |
this.disableChannel = function(channelID){ | |
$("#rlc-chat").removeClass("rlc-filter-" + channelID); | |
this.currentRooms--; | |
// no rooms selcted, run "show all" | |
if (this.currentRooms === 0){ | |
this.disableAllChannels(); | |
} else { | |
// Grab next channel name if u leave a room in multi mode | |
$("#rlc-chat").attr("data-channel-key", $(".rlc-filters span.selected").first().data("filter-name")); | |
} | |
}; | |
// turn all channels off | |
this.disableAllChannels = function(){ | |
$("#rlc-chat").attr("class", _self.defaultRoomClasses).attr("data-channel-key", ""); | |
_self.$el.find(".rlc-filters > span").removeClass("selected"); | |
this.currentRooms = 0; | |
_self.$el.find("span.all").addClass("selected"); | |
scrollToBottom(); | |
}; | |
// render tabs | |
this.drawTabs = function(){ | |
var html = ""; | |
for(var i in this.channels){ | |
if (typeof this.channels[i] === "undefined") continue; | |
html += ` <span data-filter="${i}" data-filter-name="${this.channels[i]}"> | |
${this.channels[i]}(<span>0</span>) | |
</span> `; | |
} | |
this.$el.find(".rlc-filters").html(html); | |
}; | |
// After creation of a new channel, go find if any content (not matched by a channel already) is relevant | |
this.reScanChannels = function(){ | |
$("#rlc-chat").find("li.liveupdate").each(function(idx,item){ | |
var line = $(item).find(".body .md").text().toLowerCase(); | |
tabbedChannels.proccessLine(line, $(item), true); | |
}); | |
}; | |
// Add new channel | |
this.addChannel = function(newChannel){ | |
if (this.channels.indexOf(newChannel) === -1){ | |
this.channels.push(newChannel); | |
this.unreadCounts[this.channels.length-1] = 0; | |
this.updateChannelMatchCache(); | |
this.saveChannelList(); | |
this.drawTabs(); | |
// Populate content for channel | |
this.reScanChannels(); | |
// refresh everything after redraw | |
this.disableAllChannels(); | |
} | |
}; | |
// remove existing channel | |
this.removeChannel = function(channel){ | |
if (confirm("are you sure you wish to remove the " + channel + " channel?")){ | |
var idx = this.channels.indexOf(channel); | |
delete this.channels[idx]; | |
this.updateChannelMatchCache(); | |
this.saveChannelList(); | |
this.drawTabs(); | |
// sub channels, will fall back to existing channels | |
this.reScanChannels(); | |
// refresh everything after redraw | |
this.disableAllChannels(); | |
} | |
}; | |
// save channel list | |
this.saveChannelList = function(){ | |
// clean array before save | |
var channels = this.channels.filter(function (item) { return item !== undefined; }); | |
GM_setValue("rlc-channels", channels); | |
}; | |
// Change chat mode | |
this.changeChannelMode = function(){ | |
_self.mode = $(this).data("type"); | |
// swicth bolding | |
$(this).parent().find("span").css("font-weight", "normal"); | |
$(this).css("font-weight", "bold"); | |
_self.disableAllChannels(); | |
// Update mode setting | |
GM_setValue("rlc-mode", _self.mode); | |
}; | |
this.updateChannelMatchCache = function(){ | |
var order = this.channels.slice(0); | |
order.sort(function(a, b){ | |
return b.length - a.length; // ASC -> a - b; DESC -> b - a | |
}); | |
for(var i in order){ | |
order[i] = this.channels.indexOf(order[i]); | |
} | |
// sorted array of channel name indexs | |
this.channelMatchingCache = order; | |
}; | |
// Procces each chat line to create text | |
this.proccessLine = function(text, $elment, rescan){ | |
var i, idx, channel; | |
// If rescanning, clear any existing "channel" classes | |
if (typeof rescan !== "undefined" && rescan === true){ | |
$elment.removeClass("in-channel"); | |
for(i=0; i <= this.channels.length; i++){ | |
$elment.removeClass("rlc-filter-" + i); | |
} | |
} | |
// Scan for channel identifiers | |
for(i=0; i< this.channelMatchingCache.length; i++){ // Sorted so longer get picked out before shorter ones (sub channel matching) | |
idx = this.channelMatchingCache[i]; | |
channel = this.channels[idx]; | |
if (typeof channel === "undefined") continue; | |
// Handle channel prefix in message | |
if (text.indexOf(channel) === 0){ | |
$elment.find(".body").append(`<a class='channelname'> in ${channel}</a>`); | |
$elment.addClass(`rlc-filter-${idx} in-channel`); | |
this.unreadCounts[idx]++; | |
// Remove channel name in messages | |
var newele = $elment.find(".body .md p").html().replace(channel, ""); | |
$elment.find(".body .md p").html(newele); | |
return; | |
} | |
} | |
}; | |
// If in one channel, auto add channel keys | |
this.submitHelper = function(){ | |
if ($("#rlc-chat").hasClass("rlc-filter")){ | |
// Auto add channel key | |
let channelKey = $("#rlc-chat").attr("data-channel-key"); | |
if ($("#new-update-form textarea").val().indexOf("/me") === 0){ | |
$("#new-update-form textarea").val("/me " + channelKey + " " + $("#new-update-form textarea").val().substr(3)); | |
} else if ($("#new-update-form textarea").val().indexOf("/") !== 0){ | |
// If it's not a "/" command, add channel | |
$("#new-update-form textarea").val(channelKey + " " + $("#new-update-form textarea").val()); | |
} | |
} | |
// else read from dropdown populated by channels | |
else { | |
let channelKey = $("#rlc-channel-dropdown option:selected" ).text(); | |
if (channelKey !== "") { | |
if ($("#new-update-form textarea").val().indexOf("/me") === 0){ | |
$("#new-update-form textarea").val("/me " + channelKey + " " + $("#new-update-form textarea").val().substr(3)); | |
} else if ($("#new-update-form textarea").val().indexOf("/") !== 0){ | |
// If it's not a "/" command, add channel | |
$("#new-update-form textarea").val(channelKey + " " + $("#new-update-form textarea").val()); | |
} | |
} | |
} | |
}; | |
// Update everythang | |
var waitabit = 0; | |
this.tick = function(){ | |
_self.$el.find(".rlc-filters span").each(function(){ | |
if ($(this).hasClass("selected")) return; | |
$(this).find("span").text(_self.unreadCounts[$(this).data("filter")]); | |
}); | |
/* delay loading messages from load */ | |
loadingInitialMessages = 0; | |
if (waitabit === 0) { | |
// handle existing chat messages | |
$("#rlc-chat").find("li.liveupdate").each(function(idx,item){ | |
handleNewMessage($(item), true); | |
}); | |
} | |
waitabit--; | |
// Rate limit disable | |
rateLimit = 0; | |
}; | |
// Init tab zone | |
this.init = function($el){ | |
// Load channels | |
if (GM_getValue("rlc-channels")){ | |
this.channels = GM_getValue("rlc-channels"); | |
} | |
if (GM_getValue("rlc-mode")){ | |
this.mode = GM_getValue("rlc-mode"); | |
} | |
// Init counters | |
for(var i in this.channels){ | |
this.unreadCounts[i] = 0; | |
} | |
// Update channel cache | |
this.updateChannelMatchCache(); | |
this.$el = $el; | |
// Create inital markup | |
this.$el.html("<span class='all selected'>Global</span><span><div class='rlc-filters'></div></span><span class='more'>[Channels]</span>"); | |
this.$opt = $("<div class='rlc-channel-add' style='display:none'><input name='add-channel'><button>Add channel</button> <span class='channel-mode'>Channel Mode: <span title='View one channel at a time' data-type='single'>Single</span> | <span title='View many channels at once' data-type='multi'>Multi</span></span></div>").insertAfter(this.$el); | |
// Attach events | |
this.$el.find(".rlc-filters").click(this.toggleChannel); | |
this.$el.find("span.all").click(this.disableAllChannels); | |
this.$el.find("span.more").click(function(){ $(".rlc-channel-add").toggle(); $("body").toggleClass("rlc-addchanmenu"); }); | |
this.$el.find(".rlc-filters").bind("contextmenu", function(e){ | |
e.preventDefault(); | |
e.stopPropagation(); | |
var chanID = $(e.target).data("filter"); | |
if (chanID===null)return; // no a channel | |
_self.removeChannel(_self.channels[chanID]); | |
}); | |
// Form events | |
this.$opt.find(".channel-mode span").click(this.changeChannelMode); | |
this.$opt.find("button").click(function(){ | |
var newChan = _self.$opt.find("input[name='add-channel']").val(); | |
if (newChan !== "") _self.addChannel(newChan); | |
_self.$opt.find("input[name='add-channel']").val(""); | |
}); | |
$(".save-button .btn").click(this.submitHelper); | |
// Store default room class | |
this.defaultRoomClasses = $("#rlc-chat").attr("class") ? $("#rlc-chat").attr("class") : ""; | |
// Redraw tabs | |
this.drawTabs(); | |
// Start ticker | |
setInterval(this.tick, 2000); | |
}; | |
}(); | |
/*¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ | |
RLC EVENT HANDLING SECTION BELOW | |
010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101 | |
101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010 | |
____________________________________________________________________________________________________________________________________________________________________________*/ | |
// Message history | |
var messageHistory = [], | |
messageHistoryIndex = -1, | |
lastTyped = ""; | |
// Messagebox event handling | |
function messageboxEventHandling() { | |
var textArea = $(".usertext-edit.md-container textarea"); | |
// On post message, add it to history | |
$(".save-button .btn").click(function(){ | |
var userLastMessage = textArea.val(); | |
// If message history is to long, clear it out | |
if (messageHistory.length === 25){ | |
messageHistory.shift(); | |
} | |
messageHistory.push(removeChannelKeyFromMessage(userLastMessage)); | |
messageHistoryIndex = messageHistory.length; | |
}); | |
// Handling of keypresses in messagebox textarea | |
textArea.on("keydown", function(e) { | |
// Tab autocomplete | |
if (e.keyCode === 9) { // Stole my old code from Parrot | |
processActiveUsersList(); | |
e.preventDefault(); | |
var sourceAlt= $(".usertext-edit textarea").val(); | |
var namePart = ""; | |
var space=sourceAlt.lastIndexOf(" "); | |
namePart = sourceAlt.substring(space).trim(); | |
sourceAlt = sourceAlt.substring(0, sourceAlt.lastIndexOf(" ")); | |
var found=false; | |
$.each(updateArray, function(ind,Lname){ | |
if (Lname.indexOf(namePart) === 0){ | |
namePart=Lname; | |
if (space !== -1) namePart = " "+namePart; | |
found = true; | |
return true; | |
} else if (Lname.toLowerCase().indexOf(namePart.toLowerCase()) === 0){ // This is in an else because it should give priority to case Sensitive tab completion | |
namePart = Lname; | |
if (space !== -1) namePart=" "+namePart; | |
found = true; | |
return true; | |
} | |
}); | |
if (found){ | |
$(".usertext-edit textarea").val(sourceAlt+namePart); | |
} | |
} | |
// Enter message send | |
if (e.keyCode === 13) { | |
if (e.shiftKey) { /* Exit enter handling to allow shift+enter newline */ } | |
else if (textArea.val() === "" ) { e.preventDefault(); } | |
else if (rateLimit === 1) { e.preventDefault();console.log("rate limit hit");} | |
else { | |
if (textArea.val().indexOf("/version") === 0){ | |
/* eslint-disable camelcase */ | |
$(this).val(`RLC v.${GM_info.script.version} has been released. Use the link in the sidebar to update.`); | |
/* eslint-enable camelcase */ | |
} | |
if (textArea.val().indexOf("/sharebrowser") === 0){ | |
/* eslint-disable camelcase */ | |
$(this).val( "___ Browser Details (via /sharebrowser ) : \n\n"+nVer+ "\n" +browserName+ "\n" ); | |
/* eslint-enable camelcase */ | |
} | |
if (textArea.val().indexOf("/sharesettings") === 0){ | |
var str = " {\n"; | |
str += optionsArray.map(function(key){ | |
return " "+key+": "+GM_getValue(key); | |
}).join(",\n"); | |
str += "\n }" | |
/* eslint-disable camelcase */ | |
$(this).val( "RLC settings (via /sharesettings ) : \n\n"+str ); | |
/* eslint-enable camelcase */ | |
} | |
e.preventDefault(); | |
$(".save-button .btn").click(); | |
$("#new-update-form textarea").val(""); | |
rateLimit = 1; | |
} | |
} | |
else if (e.keyCode === 38) { | |
e.preventDefault(); | |
if (messageHistoryIndex > 0) messageHistoryIndex--; | |
if (messageHistoryIndex === messageHistory.length-1) lastTyped = $(this).val(); | |
if (messageHistoryIndex > -1) $(this).val(messageHistory[messageHistoryIndex]); | |
} | |
else if (e.keyCode === 40){ | |
e.preventDefault(); | |
if (messageHistoryIndex < messageHistory.length){ | |
messageHistoryIndex++; | |
$(this).val(messageHistory[messageHistoryIndex]); | |
} | |
if (messageHistoryIndex === messageHistory.length) $(this).val(lastTyped); | |
} | |
}); | |
} | |
function mouseClicksEventHandling() { | |
// Right click author names in chat to copy to messagebox | |
$("body").on("contextmenu", ".liveupdate .author", function (event) { | |
event.preventDefault(); | |
let username = String($(this).text()).trim(); | |
let source = String($(".usertext-edit.md-container textarea").val()); | |
// Focus textarea and set the value of textarea | |
$(".usertext-edit.md-container textarea").focus().val(source + " " + username + " "); | |
}); | |
// Load old messages | |
$("#togglebarLoadHist").click(function(){ | |
loadHistory(); | |
}); | |
// Easy access options | |
$("#togglebarAutoscroll").click(function(){ | |
$( "#rlc-settings label:contains('Auto Scroll') input" ).click(); | |
}); | |
$("#togglebarTTS").click(function(){ | |
$( "#rlc-settings label:contains('Text To Speech (TTS)') input" ).click(); | |
}); | |
//$("#rlc-togglesidebar").click(function(){ $("body").toggleClass("rlc-hidesidebar"); scrollToBottom(); }); | |
$("#rlc-toggleoptions").click(function(){ $("body").removeClass("rlc-showreadmebar"); $("body").toggleClass("rlc-showoptions");}); | |
$("#rlc-toggleguide").click(function(){ $("body").removeClass("rlc-showoptions"); $("body").toggleClass("rlc-showreadmebar");}); | |
$("#rlc-sendmessage").click(function(){ $(".save-button .btn").click();}); | |
} | |
/*¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ | |
RLC INIT FUNCTIONS SECTION BELOW | |
010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101 | |
101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010 | |
____________________________________________________________________________________________________________________________________________________________________________*/ | |
function rlcSetupContainers() { | |
$("body").append(htmlPayload); | |
$(".liveupdate-listing").prependTo("#rlc-chat"); | |
$("#new-update-form").insertBefore("#rlc-sendmessage"); | |
$("#liveupdate-header").appendTo("#rlc-header #rlc-titlebar"); | |
$("#liveupdate-statusbar").appendTo("#rlc-header #rlc-statusbar"); | |
$("#liveupdate-resources").appendTo("#rlc-sidebar #rlc-main-sidebar"); | |
tabbedChannels.init($("<div id=\"filter_tabs\"></div>").insertBefore("#rlc-chat")); | |
} | |
function rlcParseSidebar() { | |
// Put anything after -RLC-README- in the sidebar into the readme | |
let str = $("#liveupdate-resources .md").html(); | |
let res = str.split("<p>--RLC-SIDEBAR-GUIDE--</p>"); | |
$("#liveupdate-resources .md").html(res[0]); | |
$("#rlc-readmebar .md").append(res[1]); | |
// Put anything before -RLC-MAIN- in the sidebar into the guide | |
str = $("#liveupdate-resources .md").html(); | |
res = str.split("<p>--RLC-SIDEBAR-MAIN--</p>"); | |
$("#liveupdate-resources .md").html(res[1]); | |
$("#rlc-guidebar .md").append(res[0]); | |
$("#rlc-main-sidebar").append("<div id='rlc-activeusers'><ul></ul></div>"); | |
$("#rlc-main-sidebar").append("<div id='banlistcontainer'><div id='bannedlist'></div></div>"); | |
/* eslint-disable camelcase */ | |
$("#rlc-statusbar").append("<div id='versionnumber'>Reddit Live Chat (RLC) v." + GM_info.script.version + "</div>"); | |
/* eslint-enable camelcase */ | |
} | |
function rlcDocReadyModifications() { | |
// Show hint about invites if there is no messagebox | |
if ($(".usertext-edit textarea").length <= 0) { | |
$("#rlc-main").append("<p style='width:100%;text-align:center;'>If you can see this you need an invite to send messages, check the sidebar.</p>"); | |
} | |
// Add placeholder text and focus messagebox | |
$(".usertext-edit textarea").attr("placeholder", "Type here to chat"); | |
$(".usertext-edit textarea").focus(); | |
// Make links external | |
$("#rlc-main a").attr("target", "_blank"); | |
$("#rlc-sidebar a").attr("target", "_blank"); | |
$("#rlc-readmebar a").attr("target", "_blank"); | |
$("#rlc-guidebar a").attr("target", "_blank"); | |
// Remove initial iframes TODO: handle them like new message embeds | |
//$("#rlc-main iframe").remove(); | |
} | |
function rlcInitEventListeners() { | |
// Detect new content being added | |
$(".liveupdate-listing").on("DOMNodeInserted", function(e) { | |
if ($(e.target).is("li.liveupdate")) { | |
// Apply changes to line | |
handleNewMessage($(e.target), false); | |
if ($(document.body).hasClass("AutoScroll")) { | |
scrollToBottom(); | |
} | |
} | |
// Remove separators | |
else if ($(e.target).is(".separator")) { | |
$(e.target).remove(); | |
} | |
}); | |
messageboxEventHandling(); | |
mouseClicksEventHandling(); | |
} | |
/*¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ | |
RLC WINDOW.LOAD SECTION BELOW | |
010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101 | |
101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010 | |
____________________________________________________________________________________________________________________________________________________________________________*/ | |
// Boot | |
$(window).load(function() { | |
// Move default elements into custom containers defined in htmlPayload | |
rlcSetupContainers(); | |
// Setup sidebar based on content | |
rlcParseSidebar(); | |
// Modify initial elements | |
rlcDocReadyModifications(); | |
// Attach event listeners | |
rlcInitEventListeners(); | |
updateMutedUsers(); | |
rowAlternator=!rowAlternator; | |
scrollToBottom(); //done adding/modding content, scroll to bottom | |
/*¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ | |
RLC OPTIONS DEFINITION SECTION BELOW | |
010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101 | |
101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010 | |
____________________________________________________________________________________________________________________________________________________________________________*/ | |
/* Create options */ | |
/* Format: Option name, function(dont touch), state(dont touch), Description(optional) */ | |
createOption("Full Size", function(checked){ | |
if (checked){ | |
$("body").addClass("rlc-fullwidth"); | |
} else { | |
$("body").removeClass("rlc-fullwidth"); | |
} | |
},false, "remove RLC max width/height"); | |
createOption("Dark Mode", function(checked){ | |
if (checked){ | |
$("body").addClass("dark-background"); | |
} else { | |
$("body").removeClass("dark-background"); | |
} | |
},false); | |
createOption("Left Panel", function(checked){ | |
if (checked){ | |
$("body").addClass("left-panel"); | |
} else { | |
$("body").removeClass("left-panel"); | |
} | |
},false, "show left panel for content embedding. click in message with embedded content to display in panel"); | |
createOption("Robin Colors", function(checked){ | |
if (checked){ | |
$("body").addClass("rlc-RobinColors"); | |
} else { | |
$("body").removeClass("rlc-RobinColors"); | |
} | |
},false, "color usernames via robin algorithm"); | |
createOption("Compact Mode", function(checked){ | |
if (checked){ | |
$("body").addClass("rlc-compact"); | |
} else { | |
$("body").removeClass("rlc-compact"); | |
} | |
scrollToBottom(); | |
},false, "hide header"); | |
createOption("Channel Colors", function(checked){ | |
if (checked){ | |
$("#rlc-main").addClass("show-colors"); | |
} else { | |
$("#rlc-main").removeClass("show-colors"); | |
} | |
// Correct scroll after spam filter change | |
scrollToBottom(); | |
},false, "give channels background colors"); | |
createOption("24-hour Timestamps", function(checked){ | |
if (checked){ | |
$("body").addClass("rlc-24hrTimeStamps"); | |
} else { | |
$("body").removeClass("rlc-24hrTimeStamps"); | |
} | |
},false, "change 11 PM to 23:00"); | |
createOption("Show Channels UI", function(checked){ | |
if (checked){ | |
$("body").addClass("rlc-showChannelsUI"); | |
} else { | |
$("body").removeClass("rlc-showChannelsUI"); | |
} | |
},false,"show channel tabs and message channel selector"); | |
createOption("Hide Channels in Global", function(checked){ | |
if (checked){ | |
$("body").addClass("rlc-hideChannelsInGlobal"); | |
} else { | |
$("body").removeClass("rlc-hideChannelsInGlobal"); | |
} | |
},false, "hide in-channel messages in global tab (note: you must have the channel added for this to work)"); | |
createOption("Notification Sound", function(checked){ | |
if (checked){ | |
$("body").addClass("rlc-notificationsound"); | |
} else { | |
$("body").removeClass("rlc-notificationsound"); | |
} | |
scrollToBottom(); | |
},false, "play sound when you are mentioned"); | |
createOption("Chrome Notifications", function(checked){ | |
if (checked && Notification && !Notification.permission !== "granted"){ | |
Notification.requestPermission(); | |
if (checked){ | |
$("body").addClass("rlc-notificationchrome"); | |
} else { | |
$("body").removeClass("rlc-notificationchrome"); | |
} | |
} | |
},false, "show notice when you are mentioned"); | |
createOption("Chrome Scroll Bars", function(checked){ | |
if (checked){ | |
$("body").addClass("rlc-customscrollbars"); | |
} else { | |
$("body").removeClass("rlc-customscrollbars"); | |
} | |
scrollToBottom(); | |
},false, "use custom scrollbars"); | |
createOption("Text To Speech (TTS)", function(checked){ | |
if (checked){ | |
$("body").addClass("rlc-TextToSpeech"); | |
} else { | |
$("body").removeClass("rlc-TextToSpeech"); | |
window.speechSynthesis && window.speechSynthesis.cancel && window.speechSynthesis.cancel(); | |
} | |
},false, "read messsges aloud"); | |
createOption("TTS Username Narration", function(checked){ | |
if (!checked) { | |
} else { | |
} | |
},false, "example: [message] said [name]"); | |
createOption("Disable User-based Voices", function(checked){ | |
if (checked){ | |
$("body").addClass("rlc-NoUserVoices"); | |
} else { | |
$("body").removeClass("rlc-NoUserVoices"); | |
} | |
},false, "do not modify TTS voices based on usernames"); | |
createOption("Auto Scroll", function(checked){ | |
if (checked){ | |
$("body").addClass("AutoScroll"); | |
} else { | |
$("body").removeClass("AutoScroll"); | |
} | |
},false, "scroll chat on new message"); | |
createOption("No Emotes", function(checked){ | |
if (checked){ | |
$("body").addClass("rlc-noemotes"); | |
} else { | |
$("body").removeClass("rlc-noemotes"); | |
} | |
},false, "disable smileys"); | |
}); | |
// Channel styles | |
var color; | |
for(var c = 0; c < 35; c++){ | |
color = colors[(c % (colors.length))]; | |
GM_addStyle(`#rlc-main.show-colors #rlc-chat li.liveupdate.rlc-filter-${c} { background: ${color};}`, 0); | |
GM_addStyle(`#rlc-chat.rlc-filter.rlc-filter-${c} li.liveupdate.rlc-filter-${c} { display:block;}`, 0); | |
} | |
})(); | |
WebFontConfig = { | |
google: { families: [ 'Open+Sans:400,400italic,600,600italic:latin' ] } | |
}; | |
(function() { | |
var wf = document.createElement('script'); | |
wf.src = 'https://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js'; | |
wf.type = 'text/javascript'; | |
wf.async = 'true'; | |
var s = document.getElementsByTagName('script')[0]; | |
s.parentNode.insertBefore(wf, s); | |
})(); | |
/*¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ | |
RLC CSS SECTION BELOW | |
010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101 | |
101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010 | |
____________________________________________________________________________________________________________________________________________________________________________*/ | |
/* CSS tip: use cssminifier.com instead of messing around with line continuation, unpack in editor and re-minify before reinsertion via cssminifier.com */ | |
GM_addStyle('.extendButton{margin-right:5px}.longMessageClosed{max-height:30px;overflow-y:hidden;overflow-x:hidden}#rlc-messagebox,#rlc-sidebar{float:right;box-sizing:border-box}div#rlc-settings label{display:block;font-size:1.4em;margin-left:10px}#hsts_pixel,.bottom-area,.content,.debuginfo,.footer-parent,.save-button{display:none}#rlc-messagebox .md,#rlc-messagebox .usertext,header#liveupdate-header{max-width:none}#rlc-sendmessage,#rlc-wrapper{-webkit-box-shadow:0 1px 2px 0 rgba(166,166,166,1);-moz-box-shadow:0 1px 2px 0 rgba(166,166,166,1);box-shadow:0 1px 2px 0 rgba(166,166,166,1)}#rlc-header,#rlc-wrapper,body{overflow:hidden}#new-update-form{margin:0}.liveupdate time.live-timestamp,.liveupdate ul.buttonrow{display:none!important}#filter_tabs,#liveupdate-resources h2,#myContextMenu,#rlc-guidebar,#rlc-readmebar,#rlc-settings,select#rlc-channel-dropdown{display:none}#rlc-messagebox .usertext-edit.md-container{max-width:none;padding:0;margin:0}header#liveupdate-header{margin:0!important;padding:15px}h1#liveupdate-title:before{content:"chat in ";color:#000}h1#liveupdate-title{font-size:1.5em;color:#9c9c9c;float:left;padding:0}#rlc-header #liveupdate-statusbar{margin:0;padding:0;border:none!important;background:0 0!important}#rlc-wrapper .liveupdate .body{max-width:none!important;margin:0;font-size:13px;font-family:"Open Sans",sans-serif}div#rlc-sidebar{max-height:550px;background-color:#EFEFED}#rlc-wrapper{height:calc(100vh - 63px);max-width:1248px;max-height:600px;margin:0 auto;border-radius:0 0 2px 2px;-moz-border-radius:0 0 2px 2px;-webkit-border-radius:0 0 2px 2px}#rlc-header{height:50px;border-bottom:1px solid #e3e3e0;border-top:0;box-sizing:border-box}#rlc-main,#rlc-titlebar{width:76%;float:left;position:relative}#rlc-sidebar{width:24%;overflow-y:auto;overflow-x:hidden;height:calc(100vh - 114px);border-left:2px solid #FCFCFC;padding:5px 0}#rlc-chat{height:calc(100vh - 202px);overflow-y:scroll;max-height:461px}#rlc-main .liveupdate-listing{max-width:100%;padding:0 0 0 15px;box-sizing:border-box;display:flex;flex-direction:column-reverse;min-height:100%}#rlc-messagebox textarea{border:1px solid rgba(128,128,128,.26);float:left;height:34px;margin:0;border-radius:2px;padding:6px}#rlc-messagebox{padding:10px;background-color:#EFEFED;width:100%}#rlc-sendmessage{background-color:#FCFCFC;height:32px;margin:10px 0 0;border-radius:2px;-moz-border-radius:2px;-webkit-border-radius:2px;padding:6px;text-align:center;cursor:pointer;width:100%;font-size:1.5em;float:left;box-sizing:border-box}#rlc-toggleguide,#rlc-toggleoptions,#rlc-update{float:left;box-sizing:border-box;text-align:center;padding:4px 0 8px;cursor:pointer;border-radius:2px;-moz-border-radius:2px;-webkit-border-radius:2px;-webkit-box-shadow:0 1px 2px 0 rgba(166,166,166,1);-moz-box-shadow:0 1px 2px 0 rgba(166,166,166,1);box-shadow:0 1px 2px 0 rgba(166,166,166,1);background:#FCFCFC;width:100%;margin-bottom:8px}#rlc-toggleguide{margin-bottom:0}.liveupdate .simpletime{float:left;padding-left:10px;box-sizing:border-box;width:75px;text-transform:uppercase;color:#A7A6B8;line-height:32px}.liveupdate a.author{float:left;padding-right:10px;margin:0;padding-top:0;font-weight:600;width:130px}.liveupdate-listing li.liveupdate .body .md{float:right;width:calc(100% - 220px);max-width:none;box-sizing:border-box;padding-right:10px}li.liveupdate.in-channel .body .md{width:calc(100% - 320px)}#rlc-activeusers{padding:15px 20px 20px 40px;font-size:1.5em}#rlc-activeusers li{list-style:outside;padding:0 0 8px}#rlc-settingsbar{width:100%;height:auto;padding:0 10px;box-sizing:border-box;margin:10px 0 20px;float:left}#rlc-main-sidebar{float:right;width:100%}#rlc-sidebar hr{height:2px;width:100%;margin-left:0;color:#FCFCFC}#rlc-sidebar h3{padding:0 10px}#rlc-statusbar{width:24%;float:right;text-align:center;padding-top:8px}#versionnumber{padding-top:5px}.rlc-showoptions #rlc-settings{display:block}.rlc-showoptions #rlc-main-sidebar{display:none}.rlc-showreadmebar #rlc-readmebar{display:block}.rlc-showreadmebar #rlc-main-sidebar{display:none}.liveupdate.user-narration .body .md{font-style:italic}.liveupdate.user-mention .body .md p{font-weight:700}body.allowHistoryScroll{height:105%;overflow:auto}.noselect{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none}.rlc-customscrollbars ::-webkit-scrollbar{width:12px}.rlc-customscrollbars ::-webkit-scrollbar-track{background-color:#FCFCFC}.dark-background.rlc-customscrollbars ::-webkit-scrollbar-track{background-color:#5C5C5C}.dark-background.rlc-customscrollbars ::-webkit-scrollbar-thumb{background-color:#404040;border:2px solid #5C5C5C}.rlc-customscrollbars ::-webkit-scrollbar-thumb{background-color:#E4E4E4;border:2px solid #FCFCFC}#myContextMenu{display:none;position:absolute;background:#bbb;box-shadow:1px 1px 2px #888}#myContextMenu ul{list-style-type:none}#myContextMenu ul li a{padding:.5em 1em;color:#000;display:block}#myContextMenu ul li:not(.disabled) a:hover{background:#ccc;color:#333;cursor:pointer}#myContextMenu ul li.disabled a{background:#ddd;color:#666}.liveupdate pre{margin:0;padding:0;background:rgba(128,128,128,.5);border:#FCFCFC;box-sizing:border-box}.liveupdate a.author,.liveupdate p{line-height:32px;min-height:32px}.rlc-channel-add button{background:0 0;border:1px solid #A9A9A9;margin:0;padding:4px;border-top:0;border-bottom:0}.channelname{color:#A9A9A9!important;display:block;float:left;width:100px;line-height:32px}#rlc-leftpanel{display:none}.left-panel #rlc-leftpanel{width:14%;float:left;display:block;background-color:#EFEFED;height:calc(100vh - 114px)}.left-panel #rlc-sidebar,.left-panel #rlc-statusbar{width:18%}.left-panel #rlc-main{width:68%}#liveupdate-description{margin-left:10px;float:left}.md{max-width:none!important}div#rlc-settingsbar a{display:inline-block}.liveupdate-listing li.liveupdate p{font-size:13px!important}.rlc-showChannelsUI #new-update-form{width:85%;float:left}.rlc-showChannelsUI select#rlc-channel-dropdown{display:block;width:15%;height:34px;float:left;background-color:#FCFCFC;border:1px solid rgba(128,128,128,.26)}.rlc-showChannelsUI #rlc-sendmessage{width:100%;float:left}.rlc-showChannelsUI div#filter_tabs{display:block;z-index:100;background:#EFEFED}.rlc-channel-add,.rlc-hideChannelsInGlobal .liveupdate.in-channel,.rlc-showChannelsUI .rlc-filter .liveupdate{display:none}.rlc-showChannelsUI .rlc-channel-add{position:absolute;top:26px;width:100%;z-index:100;padding:10px;box-sizing:border-box;background:#EFEFED}div#rlc-togglebar{float:right;display:block;height:100%;padding-right:30px}.AutoScroll #togglebarAutoscroll,.rlc-TextToSpeech #togglebarTTS{background:rgba(0,0,0,.15)}#togglebarAutoscroll,#togglebarLoadHist,#togglebarTTS{float:right;box-sizing:border-box;text-align:center;padding:5px 10px;cursor:pointer;border-radius:2px;-moz-border-radius:2px;-webkit-border-radius:2px;-webkit-box-shadow:0 1px 2px 0 rgba(166,166,166,1);-moz-box-shadow:0 1px 2px 0 rgba(166,166,166,1);box-shadow:0 1px 2px 0 rgba(166,166,166,1);width:90px;margin-left:10px;margin-top:15px}div#rlc-settings label{float:left;width:100%;margin-bottom:10px;padding-bottom:10px;border-bottom:2px solid #fff}div#rlc-settings label span{padding-top:3px;padding-bottom:5px;font-size:.7em;text-align:right;display:block;float:right;padding-right:20px}div#rlc-settings input{margin-right:5px}#option-rlc-ChromeNotifications,#option-rlc-ChromeScrollBars,#option-rlc-DisableUserbasedVoices,#option-rlc-TTSUsernameNarration{display:none!important}.rlc-TextToSpeech #option-rlc-DisableUserbasedVoices,.rlc-TextToSpeech #option-rlc-TTSUsernameNarration{display:block!important}@media screen and (-webkit-min-device-pixel-ratio:0){#option-rlc-ChromeNotifications,#option-rlc-ChromeScrollBars{display:block!important}}.md.hasEmbed iframe{width:50%;transform:scale(.25,.25);position:fixed;bottom:0}.md.hasEmbed .provider{display:none}.md.hasEmbed{position:relative;height:80px;cursor:pointer;overflow:hidden}.md.hasEmbed:before{content:"Embedded content, click to view";display:block;position:relative;top:0;font-size:16px;height:61px;padding-top:20px;z-index:1000}.rlc-compact #header{display:none}.rlc-compact #rlc-chat{height:calc(100vh - 263px);max-height:451px}.rlc-fullwidth div#rlc-chat,.rlc-fullwidth div#rlc-sidebar{max-height:none}.rlc-fullwidth div#rlc-chat{height:calc(100vh - 215px)}.rlc-fullwidth #rlc-wrapper{max-height:none;max-width:none;height:calc(100vh - 0px)}.rlc-fullwidth.left-panel #rlc-statusbar{width:18%}.rlc-fullwidth.left-panel #rlc-titlebar{width:81%}.rlc-fullwidth div#rlc-wrapper{height:100%}.rlc-compact.rlc-fullwidth #rlc-chat{height:calc(100vh - 145px)}.rlc-compact.rlc-fullwidth #rlc-sidebar{height:calc(100vh - 50px)}.dark-background.AutoScroll #togglebarAutoscroll,.dark-background.rlc-TextToSpeech #togglebarTTS{background:rgba(239,247,255,.25)}.dark-background,.dark-background #rlc-leftpanel,.dark-background #rlc-messagebox,.dark-background #rlc-messagebox textarea,.dark-background #rlc-sendmessage,.dark-background #rlc-sidebar,.dark-background #rlc-toggleguide,.dark-background #rlc-toggleoptions,.dark-background #rlc-update,.dark-background .rlc-channel-add,.dark-background option{background:#404040}.dark-background.rlc-showChannelsUI div#filter_tabs{background-color:#5C5C5C}.dark-background #rlc-sidebar{border:transparent}.dark-background.rlc-showChannelsUI select#rlc-channel-dropdown{background:0 0}.dark-background .liveupdate code{color:#000}.dark-background #rlc-sidebar h2,.dark-background #rlc-sidebar h3,.dark-background #rlc-sidebar h4,.dark-background h1#liveupdate-title:before{color:#ccc}.dark-background #rlc-messagebox textarea,.dark-background #rlc-sidebar li,.dark-background #rlc-wrapper,.dark-background #rlc-wrapper a,.dark-background #rlc-wrapper h1#liveupdate-title,.dark-background #rlc-wrapper p,.dark-background .longMessageClosed:after,.dark-background .md.hasEmbed:before,.dark-background .rlc-channel-add button,.dark-background.rlc-showChannelsUI select#rlc-channel-dropdown{color:#f5f5f5}.dark-background .alt-bgcolor{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGM6YwwAAdQBAooJK6AAAAAASUVORK5CYII=)!important}.alt-bgcolor{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGM6Uw8AAiABTnvshQUAAAAASUVORK5CYII=)!important}.mrPumpkin{height:24px;width:24px;display:inline-block;border-radius:3px;background-size:144px;position:relative;top:6px}#filter_tabs,.user-narration a.author{display:none}.dark-background .mrPumpkin{border-radius:5px}.mp_frown{background-position:-24px 0}.mp_silly{background-position:-48px 0}.mp_meh{background-position:0 -24px}.mp_angry{background-position:-48px -24px}.mp_shocked{background-position:-24px -24px}.mp_happy{background-position:-72px 120px}.mp_sad{background-position:-72px 96px}.mp_crying{background-position:0 72px}.mp_tongue{background-position:0 24px}.mp_xhappy{background-position:-48px 48px}.mp_xsad{background-position:-24px 48px}.mp_xsmile{background-position:0 48px}.mp_annoyed{background-position:-72px 72px}.mp_zen{background-position:-48px 72px}.mp_wink{background-position:-24px 72px}.rlc-compact #rlc-wrapper{margin-top:75px}.rlc-compact #rlc-header{border-top:1px solid rgba(227,227,224,.44)}.rlc-compact.rlc-fullwidth #rlc-wrapper{margin-top:0}#filter_tabs .rlc-filters>span:last-of-type{border-right:0}div#filter_tabs{width:calc(100% - 27px);left:15px}#filter_tabs{table-layout:fixed;width:100%;height:26px;position:absolute}#filter_tabs>span{width:90%;display:table-cell}#filter_tabs>span.all,#filter_tabs>span.more{width:60px;text-align:center;vertical-align:middle;cursor:pointer}#filter_tabs .rlc-filters{display:table;width:100%;table-layout:fixed;height:24px}#filter_tabs .rlc-filters>span{padding:5px 2px;text-align:center;display:table-cell;cursor:pointer;vertical-align:middle;font-size:1.1em;border-right:2px solid #262626}#filter_tabs .rlc-filters>span>span{pointer-events:none}#filter_tabs>span.all{padding:0 30px;border-right:2px solid #262626}#filter_tabs>span.more{padding:0 30px;border-left:2px solid #262626}.rlc-channel-add input{border:0;padding:0;height:24px}'); | |
/* base 64 encoded emote spritesheet - art by image author 741456963789852123/FlamingObsidian */ | |
GM_addStyle('.mrPumpkin{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANgAAAC0CAYAAAD2FuLMAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAEnQAABJ0Ad5mH3gAAAABYktHRACIBR1IAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE2LTA0LTE3VDE5OjMwOjQ5LTA1OjAw6JLuAgAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNi0wNC0xN1QxOTozMDo0OS0wNTowMJnPVr4AAAiJSURBVHhe7d1BjuREE4bh6TnALFixAwkJjjCruQRLFnAMJA6AxDFgwZJLzGqOABIS7FixmAs0E56OpirLGZnpjHBl2u8jWd1oXFHR5fzK6az6fz88fvDiwsPDw9Nv+0ie/gb9zNUPrj0HTA/U47tXy8+9PLx+v/xMDxz9fDRLP1i3BEwO1t4HKiUHTg8a/dwauR/kvXz6CSCAzDMe7/1uqJ6nH/SzasR+OIvZOIMBgQgYEMgMmEwBdOvlUcujhvKo5VFDedTyqKE8a53Z6jWY9aK2zv9baum+9PPRDP1wDWZjiggEugmY9Q4mSv9+yaMW/dhG6wfXOIMBgQgYEOgmYKWL4paLZo9a9GMbrR9c4wwGBDK/KnV5Udv77lVTS/ehn3n6YZnexncRDfRjI2BlTBGBQAQMCETAgEAEDAhEwIBABAwIRMCAQFWfgy2fd3R+9lJTo/VzHt2/VWv93n5qHu/5+mx9XVI1z8PnYLZpz2A6ILdsXgPwktVPxPNhDlMGTAfzVt6DvqYfQnZOVQHrHZC9gZhdTfg8Xx+PWmc+Xp6avou4NWSt9Uv7ewzImhre/Wi9VO3fUtuPyj1fSUt9rsFsfNnXQD82AlbGMj0QiIABgV7KKV6nHvek0w36WTdqP7BxBgMCcQO+BP3Ycv1gHbeQTdCPrdQPrjFFBAIxRUzQj40pYhvu0ZxBP7bLfpDHFBEIJPMMviqVQT82zmJlnMEcyYDTENRo3R/zIWCO5MwiW01oZB/dH8dlBkzfYT3eZT1qedRQHrVyNUohk39Lg5Wr1cKjhvKsdWar12DWi9r6jttSS/c9Sj+y39pj031yvPup0doP12A2poiB1gZ364DH3G4CZr2DidK/X/KoRT+20frBNc5gQCACBgS6CVjpGqHlGsKjFv3YRusH1ziDAYHMr0pdXtT2vnvV1NJ96Geeflimt/FdRAP92AhYGVNEIBABAwIRMCAQAQMCETAgEAEDAhEwINDhPgfTGsqjVm2N9LlrtdYfqR8+B7MdKmC5AdVbr+bxy2DreJ7a5xAt+25V/TcTMFPVFLH3YAmPGhar/h7PvTVcQh7r2aNHrejX7Cyqr8HkBe/ZgDOqDpi8y/ZswBkd5hqsdJbsqXmE1yeC9MM1mO0wy/TWoBtlQOJ8DvU52FqQCBfuiburZNCPjelhnUOdwYDRcAO+BP3Ycv1gHfdoTtCPrdQPrjFFBAIxRUzQj40pYhtWETPox3bZD/KYIgKBZJ7B/y9iBv3YOIuVcQYDAhEwIJAZMJkC6NbLo5ZHDWBPqwFbG8RbB7ZHLY8aRxb9WvBab8cU8QBk0UM27yBoPa2PdjcBKx2glgPoUcuzn6PzCpo+nmD1u1mmrzkwtS96ay3dn37+V+rHssf+LNPbThWwVmv93FNtP719tzwPAbPdTBFLL2rLQfOo5dnP0cmAXwb9h9ek53XRx2s9bMcixwF4BStF0PqZX5W6fFF7D1xNLd1nj35qlPrZ24j9MEW02WewX/5ZNo8DutR4qreV1NANmAFTRCAQAQMCETAgEAEDAhEwIBABAwIRMCBQU8Dkg8UtmzePmhF9AanqgMmAvPygt2VjMOOsqgKm4drq6CHz+Ns8X5/R+jkz+7uIv//x8ZdvP+0KmFgO2NPXpB6/+nL5mdKDWvNcsu/WnmofW9uP7ter9nlG6ofvItqmDZjYOpBa65f2Xwaaw+tT8zxipH4ImK0qYLlAtCrVqx1Ae6EfGwErY5keCETAgEAv5RSvU4970ukG/awbtR/YOIMBgcwb8O2xyKHvxum74Vo/e6AfW64frOMezQn6sZX6wTWmiEAg7tGcmK2ft2/fLj/38ubNm+Vn2g/WcY/mjNH72TtYKQma9oM8ApYxQ8Def/HN8t+pV3/++vTbNc/9CVidlyMMHiE9SC/0s+6yn3ufvYT0IL3AxiIHEIiAAYEIGBBoNWByQS1blNb69INZyVVq8e4qXhf5pXq9/95q1n50kSO3ypfTulqYo3VYSSwzp4hyoGWTA6sHdwt9vNbbin4wm6prsK0DKWrg0A9mURWwrQNB99fHe6EfzMIM2NaBk/IaSPSD2ZiriL0DJ7V1INEPZmWuIu5NBxX9rNN+SquIudXCVqX6rCKWVV2DAdiGgAGBCBgQiIABgQgYEIiAAYEIGBCIgAGBqj5olg84ez9sranR+sGu7t+qtX5t371qn4cPmucx7RlMBpsMyC2bVyCAkikDpuHaipBhL1UB6x2QvYEYncffduTX58yqz2Aasi3bGQZPz99IuI6Lb9MbRu2HRY55sEwPBCJgQCDu0Zwxcj8yNbs3pod1uLtKxuj96HXYvRCwOtyALzFbP3sHTc+eaT9Y9xwwpQduL6UDRT9z9YNrBCzBgIan4aeIo0yBRusHcxh2kWOki/jR+sE8CFjGWsD++vHv5b9rff7DZ0+/XdtSh4DNach7NN87XEJ6GLEfzIVvcgCBCBgQyAyYXBfp1suzFjCL1YCtBWFrODxrAbORq+ab/z2YNfhbF0Raaum+pUWF7/796em3Pj9/8v3Tb+v0Myjt556riIKVxPncnMFKZ5aWM49nLWBGLHIAgQgYEOgmYKVrrJZrMM9awIw4gwGBVlcR1eUiRO/ZpqaW7qOrdrnVwtzqn/f+6SrivbGKOB/zDCZB0K2XZy1gFkwRgUAEDAhEwIBABAwIZK4i7i1dRczhu4iYBWcwIBABAwJVBUymbh4bcDZVAbv8kLi0Lfv/9u5mA86IKSIQKGQVUaaDl2eth69fP5/dLDqN3Prdv9bvIpb0fhcxt1qYW10sYRVxPiFnMAmThEo37wADswibIkqodAPOimswIBABAwINeY9mXVy4J11QGK0fzIW7q2RcDujR+sE8uAFfQs9Wo/eDOTwHTOlA2ktp4NAPwZrXixf/AZq/oygOz8PlAAAAAElFTkSuQmCC)}'); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment