Gelbooru/Rule34xxx Viewer/Downloader

A simple quick and dirty image viewer for gelbooru.com and rule34.xxx supports all formats from gif to webm.

2017-04-29 기준 버전입니다. 최신 버전을 확인하세요.

// ==UserScript==
// @name         Gelbooru/Rule34xxx Viewer/Downloader
// @version      1.0
// @description  A simple quick and dirty image viewer for gelbooru.com and rule34.xxx supports all formats from gif to webm.
// @author       PineappleLover69
// @include      https://gelbooru.com*
// @include      https://rule34.xxx*
// @include      http://gelbooru.com*
// @include      http://rule34.xxx*
// @namespace https://greasyfork.org/users/120106
// ==/UserScript==

(function() {
	
   var postTop = document.getElementsByClassName("content")[0];

   var yupStuff = document.getElementsByClassName("yup")[0];
   
   var posts = document.getElementById("post-list");
   //imgList = posts.childNodes[2].childNodes[0].childNodes;
   imgList = document.getElementsByClassName("thumb");
   
   var postSources = Array(imgList.length);    
   
   BatchApiCall();
   
   isRule34 = false;
   if(document.URL.includes("rule34.xxx")){
      imgList = posts.childNodes[2].childNodes[3].childNodes;
		isRule34 = true;
   }
   
	console.log(imgList);
	imgIndex = 0;
	var imgOpened = false;

	for(i = 0; i < imgList.length;){
		try{
			//console.log(imgList[i].getAttribute("id"));
			//console.log(imgList[i].childNodes[0].getAttribute("href"));
			imgList[i].setAttribute("openRef", imgList[i].childNodes[0].getAttribute("href"));
			imgList[i].childNodes[0].removeAttribute("href");
			imgList[i].childNodes[0].addEventListener("click", ImgClick);
			i++;
		}catch(ex){
			imgList[i].remove();
		}
	}

	function ImgClick(e){
		if(!imgOpened)
			ImgView();
		var child = e.target.parentNode.parentNode;
		var parent = child.parentNode;
		// The equivalent of parent.children.indexOf(child)
		imgIndex = Array.prototype.indexOf.call(parent.children, child);
		//console.log(imgIndex);
		SetImg();
		imgViewBtn.scrollIntoView();
	}

	imgViewBtn = document.createElement("button");
	imgViewBtn.innerHTML = "Image View";
	imgViewBtn.onclick = ImgView;
	var dlAllBtn = document.createElement("button");
	dlAllBtn.innerHTML = "Download All";
	dlAllBtn.onclick = dlAll;

	//imgViewBtn.setAttribute("class", "active");
	postTop.insertBefore(dlAllBtn, postTop.childNodes[0]);
	postTop.insertBefore(imgViewBtn, postTop.childNodes[0]);
	
	function ImgView(){
		if(imgOpened)
			return;
		
		holdDiv = document.createElement("div");
		holdDiv.setAttribute("align", "center");
		postTop.insertBefore(holdDiv, postTop.childNodes[2]);
		
		imgViewImg = document.createElement("img");
		imgViewImg.setAttribute("height", 650);
		holdDiv.appendChild(imgViewImg);
		videoImg = document.createElement("video");
		videoImg.setAttribute("height", 650);
		videoImg.setAttribute("autoplay", true);
		videoImg.setAttribute("controls", true);
		videoImg.setAttribute("loop", true);
		videoImg.setAttribute("hidden", true);
		holdDiv.appendChild(videoImg);
		
		preloadImg1 = document.createElement("img");
		preloadImg2 = document.createElement("img");
		preloadImg1.setAttribute("hidden", true); preloadImg2.setAttribute("hidden", true);
		holdDiv.appendChild(preloadImg1); holdDiv.appendChild(preloadImg2);
		
		preloadImg3 = document.createElement("img");
		preloadImg4 = document.createElement("img");
		preloadImg3.setAttribute("hidden", true); preloadImg4.setAttribute("hidden", true);
		holdDiv.appendChild(preloadImg3); holdDiv.appendChild(preloadImg4);
		
		imgViewImg.addEventListener('load', DoPreload);
		//imgViewImg.addEventListener("error", WasError);
		//videoImg.addEventListener("error", WasError);
		
		prevBtn = document.createElement("button");
		prevBtn.innerHTML = "Prev";    prevBtn.onclick = PrevImg;
		nextBtn = document.createElement("button");
		nextBtn.innerHTML = "Next";    nextBtn.onclick = NextImg;
		dlBtn = document.createElement("button");
		dlBtn.innerHTML = "Download";    dlBtn.onclick = DownloadCurrent;
		opBtn = document.createElement("button");
		opBtn.innerHTML = "Open Src";    opBtn.onclick = OpenSrc;
		spacer = document.createElement("img");
		spacer.setAttribute("width", 30);
		spacer2 = document.createElement("img");
		spacer2.setAttribute("width", 30);
		spacer3 = document.createElement("img");
		spacer3.setAttribute("width", 30);
		holdDiv.appendChild(document.createElement("br"));
		holdDiv.appendChild(prevBtn);
		holdDiv.appendChild(spacer);
		holdDiv.appendChild(dlBtn);
		holdDiv.appendChild(spacer2);
		holdDiv.appendChild(opBtn);
		holdDiv.appendChild(spacer3);
		holdDiv.appendChild(nextBtn);
		
		imgOpened = true;
		//console.log(isRule34);
		if(isRule34){
			document.getElementById("header").remove();
		}else{
			document.getElementsByClassName("header")[0].remove();
			document.getElementsByClassName("submenu")[0].remove();
		}
		document.addEventListener("keydown", keyInput);
		SetImg();
	}    
   function BatchApiCall(){
       var urlItems = getJsonFromUrl();        
       var pid = 0;
       if(urlItems.pid)
           pid = urlItems.pid / 42;
       
       var tags = document.getElementById("tags").value;        
       var limit = imgList.length;
       
       var request = "/index.php?page=dapi&s=post&q=index&limit=" + limit + "&tags=" + tags + "&pid=" + pid;
       
       var xhttp = new XMLHttpRequest();
       xhttp.onreadystatechange = function() {
           if (this.readyState == 4 && this.status == 200) {
              var response = xmlToJson(this.responseXML);
               
              for(var i = 0; i < limit; i++){
                  if(!response.posts.post[i])
                     break;
                  postSources[i] = response.posts.post[i]["@attributes"].file_url;
              }
           }
       };
       xhttp.open("GET", request, true);
       xhttp.send();
   }
   
	function getJsonFromUrl() {
   var query = location.search.substr(1);
   var result = {};
   query.split("&").forEach(function(part) {
		var item = part.split("=");
      result[item[0]] = decodeURIComponent(item[1]);
   });
  return result;
	}
   
   function OpenSrc(){
      window.open(imgList[imgIndex].getAttribute("openRef"));
   }
   
	function PrevImg(){
		imgIndex--;
		if(imgIndex < 0)
			imgIndex = imgList.length - 1;
		SetImg();
	}

	function NextImg(){
		imgIndex++;
		if(imgIndex >= imgList.length)
			imgIndex = 0;
		SetImg();
	}

	function SetCurrentSrc(){
		currentSrc = GetSrcForImg(imgIndex);
	}
   
	function GetSrcForImg(getIndex){
		if(postSources[getIndex]){
			return postSources[getIndex];
		} else {    
			var tmpSrc = imgList[getIndex].id;
			tmpSrc = tmpSrc.replace("s", "");
		
			var thing = JsonHttpRequest("/index.php?page=dapi&s=post&q=index&id=" + tmpSrc.toString());
			
			tmpSrc = thing.posts.post["@attributes"].file_url;
			postSources[getIndex] = tmpSrc;
			return tmpSrc;
		}
	}
   
	function JsonHttpRequest(urlRequest){
		var xhr = new XMLHttpRequest();
		xhr.open("GET", urlRequest, false);
		xhr.send();
		return xmlToJson(xhr.responseXML);
	}

	function SetImg(){
		SetCurrentSrc();
		var dI = currentSrc.lastIndexOf(".");
		var fileExt = currentSrc.substring(dI + 1);
		
		if(fileExt.toLowerCase() == "webm"){
			videoImg.setAttribute("src", currentSrc);
			videoImg.removeAttribute("hidden");
			videoImg.play();
			imgViewImg.setAttribute("hidden", true);
			setTimeout(DoPreload, 200);
		}else{
			imgViewImg.setAttribute("src", currentSrc);
			imgViewImg.removeAttribute("hidden");
			videoImg.setAttribute("hidden", true);
			videoImg.pause();
		}
	}
   
	function DoPreload(){
		var preIndex = imgIndex + 1;
		if(preIndex >= imgList.length)
			preIndex = 0;
		preloadImg1.src = GetSrcForImg(preIndex);
		
		//preIndex++;
		//if(preIndex >= imgList.length)
		//    preIndex = 0;
		//preloadImg2.src = GetSrcForImg(preIndex);
		
		preIndex = imgIndex - 1;
		if(preIndex < 0)
			preIndex = imgList.length - 1;
		preloadImg3.src = GetSrcForImg(preIndex);
		
		//preIndex--;
		//if(preIndex < 0)
		//    preIndex = imgList.length - 1;
		//preloadImg4.src = GetSrcForImg(preIndex);
	}

	function DownloadCurrent(){
		if(!isRule34)
			SetCurrentSrc();
		var dI = currentSrc.lastIndexOf(".");
		var uI = currentSrc.lastIndexOf("/") + 5;
		var fileExt = currentSrc.substring(dI);
		var imgName = "tags-" + document.getElementById("tags").value + " ";
		if(document.getElementById("tags").value === ""){
			imgName = currentSrc.substring(uI, dI);
		}else{
			imgName += currentSrc.substring(uI, dI);
		}
		imgName += " id-" + imgList[imgIndex].childNodes[0].getAttribute("id");
		imgName += fileExt;
		//console.log(imgName);
		var dl = document.createElement("a");
			dl.setAttribute("href", currentSrc);
			dl.setAttribute("download", imgName);
			dl.click(); dl.remove();
		
		document.body.focus();
	}
	
	function dlAll(){
		var prevIndex = imgIndex;
		if(isRule34){
			
		}else{
			for(imgIndex = 0; imgIndex < imgList.length;){
					try{
						DownloadCurrent();
						imgIndex++;
					}catch(ex){
						console.log(ex);
						imgIndex++;
						//imgList[imgIndex].remove();
					}
			}
		}
		imgIndex = prevIndex;
	}
	
	var tagE = document.getElementById("tags");
	function keyInput(e){
		if(document.activeElement != tagE){			
			if(e.keyCode === 32){
				e.preventDefault();
				return false;
			}
			if(e.keyCode === 37){
				e.preventDefault();
				PrevImg();
				return false;
			}
			if(e.keyCode === 39){
				e.preventDefault();
				NextImg();
				return false;
			}
			if(e.keyCode === 40){
				e.preventDefault();
				DownloadCurrent();
				return false;
			}
		}
	}
})();


// Changes XML to JSON
function xmlToJson(xml) {
	
	// Create the return object
	var obj = {};

	if (xml.nodeType == 1) { // element
		// do attributes
		if (xml.attributes.length > 0) {
		obj["@attributes"] = {};
			for (var j = 0; j < xml.attributes.length; j++) {
				var attribute = xml.attributes.item(j);
				obj["@attributes"][attribute.nodeName] = attribute.nodeValue;
			}
		}
	} else if (xml.nodeType == 3) { // text
		obj = xml.nodeValue;
	}

	// do children
	if (xml.hasChildNodes()) {
		for(var i = 0; i < xml.childNodes.length; i++) {
			var item = xml.childNodes.item(i);
			var nodeName = item.nodeName;
			if (typeof(obj[nodeName]) == "undefined") {
				obj[nodeName] = xmlToJson(item);
			} else {
				if (typeof(obj[nodeName].push) == "undefined") {
					var old = obj[nodeName];
					obj[nodeName] = [];
					obj[nodeName].push(old);
				}
				obj[nodeName].push(xmlToJson(item));
			}
		}
	}
	return obj;
}