Turns thumbnail titles into direct links and disables lazy-loading on ranking pages.
// ==UserScript==
// @name Pixiv Direct Links
// @namespace https://greasyfork.org/scripts/4555
// @description Turns thumbnail titles into direct links and disables lazy-loading on ranking pages.
// @include *://www.pixiv.net/*
// @grant none
// @version 2019.10.13
// ==/UserScript==
//Disable lazy loading images. These appear on ranking pages and the "Recommended" section of the bookmarks page.
var dontSayLazy = true;
//----------------------------------------------------------------//
if( window == window.top )//not inside iframe
{
//Link dem titles.
linkThumbTitles(document);
new MutationObserver( function(mutationSet)
{
mutationSet.forEach( function(mutation)
{
for( let i = 0; i < mutation.addedNodes.length; i++ )
if( mutation.addedNodes[i].nodeType == Node.ELEMENT_NODE )
linkThumbTitles( mutation.addedNodes[i] );
} );
}).observe( document.body, { childList:true, subtree:true } );
if( dontSayLazy && unlazyImage() )
{
//Initial page has lazy images; listen for more images added later
new MutationObserver( function(mutationSet)
{
mutationSet.forEach( function(mutation)
{
for( let i = 0; i < mutation.addedNodes; i++ )
if( mutation.addedNodes[i].nodeType == Node.ELEMENT_NODE )
unlazyImage( mutation.addedNodes[i] );
} );
}).observe( document.body, { childList:true, subtree:true } );
}
}
//----------------------------------------------------------------//
function unlazyImage(target)
{
let images = ( target || document ).querySelectorAll("img[data-src]");
for( let i = 0; i < images.length; i++ )
images[i].src = images[i].getAttribute("data-src");
return images.length;
}
function linkThumbTitles(target)
{
//bookmark_new_illust.php, discovery, search.php
let foundTitle = target.querySelectorAll("li a[href*='/artworks/'][title]");
for( let j = 0; j < foundTitle.length; j++ )
directLinkSingle( foundTitle[j] );
//member.php, member_illust.php, new_illust.php, artworks (related works)
foundTitle = target.querySelectorAll("li > div > a[href*='/artworks/']");
for( let j = 0; j < foundTitle.length; j++ )
directLinkSingle( foundTitle[j] );
//main page
foundTitle = target.querySelectorAll("li > a[href*='/artworks/'] > .title");
for( let j = 0; j < foundTitle.length; j++ )
directLinkSingle( foundTitle[j].parentNode );
//bookmark.php
foundTitle = target.querySelectorAll("li > a[href*='mode=medium'][href*='illust_id='] > .title");
for( let j = 0; j < foundTitle.length; j++ )
directLinkSingle( foundTitle[j].parentNode );
//ranking.php
foundTitle = target.querySelectorAll("a.title[href*='/artworks/']");
for( let j = 0; j < foundTitle.length; j++ )
directLinkSingle( foundTitle[j] );
//response.php
let image = target.querySelectorAll("li a[href*='mode=medium'][href*='illust_id='] img");
for( let j = 0; j < image.length; j++ )
{
let page, title;
for( page = image[j].parentNode; page.tagName != "A"; page = page.parentNode );
//The prev/next thumbnails on mode=medium pages have text before/after the image. Text also follows the image on image responses listings.
if( !(title = page.getElementsByClassName("title")[0]) && (title = page.lastChild).nodeName != '#text' && (title = page.firstChild).nodeName != '#text' )
continue;//Can't find title element
//Start title link at mode=medium and change later.
let titleLink = document.createElement("a");
titleLink.href = page.href;
titleLink.style.color = "#333333";//Style used on some pages
//Move the title out of the thumbnail link
page.removeChild(title);
titleLink.appendChild(title);
page.parentNode.insertBefore( titleLink, page.nextSibling );
directLinkSingle( titleLink );
}
}
function directLinkSingle(titleLink)
{
let illustID;
if( !titleLink || !titleLink.href )
return;
if( !(illustID = titleLink.href.match(/\/artworks\/(\d+)/)) && !(illustID = titleLink.href.match(/illust_id=(\d+)/)) )
return;
let req = new XMLHttpRequest();
req.open( "GET", location.protocol+"//www.pixiv.net/artworks/"+illustID[1], true );
req.onload = function()
{
let scripts = req.responseXML.head.getElementsByTagName("script");
for( let i = 0; i < scripts.length; i++ )
{
//JSON requires double quotes around property names, forbids trailing commas, etc... The illust info can't be simply parsed as a raw JSON object, so just grab the values we need.
let originalURL = scripts[i].textContent.match(/"original":"(http[^"]+)"/);
if( !originalURL )
continue;
//Do nothing for ugoira (animated) images
if( originalURL.indexOf("ugoira") > 0 )
return;
//There are several pageCount properties; we just want the last one.
let pageCount = 0, rCount = RegExp( '"pageCount": *(\\d+)', 'g' ), search;
while( (search = rCount.exec( scripts[i].textContent )) !== null )
pageCount = parseInt(search[1]);
//Only link single images
if( pageCount <= 1 )
titleLink.href = originalURL[1].replace(/\\\//g,'/');
return;
}
//console.log("Unable to find direct image link for illust #"+illustID[1]);
};
req.responseType = "document";
req.send(null);
}