Docker Hub Mirrors

Show other mirrors to pull current docker image.

Bu betiği kurabilmeniz için Tampermonkey, Greasemonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Userscripts gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

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

Bu komut dosyasını yüklemek için bir kullanıcı komut dosyası yöneticisi uzantısı yüklemeniz gerekecek.

(Zaten bir kullanıcı komut dosyası yöneticim var, kurmama izin verin!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Zateb bir user-style yöneticim var, yükleyeyim!)

// ==UserScript==
// @name         Docker Hub Mirrors
// @namespace    https://github.com/iamspark1e/my-tampermonkey-scripts/blob/main/docker-mirror-urls.js
// @version      0.1.1
// @description  Show other mirrors to pull current docker image.
// @author       iamspark1e
// @license      AGPL-3.0-or-later
// @match        *://hub.docker.com/_/*
// @match        *://hub.docker.com/r/*
// @grant        GM_setValue
// @grant        GM_getValue
// ==/UserScript==

// ref: https://juejin.cn/post/7022654292880424991
// - 阿里云(杭州)   https://registry.cn-hangzhou.aliyuncs.com
// - 阿里云(上海)   https://registry.cn-shanghai.aliyuncs.com
// - 阿里云(青岛)   https://registry.cn-qingdao.aliyuncs.com
// - 阿里云(北京)   https://registry.cn-beijing.aliyuncs.com
// - 阿里云(张家口)   https://registry.cn-zhangjiakou.aliyuncs.com
// - 阿里云(呼和浩特)   https://registry.cn-huhehaote.aliyuncs.com
// - 阿里云(乌兰察布)   https://registry.cn-wulanchabu.aliyuncs.com
// - 阿里云(深圳)   https://registry.cn-shenzhen.aliyuncs.com
// - 阿里云(河源)   https://registry.cn-heyuan.aliyuncs.com
// - 阿里云(广州)   https://registry.cn-guangzhou.aliyuncs.com
// - 阿里云(成都)   https://registry.cn-chengdu.aliyuncs.com
// - 腾讯云   https://mirror.ccs.tencentyun.com
// - 微软云   https://dockerhub.azk8s.com
// - 网易   https://hub-mirror.c.163.com
// - 上海交通大学   https://mirror.sjtu.edu.cn/docs/docker-registry
// - ❤❤❤南京大学   https://docker.nju.edu.cn
// - 道客 DaoCloud   https://f1361db2.m.daocloud.io
// - 阿里云(香港)   https://registry.cn-hongkong.aliyuncs.com
// - 阿里云(日本-东京)   https://registry.ap-northeast-1.aliyuncs.com
// - 阿里云(新加坡)   https://registry.ap-southeast-1.aliyuncs.com
// - 阿里云(澳大利亚-悉尼)   https://registry.ap-southeast-2.aliyuncs.com
// - 阿里云(马来西亚-吉隆坡)   https://registry.ap-southeast-3.aliyuncs.com
// - 阿里云(印度尼西亚-雅加达)   https://registry.ap-southeast-5.aliyuncs.com
// - 阿里云(印度-孟买)   https://registry.ap-south-1.aliyuncs.com
// - 阿里云(德国-法兰克福)   https://registry.eu-central-1.aliyuncs.com
// - 阿里云(英国-伦敦)   https://registry.eu-west-1.aliyuncs.com
// - 阿里云(美国西部-硅谷)   https://registry.us-west-1.aliyuncs.com
// - 阿里云(美国东部-弗吉尼亚)   https://registry.us-east-1.aliyuncs.com
// - 阿里云(阿联酋-迪拜)   https://registry.me-east-1.aliyuncs.com
// - 谷歌云   https://gcr.io
// - 官方   https://registry.hub.docker.com

(function () {
    'use strict';
    const ALTER_HUBS = [
        { "url": "registry.cn-hangzhou.aliyuncs.com", "name": "阿里云(杭州)" },
        { "url": "mirror.ccs.tencentyun.com", "name": "腾讯云" },
        { "url": "dockerhub.azk8s.com", "name": "微软云(Azure)" },
        { "url": "hub-mirror.c.163.com", "name": "网易" },
        { "url": "mirror.sjtu.edu.cn/docs/docker-registry", "name": "上海交通大学" },
        { "url": "docker.nju.edu.cn", "name": "南京大学" },
        { "url": "f1361db2.m.daocloud.io", "name": "DaoCloud" },
        { "url": "gcr.io", "name": "Google" },
        { "url": "registry.hub.docker.com", "name": "官方" },
    ]
    const DOM_IDENTIFIER = "iamspark1e_tampermonkey_docker_mirror_helper"
    const DOM_TPL = `
        <label>
            <span>Choose a mirror: </span>
            <select>
                ${ALTER_HUBS.map(hub => `<option value="${hub.url}">${hub.name}</option>`).join("")}
            </select>
        </label>
        <div class="show_url" style="background-color:rgba(255,255,255,0.3);border-radius:4px;margin-top:4px;padding:4px;"></div>
    `

    const GENERATE_SNIPPETS = (hub, image_name) => `
        <p>URL: <span style="user-select:all;word-break:break-all;">${hub.url + '/' + image_name}</span></p>
        <p>Docker pull: <code style="user-select:all;word-break:break-all;">docker pull ${hub.url + '/' + image_name}</code></p>
    `

    let siblingNode;
    let currentHub = ALTER_HUBS[0];
    let imageFullName;
    let oldHref = window.location.href;

    function renderUrls() {
        let dom = document.querySelector(`#${DOM_IDENTIFIER} div.show_url`);
        dom.innerHTML = GENERATE_SNIPPETS(currentHub, imageFullName)
    }
    function selectHandler(e) {
        currentHub = ALTER_HUBS.find(hub => hub.url === e.target.value);
        renderUrls();
    }

    function initHelper() {
        if (!siblingNode) {
            console.error("no siblingNode, init failed");
            return;
        }
        const mountNode = siblingNode.parentNode.parentNode;
        imageFullName = siblingNode.innerText.replace("docker pull ", "");

        if (!document.querySelector(`#${DOM_IDENTIFIER}`)) {
            const testDiv = document.createElement("div")
            testDiv.setAttribute("style", "border:1px solid #c4c8d1;background-color: #e1e2e6;border-radius: 4px;padding:8px;margin-top: 8px;");
            testDiv.id = DOM_IDENTIFIER;
            testDiv.innerHTML = DOM_TPL;
            mountNode.appendChild(testDiv);

            // addEventListener
            const selector = document.querySelector(`#${DOM_IDENTIFIER} select`);
            selector.addEventListener("change", selectHandler);
            renderUrls();
        }
    }

    let observer = new MutationObserver((mutationList, observer) => {
        if(oldHref !== window.location.href) {
            siblingNode = null;
            oldHref = window.location.href;
        }
        for (const mutation of mutationList) {
            if (mutation.type === "childList" && !siblingNode) {
                const tmp = document.querySelector('code[data-testid="copyPullCommandPullCommand"]')
                if (tmp && !siblingNode) {
                    siblingNode = tmp;
                    initHelper();
                    // observer.disconnect()
                }
            }
        }
    });
    // *://hub.docker.com/_/*
    // *://hub.docker.com/r/*
    observer.observe(document.body, {
        childList: true,
        subtree: true
    })



    // TODO:
    // *://hub.docker.com/_/*/tags
    // *://hub.docker.com/r/*/tags
})();