IMVU Product Download CFL Revisions Dropdown

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         IMVU Product Download CFL Revisions Dropdown
// @namespace    http://tampermonkey.net/
// @version      1.3
// @auther       heapsofjoy
// @description  Adds a single dropdown button with all available CFL revisions for IMVU products, with forced .cfl download.
// @match        *://*.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 = 'o';
    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 addRevisionLink(revision) {
    const revisionLink = document.createElement('a');
    revisionLink.textContent = `View 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';

    // Just open the JSON file in a new tab
    revisionLink.href = `${baseUrl}/${revision}/_contents.json`;
    revisionLink.target = '_blank';
    revisionLink.rel = 'noopener noreferrer';

    dropdownMenu.appendChild(revisionLink);
}


    // Function to check if a revision exists
    function checkRevision(revision, misses = 0, maxMisses = 10) {
        const url = `${baseUrl}/${revision}/_contents.json`;
        fetch(url, { method: 'HEAD' })
            .then((response) => {
                if (response.ok) {
                    addRevisionLink(revision);
                    checkRevision(revision + 1, 0, maxMisses); // Reset misses on success
                } else {
                    if (misses < maxMisses) {
                        checkRevision(revision + 1, misses + 1, maxMisses);
                    }
                }
            })
            .catch(() => {
                if (misses < maxMisses) {
                    checkRevision(revision + 1, misses + 1, maxMisses);
                }
            });
    }    

    checkRevision(1, 0, 10);

    // 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 = 'o';
            dropdownButton.style.width = '40px';
            dropdownButton.style.height = '40px';
        }
    });
})();