Nested Twitter Replies

By Joel Lee Last update Feb 4, 2009 — Installed 90 times. Daily Installs: 0, 0, 0, 3, 0, 1, 0, 0, 0, 0, 1, 0, 0, 3, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0

There are 5 previous versions of this script.

// ==UserScript==
// @name           Nested Twitter Replies
// @namespace      http://blog.bcse.info/nested-twitter-replies
// @include        http://twitter.com/*
// ==/UserScript==

bcseNTR = {
	template: {
		"status": false,
		"content": null
	},
	regexp: {
		"id": new RegExp("%id%", "g"),
		"text": new RegExp("%text%", "g"),
		"created_at": new RegExp("%created_at%", "g"),
		"user_screen_name": new RegExp("%user.screen_name%", "g"),
		"user_name": new RegExp("%user.name%", "g"),
		"user_profile_image_url": new RegExp("%user.profile_image_url%", "g")
	},
	init: function() {
		//console.log("Locate Replies");
		var thread_node = $(".hentry[id] a[href*='status']:contains('in reply to')");

		if (thread_node.length > 0) {
			/// Generate Template
			var example_tweet = $(".hentry[id]:not(:has(.del)):first");
			if (example_tweet.length == 0) {
				example_tweet = $(".hentry[id]:first");
			}
			bcseNTR.template.content = example_tweet.clone();
			bcseNTR.build_template(bcseNTR.template.content.attr("id").match(/^\D+(\d+)$/)[1]);
		}

		thread_node.each(function(){
			//console.log("Get Status: #" + id);
			var parent = $(this).parents(".hentry[id]");
			var parent_id = $(parent).attr("id").match(/^\D+(\d+)$/)[1];
			//console.log("New Thread: #" + parent_id);
			bcseNTR.get_from_html($(this).attr("href"), parent_id);
		});
	},
	build_template: function(id) {
		//console.log("Build Template");
		bcseNTR.template.content.find(".entry-content").text("%text%");
		bcseNTR.template.content.find(".entry-meta").html('<a href="http://twitter.com/%user.screen_name%/status/%id%" class="entry-date" rel="bookmark"><span class="published">%created_at%</span></a>');
		bcseNTR.template.content.find("img.photo").attr("src", "%user.profile_image_url%");

		var user = bcseNTR.template.content.find(".status-body strong a");
		var screen_name = user.length > 0 ? user.text() : null;
		var full_name = user.length > 0 ? user.attr("title") : null;

		bcseNTR.template.content = '<li style="margin-left:24px;" class="hentry status u-%user.screen_name%" id="status_%id%">' + bcseNTR.template.content.html() + '</li>';
		bcseNTR.template.content = bcseNTR.template.content.replace(new RegExp(id, "g"), "%id%");

		bcseNTR.template.content = bcseNTR.template.content
				.replace(new RegExp(screen_name, "g"), "%user.screen_name%")
				.replace(new RegExp(full_name, "g"), "%user.name%");

		//console.log("Template is Generated");
		bcseNTR.template.status = true;
	},
	get_from_html: function(url, parent_id) {
		var id = url.match(/\/(\d+)\/?$/);
		id = id[1];

		/// Wait til template is generated
		if (bcseNTR.template.status) {
			//console.log("If status exists, just use it.");
			var reply = $("#status_" + id);
			if (reply.length > 0) {
				//console.log("Append: #" + id);
				$("#status_" + parent_id).after(reply.css("margin-left", "24px"));

				/// If this tweet is not root, try to get its parent.
				var in_reply_to_status_id = reply.find("a[href*='status']:contains('in reply to')").attr("href") || null;
				if (in_reply_to_status_id) {
					bcseNTR.get_from_html(in_reply_to_status_url, id);
				}
				return;
			}

			//console.log("Get Status via HTML: #" + id);
			$.get(url, function(tweetPage, textStatus){
				tweetPage = $(tweetPage);
				var in_reply_to_status_url = tweetPage.find("a[href*='status']:contains('in reply to')").attr("href") || null;
				var in_reply_to_status_id = in_reply_to_status_url != null ? in_reply_to_status_url.match(/\/(\d+)\/?$/) : null;
				var tweet = {
					"user": {
						"screen_name": tweetPage.find(".screen-name").text(),
						"name": tweetPage.find(".full-name").text(),
						"profile_image_url": tweetPage.find(".thumb img").attr("src")
					},
					"id": id,
					"text": tweetPage.find(".entry-content").html(),
					"created_at": tweetPage.find(".published").text(),
					"in_reply_to_status_id": in_reply_to_status_id,
					"in_reply_to_status_url": in_reply_to_status_url
				};
				var html = bcseNTR.html(tweet);
				//console.log("Append: #" + id);
				$("#status_" + parent_id).after(html);

				/// If this tweet is not root, try to get its parent.
				if (tweet.in_reply_to_status_id) {
					bcseNTR.get_from_html(tweet.in_reply_to_status_url, id);
				}
			}, "html");
		}
		else {
			window.setTimeout(function(){bcseNTR.get(id, parent_id)}, 100);
		}
	},
	html: function(tweet) {
		//console.log("Generate HTML: #" + tweet.id);
		var html = bcseNTR.template.content
			.replace(bcseNTR.regexp.id, tweet.id)
			.replace(bcseNTR.regexp.text, tweet.text)
			.replace(bcseNTR.regexp.created_at, tweet.created_at)
			.replace(bcseNTR.regexp.user_screen_name, tweet.user.screen_name)
			.replace(bcseNTR.regexp.user_name, tweet.user.name)
			.replace(bcseNTR.regexp.user_profile_image_url, tweet.user.profile_image_url);
		return html;
	}
}

function GM_wait()
{
	if (typeof unsafeWindow.jQuery == "undefined") {
		window.setTimeout(GM_wait, 100);
	}
	else {
		$ = unsafeWindow.jQuery;
		bcseNTR.init();
	}
}
GM_wait();