Sleazy Fork is available in English.

Eza's Image Glutton

Directly loads images on gallery sites, skipping comments and descriptions

Fra og med 07.10.2014. Se Den nyeste version.

// ==UserScript==
// @name        Eza's Image Glutton
// @namespace   https://inkbunny.net/ezalias
// @author			Ezalias
// @description Directly loads images on gallery sites, skipping comments and descriptions
// @license     Public domain / No rights reserved
// @include     /^https*://www\.furaffinity\.net/(view|full)/.*/
// @include     https://inkbunny.net/submissionview.php*
// @include     http://gelbooru.com/*s=view*
// @include     http://www.gelbooru.com/*s=view*
// @include     http://danbooru.donmai.us/posts/*
// @include     /^http(s|)://e(621|926)\.net/post/show*//
// @include     http://*.deviantart.com/art/*
// @include     http://*.tumblr.com/*
// @include     http://*.hentai-foundry.com/pictures/*
// @include     /^https*://www\.sofurry\.com/view/*//
// @include     https://www.weasyl.com/*
// @include     http://www.y-gallery.net/view/*
// @include     http://rule34.paheal.net/post/view/*
// @include     http://rule34.xxx/index.php?page=post*
// @include     http://rule34hentai.net/post/view/*
// @include     /^https*://derpiboo.ru/*//
// @include     /^https*://derpibooru.org/.*/
// @include     http://*.booru.org/*s=view*
// @include     http://mspabooru.com/*s=view*
// @include     http://safebooru.org/*s=view*
// @include     http://www.majhost.com/cgi-bin/gallery.cgi?i=*
// @include     http://g.e-hentai.org/s/*
// @include     http://nijie.info/view.php?id=*
// @include     http://metabooru.com/*
// @include     http://www.pixiv.net/member_illust.php?mode=medium&illust_id=*
// @include     http://sleepymaid.com/gallery/displayimage.php?*
// @include     https://*.sankakucomplex.com/post/*
// @version     1.21.3
// ==/UserScript==



// Any single-image submission will redirect to the full-size image. On multi-image submissions, every page except the first will redirect to its full-size image. 
// If you go "back" to the normal gallery page (to favorite the image, read its description, leave a comment, etc.) then this script will not send you forward again. 
// https://greasyfork.org/scripts/4713-eza-s-image-glutton
// http://userscripts-mirror.org/scripts/show/169968 (waaay out of date)

// TO DO: modify_pixiv and possibly modify_tumblr, to make links point to images, instead of struggling with more honest redirects
// for modify_tumblr: test for existence of _1280 etc. links before changing them - they won't 404, but they'll return funky error xml 
//		maybe use fake html for this, it was decently usable (separate script for seperate goals!)
// consider doing away with 'og:' stuff for scrape_tumblr, now that redirects don't fluff up the number of pages you go Back through. consistency and simplicity have their value. 
// for modify_tumblr: for photoset pages (but everywhere, to be safe) make unlinked images link to themselves. I want nice, clean, chronological tabs for multi-image comics. 
// consider redirecting to something like "data:text/html,<img src='http://example.com/image.jpg'>" instead of the plain URL. custom html would allow next/previous browsing on some sites.
// "blob://" allows binaries, if you can download the image and relay it. no idea how Image Toolbar would handle naming those files. 
// ugh. test without adblock enabled. 
// imgur single-image pages. really, why not? 
// modify_furaffinity to change prev/next/fav links with pre-appended #dnr. not raw html fiddling: use the DOM and getElementsByType or whatever. thingy.href=url_plus_dnr. 
// flickr? maybe separately. that whole site is a mess. also full-size images are sometimes gigantic, like dozens of megabytes. 
// Some guy says Weasyl is redirecting to avatars, but I can't reproduce that - hopefully the '/' fix for grabbing full-size links fixes his issue
// when doing comparisons in the future, remember that !== and === don't coerce types (requiring manual conversions), but != and == do. 
// SoFurry shouldn't redirect from stories: https://www.sofurry.com/view/719417#dnr
// inkbunny: move page links above first-page preview on multi-image submissions? - by altering divs or css, if possible. minimal molestation implies better future-proofing. 
	// weasyl: replace bespoke thumbnails with smallest preview images? eh, do these as separate scripts, once userscripts stops fucking around.
// https://openuserjs.org/user/add/scripts
// http://www.pixiv.net/member_illust.php?mode=medium&illust_id=44302315#dnr is apparently a video? ah, no: it's define as data://. wtf. 
// Consider changing some @includes to @match. 
// What the hell is @grant? 

// Owyn Tyler has a ridiculously replete script with similar goals called Handy Just Image - http://userscripts.org/scripts/show/166494
// The supported-site list is waaay longer than mine, and/but his goals are more complex. Image Glutton exists only to deliver the image. 
// He's having trouble with back-trapping, though. His solution sounds absurdly complex even compared to mine. Test the script and recommend help if possible. 

// 2.0 - general solution - foreach image on page, redirect to the biggest (iff the biggest is significantly larger than the second-biggest, to avoid redirecting to ads or banners on low-res submissions
// 		with this, I could ditch the giant for-each and just add oodles of this-looks-like-a-submission-page @includes at the top 
// 		wait, nevermind. some sites don't show the full image. maybe implement it as a general scrape_biggest_image and use where appropriate. (maybe just handle small pages as exceptions.) 





// global variables, for simplicity
var image_url = '';		// location of the full-size image to redirect to
var wait_for_dnr = false;		// some site URLs use "#" liberally, so if this var isn't empty, only "#dnr" will stop a redirect
var html_dump = document.getElementsByTagName('html')[0].innerHTML;		// read full page HTML as string - admittedly overkill, but it's kilobytes, so who really cares?
//var html_ref = document.getElementsByTagName('html')[0].innerHTML;		// pointer to innerHTML - forces nondestructive and copying-free indexOf() use, for improved efficiency 



// detect site, extract image URL, then decide whether or not to redirect
if ( address_bar_contains('e621.net') ) { extract_image_url_after( '>Respond</a>', 'https://' ); }
else if ( address_bar_contains('e926.net') ) { extract_image_url_after( '<li>Size:', 'http' ); }
else if ( address_bar_contains('gelbooru.com') ) { extract_image_url_after( '<h5>Options</h5>', 'http://' ); }
else if ( address_bar_contains('weasyl.com') ) { extract_image_url_after( '<div id="detail-art">', '/' ); }		// also redirects to plaintext/HTML on stories, haha
else if ( address_bar_contains('hentai-foundry.com') ) { extract_image_url_after( '<center><img', '//' ); }
else if ( address_bar_contains('y-gallery.net') ) { extract_image_url_after( 'a_center container2">', 'http://' ); }
else if ( address_bar_contains('rule34.xxx') ) { extract_image_url_after( '>Edit</a></li>', 'http://' ); }
else if ( address_bar_contains('derpiboo.ru') ) { extract_image_url_after( 'full res">View</a>', '//derpicdn' ); }
else if ( address_bar_contains('derpibooru.org') ) { extract_image_url_after( 'full res">View</a>', '//derpicdn' ); }
else if ( address_bar_contains('metabooru.com') ) { extract_image_url_after( 'og:image', 'http://' ); }
else if ( address_bar_contains('sankakucomplex.com' ) ) { extract_image_url_after( '<li>Original:', '//' ); } 
	//////////
else if ( address_bar_contains('rule34hentai.net') ) { extract_image_url_after( '<!--JuicyAds END-->', '/_images/' ); wait_for_dnr = true; }
else if ( address_bar_contains('rule34.paheal.net') ) { extract_image_url_after( 'shm-zoomer', 'http://' ); wait_for_dnr = true; }
else if ( address_bar_contains('majhost.com') ) { image_url = document.getElementsByTagName( "img" )[0].src; }		// first and only <img> tag
	//////////
else if ( address_bar_contains('sofurry.com') ) {
	image_url = window.location.href.replace('sofurry.com/view/','sofurryfiles.com/std/content?page='); }
else if ( address_bar_contains('danbooru.donmai.us') ) { 
	extract_image_url_after( '% of original (', '/data/' );		// resized images will say "X% of original (view full" or something like that
	if( image_url == '' ) {extract_image_url_after( 'twitter:image:src', 'http://' );		// otherwise just grab the preview-sized image (this also works on pages claiming you need Gold to see them)
	image_url = image_url.replace( '/sample/sample-', '/' ); }	 }	// if the preview-sized image is a sample, fix that - this sometimes fails for PNG images with JPG previews
else if ( address_bar_contains('furaffinity.net') ) {
	if (unsafeWindow.full_url)			// Basically stolen from http://userscripts.org/scripts/review/157574 - but FA's kind enough to define the URL as a var, so why fight the obvious approach? 
		{ image_url = unsafeWindow.full_url; } }		// use full_url variable from live window HTML
else if ( address_bar_contains('http://g.e-hentai.org/s/') ) { 
	var image_index = html_dump.indexOf( '</iframe>' );		// jump to end of navigation iframe
	image_index = html_dump.indexOf( 'http://', image_index+1 );		// find next URL (link to next page)
	image_index = html_dump.indexOf( 'http://', image_index+1 );		// find URL after that (image source)
	image_url = html_dump.substring( image_index, html_dump.indexOf( '"', image_index ) ); }		// grab image src, delimited by doublequote 
else if ( address_bar_contains('nijie.info') ) {
	extract_image_url_after( 'name="twitter:image"', 'http://' );		// some images are behind some sort of barrier, so let's grab the twitter-size image instead...
	image_url = image_url.replace( '/sp/', '/' ); }		// ... and drop the /sp/ to get the full-size URL. 
else if ( address_bar_contains('sleepymaid.com') ) { 
	extract_image_url_after( 'fullsize', 'albums/' ); 
	image_url = image_url.replace( 'normal_', '' ); 
	wait_for_dnr = true; 
}

	//////////
else if ( address_bar_contains('deviantart.com') ) { scrape_deviantart(); wait_for_dnr = true; }		// some deviantArt URLs have a hash for no damn reason... and wait_for_dnr isn't working? fuck! 
else if ( address_bar_contains('inkbunny.net') ) { scrape_inkbunny(); }
else if ( address_bar_contains('tumblr.com') ) { scrape_tumblr(); }
else if ( address_bar_contains('pixiv.net' ) ) { scrape_pixiv(); }
else if ( address_bar_contains('.booru.org' ) ) { scrape_booru(); }
else if ( address_bar_contains('mspabooru.com' ) ) { scrape_booru(); }
else if ( address_bar_contains('safebooru.org' ) ) { scrape_booru(); }



// having defined image_url by scraping the page's HTML, modify the current URL to prevent back-traps, then redirect to that full image 
if( image_url !== '' && !address_bar_contains('#') || wait_for_dnr ) 		// do nothing if image_url is empty or there's a # symbol (except on sites that need an explicit #dnr) 
{
	if( !address_bar_contains('#dnr') )		// even on sites with #search nonsense, do nothing if #dnr appears in the URL 
	{		// some images don't redirect properly, even if you manually "view image" - so we append ".jpg" to URLs without file extensions, forcing the browser to consider them images
			// even if this doesn't work, the new URL should just 404, which is better than the semi-modal "octet stream" dialog seen otherwise. 
		if( image_url.lastIndexOf( '/' ) > image_url.lastIndexOf( '.' ) ) { image_url = image_url + '.jpg'; }		// if there's not a "." after the last "/" then slap a file extension on there 
		if( image_url[ image_url.length - 1 ] == '.' ) { image_url = image_url + 'jpg'; }		// if the URL ends with a dot, slap a file extension on there 

			// modify current location, so that when the user clicks "back," they aren't immediately sent forward again
		modified_url = window.location.href + '#dnr'; 		// add do-not-redirect tag to current URL
		history.replaceState( {foo:'bar'}, 'Do-not-redirect version', modified_url);		// modify URL without redirecting. the {foo:'bar'} thing is a state object that I don't care about, but the function needs one.

//		window.location.href = image_url;		// redirect to full image
		location.assign("javascript:window.location.href=\""+image_url+"\";");		// pixiv-friendly redirect to full image: maintains referral, happens within document's scope instead of within greasemonkey's
	}
}		// end of main execution





// ----- //			Functions for readability





function extract_image_url_after( string_before_url, url_begins_with ) {		// extract the first quote-delimited string that appears after unique first var and begins with second var
	var image_index = html_dump.indexOf( string_before_url );		// find unique string shortly before URL - varies by site
	if( image_index !== -1 )		// do nothing if string_before_url isn't found
	{
		image_url = html_dump.substring(image_index);		// lose everything before whichever pre-URL string was found
		image_index = image_url.indexOf( url_begins_with );		// find start of relative highres URL - e.g. /data/ or http:
		image_url = image_url.substring(image_index);		// lose everything before URL - image_url now starts with link, delimited by a double-quote (plus entire rest of page HTML)
		var delimiter_index = image_url.indexOf('"');		// to be clear: that's a double-quote inside single-quotes. (even in monospace, it looks like five ambiguous squiggles.) 
		image_url = image_url.substring(0, delimiter_index);		// lose everything past the delimiting double-quote, append to absolute URL
	}
}		// Do not mix up image_url.indexOf and html_dump.indexOf! Mistakes are easy to make and hard to see. 

function address_bar_contains( string_to_look_for ) {	// I'm so tired of typing out window.location.etc == -1. It's stupidly verbose and it looks terrible.
	return (window.location.href.indexOf( string_to_look_for ) !== -1);		// this makes code more concise and readable. if( address_bar_contains( 'tld.com' ) ) { do tld.com stuff; }
}





// ----- //			Functions for individual websites (separated for being especially long)






// I might be able to redirect from failed tumblr pages if I don't rely on getElements or document.body - the script appears to run; it just crashes for those uncaught errors 
// maybe re-download the current URL within JS? 
function scrape_tumblr() {
	// Tumblr's goals are basically like Inkbunny's:
	//		- On a generic post or /image/ page with a single image: redirect to that image in the highest resolution available
	//		- On a multi-image post: do nothing, since photosets already are or link to their highest-resolution versions
	if( address_bar_contains('/image/') ) { 		// on centered-image pages
		extract_image_url_after( 'id="content-image"', 'http://' );		// get conveniently-labeled id="image" image
	}		// The above will handle /post/ to /image/ URL conversions in a sort of double-redirect, letting Tumblr do the hard work of finding the highest-res version of an image
	else if( address_bar_contains( '/post/' ) ) {		// on generic Tumblr posts
		image_url = window.location.href.replace( '/post/', '/image/' );  
		var comment_check_index = image_url.lastIndexOf( '/' );		// if the /post/ contained text, it gets appended after the post/image number and screws up the URL...
		if( image_url.substring( comment_check_index - 6, comment_check_index ) !== '/image' ) {		// ... so if the last '/' isn't the latter in '/image/' then we dump everything after that '/'...
			image_url = image_url.substring( 0, comment_check_index );		// ... by taking the substring up to the index of that final '/'.
		}
			// If the theme is kind enough to use proper Open Graph tags, let's use those instead for a single redirect:
		var post_image_url = image_url;		// store the double-redirect URL just in case
		extract_image_url_after( 'property="og:image"', 'http' );
		if( image_url.indexOf( '_1280.' ) == -1 ) { image_url = post_image_url; }		// if the Open Graph isn't _1280 (and thus might be misdefined at low-res), just double-redirect instead  
	}		// this might also trigger on images with no _size in the URL, but I think those are all tumblr-feed:entry items anyway. hardly matters. /image/ would still work. 

		// Now that image_url is defined, we can blank it out if we don't want to redirect. Much easier than piling on if( || && || )-style logic. 
	if( address_bar_contains( '_iframe/' ) ) { image_url = ''; }		// Do not redirect from photoset iframe pages, since they trigger their own instance of this script
	if( html_dump.indexOf( 'class="html_photoset"' ) !== -1 ) { image_url = ''; }		// Do not redirect from photosets (because photoset images always are or link to highest-res versions)
	if( html_dump.indexOf( 'content="tumblr-feed:entry"' ) !== -1 ) { image_url = ''; }	// Do not redirect if Open Graph indicates a text-only post (as opposed to tumblr-feed:photo). 
	if( html_dump.indexOf( 'content="tumblr-feed:photoset""' ) !== -1 ) { image_url = ''; }	// Do not redirect if Open Graph indicates a text-only post (as opposed to tumblr-feed:photo). 
}

// DeviantArt's HTML is an inconsistent mess. 
// maybe use the tumblr share thing, except I'd have to unescape a bunch of $2F%E6 nonsense. 
// dev-page-download? no. that's just more custom-view horseshit. 
// collect_rid? seems to be based on URL, e.g. collect_rid="1:484295327". 
function scrape_deviantart() {		// this doesn't use ditch_html_before because data-super-full-img's appear for random links - we need to avoid grabbing one from the ass-end of small-image pages
	var image_index = html_dump.indexOf( 'class="dev-view-deviation"' ); 		// jump to unique and hopefully universal dev-view-deviation div
	var image_index = html_dump.indexOf( 'src=', image_index+1 ); 		// jump to first src (preview size)
	var image_index = html_dump.indexOf( 'http://', image_index+1 ); 		// jump to the URL defined in src
	image_url = html_dump.substring( image_index, html_dump.indexOf( '"', image_index ) ); 		// grab URL, delimited by doublequote
	if( image_url.indexOf( "/PRE/" ) > 0 ) { image_url = image_url.replace( "/PRE/", "/" ); } 		// fix preview-size image to be full-size
/*		// Previous code kept 'just in case' removing /PRE/ somehow fucks up some pages I didn't test. 
	var image_index = html_dump.indexOf( 'class="dev-view-deviation"' ); 		// jump to dev-view-deviation div
	var image_index = html_dump.indexOf( 'http://', image_index+1 ); 		// jump to first src (preview size)
	var image_index = html_dump.indexOf( 'http://', image_index+1 ); 		// jump to second src (full-size, which might also be identical to preview size)
	image_url = html_dump.substring( image_index, html_dump.indexOf( '"', image_index ) ); 		// grab URL, delimited by doublequote
*/
}

function scrape_inkbunny() {
	var image_index = html_dump.indexOf( 'https://inkbunny.net/files/screen/' );		// look for screen-size image URL (used to be ///files) 
	if( image_index !== -1 )		// if that URL is found
	{
		image_url = html_dump.substring( image_index );		// dump everything before URL
		var delimiter_index = image_url.indexOf( '"' );		// find delimiter (that's a double-quote inside single-quotes)
		image_url = image_url.substring( 0, delimiter_index );		// dump everything after delimiter
		image_url = image_url.replace( '/screen/', '/full/' );		// turn screen URL into full URL - we don't care if /screen/ is already full-size, because /full/ will kindly redirect anyway
	}

	// if this page is the first image in a multi-image submission, do not redirect
	if ( html_dump.indexOf('show custom thumbnails') !== -1 && !address_bar_contains('&page=') ) {		// if 'show custom thumbnails' is found in HTML, but a page number is absent from the URL
		image_url = '';		// the page won't redirect if this string is empty
	}
}

function scrape_pixiv() {		// long time coming due to 403-happy servers - changing redirect from window.location.href=url to javascript:window.location.href.=url. made things work. 
	extract_image_url_after( 'href="member_illust.php?mode=big', 'http://' ); 		// grab preview image after link to big page - finding it is the easy part
	image_url = image_url.replace( '_m.', '.' ); 		// convert URL to full-size

	if( image_url == '') { 		// if there's no 'big' link and thus no image was grabbed, it's probably manga
		image_url = window.location.href.replace( 'mode=medium', 'mode=manga' );		// manga pages deserve their own HTML, so just go to that page 
		// Users: please consider Eza's Pixiv Fixiv, which replaces the default manga HTML with full images and none of that scroll-to-load nonsense. 
	}
}

function scrape_booru() {		// this works on a wide variety of booru-style imageboards. 
	extract_image_url_after( '>Resize image</a>', 'http://' );		// for booru's which have automatic resizing and images which require it
	if( image_url == '' ) {		// otherwise, use the image that's being displayed 
		html_dump = html_dump.substring( html_dump.indexOf( 'id="note-container"' ) );		// we ditch everything before this, but the first 'http' isn't the correct image URL
		extract_image_url_after( '<img', 'http' );		// should grab both http: and https: URLs
	} 
}

function scrape_largest_image() {		// simply find the biggest image being displayed. should make adding new sites easy, if they're not picky like pixiv or auto-resizing like gelbooru. 
	var elements = document.getElementsByTagName("img"); 		// grab all image elements
	for( var x = 0; x < elements.length; x++ ) {
		throw( elements[x].width );		// debug
		// immediate problem: this doesn't seem to get all "img" elements. 
		// secondary problem: getting the dimensions of the few images it does find is a pain in the ass. I keep throwing empty strings. wtf? 
	}
}










/*
Test suite of random URLs from the relevant sites: 
http://www.hentai-foundry.com/pictures/user/Bottlesoldier/133840/Akibabuse
http://www.hentai-foundry.com/pictures/user/Bottlesoldier/214533/Lil-Gwendolyn
https://inkbunny.net/submissionview.php?id=483550
https://inkbunny.net/submissionview.php?id=374519
http://rule34.xxx/index.php?page=post&s=view&id=1399731
http://rule34.xxx/index.php?page=post&s=view&id=1415193
http://equi.booru.org/index.php?page=post&s=view&id=56940
http://furry.booru.org/index.php?page=post&s=view&id=340299
http://derpibooru.org/470074?scope=scpe80a78d33e96a29ea172a0d93e6e90b47c6a431ea
http://mspabooru.com/index.php?page=post&s=view&id=131809
http://mspabooru.com/index.php?page=post&s=view&id=131804
http://shiniez.deviantart.com/art/thanx-for-5-m-alan-in-some-heavy-makeup-XD-413414430
http://danbooru.donmai.us/posts/1250724?tags=dennou_coil
http://danbooru.donmai.us/posts/1162284?tags=dennou_coildata:text/html,<img src='http://example.com/image.jpg'>
http://www.furaffinity.net/view/12077223/
http://gamesbynick.tumblr.com/post/67039820534/the-secrets-out-guys-the-secret-is-out
http://honeyclop.tumblr.com/post/67122645946/stallion-foursome-commission-for-ciderbarrel-d
http://shubbabang.tumblr.com/post/20990300285/new-headcanon-karkat-is-ridiculously-good-at
http://www.furaffinity.net/view/12092394/
https://e621.net/post/show?md5=25385d2349ae11f2057874f0479422ad
http://sandralvv.tumblr.com/post/64933897836/how-did-varrick-get-that-film-cuz-i-want-a-copy
*/