Endless Danbooru Pages

By ttfn Last update Jun 30, 2008 — Installed 1,750 times. Daily Installs: 4, 4, 1, 3, 0, 4, 1, 1, 2, 3, 1, 3, 1, 1, 5, 2, 3, 0, 1, 0, 0, 1, 2, 2, 4, 1, 1, 2, 2, 3, 1, 2
// ==UserScript==
// @name          Endless Danbooru Pages
// @namespace     namespace-20071209
// @description   Makes danbooru pages infinitely long instead of limited to 16 posts per page by loading more when you scroll to near the bottom of the page.
// @author        ttfn
// @include       http://danbooru.donmai.us/post*
// ==/UserScript==
// Version 7

var mainTable = null;

var nextPage = null;      // the number of the next page
var lastPage = null;
var tagSearch = null;     // tags being searched for
var danbooruURL = "http://" + window.location.host + "/post";
var danbooruQuery = "/index.json?";
var pending = false;

var danbooruLogin = document.cookie.search("login=(.+?)(;|$)") != -1 ? document.cookie.match("login=(.+?)(;|$)")[1] : "";
var danbooruPasswordHash = document.cookie.search("pass_hash=(.+?)(;|$)") != -1 ? document.cookie.match("pass_hash=(.+?)(;|$)")[1] : "";

var crlf = String.fromCharCode(10) + String.fromCharCode(13);

if (danbooruLogin && danbooruPasswordHash) {
  window.addEventListener("load", init, false);

  // Check the scroll position on a timer because we can't use onscroll (bug 189308).
  // If we do switch to onscroll, remember to call testScrollPosition after changing the page.
  // setInterval(testScrollPosition, 100);
  window.addEventListener("scroll", testScrollPosition, false);
}

function init() { 
  mainTable = findMainTable(document);
  tagSearch = document.getElementById("tags").value;

  // structure of paginator is -
  // previous
  // first
  // text node elipsis
  // page -2
  // page -1
  // text node current page
  // page +1
  // page +2
  // text node elipsis
  // last
  // next

  if (document.evaluate("//div[@id='paginator']/div[@class='pagination']/a[text()='>>']", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue) {
    // if the paginator has a '>>' "next page" element then get the current page number and the last page number.
    nextPage = Number(document.evaluate("//div[@id='paginator']/div[@class='pagination']/span[@class='current']", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue.textContent) + 1;
    // element before >> contains the last page number
    lastPage = Number(document.evaluate("//div[@id='paginator']/div[@class='pagination']/a[text()='>>']/preceding-sibling::*[1]", document, null, XPathResult.STRING_TYPE, null).stringValue.replace(",","","g"));
  }
  testScrollPosition();
}

function testScrollPosition() {
  if ((!pending) && ((nextPage <= lastPage) && (window.innerHeight + window.scrollMaxY) - window.pageYOffset < 2.5 * window.innerHeight)) {
    // We're near the bottom of the page; one press of pgdn could get close to the bottom of the page.
    // (At about 1.9 * window.innerHeight, one press of pgdn would actually hit the bottom of the page.)
    pullMore();
  }
}

function pullMore() {
  GM_xmlhttpRequest ({
    method: "GET",
    url: danbooruURL + danbooruQuery + ((tagSearch != "") ? "tags=" + escape(tagSearch) + "&" : "") + "page=" + nextPage + "&login=" + danbooruLogin + "&password_hash=" + danbooruPasswordHash,
    onload: function(responseDetails) {
      var result = eval("(" + responseDetails.responseText+ ")");
      pending = false;

      if (result["success"]==false) {
        console.debug(result["reason"]);
        return;
      }

      var arLen = result.length;
      for ( var i=0; i<arLen; ++i ) {
        // check thumb isn't already displayed
        if (!document.getElementById("p" + String( result[i]["id"] ))) {
          var imgTag=null, aTag=null, spanTag=null;

          imgTag = document.createElement("img");
          imgTag.src = result[i]["preview_url"];
          imgTag.title = result[i]["tags"];
          switch (result[i]["rating"]) {
            case "s":
              imgTag.title += " Rating: Safe";
              break;
            case "q":
              imgTag.title += " Rating: Questionable";
              break;
            case "e":
              imgTag.title += " Rating: Explicit";
              break;
            default:
              break;
          }
          imgTag.title += " Score: " + result[i]["score"];
          imgTag.alt = imgTag.title;
          switch (result[i]["status"]) {
            case "flagged":
            imgTag.className = "preview flagged"
            break;

            case "pending":
            imgTag.className = "preview pending"
            break;

            case "deleted":
            imgTag.className = "preview deleted"
            break;

            default:
            imgTag.className = "preview"
            break;
          }
          if (result[i]["has_children"] === true) {
            imgTag.className += " has-children";
          }
          if (result[i]["parent_id"] !== null) {
            imgTag.className += " has-parent";
          }
          if (result[i]["preview_height"]) {
            imgTag.height = result[i]["preview_height"];
          }
          if (result[i]["preview_width"]) {
            imgTag.width = result[i]["preview_width"];
          }

          aTag = document.createElement("a");
          aTag.href = danbooruURL + "/show/" + result[i]["id"];
          aTag.setAttribute("onclick", "return PostModeMenu.click(" + result[i]["id"] + ")" );

          spanTag = document.createElement("span");
          spanTag.className = "thumb rating-" + result[i]["rating"];
          spanTag.id = "p" + result[i]["id"];

          aTag.appendChild(imgTag);
          spanTag.appendChild(aTag);
          mainTable.appendChild(spanTag);

          // add details to existing danbooru data structures and rerun blacklist
          unsafeWindow.Post.register( result[i] );
        }
      }
      unsafeWindow.Post.init_blacklisted();

      // add a HR and page number every 160 thumbs (10 pages)
      if (((nextPage % 10) == 0) && (nextPage+1 <= lastPage) ) {
        var hrTag = null, hTag = null, a2Tag = null;

        hrTag = document.createElement("hr");
        hrTag.style.clear = "both";
        hTag = document.createElement("h2");
        a2Tag = document.createElement("a");
        a2Tag.href = danbooruURL + "?" + ((tagSearch != "") ? "tags=" + escape(tagSearch) + "&" : "") + "page=" + nextPage;
        a2Tag.textContent = "Page " + String(nextPage);

        mainTable.appendChild(hrTag);
        hTag.appendChild(a2Tag)
        mainTable.appendChild(hTag);
      }

      // call testScrollPosition again in case one page's worth of thumbs are not enough.
      testScrollPosition();
    },
    onreadtstatechange: function(responseDetails) {
    },
    onerror: function(responseDetails) {
      pending = false;
      console.debug(responseDetails);
    }
  });
  pending = true;

  nextPage += 1;
}

function findMainTable(doc) {
  return doc.evaluate("//div[@id='post-list']/div[@class='content']/div[span[@class='thumb']]", doc, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
}