|
// ==UserScript== |
|
// @name YouTube Livestream Vote Counter |
|
// @namespace 9001 |
|
// @description Counts Votes |
|
// @include https://www.youtube.com/* |
|
// @version 1.3.3 |
|
// @downloadURL https://gist.github.com/crapier/3349a3f70fbcf67aeeb4/raw/YouTube%20Livestream%20Vote%20Counter.user.js |
|
// @grant unsafeWindow |
|
// ==/UserScript== |
|
// Prevent script from running in frames and iframes |
|
|
|
if (window.top != window.self) { |
|
console.log("YLVC: Not running on an iframe"); |
|
return; |
|
} |
|
|
|
var injection = function() { |
|
// prevent script from loading on non livestream pages |
|
console.log("YLVC: Checking Page"); |
|
if (document.getElementsByClassName("concurrent-viewers watch-view-count").length > 0) { |
|
console.log("YLVC: Loading Functions"); |
|
|
|
// current options and counts |
|
var vote_options = []; |
|
var vote_counts = []; |
|
|
|
// menu to input options |
|
var menu = document.createElement("div"); |
|
menu.innerHTML = "<b>YouTube Livestream Vote Counter</b><br><input type='text' name='options' id='vote_options'><input type='submit' value='Update' id='update_button'><br>"; |
|
menu.style.cssText = "background-color:white;padding:10px"; |
|
|
|
// table that displays counts |
|
var counter_div = document.createElement("div"); |
|
counter_div.innerHTML = "<table id='counter_table' style='width:100%;border:1px solid gray;'></table>"; |
|
counter_div.style.cssText = "background-color:white;padding:10px;margin-bottom:10px"; |
|
|
|
// mutation observer to check new comments |
|
var observer; |
|
var observing = false; |
|
// config for mutation observer |
|
var config = { attributes: true, childList: true, characterData: true }; |
|
|
|
var vote_count = 0; |
|
var comment_count = 0; |
|
|
|
// update the table on the page |
|
var print_counters = function() { |
|
var table = document.getElementById("counter_table"); |
|
// clear table |
|
table.innerHTML = ""; |
|
|
|
// add column headers |
|
var row_head = table.insertRow(0); |
|
var td1_head = row_head.insertCell(0); |
|
td1_head.innerHTML = "<b>Option</b>"; |
|
td1_head.style.cssText = "padding:5px;border:1px solid gray" |
|
var td2_head = row_head.insertCell(1); |
|
td2_head.innerHTML = "<b>Votes</b>"; |
|
td2_head.style.cssText = "padding:5px;border:1px solid gray" |
|
|
|
// Add each row |
|
for (var i = 0; i < vote_options.length; i++) { |
|
var row = table.insertRow(i+1); |
|
var td1 = row.insertCell(0); |
|
td1.innerHTML = vote_options[i]; |
|
td1.style.cssText = "padding:5px;border:1px solid gray" |
|
var td2 = row.insertCell(1); |
|
td2.innerHTML = "" + vote_counts[i]; |
|
td2.style.cssText = "padding:5px;border:1px solid gray" |
|
} |
|
|
|
i++; |
|
// add extra total information |
|
var row_votes = table.insertRow(i++); |
|
var td1_votes = row_votes.insertCell(0); |
|
td1_votes.innerHTML = "<b>Total Votes</b>"; |
|
td1_votes.style.cssText = "padding:5px;border:1px solid gray" |
|
var td2_votes = row_votes.insertCell(1); |
|
td2_votes.innerHTML = "" + vote_count; |
|
td2_votes.style.cssText = "padding:5px;border:1px solid gray" |
|
|
|
var row_comments = table.insertRow(i++); |
|
var td1_comments = row_comments.insertCell(0); |
|
td1_comments.innerHTML = "<b>Total Comments</b>"; |
|
td1_comments.style.cssText = "padding:5px;border:1px solid gray" |
|
var td2_comments = row_comments.insertCell(1); |
|
td2_comments.innerHTML = "" + comment_count; |
|
td2_comments.style.cssText = "padding:5px;border:1px solid gray" |
|
}; |
|
|
|
// update options to count (keeps old counts for any option that is the same) |
|
var set_option = function(options) { |
|
var vote_options_old = vote_options; |
|
var vote_couts_old = vote_counts; |
|
vote_options = options.replace(/,\s+/g, ",").split(","); |
|
|
|
// remove empty strings |
|
while (vote_options.indexOf("") >= 0) { |
|
vote_options.splice(vote_options.indexOf(""), 1); |
|
} |
|
|
|
var only_new = true; |
|
|
|
// clear counts |
|
vote_counts = []; |
|
// initialize counts to 0 |
|
for (var i = 0; i < vote_options.length; i++) { |
|
vote_counts[i] = 0; |
|
} |
|
|
|
// copy old values for options that remain the same |
|
for (i = 0; i < vote_options.length; i++) { |
|
var new_option_split = []; |
|
// interpret as regular expression, don't split |
|
if (vote_options[i].length > 3 && vote_options[i][0] == "/" && vote_options[i][vote_options[i].length-1] == "/") { |
|
new_option_split[0] = vote_options[i]; |
|
} |
|
else { |
|
new_option_split = vote_options[i].split("+"); |
|
} |
|
for (var j = 0; j < new_option_split.length; j++) { |
|
for (var k = 0; k < vote_options_old.length; k++) { |
|
var old_option_split = []; |
|
// interpret as regular expression, don't split |
|
if (vote_options_old[k].length > 3 && vote_options_old[k][0] == "/" && vote_options_old[k][vote_options_old[k].length-1] == "/") { |
|
old_option_split[0] = vote_options_old[k]; |
|
} |
|
else { |
|
old_option_split = vote_options_old[k].split("+"); |
|
} |
|
for (var l = 0; l < old_option_split.length; l++) { |
|
if (old_option_split[l].toLowerCase() == new_option_split[j].toLowerCase()) { |
|
// options are the same so update counted value |
|
vote_counts[i] += vote_couts_old[k]; |
|
|
|
// find all options from this pair that are the same |
|
var trim_old_option_split = []; |
|
for (var m = 0; m < old_option_split.length; m++) { |
|
var found = false; |
|
for (var n = 0; n < new_option_split.length; n++) { |
|
if (old_option_split[m].toLowerCase() == new_option_split[n].toLowerCase()) { |
|
found = true; |
|
break; |
|
} |
|
} |
|
if (!found) { |
|
trim_old_option_split[trim_old_option_split.length] = old_option_split[m]; |
|
} |
|
} |
|
// create new trimmed option |
|
var trim_option = ""; |
|
for (m = 0; m < trim_old_option_split.length; m++) { |
|
trim_option += trim_old_option_split[m] + "+"; |
|
} |
|
// remove extra last "+" |
|
if (trim_option.length > 0) { |
|
trim_option = trim_option.substring(0, trim_option.length - 1); |
|
} |
|
// modify old options to prevent double counting |
|
vote_options_old[k] = trim_option; |
|
|
|
// don't compare the rest of the old split |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
//update counted votes |
|
vote_count = 0; |
|
for (i = 0; i < vote_counts.length; i++) { |
|
vote_count += vote_counts[i]; |
|
} |
|
|
|
// start observer if its not already started |
|
if (!observing) { |
|
observing = true; |
|
start_mutation_observer(); |
|
} |
|
|
|
// update table |
|
print_counters(); |
|
}; |
|
|
|
// check a message against all options |
|
var check_text = function(text) { |
|
for (var i = 0; i < vote_options.length; i++) { |
|
// interpret as regular expression if surrounded by /string/ |
|
if (vote_options[i].length > 3 && vote_options[i][0] == "/" && vote_options[i][vote_options[i].length-1] == "/") { |
|
var reg_exp = new RegExp(vote_options[i].substring(1, vote_options[i].length-2), "i"); |
|
if (reg_exp.test(text)) { |
|
vote_counts[i]++; |
|
vote_count++; |
|
} |
|
} |
|
// else just interpret as list of things to check |
|
else { |
|
var options_split = vote_options[i].split("+"); |
|
for (var j = 0; j < options_split.length; j++) { |
|
if (text.toLowerCase().indexOf(options_split[j].toLowerCase()) >= 0) { |
|
vote_counts[i]++; |
|
vote_count++; |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
}; |
|
|
|
// check new comments from muation events |
|
var check_new_comments = function(mutations) { |
|
for (var i = 0; i < mutations.length; i++) { |
|
for (var j = 0; j < mutations[i].addedNodes.length; j++) { |
|
check_text(mutations[i].addedNodes[j].childNodes[5].childNodes[5].textContent); |
|
comment_count++; |
|
} |
|
} |
|
print_counters(); |
|
} |
|
// use this function for the observer callback |
|
observer = new MutationObserver(check_new_comments); |
|
|
|
var start_mutation_observer = function() { |
|
// the comment div for the mutation observer |
|
var comments = document.getElementById("all-comments"); |
|
// start the observer |
|
console.log("YLVC: Starting Mutation Observer") |
|
observer.observe(comments, config); |
|
} |
|
|
|
console.log("YLVC: Loading Menu"); |
|
// add elements to the page, inbetween comments and suggested videos |
|
document.getElementById("watch7-sidebar").insertBefore(menu, document.getElementById("watch7-sidebar-contents")); |
|
document.getElementById("watch7-sidebar").insertBefore(counter_div, document.getElementById("watch7-sidebar-contents")); |
|
|
|
// set update button function |
|
document.getElementById("update_button").onclick = function() { |
|
set_option(document.getElementById("vote_options").value); |
|
}; |
|
|
|
// pressing enter also clicks the update button |
|
document.getElementById("vote_options").onkeyup = function(key) { |
|
if (key.keyCode == 13) { |
|
document.getElementById("update_button").click(); |
|
} |
|
} |
|
} |
|
} |
|
|
|
// create script to inject onto page |
|
var script = document.createElement("script"); |
|
screen.type = "text/javascript"; |
|
script.innerHTML = "var injection = " + injection.toString(); |
|
// append created script |
|
document.getElementsByTagName("head")[0].appendChild(script); |
|
|
|
// call injected script |
|
unsafeWindow.injection(); |