IMVU Product Minimal Revision Viewer

Adds a simple CFL revision dropdown next to "Try it On" for IMVU products, showing only real revisions.

目前為 2025-04-13 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name IMVU Product Minimal Revision Viewer
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.1.1
  5. // @description Adds a simple CFL revision dropdown next to "Try it On" for IMVU products, showing only real revisions.
  6. // @author heapsofjoy
  7. // @match *://*.imvu.com/shop/product.php?products_id=*
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. (function () {
  12. 'use strict';
  13.  
  14. // Step 1: Get product ID
  15. const urlParams = new URLSearchParams(window.location.search);
  16. const productId = urlParams.get('products_id');
  17. if (!productId) return;
  18.  
  19. const baseUrl = `https://userimages-akm.imvu.com/productdata/${productId}`;
  20.  
  21. // Step 2: Locate "Try it On" button
  22. const tryOnLink = document.getElementById('try-on-link');
  23. if (!tryOnLink) return;
  24.  
  25. // Step 3: Create a wrapper span to contain both buttons
  26. const wrapper = document.createElement('span');
  27. wrapper.style.display = 'inline-flex';
  28. wrapper.style.alignItems = 'center';
  29. wrapper.style.gap = '6px';
  30. tryOnLink.parentNode.insertBefore(wrapper, tryOnLink);
  31.  
  32. // Step 4: Create CFL button
  33. const toggleButton = document.createElement('button');
  34. toggleButton.textContent = 'contents.json';
  35. toggleButton.style.background = '#eee';
  36. toggleButton.style.border = '1px solid #ccc';
  37. toggleButton.style.borderRadius = '3px';
  38. toggleButton.style.padding = '2px 6px';
  39. toggleButton.style.fontSize = '12px';
  40. toggleButton.style.cursor = 'pointer';
  41.  
  42. // Step 5: Create dropdown container
  43. const dropdown = document.createElement('div');
  44. dropdown.style.display = 'none';
  45. dropdown.style.position = 'absolute';
  46. dropdown.style.background = '#fff';
  47. dropdown.style.border = '1px solid #ccc';
  48. dropdown.style.padding = '6px';
  49. dropdown.style.borderRadius = '4px';
  50. dropdown.style.boxShadow = '0 2px 5px rgba(0,0,0,0.1)';
  51. dropdown.style.maxHeight = '180px';
  52. dropdown.style.overflowY = 'auto';
  53. dropdown.style.fontSize = '12px';
  54. dropdown.style.zIndex = '999';
  55.  
  56. // Step 6: Toggle visibility
  57. toggleButton.addEventListener('click', () => {
  58. dropdown.style.display = dropdown.style.display === 'block' ? 'none' : 'block';
  59. });
  60.  
  61. // Step 7: Function to handle revision checking
  62. function checkRevision(revision, misses = 0, maxMisses = 10) {
  63. const url = `${baseUrl}/${revision}/_contents.json`;
  64. fetch(url, { method: 'HEAD' })
  65. .then((response) => {
  66. if (response.ok) {
  67. const link = document.createElement('a');
  68. link.href = url;
  69. link.textContent = `Revision ${revision}`;
  70. link.target = '_blank';
  71. link.style.display = 'block';
  72. link.style.color = '#007bff';
  73. link.style.textDecoration = 'none';
  74. link.style.margin = '3px 0';
  75. dropdown.appendChild(link);
  76. checkRevision(revision + 1, 0, maxMisses); // Reset misses on success
  77. } else {
  78. if (misses < maxMisses) {
  79. checkRevision(revision + 1, misses + 1, maxMisses); // Allow up to maxMisses failures
  80. }
  81. }
  82. })
  83. .catch(() => {
  84. if (misses < maxMisses) {
  85. checkRevision(revision + 1, misses + 1, maxMisses); // Handle fetch failure
  86. }
  87. });
  88. }
  89.  
  90. // Start checking from revision 1
  91. checkRevision(1, 0, 10);
  92.  
  93. // Step 8: Optional fallback if no revisions found
  94. setTimeout(() => {
  95. if (dropdown.children.length === 0) {
  96. const msg = document.createElement('div');
  97. msg.textContent = 'No revisions found.';
  98. msg.style.color = '#666';
  99. dropdown.appendChild(msg);
  100. }
  101. }, 2000);
  102.  
  103. // Step 9: Insert everything
  104. const container = document.createElement('div');
  105. container.style.position = 'relative';
  106. container.appendChild(toggleButton);
  107. container.appendChild(dropdown);
  108.  
  109. wrapper.appendChild(container);
  110. wrapper.appendChild(tryOnLink);
  111. })();