您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
A simple quick and dirty image viewer for gelbooru.com and rule34.xxx supports all formats from gif to webm.
当前为
// ==UserScript== // @name ImageBoard Viewer/Downloader // @version 1.3 // @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://rule34.xxx* // @namespace https://greasyfork.org/users/120106 // ==/UserScript== (function () { //Settings var StartImageHeight = 650; var AutoShowImageView = false; var DisableImageLinks = true; var siteInfo = { hostName: window.location.hostname, siteIndex_: "", get siteIndex() { if (!this.siteIndex_) { if (this.hostName == "gelbooru.com" || this.hostName == "rule34.xxx") { this.siteIndex_ = "gel+r34"; } else if (this.hostName == "chan.sankakucomplex.com") { this.siteIndex_ = "sankaku"; } } return this.siteIndex_; } }; var siteObj, siteSwitchObj; SetUpSiteSwitchObjs(); //this group of vars is to be set by SetVars() and depends on the current website var buttonInsertionPoint, posts, imgList, tagEntry, tagTypeLookup, postsJson, tagArray, postSources; var tagDictionary = {}; siteObj.SetVars(); BatchPostApiCall(); var imgIndex = 0; var imgOpened = false; if (DisableImageLinks) { for (let i = 0; i < imgList.length;) { try { 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 parentchildObj = {}; siteObj.ImgClickGetChildAndParent(parentchildObj, e); // The equivalent of parent.children.indexOf(child) imgIndex = Array.prototype.indexOf.call(parentchildObj.parent.children, parentchildObj.child); SetImg(); imgViewBtn.scrollIntoView(); } var 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"); buttonInsertionPoint.insertBefore(dlAllBtn, buttonInsertionPoint.childNodes[0]); buttonInsertionPoint.insertBefore(imgViewBtn, buttonInsertionPoint.childNodes[0]); var imgViewImg, videoImg, preloadImg1, preloadImg2, preloadImg3, preloadImg4; function ImgView() { if (imgOpened) return; var holdDiv = document.createElement("div"); holdDiv.setAttribute("align", "center"); buttonInsertionPoint.insertBefore(holdDiv, buttonInsertionPoint.childNodes[2]); imgViewImg = document.createElement("img"); imgViewImg.setAttribute("height", StartImageHeight); holdDiv.appendChild(imgViewImg); videoImg = document.createElement("video"); videoImg.setAttribute("height", StartImageHeight); 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('mousedown', ImageMouseDown); imgViewImg.addEventListener('mouseup', ImageMouseUp); imgViewImg.addEventListener('mousemove', ImageMouseMove); imgViewImg.addEventListener('mouseleave', ImageMouseLeave); videoImg.addEventListener('mousedown', ImageMouseDown); videoImg.addEventListener('mouseup', ImageMouseUp); videoImg.addEventListener('mousemove', ImageMouseMove); videoImg.addEventListener('mouseleave', ImageMouseLeave); 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; let header = document.getElementById("header"); if (header) header.remove(); header = document.getElementsByClassName("header")[0]; if (header) header.remove(); document.addEventListener("keydown", keyInput); SetImg(); } if (AutoShowImageView) ImgView(); function BatchPostApiCall() { var apiCallObj = getJsonFromUrl(); siteObj.posts.PostApiSelector(apiCallObj); var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function () { if (this.readyState == 4 && this.status == 200) { postsJson = xmlToJson(this.responseXML); siteObj.posts.PostSourcesSelector(apiCallObj); CreateTagBase(); } }; xhttp.open("GET", apiCallObj.request, true); xhttp.send(); } function CreateTagBase() { var uniqueTagList = []; siteObj.tags.GetSplitTagsPerPost(uniqueTagList); uniqueTagList = mergeDedupe(uniqueTagList); siteObj.tags.TagApiSelector(uniqueTagList); } function TagRequest(tagRequest) { var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function () { if (this.readyState == 4 && this.status == 200) { var tagPageJson = xmlToJson(this.responseXML); siteObj.tags.TagDictionarySetup(tagPageJson); if (imgOpened) SetNewTags(); } }; xhttp.open("GET", tagRequest, true); xhttp.send(); } function OpenSrc() { window.open(imgList[imgIndex].getAttribute("openRef")); } function SetCurrentSrc() { currentSrc = GetSrcForImg(imgIndex); } function GetSrcForImg(getIndex) { if (postSources[getIndex]) { return postSources[getIndex]; } else { return siteObj.posts.SinglePostSrc(getIndex); } } function SetNewTags() { if (!tagArray) return; siteObj.tags.RemoveTags(); siteObj.tags.AddTags(); siteObj.tags.RemoveEmptyTags(); } 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", ""); imgViewImg.removeAttribute("hidden"); videoImg.setAttribute("hidden", true); videoImg.pause(); setTimeout(SetImageAfterTimeout, 1); } SetNewTags(); } function SetImageAfterTimeout() { imgViewImg.setAttribute("src", currentSrc); } 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() { SetCurrentSrc(); var dI = currentSrc.lastIndexOf("."); var uI = currentSrc.lastIndexOf("/") + 5; var fileExt = currentSrc.substring(dI); var imgName = "tags-" + tagEntry.value + " "; if (tagEntry.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; for (imgIndex = 0; imgIndex < imgList.length;) { try { DownloadCurrent(); imgIndex++; } catch (ex) { console.log(ex); imgIndex++; //imgList[imgIndex].remove(); } } imgIndex = prevIndex; } function keyInput(e) { if (document.activeElement != tagEntry) { 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; } } } function SetUpSiteSwitchObjs() { ///this is the object that controls what should be done for each individual website supported siteSwitchObj = { //the default here serves as a master obj so that code bits can be reused if certain websites //use similar layouts in areas. it is based on the gelbooru design. default: { SetVars: function () { buttonInsertionPoint = document.getElementsByClassName("content")[0]; posts = document.getElementById("post-list"); imgList = document.getElementsByClassName("thumb"); tagEntry = document.getElementById("tags"); postSources = Array(imgList.length); tagTypeLookup = { 0: "tag-type-general", 1: "tag-type-artist", 2: "tag-type-copyright", 3: "tag-type-copyright", 4: "tag-type-character" }; }, ImgClickGetChildAndParent: function (obj, e) { obj.child = e.target.parentNode.parentNode; obj.parent = obj.child.parentNode; }, posts: { PostApiSelector: function (apiObj) { var pid = 0; if (apiObj.pid) pid = apiObj.pid / 42; apiObj.postLimit = imgList.length; var tags = encodeURIComponent(tagEntry.value); apiObj.request = "/index.php?page=dapi&s=post&q=index&limit=" + apiObj.postLimit + "&tags=" + tags + "&pid=" + pid; }, PostSourcesSelector: function (apiObj) { for (var i = 0; i < apiObj.postLimit; i++) { if (!postsJson.posts.post[i]) break; postSources[i] = postsJson.posts.post[i]["@attributes"].file_url; } }, SinglePostSrc: function (getIndex) { 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; } }, tags: { GetSplitTagsPerPost: function (uniqueTagList) { for (var i = 0; i < imgList.length; i++) { var currentPost = postsJson.posts.post[i]; var tags = currentPost["@attributes"].tags.toLowerCase(); var splitTags = tags.split(' '); uniqueTagList.push(splitTags); } }, TagApiSelector: function (uniqueTagList) { var uniqueTagString = ""; var uniqueStringArray = []; var usCount = 0; for (i = 0; i < uniqueTagList.length; i++) { if (usCount === 0) { uniqueTagString += uniqueTagList[i]; } else { uniqueTagString += " " + uniqueTagList[i]; } usCount++; if (usCount > 99 || i == uniqueTagList.length - 1) { usCount = 0; uniqueStringArray.push(uniqueTagString); uniqueTagString = ""; } } for (i = 0; i < uniqueStringArray.length; i++) { var request = "/index.php?page=dapi&s=tag&q=index&names=" + encodeURIComponent(uniqueStringArray[i]); TagRequest(request); } }, TagDictionarySetup: function (tagPageJson) { let tmpArray = tagPageJson.tags.tag; if (!tagArray) tagArray = tmpArray; else { tagArray = tagArray.concat(tmpArray); } for (i = 0; i < tmpArray.length; i++) { tagDictionary[tmpArray[i]["@attributes"].name.toLowerCase()] = tmpArray[i]["@attributes"]; } }, AddTag: function (tagName, tagParent, tagToClone, stringToReplace) { try { var clonedTag = tagToClone.cloneNode(true); tagParent.appendChild(clonedTag); clonedTag.innerHTML = clonedTag.innerHTML.replaceAll(stringToReplace, encodeURIComponent(tagName)); clonedTag.childNodes[7].innerHTML = tagName.replace(/_/g, " "); var jsonTag = tagDictionary[tagName]; var tagType = jsonTag.type; clonedTag.setAttribute("class", tagTypeLookup[tagType]); clonedTag.childNodes[9].innerHTML = jsonTag.count; } catch (ex) { console.log("Failed tag: " + tagName); console.log(ex); console.log(tagDictionary); } }, AddTags: function () { var currentPost = postsJson.posts.post[imgIndex]; var tags = currentPost["@attributes"].tags; var splitTags = tags.split(' '); var tagBar = document.getElementById("tag-sidebar"); var firstTag = tagBar.childNodes[0]; var stringToReplace = firstTag.innerHTML.substring(firstTag.innerHTML.indexOf("search=") + 7, firstTag.innerHTML.indexOf('" title="Wiki"')); for (var i = 1; i < splitTags.length; i++) { this.AddTag(splitTags[i], tagBar, firstTag, stringToReplace) } firstTag.remove(); }, RemoveTags: function () { var tagBar = document.getElementById("tag-sidebar"); for (var i = tagBar.childNodes.length - 1; i >= 1; i--) { tagBar.childNodes[i].remove(); } }, RemoveEmptyTags: function () { var tagBar = document.getElementById("tag-sidebar"); for (var i = tagBar.childNodes.length - 1; i >= 0; i--) { let tAg = tagBar.childNodes[i]; if (tAg.childNodes[7].innerHTML === "") { tAg.remove(); } } } } }, //this setup for gelbooru and r34 uses all the default calls "gel+r34": { SetVars: function () { siteSwitchObj.default.SetVars(); }, ImgClickGetChildAndParent: function (obj, e) { siteSwitchObj.default.ImgClickGetChildAndParent(obj, e); }, posts: { PostApiSelector: function (apiObj) { siteSwitchObj.default.posts.PostApiSelector(apiObj); }, PostSourcesSelector: function (apiObj) { siteSwitchObj.default.posts.PostSourcesSelector(apiObj); }, SinglePostSrc: function (getIndex) { return siteSwitchObj.default.posts.SinglePostSrc(getIndex); } }, tags: { GetSplitTagsPerPost: function (uniqueTagList) { siteSwitchObj.default.tags.GetSplitTagsPerPost(uniqueTagList); }, TagApiSelector: function (uniqueTagList) { siteSwitchObj.default.tags.TagApiSelector(uniqueTagList); }, TagDictionarySetup: function (tagPageJson) { siteSwitchObj.default.tags.TagDictionarySetup(tagPageJson); }, RemoveTags: function () { siteSwitchObj.default.tags.RemoveTags(); }, AddTag: function (tagName, tagParent, tagToClone, stringToReplace) { siteSwitchObj.default.tags.AddTag(tagName, tagParent, tagToClone, stringToReplace); }, AddTags: function () { siteSwitchObj.default.tags.AddTags(); }, RemoveEmptyTags: function () { siteSwitchObj.default.tags.RemoveEmptyTags(); } } }, "sankaku": {} }; siteObj = siteSwitchObj[siteInfo.siteIndex]; } //----------everything below here is either utility or is pretty set in stone------------------- Element.prototype.remove = function () { if (this) this.parentElement.removeChild(this); }; //String.prototype.replaceAll = function (search, replacement) { // var target = this; // return target.replace(new RegExp(search, 'g'), replacement); //}; String.prototype.replaceAll = function (search, replacement) { var target = this; return target.split(search).join(replacement); }; function mergeDedupe(arr) { return [...new Set([].concat(...arr))]; } function PrevImg() { imgIndex--; if (imgIndex < 0) imgIndex = imgList.length - 1; SetImg(); } function NextImg() { imgIndex++; if (imgIndex >= imgList.length) imgIndex = 0; SetImg(); } var imgMouseDown = false; var imgDownPosX, imgDownPosY, imgDownHeight = 0; function ImageMouseDown(e) { e.preventDefault(); imgMouseDown = true; imgDownPosX = e.screenX; imgDownPosY = e.screenY; imgDownHeight = Number(imgViewImg.getAttribute("height")); return false; } function ImageMouseUp(e) { e.preventDefault(); imgMouseDown = false; return false; } function ImageMouseMove(e) { if (imgMouseDown) { e.preventDefault(); var moveDist = e.screenY - Number(imgDownPosY); imgViewImg.setAttribute("height", imgDownHeight + moveDist * 2); videoImg.setAttribute("height", imgDownHeight + moveDist * 2); return false; } } function ImageMouseLeave(e) { e.preventDefault(); imgMouseDown = false; return false; } 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 JsonHttpRequest(urlRequest) { var xhr = new XMLHttpRequest(); xhr.open("GET", urlRequest, false); xhr.send(); return xmlToJson(xhr.responseXML); } // 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; } }) ();