// ==UserScript== // @name Pixiv Image Searches and Stuff // @namespace https://greasyfork.org/scripts/4296 // @description Searches Danbooru for pixiv IDs, adds IQDB image search links, and filters images based on pixiv favorites. // @include http://www.pixiv.net* // @grant GM_getValue // @grant GM_setValue // @grant GM_deleteValue // @grant GM_xmlhttpRequest // @version 2014.08.17 // @downloadURL none // ==/UserScript== var iqdbURL = "";//Replace with "http://danbooru.iqdb.org/?url=" (Danbooru) or "http://iqdb.org/?url=" (multi-service) to add IQDB search links (replaces bookmark counts) var addSourceSearch = false;//Danbooru post search (looks for matching pixiv IDs); **Requires GM_xmlhttpRequest** //Source search options var danbooruLogin = "";//username var danbooruApiKey = "";//api key as listed on your profile var styleSourceFound = "color:green; font-weight: bold;"; var styleSourceMissing = "color:red;"; var sourceTimeout = 20;//seconds to wait before retrying query var maxAttempts = 10;//# of times to try a query before completely giving up on source searches ////////////////////////////////////////////////////////////////////////////////////// var minFavs = 0, anyBookmarks = false, favList = []; if( typeof(GM_getValue) == "undefined" || !GM_getValue('a', 'b') ) { GM_getValue = function(name,defV){ var value = localStorage.getItem("pisas."+name); return( value === null ? defV : value ); }; GM_setValue = function(name,value) { localStorage.setItem("pisas."+name, value ); } GM_deleteValue = function(name){ localStorage.removeItem("pisas."+name); } } if( typeof(custom) != "undefined" ) custom(); //Source search requires GM_xmlhttpRequest() if( addSourceSearch && typeof(GM_xmlhttpRequest) == "undefined" ) addSourceSearch = false; //Manga images have to be handled specially if( location.search.indexOf("mode=manga") >= 0 ) { var searchID = addSourceSearch && location.search.match(/illust_id=(\d+)/); if( searchID ) { var thumbList = [], images = document.querySelectorAll(".item-container img"); for( var i = 0; i < images.length; i++ ) thumbList.push({ link: images[i].parentNode.appendChild( document.createElement("div") ).appendChild( document.createElement("a") ), pixiv_id: searchID[1], page: i }); sourceSearch( thumbList ); } } else if( window == window.top )//Don't run if inside an iframe { //Add ability to set minFavs inside Search Options var addSearch = document.getElementById("word-and"); if( addSearch ) { anyBookmarks = true; //Load "minFavs" setting if( GM_getValue("minFavs") ) minFavs = parseInt( GM_getValue("minFavs") ); //Set option addSearch = addSearch.parentNode.parentNode; var favTr = document.createElement("tr"); favTr.appendChild( document.createElement("th") ).textContent = "Minimum favorites (script)"; favInput = favTr.appendChild( document.createElement("td") ).appendChild( document.createElement("input") ); favInput.type = "text"; favInput.value = ""+minFavs; favInput.addEventListener("input", function() { if( /^ *\d+ *$/.test(this.value) && (minFavs = parseInt( this.value, 10 )) > 0 ) GM_setValue("minFavs", ""+minFavs); else { GM_deleteValue("minFavs"); minFavs = 0; } for( var i = 0; i < favList.length; i++ ) { if( favList[i].favcount < minFavs ) favList[i].thumb.style.display = "none"; else favList[i].thumb.style.removeProperty("display"); } }, true); addSearch.parentNode.insertBefore( favTr, addSearch ); } //Prevent added links sometimes being hidden for thumbnails with long titles var style = document.createElement('style'); style.type = 'text/css'; style.innerHTML = 'li.image-item{ height:auto !important; overflow:visible !important; padding:5px 0px !important } '; document.getElementsByTagName('head')[0].appendChild(style); processThumbs( [document] ); //Monitor for changes caused by other scripts var MutObj = window.MutationObserver || window.WebKitMutationObserver; if( !MutObj ) window.addEventListener( "DOMNodeInserted", function(e){ processThumbs( [e.target] ); }, true ); else new MutObj( function(mutationSet) { mutationSet.forEach( function(mutation){ processThumbs( mutation.addedNodes ); } ); }).observe( document.body, { childList:true, subtree:true } ); } //====================================== Functions ====================================== function processThumbs(target) { var thumbSearch = [], thumbList = []; //Combine the results over all targets to minimize queries by source search for( var i = 0; i < target.length; i++ ) { //Take care not to match on profile images, like those shown in the "Following" box on user profiles... var xSearch = document.evaluate("descendant-or-self::li/a[contains(@href,'mode=medium') or contains(@href,'/novel/show.php')]//img[not(@pisas)] | "+ "descendant-or-self::li[@class='image-item']/a//img[not(@pisas)] | "+ "descendant-or-self::div/a[contains(@href,'mode=medium') or contains(@href,'/novel/show.php')]/img[not(@pisas)] | "+ "descendant-or-self::div[@class='works_display']/a/img[not(@pisas)]", target[i], null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); for( var j = 0; j < xSearch.snapshotLength; j++ ) (thumbSearch[thumbSearch.length] = xSearch.snapshotItem(j)).setAttribute("pisas","done"); } for( var i = 0; i < thumbSearch.length; i++ ) { var thumbImg = thumbSearch[i]; var thumbPage = thumbImg.parentNode; while( thumbPage.tagName != "A" ) thumbPage = thumbPage.parentNode; var thumbDiv = thumbPage.parentNode; var bookmarkCount = 0, bookmarkLink = thumbDiv.querySelector("a[href*='bookmark_detail.php']"); var sourceContainer = thumbDiv; //Disable lazy loading if( thumbImg.getAttribute("data-src") ) thumbImg.src = thumbImg.getAttribute("data-src"); //Skip generic restricted thumbs if( thumbImg.src.indexOf("http://source.pixiv.net/") == 0 ) continue; //Skip special thumbs except on image pages if( thumbImg.src.indexOf("_100.") > 0 && location.search.indexOf("mode=") < 0 ) continue; if( bookmarkLink ) { //Thumb has bookmark info bookmarkCount = parseInt( bookmarkLink.getAttribute("data-tooltip","x").replace(/([^\d]+)/g,'') ) || 1; sourceContainer = bookmarkLink.parentNode; } else if( iqdbURL ) { //Thumb doesn't have bookmark info. Add a fake bookmark link to link with the IQDB. bookmarkLink = document.createElement("a"); bookmarkLink.className = "bookmark-count"; if( anyBookmarks ) { bookmarkLink.className += " ui-tooltip"; bookmarkLink.setAttribute("data-tooltip", "0 bookmarks"); } //Dummy div to force new line when needed thumbDiv.appendChild( document.createElement("div") ); thumbDiv.appendChild( bookmarkLink ); } else { //Dummy div to force new line when needed thumbDiv.appendChild( document.createElement("div") ); } if( anyBookmarks ) { favList.push({ thumb: thumbDiv, favcount: bookmarkCount }); if( bookmarkCount < minFavs ) thumbDiv.style.display = "none"; } if( iqdbURL ) { bookmarkLink.href = iqdbURL+thumbImg.src+"&fullimage="+thumbPage.href; bookmarkLink.innerHTML = "(IQDB)"; } if( addSourceSearch && thumbPage.href.indexOf("novel/show.php") < 0 && pixivIllustID( thumbImg.src ) ) { sourceContainer.appendChild( document.createTextNode(" ") ); thumbList.push({ link: sourceContainer.appendChild( document.createElement("a") ), pixiv_id: pixivIllustID( thumbImg.src ), page: -1 }); } } sourceSearch( thumbList ); } function pixivIllustID(url) { var matcher = url.match(/\/(\d+)(_|\.)[^\/]+$/); return matcher && matcher[1]; } function pixivPageNumber(url) { var matcher = url.match(/_p(\d+)\./); return matcher ? matcher[1] : "x"; } function sourceSearch( thumbList, attempt, page ) { //thumbList[index] = { link, id, page? } if( page === undefined ) { //First call. Finish initialization attempt = page = 1; for( var i = 0; i < thumbList.length; i++ ) { if( !thumbList[i].status ) thumbList[i].status = thumbList[i].link.parentNode.appendChild( document.createElement("span") ); thumbList[i].link.textContent = "Searching..."; thumbList[i].posts = []; } } if( attempt >= maxAttempts ) { //Too many failures (or Downbooru); give up. :( for( var i = 0; i < thumbList.length; i++ ) { thumbList[i].status.style.display = "none"; if( thumbList[i].link.textContent[0] != '(' ) thumbList[i].link.textContent = "(error)"; thumbList[i].link.setAttribute("style","color:blue; font-weight: bold;"); } return; } //Is there actually anything to process? if( thumbList.length == 0 ) return; //Retry this call if timeout var retry = (function(a,b,c){ return function(){ setTimeout( function(){ sourceSearch(a,b,c); }, maxAttempts == 0 ? 0 : 1000 ); }; })( thumbList, attempt + 1, page ); var sourceTimer = setTimeout( retry, sourceTimeout*1000 ); // Combine the IDs from the thumbList into a single search string var query = "status:any+pixiv:"; for( var i = 0; i < thumbList.length; i++ ) { thumbList[i].status.textContent = " ["+attempt+"]"; query += thumbList[i].pixiv_id+","; } GM_xmlhttpRequest( { method: "GET", url: 'http://danbooru.donmai.us/posts.json?limit=100&tags='+query+'0&login='+danbooruLogin+'&api_key='+danbooruApiKey+'&page='+page, onload: function(responseDetails) { clearTimeout(sourceTimer); //Check server response for errors var result = false, status = null; if( /^ *$/.test(responseDetails.responseText) ) status = "(error)";//No content else if( responseDetails.responseText.indexOf("