Free Blendermarket Downloader

Add Free Download button to Blendermarket products.

当前为 2024-11-18 提交的版本,查看 最新版本

// ==UserScript==
// @name         Free Blendermarket Downloader
// @description  Add Free Download button to Blendermarket products.
// @icon         https://assets.superhivemarket.com/site_assets/images/black_bee.png
// @version      1.0
// @author       afkarxyz
// @namespace    https://github.com/afkarxyz/misc-scripts/
// @supportURL   https://github.com/afkarxyz/misc-scripts/issues
// @license      MIT
// @match        https://blendermarket.com/*
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';

    let lastUrl = location.href;
    let observer = null;

    function getProductNameFromURL() {
        const currentURL = window.location.href;
        const match = currentURL.match(/products\/([^/?]+)/);
        if (match) {
            return decodeURIComponent(match[1].replace(/-/g, ' '));
        }
        return '';
    }

    function createCGDownloadURL(productName) {
        return `https://cgdownload.ru/?s=${encodeURIComponent(productName)}`;
    }

    function clearExistingButton() {
        const existingButton = document.querySelector('.cgdownload-button');
        if (existingButton) {
            existingButton.remove();
        }
    }

    function createButtonContent() {
        const container = document.createElement('div');
        container.style.display = 'flex';
        container.style.alignItems = 'center';
        container.style.justifyContent = 'center';
        container.style.gap = '8px';

        const img = document.createElement('img');
        img.src = 'https://cgdownload.ru/wp-content/themes/dark/images/mstile-150x150.png';
        img.style.height = '20px';
        img.style.width = '20px';
        img.alt = 'CGDownload Icon';

        const span = document.createElement('span');
        span.textContent = 'Free Download';

        container.appendChild(img);
        container.appendChild(span);
        
        return container;
    }

    function addDownloadButton() {
        if (!window.location.href.includes('/products/')) {
            return;
        }

        clearExistingButton();

        const originalForm = document.querySelector('.button_to');
        if (!originalForm) {
            return;
        }

        const newButton = document.createElement('button');
        newButton.className = 'btn btn-primary d-grid btn-lg shadow w-100 mt-2 cgdownload-button';
        newButton.appendChild(createButtonContent());

        newButton.addEventListener('click', function(e) {
            e.preventDefault();
            const productName = getProductNameFromURL();
            if (productName) {
                const cgdownloadURL = createCGDownloadURL(productName);
                window.open(cgdownloadURL, '_blank');
            }
        });

        originalForm.insertAdjacentElement('afterend', newButton);
    }

    function startObserver() {
        if (observer) {
            observer.disconnect();
        }

        observer = new MutationObserver((mutations) => {
            const buttonForm = document.querySelector('.button_to');
            const existingButton = document.querySelector('.cgdownload-button');
            
            if (buttonForm && !existingButton) {
                addDownloadButton();
            }
        });

        observer.observe(document.body, {
            childList: true,
            subtree: true
        });

        addDownloadButton();
    }

    function setupHistoryListener() {
        const pushState = history.pushState;
        history.pushState = function() {
            pushState.apply(history, arguments);
            startObserver();
        };

        const replaceState = history.replaceState;
        history.replaceState = function() {
            replaceState.apply(history, arguments);
            startObserver();
        };

        window.addEventListener('popstate', startObserver);
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', () => {
            setupHistoryListener();
            startObserver();
        });
    } else {
        setupHistoryListener();
        startObserver();
    }

    setInterval(() => {
        if (location.href !== lastUrl) {
            lastUrl = location.href;
            startObserver();
        }
    }, 100);

})();