|
|
|
// ==UserScript== |
|
// @name ExLinks |
|
// @namespace hurfdurf |
|
// @version 1.5.5 |
|
// @description Makes exhentai/e-hentai links more useful. |
|
// @include http://boards.4chan.org/* |
|
// @include https://boards.4chan.org/* |
|
// @updateURL http://userscripts.org/scripts/source/135734.user.js |
|
// ==/UserScript== |
|
|
|
// This script is still work-in-progress. Use at your own risk. |
|
// Thanks to Anonymous for doing the .hathdl data parsing. |
|
|
|
// ------------------------------ DON'T MESS WITH THESE ------------------------------ |
|
|
|
var Fetch = { |
|
Default : {value: 0, name: "Default"}, |
|
geHentai: {value: 1, name: "g.e-hentai.org"}, |
|
exHentai: {value: 2, name: "exhentai.org"} |
|
}; |
|
|
|
var THUMB_DELAY = 3000; // Warning: Setting this too low can get you banned. |
|
var THUMB_CAN_FETCH = true; |
|
|
|
var GALLERY_URL = 'http://[@DOMAIN]/g/[@GID]/[@TOKEN]/'; |
|
var STATS_URL = 'http://[@DOMAIN]/stats.php?gid=[@GID]&t=[@TOKEN]'; |
|
var TORRENT_URL = 'http://[@DOMAIN]/gallerytorrents.php?gid=[@GID]&t=[@TOKEN]'; |
|
var HATH_URL = 'http://[@DOMAIN]/hathdler.php?gid=[@GID]&t=[@TOKEN]'; |
|
var ARCHIVER_URL = 'http://[@DOMAIN]/archiver.php?gid=[@GID]&or=[@TOKEN]'; |
|
|
|
var find_regex = /https?:\/\/g?\.?e[\-x]hentai\.org\/[0-9a-z\.\?\&\-\/]+/g; |
|
var url_regex = /https?:\/\/(g?\.?e[\-x]hentai\.org)\/g\/([0-9]+)\/([0-9a-z]+)\/?/; |
|
var arc_regex = /https?:\/\/(g?\.?e[\-x]hentai\.org)\/archiver\.php\?gid\=([0-9]+)\&or\=([0-9\-a-z]+)/; |
|
var title_regex = /Title:\s+(.*)/; |
|
var tags_regex = /Tags:\s+(.*)/; |
|
var files_regex = /FILES\s+(.*)/; |
|
|
|
// ------------------------------------- OPTIONS ------------------------------------- |
|
|
|
preloadLinks = true; // Process all links automatically |
|
fetchThumbnail = true; // Fetch gallery thumbnails |
|
intelligentFetching = false; // Enable intelligent fetching |
|
intelliFetchColor = '#BC0505'; // Highlight color for above |
|
|
|
// Intelligent fetching |
|
// Enabling this feature will make all gallery links point to g.e-hentai.org by default. |
|
// However, any galleries that are pining for the fjords will link to exhentai.org. |
|
// These gallery links will be highlighted with the color defined above. |
|
// This feature overrides options fetchGallery and fetchLink. |
|
// A gallery is pining for the fjords if it includes any of the following tags: |
|
// bestiality, incest, lolicon, shotacon, toddlercon |
|
// THIS FEATURE HAS NOT BEEN IMPLEMENTED YET AND THUS DOES ABSOLUTELY NOTHING |
|
|
|
showDetails = false; // Show details by default if true |
|
showLinks = true; // Show gallery links |
|
showTags = true; // Show gallery tags |
|
archiverPopUp = true; // Use a pop-up for archiver |
|
|
|
// Fetch.Default means the original link domain will be used. |
|
|
|
fetchName = Fetch.geHentai; // Fetch domain for gallery title. |
|
fetchGallery = Fetch.Default; // Fetch domain for gallery thumbnail and archiver. |
|
|
|
fetchLink = Fetch.Default; // Domain for gallery link. |
|
fetchArchiver = Fetch.Default; // Domain for archiver. |
|
fetchHath = Fetch.Default; // Domain for H@H Download. |
|
fetchTorrent = Fetch.Default; // Domain for torrent download. |
|
|
|
// ----------------------------------------------------------------------------------- |
|
|
|
function galleryId(url) { |
|
var check = url.match(url_regex); |
|
return check[2] + '_' + check[3]; |
|
} |
|
|
|
function getUrl(url,urlFormat,fetchFormat,archiver) |
|
{ |
|
if(archiver == false) |
|
{ |
|
var check = url.match(url_regex); |
|
} else { |
|
var check = url.match(arc_regex); |
|
} |
|
var nameUrl = urlFormat; |
|
if(fetchFormat == Fetch.Default) |
|
{ |
|
nameUrl = nameUrl.replace(/\[\@DOMAIN\]/,check[1]); |
|
} else { |
|
nameUrl = nameUrl.replace(/\[\@DOMAIN\]/,fetchFormat.name); |
|
} |
|
nameUrl = nameUrl.replace(/\[\@GID\]/,check[2]); |
|
nameUrl = nameUrl.replace(/\[\@TOKEN\]/,check[3]); |
|
|
|
return nameUrl; |
|
} |
|
|
|
function insertAfter(node, referenceNode) { |
|
referenceNode.parentNode.insertBefore(node, referenceNode.nextSibling); |
|
} |
|
|
|
function eliminateDuplicates(arr) { |
|
var i, |
|
len=arr.length, |
|
out=[], |
|
obj={}; |
|
|
|
for (i=0;i<len;i++) { |
|
obj[arr[i]]=0; |
|
} |
|
for (i in obj) { |
|
out.push(i); |
|
} |
|
return out; |
|
} |
|
|
|
function fancyLinks(x) |
|
{ |
|
setTimeout(function() |
|
{ |
|
|
|
var blocks = x.getElementsByTagName("blockquote"); |
|
var blockcopy = document.createElement('blockquote'); |
|
|
|
for (var i=0;i<blocks.length;i++) |
|
{ |
|
var block = blocks[i]; |
|
var blockid = block.id; |
|
blockcopy.innerHTML = block.innerHTML; |
|
var blocklinks = blockcopy.getElementsByTagName('a'); |
|
|
|
for(var lp = 0; lp < blocklinks.length; lp++) |
|
{ |
|
var testlink = blocklinks[lp]; |
|
linkInner = testlink.innerHTML; |
|
linkHref = testlink.href; |
|
if(linkInner.match(find_regex)) |
|
{ |
|
linkInner = linkInner.replace(/http:/g, 'hEXp:'); |
|
testlink.innerHTML = linkInner; |
|
} |
|
if(linkHref.match(find_regex)) |
|
{ |
|
linkHref = linkHref.replace(/http:/g, 'hEXp:'); |
|
testlink.href = linkHref; |
|
} |
|
} |
|
|
|
var text = blockcopy.innerHTML; |
|
|
|
var matches = text.match(find_regex); |
|
|
|
if(matches!=null) |
|
{ |
|
matches = eliminateDuplicates(matches); |
|
for (var j=0;j<matches.length;j++) |
|
{ |
|
var match = matches[j]; |
|
var rematch = match.replace(/\//g,"\\/"); |
|
rematch = rematch.replace(/\./g,"\\."); |
|
rematch = rematch.replace(/\:/g,"\\:"); |
|
rematch = rematch.replace(/\-/g,"\\-"); |
|
rematch = new RegExp(rematch, "g"); |
|
text = text.replace(rematch, '<a href="'+match+'" target="_blank">'+match+'</a>'); |
|
} |
|
|
|
text = text.replace(/hEXp:/g, 'http:'); |
|
block.innerHTML = text; |
|
|
|
} |
|
|
|
|
|
var elinks = block.getElementsByTagName('a'); |
|
|
|
var counter = 0; |
|
|
|
for (var m=0;m<elinks.length;m++) |
|
{ |
|
var exlink = elinks[m]; |
|
|
|
var checkClassName = exlink.className; |
|
|
|
if(exlink.className == "exclick") |
|
{ |
|
exlink.addEventListener('click',checkExName,false); |
|
exlink.setAttribute('target', '_blank'); |
|
} |
|
if(exlink.className == "dclick") |
|
{ |
|
exlink.addEventListener('click',displayData,false); |
|
} |
|
if(checkClassName.match('exarchiver')) |
|
{ |
|
if(exlink.href != null) |
|
exlink.setAttribute('target','_blank'); |
|
} |
|
|
|
if(exlink.className == "exlink") |
|
{ |
|
exlink.setAttribute('target', '_blank'); |
|
|
|
if(fetchThumbnail) |
|
{ |
|
var gId = galleryId(exlink.href); |
|
var checkThumbnail = document.getElementById(gId+'_thumb') |
|
if(checkThumbnail != null) |
|
{ |
|
exlink.addEventListener('mouseover',function(g) { checkThumbnail.style.display = null; },false); |
|
exlink.addEventListener('mousemove',function(g) { |
|
var target = checkThumbnail; |
|
target.style.left = (g.clientX+20) + 'px'; |
|
if(target.offsetHeight + g.clientY > window.innerHeight) |
|
{ |
|
target.style.top = (g.clientY-target.offsetHeight-5) + 'px'; |
|
} else { |
|
target.style.top = (g.clientY+10) + 'px'; |
|
} |
|
},false); |
|
exlink.addEventListener('mouseout',function() { checkThumbnail.style.display = 'none'; },false); |
|
} else { |
|
exlink.addEventListener('mouseover',checkThumb,false); |
|
} |
|
} |
|
} |
|
if(exlink.className != "exclick" && exlink.className != "exlink" && exlink.className != "dclick" && exlink.className != "exdetail") |
|
{ |
|
var exurl = exlink.href; |
|
var ymatch = exurl.match(url_regex); |
|
var prefix; |
|
|
|
if (ymatch && ymatch.length > 3) |
|
{ |
|
|
|
if(ymatch[1] == "exhentai.org") |
|
{ |
|
prefix = 'Ex'; |
|
} |
|
if(ymatch[1] == "g.e-hentai.org") |
|
{ |
|
prefix = 'EH'; |
|
} |
|
|
|
var exid = ymatch[2] + "_" + ymatch[3] + "_" + blockid + "_" + counter; |
|
|
|
var nameUrl = getUrl(exurl,HATH_URL,fetchName,false); |
|
var galleryUrl = getUrl(exurl,GALLERY_URL,fetchLink,false); |
|
|
|
exlink.href = galleryUrl; |
|
exlink.className = 'exlink'; |
|
exlink.id = exid+'_ex'; |
|
exlink.setAttribute('target', '_blank'); |
|
|
|
var exbutton = document.createElement('a'); |
|
exbutton.className = 'exclick'; |
|
exbutton.href = nameUrl; |
|
exbutton.title = prefix; |
|
exbutton.id = exid; |
|
exbutton.innerHTML = '['+prefix+']'; |
|
exbutton.setAttribute('target', '_blank'); |
|
|
|
if(!preloadLinks) |
|
{ |
|
exbutton.addEventListener('click',checkExName,false); |
|
} else { |
|
checkExName(exbutton); |
|
} |
|
|
|
exlink.parentNode.insertBefore(exbutton,exlink); |
|
|
|
} |
|
counter++; |
|
} |
|
} |
|
} |
|
},10); |
|
} |
|
|
|
function checkExName(e) |
|
{ |
|
if(!preloadLinks) |
|
{ |
|
if (e.which !== 1) return; |
|
e.preventDefault(); |
|
var a = e.target; |
|
} else { |
|
var a = e; |
|
} |
|
a.innerHTML = '[...]'; |
|
GM_xmlhttpRequest( |
|
{ |
|
method:"GET", |
|
url: a.href, |
|
onload: function(x) |
|
{ |
|
replaceTitle(a, x.responseText); |
|
} |
|
}); |
|
} |
|
|
|
function replaceTitle(anchor,data) |
|
{ |
|
anchor.removeEventListener('click',checkExName,false); |
|
var ablock = document.getElementById(anchor.id+'_ex'); |
|
anchor.innerHTML = '['+anchor.title+']'; |
|
anchor.href = null; |
|
anchor.setAttribute('target', '_blank'); |
|
ablock.setAttribute('target', '_blank'); |
|
var title = title_regex.exec(data)[1]; |
|
ablock.innerHTML = title; |
|
var dblock = document.createElement('div'); |
|
dblock.id = anchor.id+'_exdatabox'; |
|
dblock.className='inline'; |
|
if(!showDetails) |
|
dblock.style.display = 'none'; |
|
dblock.style.padding = '3px'; |
|
var tags = tags_regex.exec(data)[1]; |
|
var taglinks = tags.split(", "); |
|
var tagname = ''; |
|
var files = files_regex.exec(data)[1]; |
|
|
|
var ehbutton = document.createElement('a'); |
|
ehbutton.className = 'exdetail'; |
|
ehbutton.href = getUrl(ablock.href,GALLERY_URL,Fetch.geHentai,false); |
|
ehbutton.innerHTML = 'e-hentai'; |
|
ehbutton.setAttribute('target', '_blank'); |
|
|
|
var exbutton = document.createElement('a'); |
|
exbutton.className = 'exdetail'; |
|
exbutton.href = getUrl(ablock.href,GALLERY_URL,Fetch.exHentai,false); |
|
exbutton.innerHTML = 'exhentai'; |
|
exbutton.setAttribute('target', '_blank'); |
|
|
|
var btbutton = document.createElement('a'); |
|
btbutton.className = 'exdetail'; |
|
btbutton.href = getUrl(ablock.href,TORRENT_URL,fetchTorrent,false); |
|
btbutton.innerHTML = 'torrent'; |
|
btbutton.setAttribute('target', '_blank'); |
|
|
|
var hhbutton = document.createElement('a'); |
|
hhbutton.className = 'exdetail'; |
|
hhbutton.href = getUrl(ablock.href,HATH_URL,fetchHath,false); |
|
hhbutton.innerHTML = 'hentai@home'; |
|
hhbutton.setAttribute('target', '_blank'); |
|
|
|
if(fetchThumbnail) |
|
{ |
|
var arcbutton = document.createElement('a'); |
|
arcbutton.innerHTML = 'archiver'; |
|
arcbutton.className = galleryId(ablock.href)+'_archiver exdetail exarchiver'; |
|
} |
|
|
|
if(showLinks) |
|
{ |
|
dblock.innerHTML += files+' files | View gallery on: '; |
|
dblock.appendChild(ehbutton); |
|
dblock.innerHTML +=' '; |
|
dblock.appendChild(exbutton); |
|
dblock.innerHTML +=' | Download via: '; |
|
dblock.appendChild(btbutton); |
|
dblock.innerHTML +=' '; |
|
dblock.appendChild(hhbutton); |
|
if(fetchThumbnail) |
|
{ |
|
dblock.innerHTML +=' '; |
|
dblock.appendChild(arcbutton); |
|
} |
|
dblock.innerHTML +='<br />'; |
|
} |
|
if(showTags) |
|
{ |
|
dblock.innerHTML += "Tags: " |
|
for(i = 0; i<taglinks.length; i++){ |
|
var tag = document.createElement("a"); |
|
if(fetchLink == Fetch.Default) |
|
{ |
|
if(anchor.title == "Ex") tag.href = 'http://exhentai.org/tag/'+taglinks[i]; |
|
if(anchor.title == "EH") tag.href = 'http://g.e-hentai.org/tag/'+taglinks[i]; |
|
} else { |
|
tag.href = 'http://'+fetchLink.name+'/tag/'+taglinks[i]; |
|
} |
|
tag.className = 'exdetail'; |
|
tag.innerHTML = taglinks[i]; |
|
dblock.appendChild(tag); |
|
} |
|
} |
|
anchor.className = 'dclick'; |
|
// anchor.id = anchor.id+'_exdata'; |
|
anchor.addEventListener('click',displayData,false); |
|
if(fetchThumbnail) |
|
{ |
|
ablock.addEventListener('mouseover',checkThumb,false); |
|
} |
|
insertAfter(dblock, ablock); |
|
} |
|
|
|
function displayData(e){ |
|
if (e.which !== 1) return; |
|
e.preventDefault(); |
|
var a = e.target; |
|
var d = document.getElementById(a.id+'_exdatabox'); |
|
d.style.display = (d.style.display != 'none' ? 'none' : '' ); |
|
} |
|
|
|
function checkThumb(e) |
|
{ |
|
var a = e.target; |
|
var gId = galleryId(a.href); |
|
if(!document.getElementById(gId+'_thumb')) |
|
{ |
|
var dthumb = document.createElement('div'); |
|
dthumb.innerHTML = 'Loading...'; |
|
dthumb.style.padding = '2px'; |
|
dthumb.id = gId + '_thumb'; |
|
dthumb.className = 'inline exthumb'; |
|
dthumb.style.left = (e.clientX+20) + 'px'; |
|
if(e.clientY + dthumb.offsetHeight > window.innerHeight) |
|
{ |
|
dthumb.style.top = (e.clientY-dthumb.offsetHeight-5) + 'px'; |
|
} else { |
|
dthumb.style.top = (e.clientY+10) + 'px'; |
|
} |
|
document.body.appendChild(dthumb); |
|
//insertAfter(dthumb, a); |
|
} |
|
|
|
var thumbCheck = document.getElementById(gId+'_thumb'); |
|
if(thumbCheck != null) |
|
{ |
|
a.addEventListener('mouseover',function(g) { thumbCheck.style.display = null; },false); |
|
a.addEventListener('mousemove',function(g) { |
|
var target = thumbCheck; |
|
target.style.left = (g.clientX+20) + 'px'; |
|
if(g.clientY + target.offsetHeight > window.innerHeight) |
|
{ |
|
target.style.top = (g.clientY-target.offsetHeight-5) + 'px'; |
|
} else { |
|
target.style.top = (g.clientY+10) + 'px'; |
|
} |
|
},false); |
|
a.addEventListener('mouseout',function() { thumbCheck.style.display = 'none'; },false); |
|
} |
|
|
|
if(!thumbInterval) |
|
{ |
|
thumbUpdate(a); |
|
var thumbInterval = setInterval(function(){thumbUpdate(a);},500); |
|
var thumbTimeout = setTimeout(function(){removeTimer(thumbInterval);}, THUMB_DELAY); |
|
} else { |
|
clearInterval(thumbInterval); |
|
clearTimeout(thumbTimeout); |
|
thumbUpdate(a); |
|
var thumbInterval = setInterval(function(){thumbUpdate(a);},500); |
|
var thumbTimeout = setTimeout(function(){removeTimer(thumbInterval);}, THUMB_DELAY); |
|
} |
|
} |
|
|
|
function thumbTimer() |
|
{ |
|
THUMB_CAN_FETCH = true; |
|
} |
|
|
|
function removeTimer(timer) |
|
{ |
|
clearInterval(timer); |
|
} |
|
|
|
function thumbUpdate(anchor) |
|
{ |
|
if(THUMB_CAN_FETCH) |
|
{ |
|
THUMB_CAN_FETCH = false; |
|
anchor.removeEventListener('mouseover',checkThumb,false); |
|
var fetchTimeout = setTimeout(thumbTimer, THUMB_DELAY); |
|
GM_xmlhttpRequest( |
|
{ |
|
method:"GET", |
|
url: anchor.href, |
|
onload: function(y) |
|
{ |
|
createThumb(anchor, y.responseText); |
|
} |
|
}); |
|
} |
|
} |
|
|
|
function createThumb(anchor,data) |
|
{ |
|
var gId = galleryId(anchor.href); |
|
var temp = document.createElement('div'); |
|
temp.innerHTML = data; |
|
var archiveUrl = temp.querySelectorAll('a'); |
|
var archiveButtons = document.getElementsByClassName(gId+'_archiver exdetail exarchiver'); |
|
var thumb = temp.querySelectorAll('div#gd1 img')[0]; |
|
var dthumbframe = document.getElementById(gId+'_thumb'); |
|
if(thumb) |
|
{ |
|
dthumbframe.innerHTML = '<img src="'+thumb.src+'" />'; |
|
setTimeout(function(){checkPosition(dthumbframe);},50); |
|
} else { |
|
dthumbframe.innerHTML = 'Error: Loading failure'; |
|
} |
|
for (var q = 0; q < archiveUrl.length; q++) |
|
{ |
|
if(archiveUrl[q].innerHTML == 'Archive Download') |
|
{ |
|
var archiver = archiveUrl[q].getAttribute('onclick'); |
|
var archiveKey = archiver.match(arc_regex)[0]; |
|
var archiveLink = getUrl(archiveKey,ARCHIVER_URL,fetchArchiver,true); |
|
var archiveFinal = 'return popUp(\''+archiveLink+'\',350,320)'; |
|
for(var w = 0; w < archiveButtons.length; w++) |
|
{ |
|
|
|
if(!archiverPopUp) |
|
{ |
|
archiveButtons[w].href = archiveLink; |
|
archiveButtons[w].setAttribute('target','_blank'); |
|
} else { |
|
archiveButtons[w].setAttribute('onclick',archiveFinal); |
|
} |
|
} |
|
break; |
|
} |
|
} |
|
} |
|
|
|
function checkPosition(thumbnail) |
|
{ |
|
if(thumbnail.offsetTop + thumbnail.offsetHeight > window.innerHeight) |
|
{ |
|
thumbnail.style.top = (thumbnail.offsetTop-thumbnail.offsetHeight-15) + 'px'; |
|
} |
|
} |
|
|
|
var style = document.createElement('style'); |
|
style.innerHTML = '.exlink { text-decoration: none !important; margin-left: 3px !important; } \ |
|
.exclick, .dclick { text-decoration: none !important; } \ |
|
.exthumb { position: fixed; padding: 0px; margin: 0px; z-index: 2; border-width: 4px; background: inherit; }\ |
|
.exdetail { margin: 0 2px; text-decoration: none !important; }\ |
|
.exhighlight { color: '+intelliFetchColor+' !important; }'; |
|
if(archiverPopUp) |
|
{ |
|
var arcWindow = document.createElement('script'); |
|
arcWindow.type = 'text/javascript'; |
|
arcWindow.innerHTML = 'function popUp(URL,w,h) { \ |
|
window.open(URL,"_pu"+(Math.random()+"").replace(/0\./,""),"toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width="+w+",height="+h+",left="+((screen.width-w)/2)+",top="+((screen.height-h)/2));\ |
|
return false; \ |
|
}'; |
|
document.head.appendChild(arcWindow); |
|
} |
|
document.head.appendChild(style); |
|
|
|
fancyLinks(document); |
|
document.addEventListener('DOMNodeInserted',function(e) { if (e.target.nodeName == 'DIV') fancyLinks(e.target); },false); |