Chrome Extension Button Enabler

Enables the "Add to Chrome" button for extensions marked as not following best practices

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

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

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

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

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

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

(I already have a user script manager, let me install it!)

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.

ستحتاج إلى تثبيت إضافة مثل Stylus لتثبيت هذا النمط.

ستحتاج إلى تثبيت إضافة لإدارة أنماط المستخدم لتتمكن من تثبيت هذا النمط.

ستحتاج إلى تثبيت إضافة لإدارة أنماط المستخدم لتثبيت هذا النمط.

ستحتاج إلى تثبيت إضافة لإدارة أنماط المستخدم لتثبيت هذا النمط.

(لدي بالفعل مثبت أنماط للمستخدم، دعني أقم بتثبيته!)

// ==UserScript==
// @name         Chrome Extension Button Enabler
// @name:zh-CN   Chrome扩展按钮启用器
// @name:en      Chrome Extension Button Enabler
// @namespace    http://tampermonkey.net/
// @version      1.0
// @license      MIT
// @description  Enables the "Add to Chrome" button for extensions marked as not following best practices
// @description:zh-CN  启用被标记为"未遵循最佳实践"的Chrome扩展的"添加至Chrome"按钮
// @description:en  Enables the "Add to Chrome" button for extensions marked as not following best practices
// @author       h7ml <[email protected]>
// @match        https://chrome.google.com/webstore/detail/*
// @match        https://chromewebstore.google.com/*
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';
    
    // 国际化支持: 支持多种语言的"添加到Chrome"按钮文本
    // Internationalization support: "Add to Chrome" button text in multiple languages
    const buttonTexts = {
        'en': 'Add to Chrome',
        'zh-CN': '添加至 Chrome',
        'zh-TW': '新增至 Chrome',
        'ja': 'Chromeに追加',
        'ko': 'Chrome에 추가',
        'de': 'Zu Chrome hinzufügen',
        'fr': 'Ajouter à Chrome',
        'es': 'Añadir a Chrome',
        'pt': 'Adicionar ao Chrome',
        'ru': 'Добавить в Chrome',
        'it': 'Aggiungi a Chrome',
        'ar': 'إضافة إلى Chrome',
        'hi': 'Chrome में जोड़ें',
        'tr': 'Chrome\'a ekle',
        'nl': 'Toevoegen aan Chrome',
        'pl': 'Dodaj do Chrome',
        'vi': 'Thêm vào Chrome',
        'th': 'เพิ่มใน Chrome'
    };
    
    // 启用按钮函数: 查找并启用被禁用的"添加到Chrome"按钮
    // Function to enable the button: Find and enable the disabled "Add to Chrome" button
    function enableButton() {
        // 通过多种方法定位目标按钮
        // Target the specific button using various methods
        let addButton = null;
        
        // 方法1: 使用提供的选择器
        // Method 1: Using the provided selector
        addButton = document.querySelector('button.UywwFc-LgbsSe.UywwFc-LgbsSe-OWXEXe-dgl2Hf.UywwFc-StrnGf-YYd4I-VtOx3e[jsname="wQO0od"]');
        
        if (!addButton) {
            // 方法2: 尝试通过可能常见的类名模式查找
            // Method 2: Try to find by class name patterns that might be common
            addButton = document.querySelector('button[disabled][jsname="wQO0od"]');
        }
        
        if (!addButton) {
            // 方法3: 尝试通过不同语言的按钮文本内容查找
            // Method 3: Try to find by content in different languages
            for (const lang in buttonTexts) {
                const buttonByText = Array.from(document.querySelectorAll('button')).find(
                    button => button.textContent.includes(buttonTexts[lang])
                );
                
                if (buttonByText) {
                    addButton = buttonByText;
                    break;
                }
            }
        }
        
        if (!addButton) {
            // 方法4: 查找任何可能是安装按钮的禁用按钮
            // Method 4: Find any disabled button that might be the install button
            const disabledButtons = document.querySelectorAll('button[disabled]');
            for (const button of disabledButtons) {
                // 检查是否可能是安装按钮(通常具有一些独特的类或属性)
                // Check if it's likely the install button (usually has some distinctive classes or attributes)
                if (button.classList.contains('UywwFc-LgbsSe') || 
                    button.hasAttribute('jscontroller') ||
                    button.querySelector('.UywwFc-vQzf8d')) {
                    addButton = button;
                    break;
                }
            }
        }
        
        if (addButton) {
            // 移除禁用属性
            // Remove the disabled attribute
            addButton.removeAttribute('disabled');
            
            // 使按钮在视觉上显示为启用状态
            // Make the button visually appear enabled
            addButton.style.opacity = '1';
            addButton.style.cursor = 'pointer';
            addButton.style.pointerEvents = 'auto';
            
            // 移除可能阻止点击的类
            // Remove classes that might prevent clicking
            const classesToRemove = ['UywwFc-LgbsSe-OWXEXe-QVCGsb', 'UywwFc-LgbsSe-OWXEXe-QVCGsb-Rt6MAe'];
            classesToRemove.forEach(className => {
                if (addButton.classList.contains(className)) {
                    addButton.classList.remove(className);
                }
            });
            
            // 如果可能,设置aria-disabled为false
            // Set aria-disabled to false if possible
            if (addButton.hasAttribute('aria-disabled')) {
                addButton.setAttribute('aria-disabled', 'false');
            }
            
            // 添加点击事件监听器,处理可能的覆盖层问题
            // Add click event listener to handle potential overlay issues
            addButton.addEventListener('click', function(e) {
                // 有时可能有不可见的覆盖层阻止点击
                // 这段代码帮助确保点击能够通过
                // Sometimes there might be invisible overlays preventing clicks
                // This code helps ensure the click gets through
                if (!e.isTrusted) {
                    return; // 只处理真实的用户点击 / Only process real user clicks
                }
                
                // 如果Chrome有额外的JS检查,尝试模拟一个干净的点击
                // In case Chrome has additional JS checks, try to simulate a clean click
                setTimeout(() => {
                    const clickEvent = new MouseEvent('click', {
                        bubbles: true,
                        cancelable: true,
                        view: window
                    });
                    addButton.dispatchEvent(clickEvent);
                }, 100);
            });
            
            return true; // 表示成功找到并启用按钮 / Indicate successful button finding and enabling
        } else {
            setTimeout(enableButton, 1000);
            return false; // 表示未找到按钮 / Indicate button not found
        }
    }
    
    // 初始化函数
    // Initialization function
    function initialize() {
        // 初次尝试启用按钮
        // Initial try to enable button
        enableButton();
        
        // 设置定期检查,以防按钮动态加载
        // Set up a periodic check in case the button loads dynamically
        const checkInterval = setInterval(function() {
            const possibleButtons = document.querySelectorAll('button[disabled]');
            let needToEnable = false;
            
            possibleButtons.forEach(button => {
                // 检查是否与已知的按钮文本匹配
                // Check for any text match with our known button texts
                for (const lang in buttonTexts) {
                    if (button.textContent.includes(buttonTexts[lang])) {
                        needToEnable = true;
                        break;
                    }
                }
                
                // 同时检查我们已知的特定类
                // Also check for the specific class we know about
                if (button.classList.contains('UywwFc-LgbsSe')) {
                    needToEnable = true;
                }
            });
            
            if (needToEnable) {
                enableButton();
            }
        }, 2000);
        
        // 30秒后停止检查,避免不必要的处理
        // Stop checking after 30 seconds to avoid unnecessary processing
        setTimeout(() => {
            clearInterval(checkInterval);
        }, 30000);
        
        // 设置变异观察器,检测按钮可能被动态添加的情况
        // Set up a mutation observer to detect when the button might be added dynamically
        const observer = new MutationObserver(function(mutations) {
            let shouldEnableButton = false;
            
            mutations.forEach(function(mutation) {
                if (mutation.addedNodes && mutation.addedNodes.length > 0) {
                    // 检查是否添加了禁用的按钮
                    // Check if any disabled buttons were added
                    for (let i = 0; i < mutation.addedNodes.length; i++) {
                        const node = mutation.addedNodes[i];
                        if (node.nodeType === 1) { // 元素节点 / Element node
                            if (node.tagName === 'BUTTON' && node.hasAttribute('disabled')) {
                                shouldEnableButton = true;
                                break;
                            } else if (node.querySelector && node.querySelector('button[disabled]')) {
                                shouldEnableButton = true;
                                break;
                            }
                        }
                    }
                } else if (mutation.type === 'attributes' && 
                          mutation.attributeName === 'disabled' && 
                          mutation.target.tagName === 'BUTTON') {
                    // 如果按钮的disabled属性发生变化
                    // If a button's disabled attribute changes
                    shouldEnableButton = true;
                }
            });
            
            if (shouldEnableButton) {
                enableButton();
            }
        });
        
        // 开始观察文档主体的变化
        // Begin observing the document body for changes
        observer.observe(document.body, { 
            childList: true,      // 监听子节点添加或删除 / Monitor child node additions or removals
            subtree: true,        // 监听所有后代节点 / Monitor all descendant nodes
            attributes: true,     // 监听属性变化 / Monitor attribute changes
            attributeFilter: ['disabled'] // 只监听disabled属性 / Only monitor the disabled attribute
        });
    }
    
    // 判断文档是否已经加载完成
    // Check if document is already loaded
    if (document.readyState === 'loading') {
        window.addEventListener('DOMContentLoaded', initialize);
    } else {
        initialize();
    }
    
    // 确保在页面完全加载后也尝试启用按钮
    // Ensure we also try to enable the button after the page is fully loaded
    window.addEventListener('load', function() {
        enableButton();
    });
    
    // 导出启用函数到全局,方便在控制台手动调用
    // Export enable function to global scope for manual calls from console
    window.__chromeButtonEnabler = {
        enableButton: enableButton
    };
})();