Gist URL Copier

Adds new buttons to Github Gist files | "URL" - Copies the direct file URL | "UserScript" - Copies the formatted URL (@downloadURL and @updateURL) for use in your UserScripts.

2025-09-19 기준 버전입니다. 최신 버전을 확인하세요.

// ==UserScript==
// @name               Gist URL Copier
// @name:pt-BR         Gist URL Copier
// @name:en            Gist URL Copier
// @name:es            Gist URL Copier
// @name:zh-CN         Gist URL Copier
// @namespace          https://github.com/0H4S
// @version            1.0
// @description        Adds new buttons to Github Gist files | "URL" - Copies the direct file URL | "UserScript" - Copies the formatted URL (@downloadURL and @updateURL) for use in your UserScripts.
// @description:pt-BR  Adiciona novos botões nos arquivos Gist do Github | "URL" - Copia a URL direta do arquivo | UserScript - Copia o URL formatado (@downloadURL e @updateURL) para usar em seu UserScripts.
// @description:en     Adds new buttons to Github Gist files | "URL" - Copies the direct file URL | "UserScript" - Copies the formatted URL (@downloadURL and @updateURL) for use in your UserScripts.
// @description:es     Agrega nuevos botones a los archivos de Github Gist | "URL" - Copia la URL directa del archivo | "UserScript" - Copia la URL formateada (@downloadURL y @updateURL) para usar en tus UserScripts.
// @description:zh-CN  向Github Gist文件添加新按钮 | "URL" - 复制直接文件URL | "UserScript" - 复制格式化的URL(@downloadURL和@updateURL)以供您的UserScripts使用。
// @license            MIT
// @author             OHAS
// @icon               https://cdn-icons-png.flaticon.com/512/6237/6237744.png
// @match              https://gist.github.com/*
// @require            https://update.greasyfork.org/scripts/549920/1662869/Script%20Notifier.js
// @connect            gist.githubusercontent.com
// @grant              GM_getValue
// @grant              GM_setValue
// @grant              GM_registerMenuCommand
// @grant              GM_xmlhttpRequest
// ==/UserScript==

(function() {
    'use strict';
	/* globals ScriptNotifier */
    if (window.top !== window.self) {
        return;
    }
    const SCRIPT_CONFIG = {
        notificationsUrl: 'https://gist.githubusercontent.com/0H4S/b980176bef1c7d78a2e6fd1175106993/raw/gist_url_copier_notifications.json',
        scriptVersion: '1.0',
        currentLang: navigator.language || 'en'
    };
    const notifier = new ScriptNotifier(SCRIPT_CONFIG);
    notifier.run();
    function addButtonStyles() {
        if (document.getElementById('custom-gist-buttons-style')) return;
        const style = document.createElement('style');
        style.id = 'custom-gist-buttons-style';
        style.textContent = `
            .custom-gist-button {
                margin-right: 8px !important;
            }
            .copied-message {
                color: #43c568ff !important;
                font-weight: bold !important;
                text-transform: uppercase !important;
            }
            .error-message {
                color: #cf222e !important;
                font-weight: bold !important;
                text-transform: uppercase !important;
            }
        `;
        document.head.appendChild(style);
    }
    function createUrlButton(fileActionsContainer) {
        const rawButton = fileActionsContainer.querySelector('a[href*="/raw/"]');
        if (!rawButton) return null;
        const copyButton = rawButton.cloneNode(true);
        const label = copyButton.querySelector('.Button-label');
        label.textContent = 'URL';
        copyButton.classList.add('custom-gist-button', 'copy-raw-url-button');
        copyButton.removeAttribute('href');
        copyButton.removeAttribute('data-view-component');
        copyButton.addEventListener('click', function(e) {
            e.preventDefault();
            const originalText = label.textContent;
            const rawPath = rawButton.getAttribute('href');
            const modifiedPath = rawPath.replace(/\/raw\/[a-f0-9]+\//, '/raw/');
            const finalUrl = `https://gist.githubusercontent.com${modifiedPath}`;
            navigator.clipboard.writeText(finalUrl).then(() => {
                label.textContent = 'COPIED!';
                label.classList.add('copied-message');
                copyButton.style.pointerEvents = 'none';
                setTimeout(() => {
                    label.textContent = originalText;
                    label.classList.remove('copied-message');
                    copyButton.style.pointerEvents = 'auto';
                }, 800);
            }).catch(() => {
                label.textContent = 'ERROR!';
                label.classList.add('error-message');
                setTimeout(() => {
                    label.textContent = originalText;
                    label.classList.remove('error-message');
                }, 800);
            });
        });
        return copyButton;
    }
    function createUserScriptButton(fileActionsContainer) {
        const rawButton = fileActionsContainer.querySelector('a[href*="/raw/"]');
        if (!rawButton) return null;
        const copyButton = rawButton.cloneNode(true);
        const label = copyButton.querySelector('.Button-label');
        label.textContent = 'UserScript';
        copyButton.classList.add('custom-gist-button', 'copy-userscript-button');
        copyButton.removeAttribute('href');
        copyButton.removeAttribute('data-view-component');
        copyButton.addEventListener('click', function(e) {
            e.preventDefault();
            const originalText = label.textContent;
            const rawPath = rawButton.getAttribute('href');
            const modifiedPath = rawPath.replace(/\/raw\/[a-f0-9]+\//, '/raw/');
            const finalUrl = `https://gist.githubusercontent.com${modifiedPath}`;
            const textToCopy = `// @downloadURL  ${finalUrl}\n// @updateURL    ${finalUrl}`;
            navigator.clipboard.writeText(textToCopy).then(() => {
                label.textContent = 'COPIED!';
                label.classList.add('copied-message');
                copyButton.style.pointerEvents = 'none';
                setTimeout(() => {
                    label.textContent = originalText;
                    label.classList.remove('copied-message');
                    copyButton.style.pointerEvents = 'auto';
                }, 800);
            }).catch(() => {
                label.textContent = 'ERROR!';
                label.classList.add('error-message');
                setTimeout(() => {
                    label.textContent = originalText;
                    label.classList.remove('error-message');
                }, 800);
            });
        });
        return copyButton;
    }
    function addCustomButtons() {
        const fileActionsContainers = document.querySelectorAll('.file-actions.flex-order-2.pt-0');
        fileActionsContainers.forEach(container => {
            if (!container.querySelector('.copy-userscript-button')) {
                const userScriptButton = createUserScriptButton(container);
                if (userScriptButton) {
                    container.insertBefore(userScriptButton, container.firstChild);
                }
            }
            if (!container.querySelector('.copy-raw-url-button')) {
                const urlButton = createUrlButton(container);
                if (urlButton) {
                    const userScriptButton = container.querySelector('.copy-userscript-button');
                    if (userScriptButton) {
                        container.insertBefore(urlButton, userScriptButton.nextSibling);
                    } else {
                        container.insertBefore(urlButton, container.firstChild);
                    }
                }
            }
        });
    }
    addButtonStyles();
    addCustomButtons();
    const observer = new MutationObserver(addCustomButtons);
    observer.observe(document.body, {
        childList: true,
        subtree: true
    });
})();