What.CD Advanced Buffer Calculator

By jonls Last update Jan 5, 2010 — Installed 5,835 times.

There are 8 previous versions of this script.

// ==UserScript==
// @name           What.CD Advanced Buffer Calculator
// @namespace      http://jonls.dk
// @description    Show buffer in page header and on user pages.
// @author         jonls
// @include        http://what.cd/*
// @include        https://ssl.what.cd/*
// @require        http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js
// @version        0.1.7
// @date           2010-01-05
// ==/UserScript==

(function() {
	/* Ratio gradient */
	var RATIO_GRADIENT = [
		{ color: { r: 255, g: 0, b: 0 }, size: 0.25 },
		{ color: { r: 229, g: 178, b: 68 }, size: 0.25 },
		{ color: { r: 0, g: 255, b: 0 }, size: 0.5 },
		{ color: { r: 0, g: 125, b: 198 }, size: 0 }
	];

	var RATIO_COLORING_MODEL = function(ratio) { return ratio/2; };
	/*var RATIO_COLORING_MODEL = function(ratio) { return ((Math.log(ratio) / Math.LN2) + 1) / 2; };*/

	/* Binary size constants */
	var KiB = Math.pow(2,10);
	var MiB = Math.pow(2,20);
	var GiB = Math.pow(2,30);
	var TiB = Math.pow(2,40);
	var PiB = Math.pow(2,50);

	/* Targets to cycle through */
	var targets = [3.0, 2.0, 1.5, 1.05, 1.0, 0.95, 0.7, 0.65, 0.6, 0.5, 0.4, 0.3, 0.2, 0.15];

	/* Parse binary size string  */
	function parse_binary_size(s) {
		var s = s.split(' ');
		var amount = parseFloat(s[0].replace(/,/, ''));
		var unit = s[1];

		if (unit == 'KB') amount *= KiB;
		else if (unit == "MB" ) amount *= MiB;
		else if (unit == "GB" ) amount *= GiB;
		else if (unit == "TB" ) amount *= TiB;
		else if (unit == "PB" ) amount *= PiB;

		return amount;
	}

	/* Convert byte size to string representation */
	function binary_size_string(amount) {
		var unit = 'B';
		if (Math.abs(amount) >= PiB) {
			amount /= PiB;
			unit = 'PB';
		} else if (Math.abs(amount) >= TiB) {
			amount /= TiB;
			unit = 'TB';
		} else if (Math.abs(amount) >= GiB) {
			amount /= GiB;
			unit = 'GB';
		} else if (Math.abs(amount) >= MiB) {
			amount /= MiB;
			unit = 'MB';
		} else if (Math.abs(amount) >= KiB) {
			amount /= KiB;
			unit = 'KB';
		}

		return amount.toFixed(2)+' '+unit;
	}

	/* Return human-style date difference */
	function human_date_diff(d1, d2, threshold, elements) {
		var diff = d2.getTime() - d1.getTime();
		var e = [];

		var SECOND = 1000;
		var MINUTE = 60*SECOND;
		var HOUR = 60*MINUTE;
		var DAY = 24*HOUR;
		var WEEK = 7*DAY;
		var MONTH = 30*DAY;
		var YEAR = 365*DAY;

		if (diff < threshold) return 'Just now';

		function append_element(unit, singular, plural) {
			if (diff >= unit) {
				var v = Math.floor(diff / unit);
				e[e.length] = v+' '+(v > 1 ? plural : singular);
				diff -= v*unit;
			}
		}

		append_element(YEAR, 'year', 'years');
		append_element(MONTH, 'month', 'months');
		append_element(WEEK, 'week', 'weeks');
		append_element(DAY, 'day', 'days');
		append_element(HOUR, 'hour', 'hours');
		append_element(MINUTE, 'minute', 'minutes');

		return e.slice(0, elements).join(', ');
	}

	/* Sets the color based on the amount, similar to ratio coloring */
	function ratio_class(amount) {
		if (amount > (100*GiB)) return 'r50';
		else if (amount > (10*GiB)) return 'r20';
		else if (amount > 0) return 'r10';
		else if (amount > (-1*GiB)) return 'r05';
		return 'r00';
	}

	/* Calculate color based on model suggested by Myddraal */
	function ratio_color(ratio) {
		function interpolate(c1, c2, f) {
			return { r: c1.r+f*(c2.r-c1.r), g: c1.g+f*(c2.g-c1.g), b: c1.b+f*(c2.b-c1.b) };
		}

		function lookup_color(gradient, index) {
			var offset = 0;
			for (var i = 0; i < gradient.length; i++) {
				if (index < offset + gradient[i].size) return interpolate(gradient[i].color, gradient[i+1].color, (index-offset)/gradient[i].size);
				offset += gradient[i].size;
			}
			return gradient[gradient.length-1].color;
		}

		function color_to_hex(c) {
			var rs = Math.round(c.r).toString(16);
			if (rs.length < 2) rs = '0'+rs;
			var gs = Math.round(c.g).toString(16);
			if (gs.length < 2) gs = '0'+gs;
			var bs = Math.round(c.b).toString(16);
			if (bs.length < 2) bs = '0'+bs;
			return '#'+rs+gs+bs;
		}

		return color_to_hex(lookup_color(RATIO_GRADIENT, RATIO_COLORING_MODEL(ratio)));
	}

	/* Calculate buffer size */
	function calculate_buffer(up, down, target) {
		if ((up/down) > target) {
			return (up / target) - down;
		} else {
			return up - down*target;
		}
	}

	/* Register menu command to hide buffer in header */
	var display_in_header = GM_getValue('display_in_header', true);
	GM_registerMenuCommand('What.CD Advanced Buffer Calculator: '+(display_in_header ? 'Hide buffer in header' : 'Show buffer in header'), function() {
		GM_setValue('display_in_header', !display_in_header);
		location.reload();
	});

	/* Register menu command to change ratio coloring */
	var use_ratio_coloring = GM_getValue('ratio_coloring', false);
	GM_registerMenuCommand('What.CD Advanced Buffer Calculator: '+(use_ratio_coloring ? 'Use simple ratio coloring' : 'Use advanced ratio coloring'), function() {
		GM_setValue('ratio_coloring', !use_ratio_coloring);
		location.reload();
	});

	/* Insert buffer */
	function insert_buffer(parent, up, down, save_name) {
		var target_index = parseInt(GM_getValue(save_name+'_target_index', '4'));

		/* Append buffer stats */
		var buffer_item = $('<li>Buffer: </li>');
		var buffer_stat = $('<span></span>').addClass('stat').css('cursor', 'pointer');
		var buffer_amount = $('<span></span>');
		var buffer_extend = $('<span> / </span>').hide();
		var buffer_target = $('<span></span>').css('cursor', 'pointer');
		buffer_extend.append(buffer_target);
		buffer_stat.append(buffer_amount);
		buffer_item.append(buffer_stat).append(buffer_extend);
		parent.append(buffer_item);

		if (use_ratio_coloring) buffer_amount.css('color', ratio_color(up/down));
		else buffer_amount.addClass(ratio_class(calculate_buffer(up, down, 1.0)));

		/* Change target */
		function update_target() {
			var target = targets[target_index];
			buffer_amount.text(binary_size_string(calculate_buffer(up, down, target)));
			buffer_target.text('('+target.toFixed(2)+')');
			GM_setValue(save_name+'_target_index', target_index);
		}

		/* Set buffer text */
		update_target();

		/* Set event listeners */
		buffer_stat.click(function (event) {
			buffer_extend.toggle();
		});

		buffer_target.click(function (event) {
			target_index = (target_index + 1) % targets.length;
			update_target();
		});
	}

	/* Find stats in header */
	var header_up_string, header_down_string;
	var header_ratio_span;
	var header_req_elm;
	$('#userinfo_stats').children('li').each(function() {
		if (/Up:/.test($(this).text())) header_up_string = $(this).children('.stat').text();
		else if (/Down:/.test($(this).text())) header_down_string = $(this).children('.stat').text();
		else if (/Ratio:/.test($(this).text())) header_ratio_span = $(this).find('span > span').eq(0);
		else if (/Required:/.test($(this).text())) header_req_elm = $(this);
	});

	/* Parse size strings */
	var header_up = parse_binary_size(header_up_string);
	var header_down = parse_binary_size(header_down_string);

	/* Insert buffer in header */
	if (display_in_header) {
		/* Insert buffer */
		insert_buffer($('#userinfo_stats'), header_up, header_down, 'header');
	}

	/* Change ratio color in header */
	if (use_ratio_coloring) {
		header_ratio_span.removeClass('r00 r05 r10 r20 r50');
		header_ratio_span.css('color', ratio_color(header_up/header_down));
	}

	/* Show required as title to ratio */
	header_ratio_span.attr('title', header_req_elm.text());
	header_req_elm.remove();

	if (/what\.cd\/user\.php\?id=/.test(document.URL)) {
		/* Find stats box */
		var stats_list = $('#content .box').filter(function(i) {
			return (/Stats/.test($(this).children('.head').eq(0).text()));
		}).eq(0).children('ul').eq(0);
		
		/* Find stats */
		var user_up_item, user_down_item;
		var user_join_date, user_up_string, user_down_string;
		var ratio_span;
		stats_list.children('li').each(function (i) {
			var m;
			if (m = $(this).text().match(/Uploaded: (\d.+)/)) {
				user_up_item = $(this);
				user_up_string = m[1];
			} else if (m = $(this).text().match(/Downloaded: (\d.+)/)) {
				user_down_item = $(this);
				user_down_string = m[1];
			} else if (/Joined:/.test($(this).text())) {
				user_join_date = new Date($(this).children('span').eq(0).attr('title'));
			} else if (/Ratio:/.test($(this).text())) {
				ratio_span = $(this).children('span').eq(0);
			}
		});

		/* Parse size strings */
		var user_up = parse_binary_size(user_up_string);
		var user_down = parse_binary_size(user_down_string);

		/* Insert buffer */
		insert_buffer(stats_list, user_up, user_down, 'user');

		/* Change ratio color */
		if (use_ratio_coloring) {
			ratio_span.removeClass('r00 r05 r10 r20 r50');
			ratio_span.css('color', ratio_color(user_up/user_down));
		}

		/* Calculate average speeds */
		var time_delta = (new Date().getTime() - user_join_date.getTime()) / 1000;
		var user_up_speed = user_up / time_delta;
		var user_down_speed = user_down / time_delta;
		user_up_item.attr('title', 'Average speed: '+binary_size_string(user_up_speed)+'/s');
		user_down_item.attr('title', 'Average speed: '+binary_size_string(user_down_speed)+'/s');

		/* Calculate expected class transition date */
		function append_transition_date(amount, name) {
			var now = new Date();
			var transition = new Date(now.getTime() + (((amount / user_up) - 1) * time_delta * 1000));
			var date_string = transition.toLocaleFormat('%b %d %Y, %H:%M');
			date_string = date_string.slice(0, 1).toUpperCase() + date_string.slice(1); /* Title Case the Date String */
			var human_date_string = human_date_diff(now, transition, 3*60, 2);
			stats_list.append($('<li><span title="'+binary_size_string(amount)+'">'+name+' class</span> transition: <span title="'+date_string+'">In '+human_date_string+'</span></li>'));
		}

		if (user_up < 10*GiB) append_transition_date(10*GiB, 'Member');
		else if (user_up < 25*GiB) append_transition_date(25*GiB, 'Power User');
		else if (user_up < 100*GiB) append_transition_date(100*GiB, 'Elite');
		else if (user_up < 500*GiB) append_transition_date(500*GiB, 'TorrentMaster');
	}

	/* Insert projected ratio for downloads */
	$('.torrent_table .torrent, .torrent_table .group_torrent').children('td').each(function (i) {
		var field = $(this);
		if (/^[\d.]+ (B|KB|MB|GB|TB|PB)$/.test(field.text())) {
			var size = parse_binary_size(field.text());
			var ratio = header_up / (header_down + size);
			field.attr('title', 'Projected ratio: '+ratio.toFixed(2));
		}
	});
})();