r34 Image Previewer

Lets you preview images in full resolution when hovering the thumbnail

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

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

Tendrás que instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Tendrás que instalar una extensión como Tampermonkey antes de poder instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name         r34 Image Previewer
// @namespace    ImgPreview
// @version      1.2.1
// @description  Lets you preview images in full resolution when hovering the thumbnail
// @author       haruusyren
// @source       https://github.com/innocence-studios/image-preview
// @license      MIT
// @match        *://*.rule34.xxx/*
// @icon         data:image/png;base64,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
// @run-at       document-end
// ==/UserScript==

(async function() {
    'use strict';

    document.querySelector('#post-list > span')?.remove(); // Removes the right container if it exists
    let con = document.createElement('div'); // Creates the preview container
    con.id = 'previewParent';
    if (window.location.href.includes('page=favorites')) document.body.appendChild(con);
    if (window.location.href.includes('page=post&s=list')) document.querySelector('#post-list').appendChild(con);
    if (window.location.href.includes('page=pool')) document.querySelector('#content').appendChild(con);

    let extensions = [ 'png', 'jpg', 'jpeg', 'gif' ]; // Supported extensions
    let targets = [];

    let loaderParent = document.createElement('div'); // Loading animation
    loaderParent.className = 'prev';
    con.appendChild(loaderParent);
    let loader = document.createElement('div');
    loader.className = 'loader';
    loader.style.display = 'none'
    loaderParent.appendChild(loader);

    for (let i in extensions){
        let target = document.createElement('img'); // One element per extension
        target.className = 'prev';
        target.alt = '';
        con.appendChild(target);
        targets.push(target);
    }

    let videoTarget = document.createElement('video'); // Video preview
    videoTarget.className = 'prev';
    videoTarget.autoplay = true;
    videoTarget.controls = false;
    videoTarget.loop = true;
    videoTarget.muted = getCookie('previewMuted') == 'true';
    videoTarget.disablepictureinpicture = true;
    con.appendChild(videoTarget);

    for (let el of document.querySelectorAll('.thumb')){ // Adds event for each thumbnail
        el.addEventListener('mouseenter', () => {
            loader.style.display = '';
            if ((Array.from(el.querySelectorAll('*')).map(a => a.title.includes('video'))).includes(true)) videoTarget.src = el.querySelector('img').src.replace('thumbnails', 'images').replace('thumbnail_', '').replace('wimg', 'ws-cdn-video').replace('.jpg', '.mp4');
            else {
                let url = el.querySelector('img').src.replace('thumbnails', 'images').replace('thumbnail_', '').replace('.jpg', '.EXTENSION');

                for (let i in targets) targets[i].src = url.replace('.EXTENSION', `.${extensions[i]}`);
            }
        });
        el.addEventListener('mouseleave', () => {
            loader.style.display = 'none';
            videoTarget.src = '';
            for (let i in targets) targets[i].src = '';
        });
    }

    let paramParent = document.createElement('div'); // Parameters container
    paramParent.className = 'param-parent';
    con.appendChild(paramParent);
    let muteParam = document.createElement('input'); // Mute preview video parameter
    muteParam.id = 'muteParam';
    muteParam.name = 'muteParam';
    muteParam.type = 'checkbox';
    muteParam.checked = getCookie('previewMuted') == 'true';
    paramParent.appendChild(muteParam);
    let muteLabel = document.createElement('label'); // Mute preview video parameter label
    muteLabel.for = 'muteParam';
    paramParent.appendChild(muteLabel);
    muteLabel.textContent = 'Mute preview';
    muteParam.addEventListener('change', () => {
        videoTarget.muted = !videoTarget.muted;
        document.cookie = `previewMuted=${videoTarget.muted}`;
    });

    let style = document.createElement('style'); // Usescript stylesheet
    style.id = 'previewStylesheet';
    document.head.appendChild(style);
    style.sheet.insertRule('.image-list { width: 56dvw !important; }', style.sheet.cssRules.length);
    style.sheet.insertRule('.param-parent { position: fixed; width: stretch; display: flex; justify-content: flex-start; flex-direction: row-reverse; }', style.sheet.cssRules.length);
    style.sheet.insertRule('@keyframes l1 { to { transform: rotate(.5turn) } }', style.sheet.cssRules.length);
    if (window.location.href.includes('page=favorites')){ // CSS on favorite page
        style.sheet.insertRule('#previewParent { position: fixed; min-height: 84dvh; right: 0; width: 39dvw; top: 50%; transform: translateY(-50%); }', style.sheet.cssRules.length);
        style.sheet.insertRule('.prev { position: fixed; max-height: 100dvh; object-fit: cover; width: stretch; top: 50%; transform: translateY(-50%); }', style.sheet.cssRules.length);
    } else
    if (window.location.href.includes('page=pool')){ // CSS on pool page
        style.sheet.insertRule('#previewParent { position: fixed; min-height: 79dvh; right: 0; width: 39dvw; top: 50%; transform: translateY(-50%); }', style.sheet.cssRules.length);
        style.sheet.insertRule('.prev { position: fixed; max-height: 100dvh; object-fit: cover; width: stretch; top: 50%; transform: translateY(-50%); }', style.sheet.cssRules.length);
    } else
    if (window.location.href.includes('page=post&s=list')) { // CSS on search page
        style.sheet.insertRule('#previewParent { width: stretch; }', style.sheet.cssRules.length);
        style.sheet.insertRule('.prev { position: fixed; max-height: 100dvh; object-fit: cover; width: stretch; top: 50%; transform: translateY(-50%); }', style.sheet.cssRules.length);
        style.sheet.insertRule('.loader { animation: l1 1s infinite; aspect-ratio: 1; border-radius: 50%; border: 8px solid; border-color: #000 #0000; width: 50px; margin: auto; }', style.sheet.cssRules.length);
    }
})();

function getCookie(name){ // Get cookie value with name
    const value = `; ${document.cookie}`;
    const parts = value.split(`; ${name}=`);
    if (parts.length === 2) return parts.pop().split(';').shift();
}