Create a gist now

Instantly share code, notes, and snippets.

// ==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)
}
}
}
// ==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)
}
}
}
This file has been truncated, but you can view the full file.
@badp
Owner

#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.

@badp
Owner

#How to try revision 7c5cb

  1. Paste it in the javascript console.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment