gh-proxy-buttons

add a button beside github link(releases,files and repository url), click to get alternative url according to previously specified proxy.

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

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

Necesitarás 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.

Necesitará instalar una extensión como Tampermonkey para 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)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

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

// ==UserScript==
// @name         gh-proxy-buttons
// @name:zh-CN   github加速按钮
// @namespace    https://github.com/du33169/gh-proxy-buttons
// @version      0.7
// @license      MPL-2.0
// @require      https://cdn.bootcdn.net/ajax/libs/clipboard.js/2.0.6/clipboard.min.js
// @description  add a button beside github link(releases,files and repository url), click to get alternative url according to previously specified proxy.
// @description:zh-CN  为github中的特定链接(releases、文件、项目地址)添加一个悬浮按钮,提供代理后的加速链接
// @author       du33169
// @match        *://github.com/*
// @grant        none
// @run-at       document-end
// ==/UserScript==
(function() 
{
    'use strict'; 
	
//--------------------------代理设置-------------------------------      
//用于在线代理的workers地址                                                                                                            
const proxy_url= 'https://gh-proxy.du33169.workers.dev/';
/*      
	备用: 'https://gh.api.99988866.xyz/';   (来自gh-proxy项目作者)
	代理服务器地址可自行修改,末尾斜杠不可省略!
*/
//--------------------------其他设置------------------------------
//是否打开调试输出
const open_log=true;
//鼠标离开链接或按钮后消失前等待的时间
const fade_timeout=100;//ms

//--------------------------功能代码------------------------------
    function isRepoFile(ourTarget){
        return (ourTarget.tagName=='A'
                &&ourTarget.getAttribute('aria-label')!=null//利用&&短路特性防止没有属性的元素导致脚本终止
                &&ourTarget.classList.contains("Link--primary")
                &&ourTarget.getAttribute('aria-label').endsWith('(File)')
                &&ourTarget.closest('#js-repo-pjax-container')!=null
               );
    }
    function isReleaseAsset(ourTarget){
        return (ourTarget.tagName=='A'
                &&ourTarget.getAttribute('rel')!=null
                &&ourTarget.rel=="nofollow"
                //&&/github.com/.test(ourTarget.href)==true
                &&(ourTarget.closest('#repo-content-pjax-container')!=null)||(ourTarget.closest('.js-truncated-assets-fragment')!=null)
               );
    }
    function isDownloadZip(e){
        return (e.tagName=='A'
                &&e.classList.contains("kHKEGN")
                &&e.getAttribute('rel')!=null
                &&e.rel=="nofollow"
                &&e.getAttribute('role')!=null
                &&e.role=="menuitem"
               );
    }
    function isHttpCopyGit(e){
        return (
            e.tagName=='BUTTON'
            &&e.classList.contains('hUTZcL')
            &&e.previousElementSibling!=null
            &&e.previousElementSibling.tagName=='INPUT'
            &&e.previousElementSibling.value.startsWith('https')
        );
    }


    function getBtn(originLink,filename,copy=false)
    {
        var ghBtn=document.getElementById("gh-proxy-button");
        //existed
        if(!ghBtn){
            //not existed, create instance
            ghBtn=document.createElement('a');
            ghBtn.setAttribute('class','btn');
            ghBtn.id="gh-proxy-button";
            ghBtn.title="[gh-proxy-buttons] get proxy link";
            ghBtn.style.position="absolute";
            ghBtn.role="button";
            ghBtn.style.zIndex=9999;
            //ghBtn.style.top=0;//must be set for transition
            //ghBtn.style.left=0;
            //ghBtn.style.transition="transform 0.5s ease-in-out";

            ghBtn.addEventListener('mouseenter',function(){
                if(open_log)console.debug('[gh-proxy-buttons] onbtn');
                if(ghBtn.timerId !=undefined && ghBtn.timerId!=-1){
                    clearTimeout(ghBtn.timerId);
                    ghBtn.timerId=-1;
                }
            });
            ghBtn.addEventListener('mouseleave',function(){
                if(open_log)console.debug('[gh-proxy-buttons] mouseleave-btn');
                if(ghBtn.timerId !=undefined && ghBtn.timerId!=-1)return;
                ghBtn.timerId=setTimeout(function(){
                    ghBtn.style.visibility="hidden";
                     ghBtn.timerId=-1;
                     if(open_log)console.debug('[gh-proxy-buttons] timeout fade mouseleave-btn');
                },fade_timeout);
                 if(open_log)console.debug('[gh-proxy-buttons] btn leave timerid:',ghBtn.timerId);
            });
            document.documentElement.appendChild(ghBtn);
        }
        //now gh-proxy-button exists
        if(copy)//仓库地址input标签特殊处理,使用ClipboardJS实现点击复制
		{
            ghBtn.removeAttribute('target');
            ghBtn.removeAttribute('download');
            ghBtn.href="javascript:void(0)";
			ghBtn.innerText="🚀📄";
			ghBtn.clip=new ClipboardJS(ghBtn);
            ghBtn.clip.on('success',function(){
                ghBtn.innerText="🚀📄✔";
            });
			ghBtn.setAttribute('data-clipboard-text',proxy_url+originLink);

			//console.log('[gh-proxy-buttons] input url processed');
		}
		else{
            ghBtn.innerText="🚀";
            ghBtn.target="_blank";
            if(ghBtn.clip)ghBtn.clip.destroy();
            ghBtn.clip=undefined;
            ghBtn.download=filename;
            ghBtn.removeAttribute('data-clipboard-text');
            ghBtn.href=proxy_url+originLink;
        }

        return ghBtn;
    }

	console.log('[gh-proxy-buttons] processing...');
	function moveHere(e,originLink,copy=false)//用于注册mouseenter事件,e为当前元素
	{
		//创建按钮对象,github中使用.btn的class可以为<a>标签加上按钮外观
		var btn=getBtn(originLink,e.title,copy);
        if(open_log)console.debug("[gh-proxy-buttons]",btn);
        //e.parentElement.insertBefore(btn,e);
        if(btn.timerId !=undefined && btn.timerId!=-1){
            clearTimeout(btn.timerId);
            btn.timerId=-1;
        }
        const rect = e.getBoundingClientRect();
        const btnRect=btn.getBoundingClientRect();
        const x = rect.left + window.scrollX - btnRect.width;
        const y = rect.top + window.scrollY;

        console.log(`Element coordinates (relative to document): x: ${x}, y: ${y}`);

        btn.style.left=`${x}px`;
        btn.style.top =`${y}px`;
        if(btn.style.visibility=="visible"){
            //btn.style.transform = `translate(${event.x}px, ${event.y}px)`;
        }
        else{
            //btn.style.transform="";
            btn.style.visibility="visible";
        }

		if(open_log)console.debug(`[gh-proxy-buttons] mousein, move btn to ${event.x},${event.y}`);
        e.addEventListener('mouseleave',function(){
                if(open_log)console.debug('[gh-proxy-buttons] mouseleave-target');
            if(btn.timerId !=undefined && btn.timerId!=-1)return;
                btn.timerId=setTimeout(function(){
                   btn.style.visibility="hidden";
                   btn.timerId=-1;
                     if(open_log)console.debug('[gh-proxy-buttons] timeout fade mouseleave-target');
                },fade_timeout);
            if(open_log)console.debug('[gh-proxy-buttons] target leave timerid:',btn.timerId);
            });
	}

    function eventDelegation(e)
	{
    // e.target 是事件触发的元素
		if(e.target!=null)
		{
            var ourTarget=e.target;
			while(ourTarget!=e.currentTarget&&ourTarget.tagName!='A'&&ourTarget.tagName!='BUTTON')//releases页面触发元素为<a>内的span,需要上浮寻找
			{
				ourTarget=ourTarget.parentNode;
			}
            if(ourTarget==e.currentTarget)return;
            //if(open_log)console.debug('[gh-proxy-buttons]','found A',ourTarget);
			if(isRepoFile(ourTarget)||isReleaseAsset(ourTarget)||isDownloadZip(ourTarget))
			{
				console.log('[gh-proxy-buttons] ','found target',ourTarget);
				moveHere(ourTarget,ourTarget.href);
			}else if(isHttpCopyGit(ourTarget)){
                console.log('[gh-proxy-buttons] ','found target copy button',ourTarget);
				moveHere(ourTarget,ourTarget.previousElementSibling.value,true);
            }
		}
	}
    document.body.addEventListener("mouseover", eventDelegation);
})();