Greasy Fork 还支持 简体中文。

Pixiv Direct Links

Turns thumbnail titles into direct or mode=manga links, adds direct image links on mode=manga pages, replaces the medium thumbnail on mode=medium pages with the full size, and disables lazy-loading images.

目前為 2018-01-29 提交的版本,檢視 最新版本

// ==UserScript==
// @name           Pixiv Direct Links
// @namespace      https://greasyfork.org/scripts/4555
// @description    Turns thumbnail titles into direct or mode=manga links, adds direct image links on mode=manga pages, replaces the medium thumbnail on mode=medium pages with the full size, and disables lazy-loading images.
// @include        *://www.pixiv.net/*
// @grant          none
// @version        2018.01.28
// ==/UserScript==

//Turn thumbnail titles into direct links (single images) or mode=manga links.  Some kinds of thumbnails aren't covered, and an isolated few (like #17099702) don't work.
var directTitles = false;

//Append direct links below images on mode=manga pages
var directManga = true;

//Force pixiv's 'book view' style for manga sequences to something like the normal view.  Clicking a page won't scroll the window to the next page.
var breakBookView = false;

//Replace the medium thumbnail on mode=medium pages with the full size.  The image will be relinked to the full size regardless of this setting.
var fullSizeMedium = true;

//Disable lazy loading images.  These appear on mode=manga pages, rankings, and the "Recommended" section of the bookmarks page.
var dontSayLazy = true;

//----------------------------------------------------------------//

var fullSizeWidth = "740px";

if( typeof(custom) != "undefined" )
	custom();

if( location.search.indexOf("mode=manga_big") > 0 || location.search.indexOf("mode=big") > 0 )
{
	//Make the 'big'/'manga_big' image link to itself instead of closing the window
	let image = document.getElementsByTagName("img")[0];
	if( image )
	{
		let link = document.createElement("a");
		link.href = image.src;
		link.appendChild( document.createElement("img") ).src = image.src;
		document.body.innerHTML = "";
		document.body.appendChild( link );
	}
}
else if( location.search.indexOf("mode=manga") > 0 )
{
	let container = document.getElementsByClassName("full-size-container");
	if( directManga && container.length )
	{
		//Check the mode=manga_big page for the first page, since the sample extension is always "jpg".
		let req = new XMLHttpRequest();
		req.open( "GET", location.href.replace(/page=\d+&?/,'').replace('mode=manga','mode=manga_big&page=0'), true );
		req.onload = function()
		{
			let firstImage = req.responseXML.querySelector("img[src*='_p0.']").src;
			for( let i = 0; i < container.length; i++ )
			{
				//Add direct link below each page
				let link = document.createElement("a");
				link.textContent = "direct link";
				link.style.display = "block";
				link.href = firstImage.replace( "_p0.", "_p"+i+"." );
				container[i].parentNode.appendChild( link );
			}
		};
		req.responseType = "document";
		req.send(null);
	}
	else if( breakBookView && document.head.innerHTML.indexOf("pixiv.context.images") > 0 )
	{
		//Book view (e.g. #54139174, #57045668)

		let mangaSection = document.createElement("section");
		mangaSection.className = "manga";
		
		let scripts = document.head.getElementsByTagName("script");
		let hits = 0;
		for( let i = 0; i < scripts.length; i++ )
		{
			let urls = scripts[i].innerHTML.match( /pixiv.context.images[^"]+"([^"]+)".*pixiv.context.originalImages[^"]+"([^"]+)"/ );
			if( urls )
			{
				let full = urls[2].replace( /\\\//g, "/");
				mangaSection.innerHTML += '<div class="item-container"><a href="'+full+'" class="full-size-container"><i class="_icon-20 _icon-full-size"></i></a><img style="width:auto;height:auto;max-width:1200px;max-height:1200px" src="'+full+'" class="image">'+( directManga ? '<a href="'+full+'" style="display:block">direct link</a>' : '' )+'</div>';
				hits++;
			}
		}
		
		if( hits > 0 )
		{
			let sheet = document.createElement("link");
			sheet.setAttribute("rel","stylesheet");
			sheet.setAttribute("href","http://source.pixiv.net/www/css/member_illust_manga.css");
			document.head.appendChild( sheet );
			document.getElementsByTagName("html")[0].className = "verticaltext no-textcombine no-ie";
			document.body.innerHTML = "";
			document.body.appendChild( mangaSection );
		}
	}
}
else if( window == window.top )//not inside iframe
{
	if( directTitles )
	{
		//Link dem titles.
		linkThumbTitles([document]);
		new MutationObserver( function(mutationSet)
		{
			mutationSet.forEach( function(mutation){ linkThumbTitles( mutation.addedNodes ); } );
		}).observe( document.body, { childList:true, subtree:true } );
	}
	
	let worksDisplay = document.getElementsByClassName("works_display")[0];
	if( worksDisplay )
	{
		let mainImage, fullsizeSrc = 0, mainLink = worksDisplay.querySelector("a[href*='mode=']");
		if( mainLink )
			mainLink.removeAttribute('target');//Make link open in same window
		
		let oClass = document.getElementsByClassName("original-image");
		if( oClass.length == 1 )//47235071
		{
			let worksDiv = worksDisplay.getElementsByTagName("div")[0];
			worksDisplay.removeChild( worksDiv );//Need to remove instead of hide to prevent double source search links in other script
			let link = worksDisplay.insertBefore( document.createElement("a"), worksDisplay.firstChild );
			mainImage = link.appendChild( fullSizeMedium ? document.createElement("img") : worksDiv.getElementsByTagName("img")[0] );
			fullsizeSrc = link.href = oClass[0].getAttribute("data-src");
		}
		else if( mainLink && mainLink.href.indexOf("mode=big") > 0 && (mainImage = mainLink.getElementsByTagName("img")[0]) !== null )//17099702
		{
			//New thumbnails are always jpg, need to query mode=big page to get the right file extension.
			let req = new XMLHttpRequest();
			req.open( "GET", mainLink.href, true );
			req.onload = function()
			{
				mainLink.href = req.responseXML.getElementsByTagName("img")[0].src;
				if( fullSizeMedium )
					mainImage.src = mainLink.href;
			};
			req.responseType = "document";
			req.send(null);
		}
		
		if( mainImage && fullSizeMedium )
		{
			if( fullsizeSrc )
				mainImage.src = fullsizeSrc;
			mainImage.setAttribute("style", "max-width: "+fullSizeWidth+"; height: auto; width: auto;");
			worksDisplay.style.width = fullSizeWidth;
		}
	}
}

if( dontSayLazy && unlazyImage() && window == window.top )
{
	//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++ )
				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 pushTitleLink(list, link)
{
	let matcher;
	if( link && link.href && (matcher = link.href.match(/illust_id=(\d+)/)) && matcher[1] > 0 )
		list.push({ "id": matcher[1], "link": link });
}

function linkThumbTitles(targets)
{
	let titleList = [];
	
	for( let i = 0; i < targets.length; i++ )
        if( targets[i] == document || targets[i].nodeType == Node.ELEMENT_NODE )
        {
            //search.php
            let foundTitle = targets[i].querySelectorAll("a[href*='mode=medium'][href*='illust_id='][title]");
            for( let j = 0; j < foundTitle.length; j++ )
                pushTitleLink( titleList, foundTitle[j] );

            //bookmark.php, member_illust.php, new_illust.php, member.php (uploads), mypage.php (new works)
            foundTitle = targets[i].querySelectorAll("a[href*='mode=medium'][href*='illust_id='] > .title");
            for( let j = 0; j < foundTitle.length; j++ )
                pushTitleLink( titleList, foundTitle[j].parentNode );

            //ranking.php
            foundTitle = targets[i].querySelectorAll(".ranking-item a.title[href*='mode=medium'][href*='illust_id=']");
            for( let j = 0; j < foundTitle.length; j++ )
                pushTitleLink( titleList, foundTitle[j] );

            //member_illust.php (what image was responding to)
            foundTitle = targets[i].querySelector(".worksImageresponseInfo a.response-out-work[href*='mode=medium'][href*='illust_id=']");
            if( foundTitle )
                pushTitleLink( titleList, foundTitle );

            //response.php, member_illust.php (before/after thumbnails), ?member.php (bookmarks)?
            let image = targets[i].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 );

                pushTitleLink( titleList, titleLink );
            }
	}
	
	for( let i = 0; i < titleList.length; i++ )
		directLinkSingle( titleList[i] );
}

//Query an image's mode=medium page.
function directLinkSingle(title)
{
	let req = new XMLHttpRequest();
	req.open( "GET", location.protocol+"//www.pixiv.net/member_illust.php?mode=medium&illust_id="+title.id, true );
	req.onload = function()
	{
		let select = req.responseXML.getElementsByClassName("original-image");
		if( select.length == 1 )
			title.link.href = select[0].getAttribute("data-src");
		else if( (select = req.responseXML.querySelector(".works_display a[href*='mode=manga']")) !== null )
		{
			title.link.href = select.href;
			let page = req.responseXML.querySelectorAll("ul.meta li")[1].textContent.match(/(\d+)P$/);
			if( page )
				( title.link.firstChild.nodeName == '#text' ? title.link : title.link.firstChild ).title += " ("+page[1]+" pages)";
		}
	};
	req.responseType = "document";
	req.send(null);
}