IMVU Product Download CFL Revisions Dropdown

Adds a single dropdown button with all available CFL revisions for IMVU products, with forced .cfl download.

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください。
// ==UserScript==
// @name         IMVU Product Download CFL Revisions Dropdown
// @namespace    http://tampermonkey.net/
// @version      1.0
// @auther       heapsofjoy
// @description  Adds a single dropdown button with all available CFL revisions for IMVU products, with forced .cfl download.
// @match        https://www.imvu.com/shop/product.php?products_id=*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // Extract the product ID from the URL
    const urlParams = new URLSearchParams(window.location.search);
    const productId = urlParams.get('products_id');
    if (!productId) return; // Exit if no productId found

    // Set the HTTPS base URL for the product files
    const baseUrl = `https://userimages-akm.imvu.com/productdata/${productId}`;

    // Create the dropdown button
    const dropdownButton = document.createElement('button');
    dropdownButton.innerHTML = '📥';
    dropdownButton.title = 'Download CFL Revisions';
    dropdownButton.style.position = 'fixed';
    dropdownButton.style.bottom = '10px';
    dropdownButton.style.right = '10px';
    dropdownButton.style.width = '40px';
    dropdownButton.style.height = '40px';
    dropdownButton.style.backgroundColor = '#ff69b4';
    dropdownButton.style.color = 'white';
    dropdownButton.style.border = 'none';
    dropdownButton.style.borderRadius = '20px';
    dropdownButton.style.cursor = 'pointer';
    dropdownButton.style.fontFamily = 'Arial, sans-serif';
    dropdownButton.style.fontSize = '20px';
    dropdownButton.style.boxShadow = '0px 4px 10px rgba(0,0,0,0.2)';
    dropdownButton.style.zIndex = '1000';

    // Create the dropdown menu (initially hidden and positioned above the button)
    const dropdownMenu = document.createElement('div');
    dropdownMenu.style.display = 'none';
    dropdownMenu.style.position = 'fixed';
    dropdownMenu.style.bottom = '60px';
    dropdownMenu.style.right = '10px';
    dropdownMenu.style.width = '250px';
    dropdownMenu.style.backgroundColor = 'rgba(0, 0, 0, 0.85)';
    dropdownMenu.style.color = 'white';
    dropdownMenu.style.padding = '10px';
    dropdownMenu.style.border = '1px solid #ddd';
    dropdownMenu.style.borderRadius = '10px';
    dropdownMenu.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.2)';
    dropdownMenu.style.zIndex = '1001';

    // Toggle dropdown menu visibility and button expansion on click
    dropdownButton.onclick = () => {
        dropdownMenu.style.display = dropdownMenu.style.display === 'none' ? 'block' : 'none';
        dropdownButton.style.width = dropdownMenu.style.display === 'none' ? '40px' : '60px';
        dropdownButton.style.height = dropdownMenu.style.display === 'none' ? '40px' : '40px';
        dropdownButton.innerHTML = dropdownMenu.style.display === 'none' ? '📥' : 'Close ▼';
    };

    // Function to add a revision link to the dropdown menu
    function addRevisionLink(revision) {
        const revisionLink = document.createElement('a');
        revisionLink.textContent = `Download Revision ${revision}`;
        revisionLink.style.display = 'block';
        revisionLink.style.padding = '8px 0';
        revisionLink.style.color = '#ff69b4';
        revisionLink.style.textDecoration = 'none';
        revisionLink.style.borderBottom = '1px solid #444';

        // Add click handler to fetch and download the file with .cfl extension
        revisionLink.onclick = (event) => {
            event.preventDefault();
            const fileUrl = `${baseUrl}/${revision}`;

            // Fetch the file, create a Blob, and trigger a download
            fetch(fileUrl)
                .then(response => response.blob())
                .then(blob => {
                    const downloadUrl = URL.createObjectURL(blob);
                    const a = document.createElement('a');
                    a.href = downloadUrl;
                    a.download = `${productId}_revision_${revision}.cfl`;
                    document.body.appendChild(a);
                    a.click();
                    a.remove();
                    URL.revokeObjectURL(downloadUrl); // Clean up URL object
                })
                .catch(error => console.error(`Failed to download revision ${revision}:`, error));
        };

        // Add the link to the dropdown menu
        dropdownMenu.appendChild(revisionLink);
    }

    // Function to check if a revision exists
    function checkRevision(revision) {
        const url = `${baseUrl}/${revision}`;
        fetch(url, { method: 'HEAD' })
            .then((response) => {
                if (response.ok) {
                    addRevisionLink(revision); // Add link if the revision exists
                    checkRevision(revision + 1); // Check the next revision
                }
            })
            .catch((error) => console.error(`Failed to fetch revision ${revision}:`, error));
    }

    // Start checking from revision 1
    checkRevision(1);

    // Append the dropdown button and menu to the page
    document.body.appendChild(dropdownButton);
    document.body.appendChild(dropdownMenu);

    // Hide dropdown if clicked outside
    document.addEventListener('click', (event) => {
        if (!dropdownButton.contains(event.target) && !dropdownMenu.contains(event.target)) {
            dropdownMenu.style.display = 'none';
            dropdownButton.innerHTML = '📥';
            dropdownButton.style.width = '40px';
            dropdownButton.style.height = '40px';
        }
    });
})();