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.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';
}
});
})();