IMVU Badge Granting Automation (Improved UI with URL-based Username)

Automate badge granting on IMVU avatars page with pop-out interface and clean layout

  1. // ==UserScript==
  2. // @name IMVU Badge Granting Automation (Improved UI with URL-based Username)
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.0
  5. // @description Automate badge granting on IMVU avatars page with pop-out interface and clean layout
  6. // @author heapsofjoy
  7. // @match https://avatars.imvu.com/*
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. (function() {
  12. 'use strict';
  13.  
  14. // Extract username from the URL
  15. const getUsernameFromUrl = () => {
  16. const url = window.location.href; // Get the current URL
  17. console.log("Current URL:", url); // Debugging: check if URL is correct
  18. const match = url.match(/https:\/\/avatars\.imvu\.com\/([A-Za-z0-9_]+)/); // Match the username part in the URL
  19. if (match) {
  20. console.log("Username extracted from URL:", match[1]); // Debugging: show username extracted
  21. return match[1];
  22. } else {
  23. console.error("Username extraction failed from URL."); // Error if username isn't found
  24. return null;
  25. }
  26. };
  27.  
  28. // Fetch CID for the entered username
  29. const getCid = (name) => {
  30. return fetch(`https://api.imvu.com/user?username=${name}`, { credentials: 'include' })
  31. .then(response => response.json())
  32. .then(data => {
  33. return Object.entries(data.denormalized)[0][1].data.legacy_cid;
  34. })
  35. .catch(err => {
  36. console.error("Error fetching CID:", err); // Debugging: if fetch fails
  37. });
  38. };
  39.  
  40. // Start granting badges
  41. let cancelGranting = false; // Flag to control the cancellation of the badge granting process
  42. const startGrantingBadges = async (referrer, outputBox, titleElement) => {
  43. const cid = await getCid(referrer);
  44. if (!cid) {
  45. showProgress(outputBox, 'Error: Unable to get CID for the username.');
  46. return;
  47. }
  48.  
  49. // Function to grant a badge
  50. const func = async (i) => {
  51. if (cancelGranting) return; // Stop if the user has clicked the stop button
  52.  
  53. // Grant the badge
  54. const response = await fetch('https://avatars.imvu.com/api/service/grant_badge.php', {
  55. credentials: 'include', // Include credentials (cookies/session info)
  56. headers: {
  57. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:87.0) Gecko/20100101 Firefox/87.0',
  58. 'Accept': '*/*',
  59. 'Accept-Language': 'en-US,en;q=0.5',
  60. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
  61. 'X-Requested-With': 'XMLHttpRequest',
  62. },
  63. referrer: `https://avatars.imvu.com/${referrer}`,
  64. body: `sauce=${IMVU.sauce}&badgeid=badge-${cid}-${i}`,
  65. method: 'POST',
  66. mode: 'cors',
  67. });
  68.  
  69. // If the badge was granted (check for successful response)
  70. if (response.ok) {
  71. showProgress(outputBox, `Granted badge #${i}`);
  72. } else {
  73. showProgress(outputBox, `Failed to grant badge #${i}. Trying next.`);
  74. }
  75. };
  76.  
  77. // Recursive function to iterate badge granting
  78. const recursive = async (i) => {
  79. if (cancelGranting) return; // Stop if the user has clicked the stop button
  80. setTimeout(async () => {
  81. await func(i); // Try granting the badge
  82. recursive(i + 1); // Move to the next badge
  83. }, 2500); // Delay between badge granting
  84. };
  85.  
  86. // Update the title to indicate the process is running
  87. titleElement.innerText = `Granting badges for ${referrer}...`;
  88.  
  89. // Start the recursive badge granting process
  90. recursive(1);
  91. };
  92.  
  93. // Show progress in the output box
  94. const showProgress = (outputBox, message) => {
  95. outputBox.textContent += `\n${message}`;
  96. outputBox.scrollTop = outputBox.scrollHeight; // Scroll to the bottom
  97. };
  98.  
  99. // Create pop-out button to toggle the interface visibility
  100. const createPopoutButton = () => {
  101. const button = document.createElement('button');
  102. button.innerText = '▶'; // Use a play button icon for a more intuitive look
  103. button.style.position = 'fixed';
  104. button.style.bottom = '20px';
  105. button.style.right = '20px';
  106. button.style.width = '40px';
  107. button.style.height = '40px';
  108. button.style.borderRadius = '50%';
  109. button.style.backgroundColor = '#4CAF50';
  110. button.style.color = 'white';
  111. button.style.border = 'none';
  112. button.style.fontSize = '20px';
  113. button.style.cursor = 'pointer';
  114. button.style.boxShadow = '0 4px 8px rgba(0,0,0,0.3)';
  115. button.style.transition = 'background-color 0.3s, transform 0.3s';
  116.  
  117. // Hover effect
  118. button.addEventListener('mouseover', () => {
  119. button.style.backgroundColor = '#45a049';
  120. button.style.transform = 'scale(1.1)';
  121. });
  122. button.addEventListener('mouseout', () => {
  123. button.style.backgroundColor = '#4CAF50';
  124. button.style.transform = 'scale(1)';
  125. });
  126.  
  127. // Toggle pop-out box visibility
  128. button.addEventListener('click', () => {
  129. const popoutBox = document.getElementById('badge-granting-box');
  130. popoutBox.style.display = (popoutBox.style.display === 'none' || !popoutBox.style.display) ? 'block' : 'none';
  131. });
  132.  
  133. document.body.appendChild(button);
  134. };
  135.  
  136. // Create the interface container
  137. const createInterfaceBox = () => {
  138. const box = document.createElement('div');
  139. box.id = 'badge-granting-box';
  140. box.style.position = 'fixed';
  141. box.style.bottom = '20px';
  142. box.style.right = '20px';
  143. box.style.width = '320px';
  144. box.style.height = '400px';
  145. box.style.backgroundColor = '#fff';
  146. box.style.border = '1px solid #ccc';
  147. box.style.borderRadius = '8px';
  148. box.style.boxShadow = '0 4px 8px rgba(0,0,0,0.3)';
  149. box.style.padding = '15px';
  150. box.style.display = 'none'; // Initially hidden
  151.  
  152. // Add Title Above Output Box
  153. const titleElement = document.createElement('h3');
  154. titleElement.innerText = 'Initializing...';
  155. titleElement.style.textAlign = 'center';
  156. titleElement.style.marginBottom = '10px';
  157. titleElement.style.fontSize = '18px';
  158. titleElement.style.fontWeight = 'bold';
  159. box.appendChild(titleElement);
  160.  
  161. // Create output box for displaying progress
  162. const outputBox = document.createElement('div');
  163. outputBox.style.height = '250px';
  164. outputBox.style.overflowY = 'auto';
  165. outputBox.style.backgroundColor = '#f8f8f8';
  166. outputBox.style.border = '1px solid #ccc';
  167. outputBox.style.borderRadius = '5px';
  168. outputBox.style.fontSize = '14px';
  169. outputBox.style.padding = '10px';
  170. outputBox.style.whiteSpace = 'pre-wrap'; // Preserve line breaks
  171. box.appendChild(outputBox);
  172.  
  173. // Create run and stop buttons
  174. const buttonContainer = document.createElement('div');
  175. buttonContainer.style.display = 'flex';
  176. buttonContainer.style.justifyContent = 'space-between';
  177. buttonContainer.style.marginTop = '10px';
  178.  
  179. // Run Button
  180. const runButton = document.createElement('button');
  181. runButton.innerText = 'Run';
  182. runButton.style.flex = '1';
  183. runButton.style.padding = '10px';
  184. runButton.style.backgroundColor = '#4CAF50';
  185. runButton.style.color = 'white';
  186. runButton.style.border = 'none';
  187. runButton.style.borderRadius = '5px';
  188. runButton.style.cursor = 'pointer';
  189. runButton.addEventListener('click', () => {
  190. const username = getUsernameFromUrl(); // Get username from the URL
  191. if (username) {
  192. showProgress(outputBox, 'Starting badge granting...');
  193. startGrantingBadges(username, outputBox, titleElement);
  194. } else {
  195. showProgress(outputBox, 'Error: Could not extract username.');
  196. }
  197. });
  198.  
  199. // Stop Button
  200. const stopButton = document.createElement('button');
  201. stopButton.innerText = 'Stop';
  202. stopButton.style.flex = '1';
  203. stopButton.style.padding = '10px';
  204. stopButton.style.backgroundColor = '#f44336';
  205. stopButton.style.color = 'white';
  206. stopButton.style.border = 'none';
  207. stopButton.style.borderRadius = '5px';
  208. stopButton.style.cursor = 'pointer';
  209. stopButton.addEventListener('click', () => {
  210. cancelGranting = true; // Stop the granting process
  211. showProgress(outputBox, 'Process stopped.');
  212. titleElement.innerText = 'Stopped';
  213. });
  214.  
  215. buttonContainer.appendChild(runButton);
  216. buttonContainer.appendChild(stopButton);
  217. box.appendChild(buttonContainer);
  218.  
  219. document.body.appendChild(box);
  220. };
  221.  
  222. // Initialize everything
  223. createPopoutButton();
  224. createInterfaceBox();
  225. })();