TPB Full Search

By Stefan Berndtsson Last update Aug 18, 2005 — Installed 3,178 times.
// ==UserScript==
// @name         TPB Full Search
// @namespace    http://www.nocrew.org/~stefan/gm/
// @description  Allow search in specific subcategory.
// @include      http://*.thepiratebay.*/*
// @include      http://thepiratebay.*/*
// ==/UserScript==

/*
 * This is a Greasemonkey script for use with ThePirateBay.
 *
 * Now you can search in a specific category and not just in the
 * main categories the people at ThePirateBay thinks you want to
 * search in.
 * 
 * For example, you can search for "1985" in "Video/Music videos" only,
 * and not having to manually filter away all those useless entries in
 * other categories you're not interested in.
 *
 * This script also traverses down into the following pages to fill up
 * your search result list with enough entries. Due to this function,
 * it can take a few seconds longer to complete the search. A small 
 * page-traverse counter is shown in the upper left side of the page.
 * 
 * Apart from the search extending features, this one also adds two more
 * things. It adds a checkbox for showing only seeded torrents, and thereby
 * replacing the "tpbhideseedless.user.js" script, which most likely will not
 * work very well with this one.
 * 
 * The second extra feature is that it will strip away most of the ads.
 * This is all done using global css (in the PageCleanup function).
 *
 *
 *
 * Fixes in v0.5 (which is the first actually numbered version):
 *
 * - Some fixes has been done to the page numbering. The "next"-arrow now
 *   points to the first page not yet having been scanned. Yes, it updates
 *   live, so even if you stop, it will be set correctly.
 *
 * - Default maxResult value has been lowered to 20. This does not mean
 *   that the maximum limit of results is 20, but rather that after 20 has
 *   been reached, no more pages will be scanned after the current one.
 *
 * Fixes in v0.6:
 *
 * - Extended search options now also available on the front page.
 * 
 * - Some cosmetic fixes.
 *
 *
 *
 * This has been tested only with the 0.5 beta version of Greasemonkey.
 *
 * Several known bugs exists:
 *
 * - The page numbering is flawed, due to the traversal method, and apart
 *   from rewriting the links to include the new search category and noseed
 *   options, page numbers are left as they were in the original search
 *   (apart from the "next"-arrow fixup in v0.5).
 * - The script isn't checking completely if it's on a proper page for
 *   for applying itself, so weird things _may_ happen.
 * - The options only seem to appear on the search result page, and not
 *   on the main search (the one with the big logo) page.
 * - Some javascript error appears in the javascript console, and I don't
 *   know why at this point.
 * - Probably a bunch more I'm not aware of.
 * 
 */

/* LICENSE
 * Copyright (C) 2005 Stefan Berndtsson
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You can download a copy of the GNU General Public License at
 * http://www.gnu.org/licenses/gpl.txt
 * or get a free printed copy by writing to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/


(function() {
  /* Settings */
  var urlBase = 'http://thepiratebay.org/';
  var urlCategories = urlBase+'browse.php';
  var selectTextStr = 'Search in specific category: ';
  var checkTextStr = 'Only seeded';
  var searchTextStr = 'Searching page ';
  var doneTextStr = 'Search done';
  var brokenTextStr = 'Search aborted. Click on right arrow to continue.'
  var stopTextStr = ' (click to stop)';

  var maxResults = 20;
  var retVal = 0;

  var catNum = new Array();
  var catName = new Array();
  var catMain = new Array();

  function addGlobalStyle(css) {
    style = document.createElement("style");
    style.type = "text/css";
    style.innerHTML = css;
    document.getElementsByTagName('head')[0].appendChild(style);
  }

  function pageCleanup() {
    addGlobalStyle('.ad { display: none ! important }');
    addGlobalStyle('table[height="165"] { display: none !important }');
    addGlobalStyle('#searchfield { margin-left: auto !important; '+
		   'margin-right: auto !important; '+
		   'width: 80% !important; '+
		   'height: auto !important }');
    addGlobalStyle('#q { text-align: center !important; height: auto !important }');
    addGlobalStyle('#banner1 { height: auto !important }');
    // addGlobalStyle('.img { display: none !important }');
    addGlobalStyle('#TPBlogo { display: none !important; float: none !important;}');
    addGlobalStyle('iframe#tpb_cat_page { display: inline !important}'); 
    addGlobalStyle('iframe { display: none !important; }');
  }
  
  function getMainName(mainNum) {
    for(var i=0;i<catNum.length;i++) {
      if(catNum[i] == mainNum) {
	return catName[i];
      }
    }
  }
 
  function isFirstPage(root) {
    if(!root.document.location.search.match(/\?/)) return 1;
    return 0;
  }

  function getVar(qvar) {
    if(isFirstPage(top)) return "";
    var data = top.document.location.search.split("?")[1].split("&");
    for(var i=0;i<data.length;i++) {
      var tmp = data[i].split("=");
      if(qvar == tmp[0]) {
	return tmp[1];
      }
    }
    return "";
  }
   
  function getSubVar(qvar) {
    if(!self.document) return;
    if(isFirstPage(self)) return;
    var data = self.document.location.search.split("?")[1].split("&");
    for(var i=0;i<data.length;i++) {
      var tmp = data[i].split("=");
      if(qvar == tmp[0]) {
	return tmp[1];
      }
    }
    return "";
  }
   
  function setupCategoriesFrame() {
    var page=document.createElement('iframe');
    page.src=urlCategories+"?tpb_placeholder=1";
    page.width=1;
    page.height=1;
    page.border=0;
    page.id="tpb_cat_page";
    top.document.getElementsByTagName('form')[0].appendChild(page);
  }

  function getCategories () {
    var cats =
      document.evaluate("//a[starts-with(@href, 'brwsearch.php')]",
			document, null,
			XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
			null);
   
    if(cats.snapshotLength < 5) {
      return;
    }
   
    //	alert("DEBUG: Got "+cats.snapshotLength+" nodes");
   
    for(var i=0;i<cats.snapshotLength;i++) {
      var cat = cats.snapshotItem(i);
     
      if(cat.parentNode.nodeName == "DT") {
	/* Main category */
       
	var r = cat.href.match(/brwsearch.php\?b=1&d=(\d00)/);
	catNum.push(r[1]);
	catMain.push(r[1]);
	catName.push(cat.innerHTML);
      } else if(cat.parentNode.nodeName == "NOBR") {
	/* Sub category */
       
	var r = cat.href.match(/brwsearch.php\?b=1&c=(\d)(\d+)/);
	catNum.push(r[1]+r[2]);
	catMain.push(r[1]+'00');
	catName.push(cat.innerHTML);
      }
    }
   
    if(!catNum.length) return;
   
    var div = document.createElement('div');

    var sel = document.createElement('select');
    sel.setAttribute('name', 'tpb_subcat');
    var selText = document.createElement('b');
    selText.innerHTML = selectTextStr;


    var chk = document.createElement('input');
    chk.setAttribute('type', 'checkbox');
    chk.setAttribute('name', 'tpb_noseed');
    if(getVar("tpb_noseed")) {
      chk.setAttribute('checked', '1');
    }
    chk.setAttribute('value', '1');

    var chkLabel = document.createElement('label');
    chkLabel.setAttribute('for', 'noseed');
    var chkText = document.createTextNode(checkTextStr);
    chkLabel.appendChild(chk);
    chkLabel.appendChild(chkText);

    var opt;
    var label;
   
    opt = document.createElement('option');
    opt.setAttribute('value', '0');
    opt.innerHTML = "---";
    sel.appendChild(opt);
   
    for(i=0;i<catNum.length;i++) {
      if(catNum[i] == catMain[i]) {
	label = catName[i];
      } else {
	label = getMainName(catMain[i])+' / '+catName[i];
      }
     
      opt = document.createElement('option');
      opt.setAttribute('value', catNum[i]);
      if(getVar("tpb_subcat") == catNum[i]) {
	opt.setAttribute('selected', '1');
      }
      opt.innerHTML = label;
      sel.appendChild(opt);
    }
    
    div.appendChild(selText);
    div.appendChild(sel);
    div.appendChild(document.createElement('br'));
      
    if(isFirstPage(top)) {
      var labelParent = top.document.getElementsByTagName('label')[0].parentNode;
      
      labelParent.appendChild(chkLabel);
      labelParent.appendChild(div);
    } else {
      var form = top.document.getElementsByTagName('form')[0];

      form.appendChild(chkLabel);
      form.appendChild(div);
    }
   
    var t = top.document.getElementById("tpb_cat_page");
    t.parentNode.removeChild(t);
  }

  function getPageUrl(pnum) {
    var tmp = getVar("page");
    if(tmp == "") {
      var tmp2 = top.location.href.replace("#", "");
      return tmp2+"&page="+pnum;
    } else {
      var oldnum = parseInt(tmp);
      return top.location.href.replace("&page="+oldnum, "&page="+pnum);
    }
  }

  function getThisPageNum() {
    var tmp = getVar("page");
    
    if(tmp == "") {
      return 0;
    }

    return parseInt(tmp);
  }

  function getNextPage(pnum) {
    var url = getPageUrl(pnum);

    GM_xmlhttpRequest({
      method:'GET',
	       url: url,
	       onload: function(result) {
	
	var thisPage = parseInt(top.document.body.getAttribute("nextpage"));
	var resultCnt = parseInt(top.document.body.getAttribute("counter"));
	var stopSearch = parseInt(top.document.body.getAttribute("stopsearch"));
	var startPage = parseInt(top.document.body.getAttribute("startpage"));

	function isSearchBroken(data) {
	  if(!data.match(/<body[^>]*>\n/)) {
	    var r = data.match(/(<body.*)/);
	    alert("DEBUG: Broken page: \""+r[1].substr(0,40)+"\"");
	    return 1;
	  }
	  return 0;
	}

	function isLastPage(data) {
	  if(data.match(/\/img\/next\.gif/)) {
	    return 0;
	  }
	  return 1;
	}
	
	function getRowData(data) {
	  var tmp = data.split("</thead>");
	  var raw = tmp[1];
	  
	  return raw.split("<tr><td colspan")[0];
	}

	function makeRowList(rowDataFull) {
	  var out = new Array();

	  var list = rowDataFull.split("</tr>");

	  for(var i=0;i<list.length;i++) {
	    var tmp = list[i];
	    tmp = tmp.replace("<tr>", "");
	    tmp = tmp.replace('<tr class="alt">', '');

	    out.push(tmp);
	  }
	  
	  return out;
	}

	var data = result.responseText;

	if(isSearchBroken(data)) {
	  var text = top.document.evaluate("//b[@class='tpb_search_status']",
					   top.document, null,
					   XPathResult.FIRST_ORDERED_NODE_TYPE,
					   null).singleNodeValue;
	  text.innerHTML = brokenTextStr;
	  return 0;
	}

	var cat = getVar("tpb_subcat");
	var hideseed = 0;

	if(getVar("tpb_noseed") == "1") {
	  hideseed = 1;
	}
	
	var rows = makeRowList(getRowData(data));

	var insertPoint = 
	  top.document.evaluate("//td[@colspan='9']", top.document, null,
				XPathResult.FIRST_ORDERED_NODE_TYPE,
				null).singleNodeValue.parentNode;
	  
	for(var i=0;i<rows.length;i++) {
	  var show = 0;

	  /* Check category */

	  var r = rows[i].match(/brwsearch.php\?b=1.*c=(\d+)/);
	  if(!r) continue;

	  if((cat.substring(1,3) == "00") &&
	     (r[1].substr(0,1) == cat.substr(0,1))) {
	    show = 1;
	  } else if(cat == r[1]) {
	    show = 1;
	  }

	  /* Check seed */
	  
	  if(hideseed && show) {
	    var line = rows[i].split("\n");
	    if(line[8].match(/<td align="right">0<\/td>/)) {
	      show = 0;
	    }
	  }

	  if(show) {
	    var tr = top.document.createElement('tr');
	    insertPoint.parentNode.insertBefore(tr, insertPoint);
	    tr.innerHTML = rows[i];
	    resultCnt++;
	  }
	}

	if(!stopSearch && data.match(/\/img\/next\.gif/) && 
	   (resultCnt < maxResults)) {
	  //	  alert("DEBUG: Next page is "+(thisPage+1));
	  var text = top.document.evaluate("//b[@class='tpb_search_status']",
					   top.document, null,
					   XPathResult.FIRST_ORDERED_NODE_TYPE,
					   null).singleNodeValue;
	  text.innerHTML = searchTextStr+(thisPage+1)+stopTextStr;

	  top.document.body.setAttribute("nextpage", thisPage+1);
	  top.document.body.setAttribute("counter", resultCnt);
	  /*
	  for(var i = startPage; i<=thisPage;i++) {
	    var link = top.document.getElementById('tpb_link_page_'+i);
	    if(link) link.style.display = 'none';
	  }
	  */
	  var link = top.document.getElementById('tpb_link_next');
	  var r = link.href.match(/&page=(\d+)/);
	  if(r) {
	    link.href = link.href.replace("&page="+r[1],
					  "&page="+(thisPage+1));
	  }
	  getNextPage(thisPage+1);
	} else {
	  if(!data.match(/\/img\/next.gif/)) {
	    var link = top.document.getElementById('tpb_link_next');
	    if(link) link.style.display = 'none';
	  }
	  var text = top.document.evaluate("//b[@class='tpb_search_status']",
					   top.document, null,
					   XPathResult.FIRST_ORDERED_NODE_TYPE,
					   null).singleNodeValue;
	  text.innerHTML = doneTextStr;
	}
      }
    });
    
    return retVal;
  }
  
  function hideOtherCategories() {
    if(self.location.href!=top.location.href) {
      return;
    }
    
    var resultCnt = 0;
    var rows = document.evaluate("//td[@class='vertTh']", document, null,
				 XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
				 null);
    var cat = getVar("tpb_subcat");
    var hideseed = 0;

    if(getVar("tpb_noseed") == "1") {
      hideseed = 1;
    }

    for(i=0;i<rows.snapshotLength;i++) {
      var cell = rows.snapshotItem(i);
      var row = cell.parentNode;
      var link = cell.childNodes[0];
     
      var r = link.href.match(/brwsearch.php\?b=1&[cd]=(\d+)/);
      var show;
      if(!cat || cat == '0' || cat == '') {
	show = 1;
      } else {
	show = 0;
      }
     
      if((cat.substring(1,3) == "00") &&
	 (r[1].substr(0,1) == cat.substr(0,1))) {
	show = 1;
      } else if(cat == r[1]) {
	show = 1;
      }
     
      if(hideseed && row.childNodes[13].innerHTML == "0") {
	show = 0;
      }
     
      if(show) {
	if(row.style.display != 'none') {
	  row.style.display = 'table-row';
	  resultCnt++;
	}
      } else {
	row.style.display = 'none';
      }
    }

    if(resultCnt < maxResults) {
      var head2 = top.document.getElementsByTagName('h2')[0];
      if(head2.childNodes[1].nodeValue.length != 1) return;
      var link = top.document.createElement('a');
      link.setAttribute('href', '#');
      link.setAttribute('onclick', 
			"top.document.body.setAttribute('stopsearch', '1');");
      var text = top.document.createElement('b');
      text.setAttribute('class', 'tpb_search_status');
      var pnum = getThisPageNum();
      var nextPage = pnum+1;

      text.innerHTML = searchTextStr + nextPage + stopTextStr;
      link.appendChild(text);
      head2.appendChild(link);

      top.document.body.setAttribute("startpage", pnum);
      top.document.body.setAttribute("nextpage", nextPage);
      top.document.body.setAttribute("counter", resultCnt);
      top.document.body.setAttribute("stopsearch", "0");
      getNextPage(nextPage);
    }

    return;
  }

  function rewriteLinks() {
    if(self.location.href!=top.location.href) {
      return;
    }

    var links = 
      document.evaluate("//td[@colspan='9']/a[starts-with(@href,'?q=')]",
			document, null,
			XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);

    var last = 1;

    for(var i=0;i<links.snapshotLength;i++) {
      var link = links.snapshotItem(i);
      var href = link.href;
      if(link.childNodes.length > 0) {
	if((link.childNodes[0].nodeName == 'IMG') &&
	   (link.childNodes[0].src.match(/next.gif/))) {
	  last = 0;
	}
      }

      var r = link.href.match(/&page=(\d+)/);

      link.href = href.replace("?q=",
			       "?tpb_subcat="+getVar("tpb_subcat")+
			       "&tpb_noseed="+getVar("tpb_noseed")+
			       "&q=");
      if(r) {
	link.setAttribute('id', 'tpb_link_page_'+r[1]);
	if(!last) {
	  link.setAttribute('id', 'tpb_link_next');
	}
      }
    }

    lastPage = last;
  }

  pageCleanup();

  if(top.location.href == self.location.href) {
    setupCategoriesFrame();
    rewriteLinks();
    hideOtherCategories();
  } else {
    if(getSubVar("tpb_placeholder") == "1") {
      getCategories();
    }
  }
 

})();