ShareTwitterOnHatenaDiary

By ku Last update Apr 2, 2008 — Installed 9 times. Daily Installs: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
// ==UserScript==
// @name           ShareTwitterOnHatenaDiary
// @namespace      http://ido.nu/kuma/
// @description    Share Twitter conversation on Hatena Diary s***s
// @include        http://twitter.com/*
// @include        https://twitter.com/*
// @include        http://twitter.1x1.jp/search/*
// @include        http://terraminds.com/twitter/*
// ==/UserScript==

// this script require Minibuffer.user.js and LDRize.user.js.
//
// How to use:
//  1. access http://twitter.com/home
//  2. type 'j' or 'k' to select status
//  3. type 'p' to pin
//  4. type M-x ( this mean Alt+x )
//  5. type "pinned-or-current-link | share-twitter-on-tumblr" ( not need " ) and Enter
//  6. access your tumblr. status you pinned will be listed.
//

(function(){

var $X = window.Minibuffer.$X
var D = window.Minibuffer.D
var status = window.Minibuffer.status

function getSource(url){with(D()){return xhttp.get(url)}}
function postData(url, aData){with(D()){return xhttp.post(url, aData)}}

function isTwitterStatusURL(aURL){
	return aURL.match("^https?://twitter\\.com/[^/]+/statuses/\\d+") ? true : false;
}

function convertToHTMLDocument(html){
	var xsl = (new DOMParser()).parseFromString(
		'<?xml version="1.0"?>\
			<stylesheet version="1.0" xmlns="http://www.w3.org/1999/XSL/Transform">\
				<output method="html"/>\
			</stylesheet>', "text/xml");
	var xsltp = new XSLTProcessor();
	xsltp.importStylesheet(xsl);
	var doc = xsltp.transformToDocument(document.implementation.createDocument("", "", null));
	doc.appendChild(doc.createElement("html"));
	var range = doc.createRange();
	range.selectNodeContents(doc.documentElement);
	doc.documentElement.appendChild(range.createContextualFragment(html));
	return doc;
}

function parseStatus(doc, aURL){
	function normalizeText(arr){
		return arr.map(function(a){return a.nodeValue.replace(/^\s+|\s+$/g,'')}).join(' ')
	}
	// normalize external anchor
	var arr = $X('id("permalink")/div/p[1]/a[starts-with(@href,"http")]',doc);
	arr.forEach(function(node){
		node.parentNode.replaceChild( doc.createTextNode(node.getAttribute('href')),node);
	});
	// normalize anchor for reply
	var arr = $X('id("permalink")/div/p[1]/a[starts-with(@href,"/")]', doc);
	arr.forEach(function(node){
		node.parentNode.replaceChild(
			doc.createTextNode(node.previousSibling.textContent +node.textContent) ,
			node.previousSibling);
		node.parentNode.removeChild(node);
	});
	// scrape status
	var body = normalizeText($X('id("permalink")/div/p[1]//text()', doc));
	var name = aURL.match('https?://twitter\\.com/([^/]+)')[1];
	var ago = $X('id("permalink")//span[@class="meta"]/text()[1]', doc, String);

	return {
		name: name,
		  tweet: body,
		  permalink: aURL,
		  // FIXME: normalizeText() something wrong for this script.
		  ago: ago[0].nodeValue.replace(/^\s+|\s+$|from/g, '').replace(/\s+/g, ' ')
	};
}


function HTMLForm(doc, base) {
	function resolveLink(base, ref) {
		if ( ref.match( /^\w+:\/\// ) ) {
			return ref;
		} else {
			if ( ref[0] == "/" ) {
				return base.match( /^\w+:\/\/[^\/]+/ )[0] + ref;
			} else {
				return base.replace( /[^\/]+$/, '' ) + ref.replace(/^\.\//, '');
			}
		}
	}

	var self = {};
	var forms = $X("//form", doc).map( function(f, index) {
		var form = {
			action: resolveLink(base, f.action),
			method: f.getAttribute('method') || 'GET',
			_domnode: f,
			click: function (name) {
				var data = {};
				var inputTypeSubmit = null;
				if ( name ) {
					inputTypeSubmit = self[name];
				} else {
					inputTypeSubmit = self.elements.filter( function (i) {
						return ( i.type == 'submit' );
					} ).shift();
				}

				if ( inputTypeSubmit ) {
					data[ inputTypeSubmit.name ] = inputTypeSubmit.value;
				}
				this.elements.map( function (i) {
					if ( i.name ) {
						if ( i.type == 'submit' ) return;
						if ( i.type == 'checkbox' && ! i.checked ) return;
							data[ i.name ] = i.value
					}
				} );

				var params = [];
				for ( var k in data ) {
					params.push( [k, data[k]].map(encodeURIComponent).join("=") );
				}
				var query = params.join("&");

				return postData(this.action, query);
			}
		};

		(
			form.elements = $X('.//*[(name()="INPUT") or name()="TEXTAREA" or name()="SELECT"]', f)
		).map( function (i) {
			if ( i.name ) {
				form[i.name] = i;
			}
		} );

		self[index] = form;
		if ( form._domnode.name ) {
			self[form._domnode.name] = form;
		}

	} );
	self.length = forms.length;
	return self;
}

function share(body) {
	with(D()) {
		var u = 'http://www.hatena.ne.jp/login';
		var d = xhttp.get(u).next( function (res) {
			var doc = convertToHTMLDocument(res.responseText);
			var result = $X('//td[@class="username"]//a/text()', doc, String);

			if ( !result || result[0] == '' ) {
				d.fail("notloggedin");
			}
			var username = result[0].nodeValue;
			return username;
		} ).next( function (username) {
			return xhttp.get( [
				'http://d.hatena.ne.jp',
				username,
				'edit'
			].join('/') );
		} ).next( function (res) {
try {
			var doc = convertToHTMLDocument(res.responseText);
			var htmlForm = new HTMLForm(doc, res.finalUrl);
			var f = htmlForm.edit;
			f.body.value = '*[chat]twitter log\n' +
				body.map( function (stat) {
					return [
						'',
						'[http://twitter.com/' + stat.name + ':title=' + stat.name + ']',
						stat.tweet.replace(/\|/g, '&#124;'),
						'[' + stat.permalink + ':title=' + stat.ago + ']',
						''
					].join( '|');
				} ).join("\n") + '\n\n\n' + f.body.value;
			return f.click('edit');

}catch(e){
		console.log(e)
}
		} ).error( function(res) {
			if ( res == 'notloggedin' ) {
				window.Minibuffer.message('plz login.', 2000);
			}
		} );
	}
}

window.Minibuffer.addCommand({
  name: 'share-twitter-on-hatenaDiary',
  command: function(stdin){
	  var args = this.args;
	  var urls = [];
	  if(!stdin.length){
		  // command line is just 'share-twitter-on-hatenaDiary'
		  urls = [window.location.href];
	  }else if(stdin.length && stdin.every(function(a){return a.nodeName == 'A'})){
		  // command line is 'pinned-or-current-link | share-twitter-on-hatenaDiary'
		  urls = stdin.map(function(node){return node.href});
	  }else{
		  status('ShareTwitterOnTumblr'+time, 'command line error!', 1000);
		  return stdin;
	  }
	  var time = new Date().getTime();
	  if(!urls.every(isTwitterStatusURL)){
		  status('ShareTwitterOnTumblr'+time, 'There is invalid URL', 1000);
		  return stdin;
	  }
	  // older -> newer
	  urls.sort(function(a,b){
		  return a.match(/\d+$/)[0] - b.match(/\d+$/)[0];
	  })
	  with(D()){
		  status('ShareTwitterOnTumblr'+time, 'Share ...');
		  parallel(urls.map(function(aURL){
			  return getSource(aURL).
				     next(function(res){
						 return parseStatus( convertToHTMLDocument(res.responseText), aURL);
					 })})).
			next(function(arg){
				function toArray(o){var res=[];for(var i in o)res[i]=o[i];return res;}
				share(toArray(arg));
			}).
			next(function(arg){
				status('ShareTwitterOnTumblr'+time, 'Share ... done', 100);
			})
	  }
	  return stdin;
  }
});


})()