VSCode Extension Downloader

在VS Code marketplace添加VSIX下载按钮

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         VSCode Extension Downloader
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  在VS Code marketplace添加VSIX下载按钮
// @author       microchang
// @match        https://marketplace.visualstudio.com/items*
// @grant        none
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    // 创建一个悬浮按钮
    function createFloatingButton() {
        const button = document.createElement('button');
        button.innerHTML = 'download';
        button.style.position = 'fixed';
        button.style.bottom = '20px';
        button.style.right = '20px';
        button.style.zIndex = '9999';
        button.style.padding = '10px 20px';
        button.style.backgroundColor = '#0078D4';
        button.style.color = 'white';
        button.style.border = 'none';
        button.style.borderRadius = '4px';
        button.style.cursor = 'pointer';
        button.style.fontWeight = 'bold';
        button.style.boxShadow = '0 2px 5px rgba(0,0,0,0.2)';

        // 悬停效果
        button.onmouseover = function() {
            this.style.backgroundColor = '#106EBE';
        };
        button.onmouseout = function() {
            this.style.backgroundColor = '#0078D4';
        };

        // 点击事件处理
        button.onclick = function() {
            // 执行第一个下载脚本
            executeFirstScript();
            // 延迟1秒后执行第二个脚本作为备选
            setTimeout(executeSecondScript, 1000);
        };

        document.body.appendChild(button);
    }

    // 实现第一个下载脚本
    function executeFirstScript() {
        const extensionData = {
            version: "",
            publisher: "",
            identifier: "",
            getDownloadUrl: function() {
                // 添加调试日志
                console.log('Debug info:', {
                    version: this.version,
                    publisher: this.publisher,
                    identifier: this.identifier
                });

                const publisher = this.publisher.replace('@', '');
                const extension = this.identifier.split('.')[1];

                // 验证数据是否存在
                if (!publisher || !extension || !this.version) {
                    console.error('Missing required data:', {publisher, extension, version: this.version});
                    return null;
                }

                return `https://${publisher}.gallery.vsassets.io/_apis/public/gallery/publisher/${publisher}/extension/${extension}/${this.version}/assetbyname/Microsoft.VisualStudio.Services.VSIXPackage`;
            },
            getFileName: function() {
                return `${this.identifier}_${this.version}.vsix`;
            }
        };

        const metadataMap = {
            Version: "version",
            Publisher: "publisher",
            "Unique Identifier": "identifier"
        };

        // 修改选择器以确保能找到正确的元素
        const metadataRows = document.querySelectorAll("table.ux-table-metadata tr, .ux-table-metadata tr");

        let foundData = false;
        for (let i = 0; i < metadataRows.length; i++) {
            const row = metadataRows[i];
            const cells = row.querySelectorAll("td");
            if (cells.length === 2) {
                const key = cells[0].innerText.trim();
                const value = cells[1].innerText.trim();
                if (metadataMap.hasOwnProperty(key)) {
                    extensionData[metadataMap[key]] = value;
                    foundData = true;
                    console.log(`Found ${key}: ${value}`);
                }
            }
        }

        // 验证是否成功获取到数据
        if (!foundData) {
            console.error('Failed to find metadata in the page');
            return;
        }

        // 获取下载URL
        const downloadUrl = extensionData.getDownloadUrl();
        if (!downloadUrl) {
            console.error('Failed to generate download URL');
            return;
        }

        // 创建下载链接并触发下载
        const link = document.createElement("a");
        link.href = downloadUrl;
        link.download = extensionData.getFileName();
        link.click();
    }

    // 实现第二个下载脚本(作为备选方案)
    function executeSecondScript() {
        const URL_VSIX_PATTERN = 'https://marketplace.visualstudio.com/_apis/public/gallery/publishers/${publisher}/vsextensions/${extension}/${version}/vspackage';
        const itemName = new URL(window.location.href).searchParams.get('itemName');
        if (!itemName) return;

        const [publisher, extension] = itemName.split('.');
        const versionElement = document.querySelector('#versionHistoryTab tbody tr .version-history-container-column');
        if (!versionElement) return;

        const version = versionElement.textContent;
        const url = URL_VSIX_PATTERN
        .replace('${publisher}', publisher)
        .replace('${extension}', extension)
        .replace('${version}', version);

        window.open(url, '_blank');
    }

    // 等待页面加载完成后创建按钮
    window.addEventListener('load', function() {
        createFloatingButton();
    });
})();