torrentz.com OnClick Download

By sparky Last update Apr 27, 2008 — Installed 6,801 times. Daily Installs: 16, 16, 14, 22, 6, 9, 6, 12, 11, 9, 11, 18, 13, 7, 13, 14, 12, 8, 20, 6, 11, 12, 6, 8, 18, 7, 16, 17, 12, 18, 18, 29
// ==UserScript==
// @name			torrentz.com OnClick Download
// @author			Przemyslaw Iskra <sparky@pld-linux.org>
// @namespace		http://sparky.homelinux.org
// @description		Allows direct .torrent file download on torrentz.com
// @version			0.2.5
// @date			2008-04-27
// @include			http://torrentz.com/*
// @include			http://*.torrentz.com/*
// @include			http://sumotorrent.com/*
// @include			http://*.sumotorrent.com/*
// @include			http://monova.org/*
// @include			http://*.monova.org/*
// ==/UserScript==


function hrefToTorrent( host, href ) {
	// turn page location into torrent file location
	// type of returned value:
	// - string - treated as exact file location
	// - function - regular expression used to find file name on page
	// - bool true - requires indirect download
	// - bool false - unsupported

	switch ( host.toLowerCase() ) {

		case 'bittorrent.am':
		case 'torrents.am':
		case 'torrentz.ru':
			return href.replace(
				/(http:\/\/[^\/]+)\/torrent\/(\d+)\/\d+\/\d+\/(.*)\.html/,
				"$1/get/$2/$3.torrent"
			);

		case 'btmon.com':
			return href.replace(/\.html$/, '');

		case 'extratorrent.com':
			return href
				.replace( "/torrent/", "/download/" )
				.replace( /\.html$/, ".torrent" );

		case 'fenopy.com':
			return href.replace(/index\.html$/, 'download.html');

		case 'fulldls.com':
			return /<a href="(download-.*?\.torrent)"/;

		case 'mininova.org':
			return href.replace('tor', 'get');

		case 'monova.org': // evil !
			// needs to be redirected to the torrent from it's own site
			return true;

		case 'mybittorrent.com':
			return 'http://www.mybittorrent.com/dl/' + href.match( /\d+/ ) + '/';

		case 'newtorrents.info':
			return href.replace(
					/(http:\/\/[^\/]+)\/torrent\/(\d+)\/(.*?)\.html/g,
					"$1/down.php?id=$2"
				);

		case 'seedpeer.com':
			return /<a rel="nofollow" href="(.*?)">Download This Torrent<\/a>/;

		case 'snarf-it.org':
			return href
				.replace( 'viewTorrent', 'downloadTorrent')
				.replace('.html', '.torrent');

		case 'sumotorrent.com': // evil !
			// needs to be redirected to the torrent from it's own site
			return true;

		case 'thepiratebay.org':
			return 'http://torrents.thepiratebay.org'
				+ href.match( /\/\d+\/.*$/ )
				+ ".TPB.torrent";

		case 'thetorrentsite.com':
			return href.replace( "/viewTorrent/", "/downloadTorrent/" )
				.replace( /\.html$/, ".torrent" );

		case 'torrenthound.com':
			return href.replace(
					/(http:\/\/[^\/]+)\/hash\/([0-9a-f]+)(\/.*)?/,
					'$1/torrent/$2'
				);
		case 'torrentportal.com':
			return href.replace('details', 'download');

		case 'torrentreactor.net':
			var link = href.replace(
					/(http:\/\/)[^\/]+\/torrents\/(\d+)\/(.*?)/,
					"$1dl.torrentreactor.net/download.php?id=$2&name=$3"
				);
			// if first quess was wrong try something else
			if ( link == href ) {
				var torrentName = document
					.getElementById( 'p-body-download-locations' )
					.getElementsByTagName( 'h2' )[0].innerHTML;
				return href.replace(
					/\/view.php\?id=(\d+)/,
					"/download.php?id=$1&name=" + encodeURIComponent( torrentName )
				);
			}
			return link;
	}
	return false;
}

// Adds javascript to the page so it will be executed in page context.
function addJS( js ) {
	var head = document.getElementsByTagName('head')[0];
	if (!head) return;
	var jscript = document.createElement('script');
	jscript.type = 'text/javascript';
	jscript.appendChild( document.createTextNode( js ) );
	head.appendChild( jscript );
}

var requestDownload = "#downloadThisDamnTorrent";

// Main part
function torrentz() {

	// add favicon link
	var icon = document.createElement( 'link' );
	icon.setAttribute( 'rel', 'shortcut icon' );
	icon.setAttribute( 'type', 'image/x-icon' );
	icon.setAttribute( 'href', '/favicon.ico' );
	var head = document.getElementsByTagName('head')[0];
	head.appendChild( icon );

	var divs = document.getElementsByTagName( 'div' );
	var downloadLocations;
	for ( var i = 0; i < divs.length; i++ )
		if ( divs[i].getAttribute( 'class' ) == 'download' ) {
			downloadLocations = divs[i];
			break;
		}

	if (!downloadLocations)
		return;

	GM_addStyle(
		'div.download > dl.download-immediate' +
		'{ background: #e0e0ff; }' +
		'div.download > dl.download-search-ok' +
		'{ background: #cfc; }' +
		'div.download > dl.download-search' +
		'{ background: #eeb; }' +
		'div.download > dl.download-search-failed' +
		'{ background: #f99; }' +
		'div.download > dl.download-unsupported' +
		'{ background: #fcc; }' +
		'div.download > dl.download-indirect' +
		'{ background: #ff8; }' +
		'div.download > dl.download-get-all' +
		'{ background: #eee; }' +
		'.download-invisible' +
		'{ width: 0; height: 0; border: 0; }' +
		'');

	// Track all events to be able to remove them later
	var eventList = new Array();

function setOnClick( a, onclick, index ) {
	// remove old and set new onclick handler
	if ( eventList[ index ] )
		a.removeEventListener( 'click', eventList[ index ], false );
	if ( onclick ) {
		eventList[ index ] = onclick;
		a.addEventListener( 'click', onclick, false );
	}
}

function getAll( max, ignore1, ignore2, event ) {
	// execute all the handlers
	for ( var i = 0; i < max; i++ ) {
		var onclick = eventList[i];
		if ( onclick )
			onclick( event );
	}
}

function OnClick_noDefault( func, arg1, arg2, arg3 ) {
	// return function to use as onclick handler
	return function( event ) {
		func( arg1, arg2, arg3, event );
		event.preventDefault();
	};
}

function noReferer( link ) {
	// opens link location removing referer informarion
	// works like opening using dereferer site (http://ultimod.org/),
	// but much faster, and no need to use external server

	var redir_js = 'document.location="' + link + '"';
	var redir_html = '<html><head><script>'
			+ redir_js + '</script></head></html>';
	var redir = 'data:text/html,' + escape( redir_html );

	return redir;
}

function OpenTorrent( a, link ) {
	// open torrent in iframe

	var p = a.parentNode;
	var iframe = p.getElementsByTagName( 'iframe' );
	if ( iframe && iframe.length > 0 ) {
		iframe = iframe[0];
	} else {
		iframe = document.createElement( 'iframe' );
		iframe.setAttribute( 'class', 'download-invisible' );
		p.appendChild( iframe );
	}
	iframe.src = noReferer( link );
}

function FindAndPrepare( a, regex, index ) {
	// does lots of stuff needed for pages which have to be searched for file name

	var href = a.href;
	var p = a.parentNode.parentNode;

	// blink while checking
	var int = window.setInterval( function() {
			p.setAttribute( 'class',
				'download-search' + (p.getAttribute( 'class' ) == 'download-search' ? '-ok' : '')
			);
		}, 150 );

	// called on error
	var failed = function( a, error ) {
		window.clearInterval( int );
		a.parentNode.parentNode.setAttribute( 'class', 'download-search-failed');
		a.setAttribute( 'title', 'Page search failed: ' + error );
	}

	var onLoad = function( res ) {
		if ( !res.responseText )
			return failed( a, "No data" );

		var link = res.responseText.match( regex );
		if ( !link || link.length < 1 )
			return failed( a, "Link not found" );

		link = link[1].toString();
		if ( link.match( /^http:\/\// ) ) {
			// full URI - nothing to do
		} else if ( link.match( /^\// ) ) {
			// full path, no domain name - add domain
			link = href.match( /(https?:\/\/[^\/]+)\// )[1]
				+ link;
		} else {
			// just file name - add domain and path
			link = href.match( /^(.+\/)[^\/]*$/ )[1]
				+ link;
		}

		window.clearInterval( int );
		a.parentNode.parentNode.setAttribute( 'class', 'download-search-ok' );
		a.setAttribute( 'title', "Direct download: " + link );
		OpenTorrent( a, link );
		// don't trigger page searching again, just download
		setOnClick( a, OnClick_noDefault( OpenTorrent, a, link ), index );
	}

	GM_xmlhttpRequest({
		method: 'get',
		url: href,
		onload: onLoad
	});
}



	var div = downloadLocations.getElementsByTagName( 'p' )[0];
	downloadLocations.removeChild( div );

	var anchorElements = downloadLocations.getElementsByTagName( 'a' );

	var torrentIdRegex = /\d+/;
	var urlRegex = new RegExp(
		'(https?):\/\/' +						// protocol
			'(www\.)?([-A-Z0-9\.]+)' +			// hostname
			'(\/[-A-Z0-9+&@#\/%=~_|!:,.;?]*)?',	// pathname
		'i');

	for (var index = 0, anchorElement;
		anchorElement = anchorElements[index];
		index++)
	{
		var hrefAttributeValue = anchorElement.getAttribute('href');
		var match = urlRegex.exec(hrefAttributeValue);

		if (!match || !(match.length > 1))
			continue;

		var resp = hrefToTorrent( match[3], hrefAttributeValue );

		var class, title, onclick = null;

		switch ( typeof resp ) {
			case 'boolean':
				if ( resp == true ) {
					// indirect
					class = 'indirect';
					title = "Indirect download";
					onclick = OnClick_noDefault( OpenTorrent,
						anchorElement, hrefAttributeValue + requestDownload );
				} else {
					// unsupported
					class = 'unsupported';
					title = "Direct download not supported";
				}
				break;
			case 'string':
				// immediate
				class = 'immediate';
				title = "Direct download: " + resp;
				onclick = OnClick_noDefault( OpenTorrent, anchorElement, resp );
				break;
			case 'function':
				// search
				class = 'search';
				title = "Click to find";
				onclick = OnClick_noDefault( FindAndPrepare,
					anchorElement, resp, index );
				break;

			default:
				continue;
		}

		anchorElement.parentNode.parentNode.setAttribute( 'class', 'download-' + class );
		anchorElement.setAttribute( 'title', title );
		if ( onclick )
			setOnClick( anchorElement, onclick, index );
	}

	if ( index > 1 ) {
		var dl = document.createElement( 'dl' );
		var dt = document.createElement( 'dt' );
		dl.appendChild( dt );
		var dd = document.createElement( 'dd' );
		dl.appendChild( dd );
		var a = document.createElement( 'a' );
		dt.appendChild( a );
		dl.setAttribute( 'class', 'download-get-all' );

		var span = document.createElement( 'span' );
		span.setAttribute( 'class', 'u' );
		span.appendChild( document.createTextNode( "get all !" ) );
		a.appendChild( span );

		span = document.createElement( 'span' );
		span.setAttribute( 'class', 'n' );
		span.appendChild( document.createTextNode( "Download" ) );
		a.appendChild( span );
		a.appendChild( document.createTextNode( " all the torrents" ) );

		a.setAttribute( 'href', '#' );
		a.addEventListener( 'click', OnClick_noDefault( getAll, index ), false );

		downloadLocations.appendChild( dl );
	}
	
	downloadLocations.appendChild( div );
}


// for evil pages which need to be redirected to the torrent from it's own site
function indirectDownload( host ) {
	var regex = new RegExp(
		'^http://' + host + '/download/'
		+ '[0-9]+/[0-9-]+/.+\.torrent$'
	);
	var anchorElements = document.getElementsByTagName( 'a' );
	for ( var i = 0; i < anchorElements.length; i++ ) {
		var a = anchorElements[i];
		if ( a.href.match( regex ) ) {
			document.location = a.href;
			break;
		}
	}
}



{
	var host = document.location.hostname.match( /[^\.]+\.[^\.]+$/ ).toString();
	switch ( host ) {
		case 'torrentz.com':
			torrentz();
			break;
		case 'sumotorrent.com':
			if ( document.location.hash == requestDownload ) {
				// must be redirected to the torrent file in page context,
				// not in GM context; for referer to be set
				addJS( '(' + indirectDownload.toSource()
					+ ')("torrents\.sumotorrent\.com")' );
			}
			break;
		case 'monova.org':
			if ( document.location.hash == requestDownload ) {
				// must be redirected to the torrent file in page context,
				// not in GM context; for referer to be set
				addJS( '(' + indirectDownload.toSource()
					+ ')("www\.monova\.org")' );
			}
			break;
		default:
			GM_log( "Unknown service: " + host + "\n" );
			break;
	}
}

// vim: ts=4:sw=4