public
Last active

  • Download Gist
Screenshot AskUbuntu.png
Screenshot chat.SE.png
so_live.user.js
JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
// ==UserScript==
// @name SO Live!
// @namespace tag://badp/
// @version 1.1 (now with update feedback)
// @description Bring Live reputation updates to the StackExchange™ EgoEmpowering HumanWorth™ counter.
// @include http://stackoverflow.com/*
// @include http://meta.stackoverflow.com/*
// @include http://superuser.com/*
// @include http://meta.superuser.com/*
// @include http://serverfault.com/*
// @include http://meta.serverfault.com/*
// @include http://askubuntu.com/*
// @include http://meta.askubuntu.com/*
// @include http://answers.onstartups.com/*
// @include http://meta.answers.onstartups.com/*
// @include http://nothingtoinstall.com/*
// @include http://meta.nothingtoinstall.com/*
// @include http://seasonedadvice.com/*
// @include http://meta.seasonedadvice.com/*
// @include http://stackapps.com/*
// @include http://*.stackexchange.com/*
// @exclude http://chat.stackexchange.com/*
// @exclude http://chat.*.stackexchange.com/*
// @exclude http://api.*.stackexchange.com/*
// @exclude http://odata.stackexchange.com/*
// @exclude http://area51.stackexchange.com/*
// @exclude http://*/reputation
// ==/UserScript==
 
//balpha <3
function with_plugin(url, callback) {
var script = document.createElement("script");
script.setAttribute("src", url);
script.addEventListener("load", function () {
var script = document.createElement("script");
script.type = "text/javascript";
if(callback.name)
script.textContent = callback.toString() + ";" + callback.name + "(jQuery);";
else
script.textContent = "(" + callback.toString() + ")(jQuery)";
document.body.appendChild(script);
}, false);
document.body.appendChild(script);
}
 
with_plugin("http://soapi.info/code/js/stable/scripts/Soapi.js", SO_Live)
 
function SO_Live($){
var debug = 0;
var site = window.location.hostname;
if(site !== "meta.stackoverflow.com") // metas do not count
site = site.replace("meta.", ""); //get rep updates from parent instead.
 
var user_id = $("#hlinks-user a").first().attr("href").match(/[0-9]+/)[0];
// get the URL address of the link to the user page; the sequence of digits is the user number, right? Right?
var rep_number_obj = $("#hlinks-user .reputation-score").first();
var api = Soapi.RouteFactory("api." + site, "a4T4v6g2pESuXB5InP2CWg");
var last_update = now();
 
function update_reputation_since(date){
if(date === undefined)
throw new Error("Please specify a date object.");
to_date = now()
rep_number_obj.fadeTo(0, 0.4) //visual feedback
api.UsersByIdReputation(
{ id: user_id,
fromdate: date,
todate: to_date
}).getResponse( function(data)
{
last_update = now(); //only update on successful update
rep_number_obj.fadeTo(1000, 1);
if(data.items.length)
$.each(data.items, _parse_api_result);
if(debug)
window.console.debug("Updates received: " + data.items);
});
_schedule_next_update();
}
 
function _schedule_next_update(){
if(debug)
window.console.debug("Scheduling next update in 60 seconds, checking activity since " + last_update);
setTimeout( function(){update_reputation_since(last_update) },
60000);
}
//entry point
_schedule_next_update();
function get_current_reputation(){
return to_num(rep_number_obj.text().replace(",", ""));
}
 
function _change_rep_number_by(difference){
var prev_rep = get_current_reputation();
var new_rep = prev_rep + difference;
rep_number_obj.text(add_commas(new_rep));
return new_rep;
}
 
function lightweight_notify(show_this_message, duration){
 
/*
0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2.0
|---'---'---|---'---'---|---'---'---'---'---'---'---'---|---'---'---|---'---'---|
| fade out | fade in | display message | fade out | fade in |
| #hlinks | message | | message | #hlinks |
|<---300--->|<---300--->|<-------------800------------->|<---300--->|<---300--->|
|<---300--->|<------------------------1,400------------------------>|<---300--->|
*/
if(duration === undefined){
duration = 800;
}
var fade_time = 300;
if( $(".lightweight_notify").length ) { //delay -- TODO: handle this better
throw new Error("lightweight notifies overlap");
}
 
$("#hlinks")
.fadeOut(fade_time)
.delay(fade_time + duration + fade_time) //give the time for the message to appaear
.fadeIn(fade_time);
 
$("<span />")
.css({'float': 'left',
'text-align': 'right',
'margin-right': 20,
'width': '500px', //960-340=620-20=600 on SO, let's take less space for SE sites
'overflow': 'hidden',
'text-overflow': 'ellipsis',
'-o-text-overflow': 'ellipsis',
'white-space': 'nowrap',
'font-weight': 'bold'
})
.addClass('hot transient-notification')
.insertBefore("#hsearch")
.hide()
.delay(fade_time) //give the time for #links to fade out
.fadeIn(fade_time)
.delay(duration)
.fadeOut(fade_time)
[0] //get DOM object
.innerHTML = show_this_message;
setTimeout("$(\".transient-notification\").remove()", fade_time*3 + duration);
}
 
//http://stackoverflow.com/q/3953746/13992
function _schedule_rep_number_change(diff, step, number){
setTimeout( function(){ _change_rep_number_by(diff) },
4200 + step*25 + number*5000);
}
 
function _schedule_lightweight_notify(message, number){
setTimeout( function(){ lightweight_notify(message, 3000)},
number*5000
);
}
 
function linkify(change){
return $("<a/>").text(change.title)
.attr("href", "http://" + site + "/questions/" + change.post_id + "/-1") //give Community some love
[0] //get dom object
.outerHTML //cringe
}
 
function _parse_api_result(number, change){
//lit up the envelope
$(".envelope-off").toggleClass(".envelope-on", true)
.toggleClass(".envelope-off", false)
.attr("title", "You have new replies");
var rep_net_change = change.positive_rep - change.negative_rep;
var step = 1;
var msg = rep_net_change > 0 ? "Gained " : "Spent ";
msg += Math.abs(rep_net_change);
msg += " reputation for ";
msg += linkify(change);
_schedule_lightweight_notify(msg, number);
while(rep_net_change){
if(rep_net_change > 0)
var diff = Math.ceil(rep_net_change / 10);
else
var diff = Math.floor(rep_net_change / 10);
_schedule_rep_number_change(diff, step, number);
rep_net_change -= diff;
step++;
}
} // _parse_api_result(0, debug_change)
 
//for the I can't believe I had to write this™ series
function now(){
return new Date();
}
 
function to_num(val){
var number = parseInt(val, 10);
if( isNaN(number) )
throw new Error(val + " is not a number");
return number;
}
 
//http://www.mredkj.com/javascript/numberFormat.html
function add_commas(nStr)
{
if(nStr > 999999) //this function breaks above one million.
throw new Error("Sorry, you are too awesome for this mere function.");
nStr += '';
var x = nStr.split('.');
var x1 = x[0];
var x2 = x.length > 1 ? '.' + x[1] : '';
var rgx = /(\d+)(\d{3})/;
while (rgx.test(x1)) {
x1 = x1.replace(rgx, '$1' + ',' + '$2');
}
return x1 + x2;
}
window._start_SO_Live_debug = function(){
lightweight_notify("Hello! Now try <code>SO_Live_demo()</code> to replay a month's worth of rep changes.", 5000)
debug = 1;
window.SO_Live = SO_Live;
window.SO_Live_demo = function(){
var one_month_ago = new Date(now() - 100*86400*30)
update_reputation_since(one_month_ago)
}
}
}
so_live_chat.user.js
JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
 
// ==UserScript==
// @name SO Live! Chat Edition 1.1
// @namespace tag://badp/
// @version 1.1
// @description Bring Live reputation updates to the StackExchange™ DismissalProne AwesomeNotifier™
// @include http://chat.stackoverflow.com/rooms/*
// @include http://chat.meta.stackoverflow.com/rooms/*
// @include http://chat.superuser.com/rooms/*
// @include http://chat.serverfault.com/rooms/*
// @include http://chat.askubuntu.com/rooms/*
// @include http://chat.answers.onstartups.com/rooms/*
// @include http://chat.nothingtoinstall.com/rooms/*
// @include http://chat.seasonedadvice.com/rooms/*
// @include http://chat.stackapps.com/rooms/*
// @include http://chat.*.stackexchange.com/rooms/*
// @include http://chat.stackexchange.com/rooms/*
// ==/UserScript==
 
//balpha <3
function with_plugin(url, callback) {
var script = document.createElement("script");
script.setAttribute("src", url);
script.addEventListener("load", function () {
var script = document.createElement("script");
script.type = "text/javascript";
if(callback.name)
script.textContent = callback.toString() + ";" + callback.name + "(jQuery);";
else
script.textContent = "(" + callback.toString() + ")(jQuery)";
document.body.appendChild(script);
}, false);
document.body.appendChild(script);
}
 
with_plugin("http://soapi.info/code/js/stable/scripts/Soapi.js", SO_Live_Chat)
 
function SO_Live_Chat($){
var so_live_site = $("#footer-logo a").first().attr("href").replace("http://", "")
var debug = 0;
 
// get user for site -- a waste on non-SE chats.
var chat_user_id = $('#active-user').data('user');
var user_id = -1;
$.get("/users/sites/" + chat_user_id, _get_real_user_id)
function _get_real_user_id(associations){
$.each(associations, function(x, association){ // MAXIMUM JQUERY
if(association.Host == so_live_site){
user_id = association.UserId
console.debug("Found user id on", so_live_site, ":", user_id)
}
})
}
var api = Soapi.RouteFactory("api." + so_live_site, "a4T4v6g2pESuXB5InP2CWg");
var last_update = now();
 
function update_reputation_since(date){
if(date === undefined)
throw new Error("Please specify a date object.");
api.UsersByIdReputation(
{ id: user_id,
fromdate: date
}).getResponse( function(data)
{
last_update = now(); //only update on successful update
if(data.items.length)
$.each(data.items, _parse_api_result);
if(debug)
console.debug("Updates received: " + data.items);
});
_schedule_next_update();
}
 
function _schedule_next_update(){
if(debug)
console.debug("Scheduling next update in 60 seconds, checking activity since " + last_update);
setTimeout( function(){update_reputation_since(last_update) },
60000);
}
//entry point
if(so_live_site !== "stackexchange.com")
_schedule_next_update();
else
console.warn("SO Live! disabled -- room not bound to a site.");
function notify(message){
window.Notifier().notify(message);
}
 
function linkify(change){
// see http://chat.stackoverflow.com/transcript/message/479425#479425
dummy = $("<hack></hack>")
what_I_want = $("<a></a>").text(change.title)
.attr("href", "http://" + so_live_site + "/q/" + change.post_id + "/-1") //give Community some love
dummy.append(what_I_want)
return dummy[0].innerHTML
}
 
function _parse_api_result(number, change){
var rep_net_change = change.positive_rep - change.negative_rep;
var message = rep_net_change > 0 ? "Gained " : "Spent ";
message += "<b>";
message += Math.abs(rep_net_change);
message += "</b>";
message += " reputation for ";
message += linkify(change);
notify(message);
} // _parse_api_result(0, debug_change)
 
//for the I can't believe I had to write this™ series
function now(){
return new Date();
}
window._start_SO_Live_debug = function(){
notify("Hello! Now try <code>SO_Live_demo()</code> to replay a week's worth of rep change notifications.")
debug = 1;
window.SO_Live_Chat = SO_Live_Chat;
window.SO_Live_demo = function(){
var one_week_ago = new Date(now() - 100*86400*30)
update_reputation_since(one_week_ago)
}
}
}

#How to try revision 6ab9d

  1. Paste it in, get error SoApi is not defined
  2. Paste it in again
  3. update_reputation_since(new Date("2010-09-01 00:00:00Z"))

Following updates are actually functional.

#How to try revision 7c5cb

  1. Paste it in the javascript console.

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.