Redgifs download button

2/2/2026, 7:08:27 PM

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name        Redgifs download button
// @namespace   Violentmonkey Scripts
// @match       https://www.redgifs.com/*
// @license       GPL-3.0-or-later
// @version     1.0
// @author      pr0nusr
// @description 2/2/2026, 7:08:27 PM
// ==/UserScript==
async function dl({src}, title) {
    const extension = (document.querySelector("video").src.substring(0, 4) == "blob") ? 'm4s' : 'mp4';
    const u = `${src.substring(0, src.length - 11)}.${extension}`;

    const response = await fetch(u);
    const blob = await response.blob();

    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");

    a.href = url;
    a.download = u;
    document.body.appendChild(a);
    a.click();

    document.body.removeChild(a);
    URL.revokeObjectURL(url);
}

const createButton = (parent) => {
    if (parent.className.includes('StreamateCameraDispatch')) {
      parent.parentNode.remove();
      return;
    }
    if (parent.children.length === 0) {
      parent.dataset.buttonadded = false;
      return
    }
    if (parent.dataset.buttonadded === 'true' && ( parent.className.includes('GifPreview_isVideo') ||  parent.className.includes('GifPreview_isActive'))) {
      return;
    }
    if (parent.dataset.buttonadded === 'true' && !parent.className.includes('GifPreview_isVideo')) {
      parent.dataset.buttonadded = false;
    }

    const dlProps = {
      id: 'redgifs_dl_button',
      className: 'LikeButton',
      style: 'margin-bottom: 20px',
      onclick: () => dl(parent.querySelector('img.Player-Poster'))
    };

    const dl_button = Object.assign(document.createElement("button"), dlProps);
    dl_button.dataset.itemId= parent.dataset.feedItemId;

    const svgElement = document.createElement('svg');
    svgElement.innerHTML = `
        <svg
        width="30"
        height="20"
        viewBox="0 0 24 24"
        fill="none"
        xmlns="http://www.w3.org/2000/svg"
        >
        <path
            d="M5 3h11l3 3v15a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1Z"
            stroke="white"
            stroke-width="1"
            stroke-linejoin="round"
        />
        <path
            d="M7 3v6h8V3"
            stroke="white"
            stroke-width="1"
            stroke-linejoin="round"
        />
        <rect
            x="7"
            y="14"
            width="10"
            height="6"
            stroke="white"
            stroke-width="1"
            rx="1"
        />
        </svg>
    `;
    dl_button.appendChild(svgElement);
    const sidebarChildren = parent.getElementsByClassName('sideBar')[0]?.children;
    if (sidebarChildren) {
        const childrenLength = Object.keys(sidebarChildren).length
        const insertTarget = sidebarChildren.item(childrenLength -1)
        insertTarget.parentNode.insertBefore(dl_button, insertTarget);
        parent.dataset.buttonadded = 'true';
    }
}

let append_dl_button_interval = setInterval(() => {
    const nodes = document.querySelectorAll('.GifPreview')
    nodes.forEach(createButton)
}, 500);