Eza's Image Glutton

Directly loads images on gallery sites, skipping comments and descriptions

Od 14.10.2014.. Pogledajte najnovija verzija.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==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/*
// @exclude    http://www.deviantart.com/users/outgoing?*
// @version     1.21.5
// ==/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? 
// image glutton needs a better description. 'redirects to the image from gallery pages?' 

// 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
	////////// 		Simple extract_image_url_after sites
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:', '//' ); } 
	////////// 		Slightly complicated extract_image_url_after sites
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
	////////// 		Simple custom sites
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; 
}
	////////// 		Sites complex enough to shove into a function down below 
else if ( address_bar_contains('deviantart.com') ) { scrape_deviantart(); wait_for_dnr = true; }
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. The CDN is different, so DA might complain. 
	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( '<form id="changethumboriginal_form"' ) !== -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
*/