您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Refining yande.re
当前为
// ==UserScript== // @name yande.re refine // @namespace https://greasyfork.org/scripts/397612-yande-re-refine // @description Refining yande.re // @include *://behoimi.org/* // @include *://www.behoimi.org/* // @include *://*.donmai.us/* // @include *://konachan.tld/* // @include *://yande.re/* // @include *://chan.sankakucomplex.com/* // @version 2020.03.10 // @grant none // ==/UserScript== //If true, each added page retains its paginator. If false, elements are smoothly joined together. var pageBreak = false //Minimum amount of window left to scroll, maintained by loading more pages. var scrollBuffer = 600 //Time (in ms) the script will wait for a response from the next page before attempting to fetch the page again. If the script gets trapped in a loop trying to load the next page, increase this value. var timeToFailure = 15000 var previewLocked = false //============================================================================ //=========================Script initialization============================== //============================================================================ var nextPage, mainTable, mainParent, pending, timeout, iframe if (typeof customF != 'undefined') customF() injectGlobalStyle() initialize() function initialize() { //Stop if inside an iframe if (window != window.top || scrollBuffer == 0) return //Stop if no "table" mainTable = getMainTable(document) if (!mainTable) return injectStyle() processItems() //Stop if no paginator var paginator = getPaginator(document) if (!paginator) return //Stop if no more pages nextPage = getNextPage(paginator) if (!nextPage) return //Hide the blacklist sidebar, since this script breaks the tag totals and post unhiding. var sidebar = document.getElementById('blacklisted-sidebar') if (sidebar) sidebar.style.display = 'none' //Other important variables: scrollBuffer += window.innerHeight mainParent = mainTable.parentNode pending = false iframe = document.createElement('iframe') iframe.width = iframe.height = 0 iframe.style.visibility = 'hidden' document.body.appendChild(iframe) //Slight delay so that Danbooru's initialize_edit_links() has time to hide all the edit boxes on the Comment index iframe.addEventListener( 'load', function(e) { setTimeout(appendNewContent, 100) }, false ) //Stop if empty page if ( /<p>(Nothing to display.|Nobody here but us chickens!)<.p>/.test( mainTable.innerHTML ) ) return //Add copy of paginator to the top mainParent.insertBefore(paginator.cloneNode(true), mainParent.firstChild) if (!pageBreak) paginator.style.display = 'none' //Hide bottom paginator else { //Reposition bottom paginator and add horizontal break mainTable.parentNode.insertBefore( document.createElement('hr'), mainTable.nextSibling ) mainTable.parentNode.insertBefore(paginator, mainTable.nextSibling) } //Listen for scroll events window.addEventListener('scroll', testScrollPosition, false) testScrollPosition() } //============================================================================ //============================Script functions================================ //============================================================================ //Some pages match multiple "tables", so order is important. function getMainTable(source) { //Special case: Sankaku post index with Auto Paging enabled if ( /sankaku/.test(location.host) && /auto_page=1/.test(document.cookie) && /^(post(\/|\/index\/?)?|\/)$/.test(location.pathname) ) return null var xpath = [ ".//div[@id='c-favorites']//div[@id='posts']", // Danbooru (/favorites) ".//div[@id='posts']/div", // Danbooru; don't want to fall through to the wrong xpath if no posts ("<article>") on first page. ".//div[@id='c-pools']//section/article/..", // Danbooru (/pools/####) ".//div[@id='a-index']/table[not(contains(@class,'search'))]", // Danbooru (/forum_topics, ...), take care that this doesn't catch comments containing tables ".//div[@id='a-index']", // Danbooru (/comments, ...) ".//table[contains(@class,'highlight')]", // large number of pages ".//div[@id='content']/div/div/div/div/span[@class='author']/../../../..", // Sankaku: note search ".//div[contains(@id,'comment-list')]/div/..", // comment index ".//*[not(contains(@id,'popular'))]/span[contains(@class,'thumb')]/a/../..", // post/index, pool/show, note/index ".//li/div/a[contains(@class,'thumb')]/../../..", // post/index, note/index ".//div[@id='content']//table/tbody/tr[@class='even']/../..", // user/index, wiki/history ".//div[@id='content']/div/table", // 3dbooru user records ".//div[@id='forum']" // forum/show ] for (var i = 0; i < xpath.length; i++) { getMainTable = (function(query) { return function(source) { var mTable = new XPathEvaluator().evaluate( query, source, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ).singleNodeValue if (!mTable || !pageBreak) return mTable //Special case: Danbooru's /favorites lacks the extra DIV that /posts has, which causes issues with the paginator/page break. var xDiv = document.createElement('div') xDiv.style.overflow = 'hidden' mTable.parentNode.insertBefore(xDiv, mTable) xDiv.appendChild(mTable) return xDiv } })(xpath[i]) var result = getMainTable(source) if (result) { //alert("UPW main table query: "+xpath[i]+"\n\n"+location.pathname); return result } } return null } function getPaginator(source) { var pager = new XPathEvaluator().evaluate( "descendant-or-self::div[@id='paginator' or @class='paginator' or @id='paginater']", source, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ).singleNodeValue // Need clear:none to prevent the 2nd page from being pushed to below the sidebar on the Post index... but we don't want this when viewing a specific pool, // because then the paginator is shoved to the right of the last images on a page. Other sites have issues with clear:none as well, like //yande.re/post. if ( pager && location.host.indexOf('donmai.') >= 0 && document.getElementById('sidebar') ) pager.style.clear = 'none' return pager } function getNextPage(source) { let page = getPaginator(source) if (page) page = new XPathEvaluator().evaluate( ".//a[@alt='next' or @rel='next' or contains(text(),'>') or contains(text(),'Next')]", page, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null ).singleNodeValue return page && page.href } function testScrollPosition() { if (!nextPage) testScrollPosition = function() {} //Take the max of the two heights for browser compatibility else if ( !pending && window.pageYOffset + scrollBuffer > Math.max( document.documentElement.scrollHeight, document.documentElement.offsetHeight ) ) { pending = true timeout = setTimeout(function() { pending = false testScrollPosition() }, timeToFailure) iframe.contentDocument.location.replace(nextPage) } } function appendNewContent() { //Make sure page is correct. Using 'indexOf' instead of '!=' because links like "https://danbooru.donmai.us/pools?page=2&search%5Border%5D=" become "https://danbooru.donmai.us/pools?page=2" in the iframe href. clearTimeout(timeout) if (nextPage.indexOf(iframe.contentDocument.location.href) < 0) { setTimeout(function() { pending = false }, 1000) return } //Copy content from retrived page to current page, but leave off certain headers, labels, etc... var sourcePaginator = document.adoptNode(getPaginator(iframe.contentDocument)) var nextElem, deleteMe, source = document.adoptNode(getMainTable(iframe.contentDocument)) if ( /<p>(Nothing to display.|Nobody here but us chickens!)<.p>/.test( source.innerHTML ) ) nextPage = null else { nextPage = getNextPage(sourcePaginator) if (pageBreak) mainParent.appendChild(source) else { //Hide elements separating one table from the next (h1 is used for user names on comment index) var rems = source.querySelectorAll('h2, h3, h4, thead, tfood') for (var i = 0; i < rems.length; i++) rems[i].style.display = 'none' //Move contents of next table into current one var fragment = document.createDocumentFragment() while ((nextElem = source.firstChild)) fragment.appendChild(nextElem) mainTable.appendChild(fragment) } } //Add the paginator at the bottom if needed. if (!nextPage || pageBreak) mainParent.appendChild(sourcePaginator) if (pageBreak && nextPage) mainParent.appendChild(document.createElement('hr')) //Clear the pending request marker and check position again processItems() pending = false testScrollPosition() } function injectGlobalStyle() { const s = document.createElement('style') s.innerHTML = ` #title { display: none !important; } #header { margin: 0 !important; text-align: center; } #header ul { float: none !important; display: inline-block;} ` document.body.appendChild(s) } function injectStyle() { const s = document.createElement('style') s.innerHTML = ` a.directlink { display: none !important; } .sidebar { position: absolute; top: 10px; right: 10px; } .sidebar #tag-sidebar, .sidebar h5 { display: none !important; } div.content { width: 100vw; } ul#post-list-posts { display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; } ul#post-list-posts li { width: auto !important; margin: auto; padding: 5px; transition: .3s ease-out; overflow: visible; } ul#post-list-posts li img, ul#post-list-posts li .inner { width: auto !important; height: auto !important; } ul#post-list-posts li img { border-radius: 5px; } ul#post-list-posts li a { transition: .3s ease-out; } ul#post-list-posts li a.liked img { border: 2px solid pink; } ul#post-list-posts li:hover { transform: scale(1.3); z-index: 1; } ul#post-list-posts li:hover a { opacity: 1; box-shadow: 6px 6px 20px 0px rgba(50, 50, 50, 0.75); } .hidden { display: none !important; } .preivew-dialog { position: fixed; top: 0; left: 0; height: 100vh; width: 100vw; background: rgba(0,0,0,0.7); z-index: 100; } .preivew-dialog iframe { position: absolute; height: 90vh; width: 80vw; top: 50%; left: 50%; transform: translate(-50%, -50%); background: grey; border: none; border-radius: 5px; overflow: hidden; } ` document.body.appendChild(s) } let previewIframe, previewIframeDialog function initPreviewIframe() { previewIframeDialog = document.createElement('div') previewIframeDialog.addClassName('preivew-dialog hidden') previewIframe = document.createElement('iframe') previewIframeDialog.appendChild(previewIframe) previewIframeDialog.onclick = e => { if (e.target === previewIframeDialog) previewIframeDialog.classList.toggle('hidden', true) } document.body.appendChild(previewIframeDialog) } function processItems() { document .querySelectorAll('ul#post-list-posts li a.thumb:not([_init])') .forEach(a => { a.setAttribute('_init', true) const url = a.href a.href = 'javascript:;' if (!url) return const id = url.split('/').slice(-1)[0] let lastClicked = -Infinity let timer = null let liked = false a.onclick = e => { e.preventDefault() if (Date.now() - lastClicked < 500) { if (liked) vote(id, 2) else vote(id, 3) liked = !liked a.classList.toggle('liked', liked) clearTimeout(timer) } else { lastClicked = +Date.now() timer = setTimeout(() => openUrl(url), 600) } return false } }) } function openUrl(url) { console.log(url) if (!previewIframe) initPreviewIframe() previewIframe.onload = () => { if (previewIframe.contentWindow.location.href !== url) { location.href = previewIframe.contentWindow.location.href previewIframeDialog.classList.toggle('hidden', true) previewIframe.onload = null } } previewIframe.src = url previewIframeDialog.classList.toggle('hidden', false) } async function vote(id, score) { let body = new FormData() body.append('id', id) body.append('score', score) const rawResponse = await fetch('https://yande.re/post/vote.json', { method: 'POST', headers: { 'X-CSRF-Token': document.querySelector('meta[name=csrf-token]').attributes .content.value }, body }) const content = await rawResponse.json() console.log(content) }