Create a modal gallery for rule34. Works in post and pools
Ekde
// ==UserScript==
// @name Modal Image in rule
// @namespace http://tampermonkey.net/
// @version 4.1
// @description Create a modal gallery for rule34. Works in post and pools
// @author falaz
// @match https://rule34.xxx/index.php?page=po*
// @icon https://www.google.com/s2/favicons?domain=rule34.xxx
// @grant none
// @license MIT
// ==/UserScript==
// @ts-check
class Modal{
constructor(document, dp){
this.pointer = 0;
this.dp = dp;
this.medias = this.populateMedias(document);
this.createModalNode(document);
this.nextSended = false;
}
createModalNode(document){
const div = document.createElement('div');
const css = document.createElement('style');
div.innerHTML = '<div id="modal-container" style="display:none">\
<div id="modal">\
</div></div>';
css.innerHTML = '#modal-container{background: #000000a8;width: 100%;height: 100%;position: fixed;z-index: 10;}\
#modal{height: 90%;width: 80%;background: transparent;padding: 0% 5%;margin: 2% 5% 2% 0;position: fixed}\
#modal img{width: auto%;border: none;vertical-align: middle;height: auto;}\
#modal video{width: 100%;heigth:100%}';
document.body.prepend(div);
document.head.prepend(css);
this.modalContainer = document.querySelector('#modal-container');
this.modal = document.querySelector('#modal');
let paginator = document.querySelector('#paginator [alt="next"]');
this.nextPage = paginator? paginator.href: null;
}
/**
* @param {Media} media
*/
render(media){
if(!this.modalContainer){
this.createModalNode(document);
}
if(media.type== 'video'){
this.modal.innerHTML = `<video src="${media.src}" autoplay controls loop></video>`
}else{
this.modal.innerHTML = `<img src="${media.src}"/>`
}
this.modalContainer.style.display = 'block';
}
close(){
if(!this.modalContainer){
this.createModalNode(document);
}
try{
this.modal.querySelector('video').pause()
}catch(e){
}
this.modalContainer.style.display = 'none'
}
nextMedia(){
if(this.pointer < this.medias.length -1){
this.pointer ++;
this.render(this.medias[this.pointer]);
}else{
console.error('Reach the end of the medias');
}
if(this.pointer < this.medias.length -5 && this.nextSended){
this.nextSended= true;
this.getNextPage();
}
}
prevMedia(){
if(this.pointer > 0){
this.pointer --;
this.render(this.medias[this.pointer]);
}else{
console.error('Reach the end of the medias');
}
}
async getNextPage(){
if(!this.nextPage){
this.nextPage = document.querySelector('#paginator [alt="next"]').href;
}
if(this.nextPage){
const response = await fetch(this.nextPage);
const body = await response.text();
const dp = new DOMParser();
const pageDocument = dp.parseFromString(body,'text/html');
const medias = this.populateMedias(pageDocument);
this.addMedias(medias);
this.nextSended = false;
}
}
addMedias(medias){
const mediasTemp = [...this.medias, medias];
this.medias = mediasTemp;
}
populateMedias(document){
const thumbsNode = document.querySelectorAll('#content .thumb');
const medias = []
for(const node of thumbsNode){
const title = node.querySelector('img').title;
const media = new Media(
node.querySelector('a').href,
/animated|video/.test(title)? 'video': 'image',
node.querySelector('img').src,
this.dp
)
medias.push(media);
}
return medias;
}
}
class Media{
/**
* @param {string} _page This is the page of the media. Not the real src.
* @param {string} _type
* @param {string} _thumb
*/
constructor(_page, _type, _thumb, dp){
this.page = _page
this.type = _type;
this.thumb = _thumb;
this.dp = dp;
this.getSrc().then(src=>{
this.src = src;
});
}
async getSrc (){
const response = await fetch(this.page);
const body = await response.text();
const dp = new DOMParser();
const pageDocument = dp.parseFromString(body,'text/html');
const video = pageDocument.querySelector('video source');
const image = pageDocument.querySelector('.flexi img')
if(video){
this.type ='video';
return video.src;
}else{
this.type = 'image';
return image.src;
}
}
}
const dp = new DOMParser();
let modalObj;
const loadingSVG = "https://samherbert.net/svg-loaders/svg-loaders/puff.svg";
(function() {
'use strict';
modalObj = new Modal(document, dp);
document.querySelectorAll('.content .thumb').forEach(addEventToClick);
document.querySelectorAll('#content .thumb').forEach(addEventToClick);
document.addEventListener('keydown',(e)=>{
if(e.key == 'ArrowRight'){
modalObj.nextMedia();
}else if(e.key == 'ArrowLeft'){
modalObj.prevMedia();
}else if(e.key == 'Escape'){
modalObj.close();
}
})
// Your code here...
})();
function addEventToClick(element){
element.addEventListener('click',(e)=>{
e.preventDefault();
modalObj.render(modalObj.medias[modalObj.pointer]);
})
}