您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Add a modal viewer to the main page. With infinity scroll.
// ==UserScript== // @name Viewer on Rule34Paheal // @namespace http://tampermonkey.net/ // @version 1.0 // @description Add a modal viewer to the main page. With infinity scroll. // @author Falaz // @match *://rule34.paheal.net/post/list/* // @icon https://www.google.com/s2/favicons?sz=64&domain=paheal.net // @grant none // @run-at document-end // @license MIT // ==/UserScript== /*jshint esversion: 6 */ class CssModal{ constructor(){ this.css = ` ${document.debug?'img, video {filter: brightness(0.0);}':''} BODY, #header,FOOTER{ background:#222!important } SECTION>H3,SECTION>.blockbody, .comment, .setupblock,#menuh a{ background:#333!important; border: 1px solid #000!important; } #modal-container{ width: 100%; height: 100%; position: fixed; display: block; background: #000000b0; z-index: 1; } .hidden{ display: none!important; } #media-container{ height:100%; justify-content: center; display: flex; align-items: center; } #modal-container #modal{ width: 80%; height: 100%; display: flex; align-content: center; justify-content: center; align-items: center; } #modal-container #imgContainer{ width: auto; height: auto; max-height: 100%; } #modal-container button { background: #40bf40; font-size: 14px; padding: 10px 15px; border: none; border-radius: 7px; font-weight: bold; position: absolute; right: 20%; z-index: 1; } #modal-container button:hover { background: #89e989; } #modal-container button:active{ background: #2c892c; } #modal-container #close { top: 10px; } #modal-container #left{ top: 46px; } #modal-container #right{ top: 79px } #modal-container #loading{ top: 120px; right: 20%; position: fixed; } #modal-container video, #modal-container .fluid_video_wrapper,.media-container{ width: auto; height: auto; max-width: 95%; max-height: 95%; padding: 10px; } `; const cssTag = document.createElement('style'); cssTag.innerHTML = this.css; document.head.prepend(cssTag); } } class Page{ constructor(num,doc,_modal=null){ this.num = num; this.document = doc; this.modal = _modal? _modal.addNewMedias(this.getElements()):new Modal(this.getElements()); } getElements(){ return this.document.querySelectorAll('.shm-image-list div') } addEventListenersToImages(elements = this.getElements()){ for(const node of elements){ node.addEventListener('click',e=>{ e.preventDefault(); console.log('click'); this.modal.render(node.dataset.postId) }); } } } class Modal{ constructor(mediasNode){ this.active = false; /**@type {Media} */ this.medias = []; this.populateMedias(mediasNode); this.container = this.initEmptyContainer(); this.renderedMedia = null; this.loading= this.container.querySelector('#loading'); } initEmptyContainer(){ const div = document.createElement('div'); div.id = "modal-container"; div.classList.add('hidden'); const buttons = `<button id="close" onClick="document.modal.closeModal()">X</button><button id="left" onClick="document.modal.prevMedia()"><</button><button id="right" onClick="document.modal.nextMedia()">></button> <img id="loading" class="hidden" src="https://samherbert.net/svg-loaders/svg-loaders/oval.svg">` div.innerHTML = `<div id="modal"><div>${buttons}</div><div id="media-container"></div></div>` document.body.prepend(div); return div; } createImageContainer(){ this.container.querySelector('#media-container').innerHTML = `<img id="imgContainer"></img>` } createVideoContainer(){ this.container.querySelector('#media-container').innerHTML = `<video id="videoContainer" controls loop autoplay ></video>`; } render(postId){ const [media] = this.medias.filter(e=>e.index==postId) if(media){ this.renderModal(media) } } renderModal(media){ this.active = true; this.container.classList.remove('hidden'); this.renderedMedia = media; if(media.type == 'video'){ this.createVideoContainer(); this.videoContainer = this.container.querySelector('#videoContainer'); this.videoContainer.src = media.src; this.videoContainer.volume = 0; this.videoContainer.mute = document.debug; fluidPlayer(this.videoContainer,{layoutControls:{autoPlay:true, allowDownload:true,loop:true,doubleclickFullscreen:false, mute: document.debug, fillToContainer:true}}) }else{ this.createImageContainer(); this.imgContainer = this.container.querySelector('#imgContainer'); this.loading.classList.remove('hidden'); this.imgContainer.src = media.src; this.imgContainer.onload = ()=>this.loading.classList.add('hidden'); } } closeModal(){ this.active = false; this.container.classList.add('hidden'); } nextMedia(){ const i = this.medias.indexOf(this.renderedMedia) if(i>this.medias.length-3){ document.infinity.fillNextPage() }else{ this.renderModal(this.medias[i+1]) } } prevMedia(){ const i = this.medias.indexOf(this.renderedMedia) if(i>0){ this.renderModal(this.medias[i-1]) }else{ this.renderModal(this.medias[this.medias.length-1]) } } populateMedias(mediasNode){ for(const node of mediasNode){ const media = new Media( node.querySelector('a:last-of-type').href, ['mp4','webm'].includes(node.dataset.ext)?'video':'image', node.dataset.ext, node.querySelector('img').src, node.dataset.postId ) this.medias.push(media); } } addNewMedias(medias){ this.populateMedias(medias); this.addNewMediasToCurrentPage(medias); return this; } addNewMediasToCurrentPage(medias){ for(const node of medias){ document.querySelector('.shm-image-list ').appendChild(node); } } } class Media{ constructor(src, type,ext, thumb,index){ this.src = src; this.type = type; this.ext = ext; this.thumb = thumb; this.index = index; } } class InfinityScroll{ constructor(doc,page,modal){ this.doc = doc; this.page = page; this.modal = modal; this.last = this.getLastNode(this.doc); this.next = this.getNextNode(this.doc); this.triggered = false; } getNextNode(doc){ const [next] = Array.from(doc.querySelector('#paginator .blockbody').querySelectorAll('a')).filter(e=>e.text=='Next') return next; } getLastNode(doc){ const [last] = Array.from(doc.querySelector('#paginator .blockbody').querySelectorAll('a')).filter(e=>e.text=='Last') return last; } async fillNextPage(){ if(!this.triggered){ this.triggered = true; const {page,pageDocument} = await this.getNextPage(); this.page = new Page(page, pageDocument, this.modal); this.page.addEventListenersToImages(document.page.getElements()); this.next = this.getNextNode(this.page.document); } } async getNextPage(){ const nextNode = this.next; const page = nextNode.href.slice(-1); const response = await fetch(nextNode.href); if([200,201,202,204].includes(response.status)){ const body = await response.text(); const dp = new DOMParser(); const pageDocument = dp.parseFromString(body, "text/html"); this.triggered = false; return {page,pageDocument}; } } } document.debug = false; document.cssModal = null; document.page = null; document.modal = null; document.init = ()=>{ try{ console.log('initialized'); const fluidPlayer = document.createElement('script'); fluidPlayer.src = "https://cdn.fluidplayer.com/v3/current/fluidplayer.min.js" document.head.prepend(fluidPlayer); document.page.addEventListenersToImages(); document.infinity = new InfinityScroll(document,document.page, document.modal); document.addEventListener("scroll", (e) => { const inner = window.innerHeight; /* console.log({ scrollY: window.scrollY, inner, scorllHeight: document.documentElement.scrollHeight, sum: window.scrollY + inner, comparative: document.documentElement.scrollHeight - inner }) */ if (window.scrollY + inner >document.documentElement.scrollHeight - inner) { document.infinity.fillNextPage() } }) }catch(e){ console.error(e); } } (function() { try{ const cssModal = new CssModal(); document.cssModal = cssModal; document.page = new Page(1, document); document.modal = document.page.modal; //'use strict'; //document.addEventListener('readystatechange', ()=>{ window.addEventListener('load',()=>{ document.init(); }) }catch(e){ console.error(e); } })();