Sleazy Fork is available in English.

Redgifs Tweaks

tweaks for redgifs page(NOT iframe/embed gifs)

// ==UserScript==
// @name               Redgifs Tweaks
// @namespace          https://greasyfork.org/users/821661
// @match              https://www.redgifs.com/*
// @exclude-match      https://www.redgifs.com/ifr/*
// @grant              GM_registerMenuCommand
// @grant              GM_addElement
// @grant              GM_setValue
// @grant              GM_getValue
// @grant              GM_download
// @run-at             document-start
// @version            0.3.6
// @author             hdyzen
// @description        tweaks for redgifs page(NOT iframe/embed gifs)
// @license            MIT
// @noframes
// ==/UserScript==
// 'use strict';

const menu = {
    notPauseOnVisibility: { state: false, label: 'Disable pause video when change page' },
    midClickIfr: { state: false, label: 'Middle click in video open ifr link' },
    preventMute: { state: true, label: 'Prevent auto mute video' },
    downloadBtn: { state: true, label: 'Download button' },
    downloadPoster: { state: true, label: 'Download poster' },
    screenshotBtn: { state: false, label: 'Screenshot video frame' },
    reloadBtn: { state: false, label: 'Reload video button' },
    removeBoosted: { state: true, label: 'Remove boosted/promoted gifs' },
    removeAnnoyances: { state: true, label: 'Remove annoyances' },
};

const pathsItems = [
    { id: 'downloadBtn', path: '<path d="M12.5535 16.5061C12.4114 16.6615 12.2106 16.75 12 16.75C11.7894 16.75 11.5886 16.6615 11.4465 16.5061L7.44648 12.1311C7.16698 11.8254 7.18822 11.351 7.49392 11.0715C7.79963 10.792 8.27402 10.8132 8.55352 11.1189L11.25 14.0682V3C11.25 2.58579 11.5858 2.25 12 2.25C12.4142 2.25 12.75 2.58579 12.75 3V14.0682L15.4465 11.1189C15.726 10.8132 16.2004 10.792 16.5061 11.0715C16.8118 11.351 16.833 11.8254 16.5535 12.1311L12.5535 16.5061Z" fill="#fff"></path><path d="M3.75 15C3.75 14.5858 3.41422 14.25 3 14.25C2.58579 14.25 2.25 14.5858 2.25 15V15.0549C2.24998 16.4225 2.24996 17.5248 2.36652 18.3918C2.48754 19.2919 2.74643 20.0497 3.34835 20.6516C3.95027 21.2536 4.70814 21.5125 5.60825 21.6335C6.47522 21.75 7.57754 21.75 8.94513 21.75H15.0549C16.4225 21.75 17.5248 21.75 18.3918 21.6335C19.2919 21.5125 20.0497 21.2536 20.6517 20.6516C21.2536 20.0497 21.5125 19.2919 21.6335 18.3918C21.75 17.5248 21.75 16.4225 21.75 15.0549V15C21.75 14.5858 21.4142 14.25 21 14.25C20.5858 14.25 20.25 14.5858 20.25 15C20.25 16.4354 20.2484 17.4365 20.1469 18.1919C20.0482 18.9257 19.8678 19.3142 19.591 19.591C19.3142 19.8678 18.9257 20.0482 18.1919 20.1469C17.4365 20.2484 16.4354 20.25 15 20.25H9C7.56459 20.25 6.56347 20.2484 5.80812 20.1469C5.07435 20.0482 4.68577 19.8678 4.40901 19.591C4.13225 19.3142 3.9518 18.9257 3.85315 18.1919C3.75159 17.4365 3.75 16.4354 3.75 15Z" fill="#fff"></path>' },
    { id: 'downloadPoster', path: '<path d="M22.71,6.29a1,1,0,0,0-1.42,0L20,7.59V2a1,1,0,0,0-2,0V7.59l-1.29-1.3a1,1,0,0,0-1.42,1.42l3,3a1,1,0,0,0,.33.21.94.94,0,0,0,.76,0,1,1,0,0,0,.33-.21l3-3A1,1,0,0,0,22.71,6.29ZM19,13a1,1,0,0,0-1,1v.38L16.52,12.9a2.79,2.79,0,0,0-3.93,0l-.7.7L9.41,11.12a2.85,2.85,0,0,0-3.93,0L4,12.6V7A1,1,0,0,1,5,6h8a1,1,0,0,0,0-2H5A3,3,0,0,0,2,7V19a3,3,0,0,0,3,3H17a3,3,0,0,0,3-3V14A1,1,0,0,0,19,13ZM5,20a1,1,0,0,1-1-1V15.43l2.9-2.9a.79.79,0,0,1,1.09,0l3.17,3.17,0,0L15.46,20Zm13-1a.89.89,0,0,1-.18.53L13.31,15l.7-.7a.77.77,0,0,1,1.1,0L18,17.21Z"/>' },
    { id: 'screenshotBtn', path: '<path d="M17,5 C18.0543909,5 18.9181678,5.81587733 18.9945144,6.85073759 L19,7 L19,17 L21,17 C21.5523,17 22,17.4477 22,18 C22,18.51285 21.613973,18.9355092 21.1166239,18.9932725 L21,19 L19,19 L19,21 C19,21.5523 18.5523,22 18,22 C17.48715,22 17.0644908,21.613973 17.0067275,21.1166239 L17,21 L17,7 L9,7 L9,5 L17,5 Z M6,2 C6.51283143,2 6.93550653,2.38604429 6.9932722,2.88337975 L7,3 L7,17 L15,17 L15,19 L7,19 C5.94563773,19 5.08183483,18.18415 5.00548573,17.1492661 L5,17 L5,7 L3,7 C2.44772,7 2,6.55228 2,6 C2,5.48716857 2.38604429,5.06449347 2.88337975,5.0067278 L3,5 L5,5 L5,3 C5,2.44772 5.44772,2 6,2 Z" fill="#fff"> </path>' },
    { id: 'reloadBtn', path: '<path d="M4,12a1,1,0,0,1-2,0A9.983,9.983,0,0,1,18.242,4.206V2.758a1,1,0,1,1,2,0v4a1,1,0,0,1-1,1h-4a1,1,0,0,1,0-2h1.743A7.986,7.986,0,0,0,4,12Zm17-1a1,1,0,0,0-1,1A7.986,7.986,0,0,1,7.015,18.242H8.757a1,1,0,1,0,0-2h-4a1,1,0,0,0-1,1v4a1,1,0,0,0,2,0V19.794A9.984,9.984,0,0,0,22,12,1,1,0,0,0,21,11Z"></path>' },
];

// Map to storage url to download
const urlsMap = new Map();
const log = (...args) => console.log('[RGT]:', ...args);
const addCSS = text => document.documentElement.insertAdjacentHTML('beforeend', `<style rel='stylesheet'>${text}</style>`);

// Create/reload options in menu
function menuOpt(obj) {
    Object.entries(obj).forEach(([key, value]) => {
        const state = getState(key);

        if (['downloadBtn', 'downloadPoster', 'screenshotBtn', 'reloadBtn'].includes(key)) displayItems(state, key);

        if (key === 'removeAnnoyances') annoyancesToggle(state);

        GM_registerMenuCommand(`[${state ? '✔️' : '❌'}]: ${value.label}`, () => optChange(key, state), { id: key, autoClose: false });
    });
}
menuOpt(menu);

// Get state
function getState(key) {
    const menuSaved = GM_getValue('menu', menu); // Get saved options

    return menuSaved.hasOwnProperty(key) && menuSaved[key].hasOwnProperty('state') ? menuSaved[key].state : menu[key].state;
}

// Toggle option in menu
function optChange(key, state) {
    menu[key].state = !state;
    GM_setValue('menu', menu); // Save options
    menuOpt(menu); // Reload options
    // window.location.reload();
}

// Middle click open embed link
function openIfr() {
    let canOpen = false;
    document.addEventListener('mousedown', e => {
        const gifOverlay = e.target.classList.contains('Player-OverLayer');
        if (getState('midClickIfr') && e.button === 1 && gifOverlay) {
            canOpen = true;
            e.preventDefault();
        }
    });
    document.addEventListener('mouseup', e => {
        const gifPlayer = e.target.closest('.GifPreview_isActive');
        if (canOpen === true && gifPlayer) {
            window.open(`https://www.redgifs.com/ifr/${gifPlayer.id.slice(4)}`, '_blank');
            canOpen = false;
        }
    });
}
openIfr();

// Display button in sidebar
function displayItems(state, eClass) {
    if (!state) {
        document.documentElement.classList.add(eClass);
    } else {
        document.documentElement.classList.remove(eClass);
    }
}

// Get template svg
function getTemplateSvg(id, path) {
    return `<li class="SideBar-Item" ><div id="${id}" style="display: inline-block; cursor: pointer;" ><svg style="pointer-events: none;" width="28px" height="28px" viewBox="0 0 24 24" fill="#fff" xmlns="http://www.w3.org/2000/svg">${path}</svg></div></li>`;
}

// Create action button
function createActionButton(append) {
    // Create buttons
    pathsItems.forEach(item => {
        append.querySelector('.SideBar-Item:last-of-type').insertAdjacentHTML('beforebegin', getTemplateSvg(item.id, item.path));
    });

    append.addEventListener('click', e => {
        const gifId = e.target.closest('[id^="gif_"]').id.slice(4),
            urls = urlsMap.get(gifId);

        switch (e.target.id) {
            case 'downloadBtn':
                download(localStorage.getItem('gifQuality') === 'hd' && urls.hd ? urls.hd : urls.sd);
                break;
            case 'downloadPoster':
                download(urls.poster);
                break;
            case 'screenshotBtn':
                getScreenshot(document.querySelector('video.isLoaded'), urls.sd);
                break;
            case 'reloadBtn':
                document.querySelector('video.isLoaded').load();
                break;
            default:
                break;
        }
    });
}

// Get gif name
function getNameGif(url) {
    return url.substring(url.lastIndexOf('/') + 1, url.indexOf('?'));
}

// Download video
function download(url) {
    GM_download({
        url: url,
        name: getNameGif(url),
    });
}

// Get screenshot of video
function getScreenshot(video, url) {
    const name = getNameGif(url),
        canvas = document.createElement('canvas'),
        ctx = canvas.getContext('2d');

    canvas.width = video.videoWidth;
    canvas.height = video.videoHeight;
    ctx.drawImage(video, 0, 0, canvas.width, canvas.height);

    const imagemData = canvas.toDataURL(),
        link = document.createElement('a');

    link.download = name.substring(0, name.indexOf('-'));
    link.href = imagemData;

    document.body.appendChild(link);
    link.click();
    canvas.remove();
    document.body.removeChild(link);
}

// Annoyances toggle
function annoyancesToggle(state) {
    if (state) {
        localStorage.setItem('cookie_notice', 'cancel');
        localStorage.setItem('dismiss_scroll_more', 'true');
        sessionStorage.setItem('tooltip_feedback', 'true');
    } else {
        localStorage.removeItem('cookie_notice', 'cancel');
        localStorage.removeItem('dismiss_scroll_more', 'true');
        sessionStorage.removeItem('tooltip_feedback', 'true');
    }
}

// Get gif url from JSON.parse() patched
function getUrlGif(parsed) {
    if (parsed.gif) {
        urlsMap.set(parsed.gif.id, { hd: parsed.gif.urls.hd, sd: parsed.gif.urls.sd, poster: parsed.gif.urls.poster });
    } else if (parsed.gifs?.length) {
        parsed.gifs?.forEach(gif => urlsMap.set(gif.id, { hd: gif.urls.hd, sd: gif.urls.sd, poster: gif.urls.poster }));
    }

    return parsed;
}

// Patch parse() to get gif url/remove boosted
const originalParse = JSON.parse;

JSON.parse = function (json, reviver) {
    const parsed = originalParse.apply(this, arguments);
    if (getState('removeBoosted') && parsed?.niches?.length + parsed?.tags?.length === 0) return;
    if (getState('removeAnnoyances') && parsed.hasOwnProperty('noAds')) parsed.noAds = true;

    return getState('downloadBtn') ? getUrlGif(parsed) : parsed;
};

// Patch appendChild() to append (download, reload) button
const originalAppendChild = Node.prototype.appendChild;

Node.prototype.appendChild = function (newNode) {
    if ((getState('downloadBtn') || getState('downloadPoster') || getState('screenshotBtn') || getState('reloadBtn')) && newNode.classList && newNode.classList.contains('SideBar')) createActionButton(newNode);

    return originalAppendChild.apply(this, arguments);
};

// Patch addEventListener() to prevent pause video when change page
const originalAddEventListener = EventTarget.prototype.addEventListener;

EventTarget.prototype.addEventListener = function (type, listener, options) {
    return type === 'visibilitychange' ? originalAddEventListener.call(this, type, ev => (getState('notPauseOnVisibility') ? listener(ev) : ''), options) : originalAddEventListener.apply(this, arguments);
};

// Path catch() to prevent mute video if autoplay disabled
const originalCatch = Promise.prototype.catch;

Promise.prototype.catch = function (onRejected) {
    if (getState('preventMute') && onRejected.toString().includes('Failed to play')) return;

    return originalCatch.call(this, onRejected);
};

addCSS(`.downloadBtn #downloadBtn, .downloadPoster #downloadPoster, .screenshotBtn #screenshotBtn, .reloadBtn #reloadBtn { display: none !important; } `);