您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Customize gradients and colors on cracked.io, add particle effects, and integrate a YouTube music player with loop functionality.
// ==UserScript== // @name Spectify // @version 1.0 // @description Customize gradients and colors on cracked.io, add particle effects, and integrate a YouTube music player with loop functionality. // @author SpEc // @match https://*.cracked.io/* // @icon https://static.cracked.io/uploads/avatars/avatar_3116424.gif?dateline=1719456680 // @grant none // @supportURL https://cracked.io/spec // @license MIT // @namespace https://your-unique-namespace.com/ // ==/UserScript== (function() { 'use strict'; // ========================= // 1. Define Themes // ========================= const baseThemes = { 'Custom Theme': { '--gradient-1': '#4B0000', '--gradient-2': '#2A2A2A', '--gradient-3': '#1C1C1C', '--gradient-4': '#333333', '--background-main': '#000000', '--background-secondary': '#1E1E1E', '--background-light': '#2C2C2C', '--background-floating': '#2A2A2A', '--background-floating-alt': '#333333', '--background-floating-light': '#262626', '--border-color': '#444444', '--border': '1px solid var(--border-color)', '--radius': '10px', '--banner-padding': '20px', '--btn': '#4444447a', '--btn-hover': 'linear-gradient(45deg, #CCCCCC, #999999)', '--dropdown-hover': 'linear-gradient(45deg, #999999, #CCCCCC)', '--text-dark': '#FFFFFF', '--forumtabs-icon-color': '#2adbf9a3', '--panel-upper-icon-color': '#ff302e', '--trow-border-top-color': '#ff0000', '--trow-border-bottom-color': '#1b1b1b', '--trow-text-color': '#f90a0a', '--reputation-positive-color': '#a13a3a', '--helpdocs-number-color': '#00b6e1', '--footer-color': '#1E1E1E', '--particle-color': '#FFFFFF', '--particle-sway-amplitude': '50px' }, 'Ocean Blue': { '--gradient-1': '#1A2980', '--gradient-2': '#26D0CE', '--gradient-3': '#2980B9', '--gradient-4': '#6DD5FA', '--background-main': '#001f3f', '--background-secondary': '#004085', '--background-light': '#0b1b2d', '--background-floating': '#004085', '--background-floating-alt': '#0056b3', '--background-floating-light': '#007bff', '--border-color': '#0056b3', '--border': '1px solid var(--border-color)', '--radius': '10px', '--banner-padding': '20px', '--btn': '#007bff7a', '--btn-hover': 'linear-gradient(45deg, #66b3ff, #3399ff)', '--dropdown-hover': 'linear-gradient(45deg, #3399ff, #66b3ff)', '--text-dark': '#FFFFFF', '--forumtabs-icon-color': '#66FF66', '--panel-upper-icon-color': '#33CC33', '--trow-border-top-color': '#33CC33', '--trow-border-bottom-color': '#1b1b1b', '--trow-text-color': '#66FF66', '--reputation-positive-color': '#3cb371', '--helpdocs-number-color': '#7CFC00', '--footer-color': '#004085', '--particle-color': '#66B2FF', '--particle-sway-amplitude': '70px' }, 'Neon Lights': { '--gradient-1': '#ff00cc', '--gradient-2': '#333399', '--gradient-3': '#cc00ff', '--gradient-4': '#6600ff', '--background-main': '#111111', '--background-secondary': '#222222', '--background-light': '#333333', '--background-floating': '#444444', '--background-floating-alt': '#555555', '--background-floating-light': '#666666', '--border-color': '#ff00cc', '--border': '1px solid var(--border-color)', '--radius': '10px', '--banner-padding': '20px', '--btn': '#ff00cc7a', '--btn-hover': 'linear-gradient(45deg, #ff66cc, #cc33ff)', '--dropdown-hover': 'linear-gradient(45deg, #cc33ff, #ff66cc)', '--text-dark': '#FFFFFF', '--forumtabs-icon-color': '#ff66cc', '--panel-upper-icon-color': '#cc33ff', '--trow-border-top-color': '#cc33ff', '--trow-border-bottom-color': '#1b1b1b', '--trow-text-color': '#ff66cc', '--reputation-positive-color': '#ff1493', '--helpdocs-number-color': '#ff69b4', '--footer-color': '#cc33ff', '--particle-color': '#FF66CC', '--particle-sway-amplitude': '60px' }, 'Forest Green': { '--gradient-1': '#265d26', '--gradient-2': '#006400', '--gradient-3': '#2e8b56', '--gradient-4': '#3cb372', '--background-main': '#0B3D0B', '--background-secondary': '#145214', '--background-light': '#1E691E', '--background-floating': '#256025', '--background-floating-alt': '#2E8B57', '--background-floating-light': '#3FA06F', '--border-color': '#145214', '--border': '1px solid var(--border-color)', '--radius': '10px', '--banner-padding': '20px', '--btn': '#1A1A1A', '--btn-hover': 'linear-gradient(45deg, #33cc33, #009900)', '--dropdown-hover': 'linear-gradient(45deg, #009900, #33cc33)', '--text-dark': '#f0f0f0', '--forumtabs-icon-color': '#33cc33', '--panel-upper-icon-color': '#009900', '--trow-border-top-color': '#009900', '--trow-border-bottom-color': '#1b1b1b', '--trow-text-color': '#33cc33', '--reputation-positive-color': '#2E8B57', '--helpdocs-number-color': '#6ECB00', '--footer-color': '#145214', '--particle-color': '#66FF66', '--particle-sway-amplitude': '80px' }, 'Sunset Glow': { '--gradient-1': '#FF5F6D', '--gradient-2': '#FFC371', '--gradient-3': '#FF9A8B', '--gradient-4': '#FF3F4A', '--background-main': '#0d0d0d', '--background-secondary': '#1E1E1E', '--background-light': '#2C2C2C', '--background-floating': '#2A2A2A', '--background-floating-alt': '#333333', '--background-floating-light': '#262626', '--border-color': '#444444', '--border': '1px solid var(--border-color)', '--radius': '10px', '--banner-padding': '20px', '--btn': '#4444447a', '--btn-hover': 'linear-gradient(45deg, #FF5F6D, #FFC371)', '--dropdown-hover': 'linear-gradient(45deg, #FFC371, #FF9A8B)', '--text-dark': '#FFFFFF', '--forumtabs-icon-color': '#2adbf9a3', '--panel-upper-icon-color': '#ff302e', '--trow-border-top-color': '#ff0000', '--trow-border-bottom-color': '#1b1b1b', '--trow-text-color': '#f90a0a', '--reputation-positive-color': '#a13a3a', '--helpdocs-number-color': '#00b6e1', '--footer-color': '#1E1E1E', '--particle-color': '#FF5F6D', '--particle-sway-amplitude': '50px' }, 'Christmas': { '--gradient-1': '#8B0000', '--gradient-2': '#006400', '--gradient-3': '#CDA434', '--gradient-4': '#B22222', '--background-main': '#0A0A0A', '--background-secondary': '#141414', '--background-light': '#1A1A1A', '--background-floating': '#141414', '--background-floating-alt': '#1A1A1A', '--background-floating-light': '#262626', '--border-color': '#004D40', '--border': '1px solid var(--border-color)', '--radius': '10px', '--banner-padding': '20px', '--btn': '#004D407a', '--btn-hover': 'linear-gradient(45deg, #8B0000, #006400)', '--dropdown-hover': 'linear-gradient(45deg, #006400, #8B0000)', '--text-dark': '#ECEFF1', '--forumtabs-icon-color': '#8B0000', '--panel-upper-icon-color': '#006400', '--trow-border-top-color': '#006400', '--trow-border-bottom-color': '#1b1b1b', '--trow-text-color': '#28a745', '--reputation-positive-color': '#28a745', '--helpdocs-number-color': '#28a745', '--footer-color': '#006400', '--particle-color': '#FFFFFF', '--particle-sway-amplitude': '60px' }, 'Space Theme': { '--gradient-1': '#000000', '--gradient-2': '#0d0d0d', '--gradient-3': '#1a1a1a', '--gradient-4': '#262626', '--background-main': '#000000', '--background-secondary': '#0a0a0a', '--background-light': '#141414', '--background-floating': '#1c1c1c', '--background-floating-alt': '#262626', '--background-floating-light': '#2e2e2e', '--border-color': '#444444', '--border': '1px solid var(--border-color)', '--radius': '10px', '--banner-padding': '20px', '--btn': '#3d3d3d7a', '--btn-hover': 'linear-gradient(45deg, #666666, #333333)', '--dropdown-hover': 'linear-gradient(45deg, #333333, #666666)', '--text-dark': '#ffffff', '--forumtabs-icon-color': '#888888', '--panel-upper-icon-color': '#aaaaaa', '--trow-border-top-color': '#4a4a4a', '--trow-border-bottom-color': '#1a1a1a', '--trow-text-color': '#ffffff', '--reputation-positive-color': '#4a4a4a', '--helpdocs-number-color': '#b3b3b3', '--footer-color': '#000000', '--particle-color': '#ffffff', '--particle-sway-amplitude': '50px', '--snow-enabled': 'true' } }; // ========================= // 2. Utility Functions // ========================= // Function to apply CSS variables to :root function applyCSSVariables(variables) { const root = document.documentElement; for (let varName in variables) { root.style.setProperty(varName, variables[varName]); } } // Function to extract YouTube Video ID using URL API function extractYouTubeID(url) { try { const parsedURL = new URL(url); if (parsedURL.hostname.includes('youtube.com')) { return parsedURL.searchParams.get('v'); } else if (parsedURL.hostname === 'youtu.be') { return parsedURL.pathname.slice(1); } else { return null; } } catch (e) { return null; } } // Function to convert HEX to HSL function hexToHSL(hex) { // Convert hex to RGB first let r = 0, g = 0, b = 0; if (hex.length === 4) { r = parseInt(hex[1] + hex[1], 16); g = parseInt(hex[2] + hex[2], 16); b = parseInt(hex[3] + hex[3], 16); } else if (hex.length === 7) { r = parseInt(hex[1] + hex[2], 16); g = parseInt(hex[3] + hex[4], 16); b = parseInt(hex[5] + hex[6], 16); } r /= 255; g /= 255; b /= 255; let cmin = Math.min(r, g, b), cmax = Math.max(r, g, b), delta = cmax - cmin, h = 0, s = 0, l = 0; if (delta === 0) h = 0; else if (cmax === r) h = ((g - b) / delta) % 6; else if (cmax === g) h = (b - r) / delta + 2; else h = (r - g) / delta + 4; h = Math.round(h * 60); if (h < 0) h += 360; l = (cmax + cmin) / 2; s = delta === 0 ? 0 : delta / (1 - Math.abs(2 * l - 1)); s = +(s * 100).toFixed(1); l = +(l * 100).toFixed(1); return {h, s, l}; } // Function to convert HSL to HEX function HSLToHex(h, s, l) { s /= 100; l /= 100; let c = (1 - Math.abs(2 * l - 1)) * s, x = c * (1 - Math.abs((h / 60) % 2 - 1)), m = l - c / 2, r = 0, g = 0, b = 0; if (0 <= h && h < 60) { r = c; g = x; b = 0; } else if (60 <= h && h < 120) { r = x; g = c; b = 0; } else if (120 <= h && h < 180) { r = 0; g = c; b = x; } else if (180 <= h && h < 240) { r = 0; g = x; b = c; } else if (240 <= h && h < 300) { r = x; g = 0; b = c; } else if (300 <= h && h < 360) { r = c; g = 0; b = x; } r = Math.round((r + m) * 255).toString(16).padStart(2, '0'); g = Math.round((g + m) * 255).toString(16).padStart(2, '0'); b = Math.round((b + m) * 255).toString(16).padStart(2, '0'); return `#${r}${g}${b}`; } // Function to adjust hue and saturation function adjustHueSaturation(hex, hueShift, saturationShift) { const hsl = hexToHSL(hex); hsl.h = (hsl.h + hueShift) % 360; hsl.s = Math.min(Math.max(hsl.s + saturationShift, 0), 100); // Clamp between 0 and 100 return HSLToHex(hsl.h, hsl.s, hsl.l); } // Function to adjust gradient hues and saturations function adjustGradient(gradient, hueShift, saturationShift) { // Regex to match hex colors in the gradient const hexColorRegex = /#([0-9A-Fa-f]{3}){1,2}/g; const colors = gradient.match(hexColorRegex); if (!colors) return gradient; let adjustedGradient = gradient; colors.forEach(color => { const adjustedColor = adjustHueSaturation(color, hueShift, saturationShift); adjustedGradient = adjustedGradient.replace(color, adjustedColor); }); return adjustedGradient; } // ========================= // 3. Cookie Management Functions // ========================= // Function to set a cookie function setCookie(name, value, days) { let expires = ""; if (days) { const date = new Date(); date.setTime(date.getTime() + (days*24*60*60*1000)); expires = "; expires=" + date.toUTCString(); } document.cookie = name + "=" + (value || "") + expires + "; path=/; domain=.cracked.io"; } // Function to get a cookie function getCookie(name) { const nameEQ = name + "="; const ca = document.cookie.split(';'); for(let i=0;i < ca.length;i++) { let c = ca[i]; while (c.charAt(0)==' ') c = c.substring(1,c.length); if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); } return null; } // Function to erase a cookie function eraseCookie(name) { document.cookie = name+'=; Max-Age=-99999999; path=/; domain=.cracked.io'; } // ========================= // 4. Initialize Settings // ========================= // Load settings from localStorage or set defaults const savedSettings = JSON.parse(localStorage.getItem('spectifySettings')) || { theme: 'Custom Theme', // Set to 'Custom Theme' by default hue: 0, saturation: 0, buttonHidden: false, particlesEnabled: false, particleColor: '#FFFFFF', particleWind: 50, reputationPositiveColor: '#a13a3a', helpdocsNumberColor: '#00b6e1', panelUpperIconColor: '#ff302e', // Added default for panel upper icon color trowBorderTopColor: '#ff0000', // Added default for table row border top color footerColor: '#1E1E1E', musicURL: '', musicLoop: true, musicPlayerOpen: false, musicPlaying: false, shoutboxRemoved: false, // New setting pinnedToolsRemoved: false // New setting }; // Override particlesEnabled from cookie if exists const particlesCookie = getCookie('spectifyParticlesEnabled'); if (particlesCookie !== null) { savedSettings.particlesEnabled = (particlesCookie === 'true'); } // Apply base theme applyCSSVariables(baseThemes[savedSettings.theme]); // Adjust theme based on hue and saturation function applyAdjustments(themeVariables, hueShift, saturationShift) { const adjustedVariables = { ...themeVariables }; for (let varName in adjustedVariables) { if (varName.startsWith('--gradient')) { adjustedVariables[varName] = adjustHueSaturation( themeVariables[varName], hueShift, saturationShift ); } else if ( varName.startsWith('--btn') || varName.startsWith('--dropdown') || varName.startsWith('--forumtabs-icon-color') || varName.startsWith('--panel-upper-icon-color') || varName.startsWith('--trow-border-top-color') || varName.startsWith('--trow-border-bottom-color') || varName.startsWith('--trow-text-color') || varName.startsWith('--reputation-positive-color') || varName.startsWith('--helpdocs-number-color') || varName.startsWith('--footer-color') ) { if (themeVariables[varName].startsWith('linear-gradient')) { adjustedVariables[varName] = adjustGradient( themeVariables[varName], hueShift, saturationShift ); } else { adjustedVariables[varName] = adjustHueSaturation( themeVariables[varName], hueShift, saturationShift ); } } else { adjustedVariables[varName] = themeVariables[varName]; } } applyCSSVariables(adjustedVariables); } // Apply initial adjustments based on saved settings applyAdjustments(baseThemes[savedSettings.theme], savedSettings.hue, savedSettings.saturation); // ========================= // 5. Create UI Elements // ========================= // Create the Spectify button const spectifyButton = document.createElement('button'); spectifyButton.id = 'spectify-button'; spectifyButton.innerHTML = `<span style="font-size: 24px;">🎨</span>`; document.body.appendChild(spectifyButton); // Create Styles const style = document.createElement('style'); style.innerHTML = ` /* Spectify Button Styles */ #spectify-button { position: fixed; bottom: 30px; right: 30px; width: 60px; height: 60px; background: var(--btn); color: #fff; border: none; border-radius: 50%; box-shadow: 0 4px 12px rgba(0,0,0,0.3); cursor: pointer; font-size: 24px; z-index: 10000; transition: transform 0.3s, background 0.3s, box-shadow 0.3s; display: flex; align-items: center; justify-content: center; animation: floatButton 3s ease-in-out infinite; } #spectify-button:hover { background: var(--btn-hover); transform: scale(1.1); box-shadow: 0 6px 16px rgba(0,0,0,0.4); } #spectify-button:active { transform: scale(0.95); } @keyframes floatButton { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-10px); } } /* Spectify Panel Styles */ #spectify-panel { position: fixed; bottom: 100px; right: 30px; width: 320px; max-height: 600px; background: var(--background-floating); border: 1px solid var(--border-color); border-radius: 12px; box-shadow: 0 6px 20px rgba(0,0,0,0.5); padding: 25px; z-index: 9999; display: none; opacity: 0; transform: translateY(20px); transition: opacity 0.4s ease, transform 0.4s ease; overflow-y: auto; color: #fff; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } #spectify-panel.visible { display: block; opacity: 1; transform: translateY(0); } #spectify-panel.hidden { opacity: 0; transform: translateY(20px); } #spectify-panel h2 { margin-top: 0; text-align: center; font-size: 22px; margin-bottom: 20px; color: #fff; } .spectify-section { margin-bottom: 25px; } .spectify-section label { display: block; margin-bottom: 10px; font-size: 16px; color: #fff; } .spectify-section input[type="range"], .spectify-section input[type="text"], .spectify-section input[type="color"] { width: 100%; padding: 5px; border: 1px solid var(--border-color); border-radius: 4px; background: var(--background-light); color: var(--text-dark); } .spectify-section input[type="text"]::placeholder { color: #ccc; } .theme-buttons { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; } .theme-button { flex: 1 1 45%; padding: 10px; background: var(--btn); color: #fff; border: none; border-radius: 8px; cursor: pointer; font-size: 14px; transition: background 0.3s, transform 0.3s, box-shadow 0.3s; text-align: center; } .theme-button:hover { background: var(--btn-hover); transform: scale(1.05); box-shadow: 0 4px 8px rgba(0,0,0,0.2); } .theme-button:active { transform: scale(0.95); } /* Consistent Button Styles for Play/Pause, Loop */ .control-button { padding: 8px 12px; background: var(--btn); color: #fff; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; transition: background 0.3s, transform 0.3s; } .control-button:hover { background: var(--btn-hover); transform: scale(1.05); } .control-button:active { transform: scale(0.95); } /* Button Group Styles */ .button-group { display: flex; gap: 10px; margin-top: 10px; } .button-group .control-button { flex: 1; text-align: center; } /* Reset Button */ #reset-spectify { width: 100%; padding: 10px; background: #ff4d4d; color: #fff; border: none; border-radius: 8px; cursor: pointer; font-size: 14px; transition: background 0.3s, transform 0.3s; } #reset-spectify:hover { background: #e60000; transform: scale(1.02); } #reset-spectify:active { transform: scale(0.98); } /* Notification Styles */ #spectify-notification { position: fixed; top: 30px; right: 30px; background: rgba(0, 0, 0, 0.8); color: #fff; padding: 15px 25px; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.3); display: none; align-items: center; gap: 10px; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; z-index: 10001; animation: slideIn 0.5s forwards; font-size: 16px; } @keyframes slideIn { from { opacity: 0; transform: translateY(-20px); } to { opacity: 1; transform: translateY(0); } } @keyframes slideOut { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(-20px); } } /* Scrollbar Styling for Panel */ #spectify-panel::-webkit-scrollbar { width: 8px; } #spectify-panel::-webkit-scrollbar-thumb { background: var(--background-secondary); border-radius: 4px; } #spectify-panel::-webkit-scrollbar-thumb:hover { background: var(--gradient-2); } /* Responsive Design */ @media (max-width: 400px) { #spectify-panel { width: 90%; right: 5%; } #spectify-notification { right: 5%; width: 90%; } /* Adjust button sizes on small screens */ .theme-button { flex: 1 1 100%; } .button-group { flex-direction: column; } } /* Entry and Reset Overlays */ #spectify-entry-overlay, #spectify-reset-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.8); backdrop-filter: blur(5px); display: flex; align-items: center; justify-content: center; z-index: 10002; color: #fff; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; flex-direction: column; padding: 20px; text-align: center; } #spectify-entry-overlay button, #spectify-reset-overlay button { margin-top: 20px; padding: 10px 20px; background: var(--btn); color: #fff; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; transition: background 0.3s, transform 0.3s; } #spectify-entry-overlay button:hover, #spectify-reset-overlay button:hover { background: var(--btn-hover); transform: scale(1.05); } #spectify-entry-overlay button:active, #spectify-reset-overlay button:active { transform: scale(0.95); } /* Particle Effects */ #spectify-particles { position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 9997; background: transparent; } @keyframes particle-move { 0% { transform: translateY(-10px) translateX(0); opacity: 1; } 25% { transform: translateY(25vh) translateX(var(--particle-sway-amplitude)); opacity: 0.75; } 50% { transform: translateY(50vh) translateX(-var(--particle-sway-amplitude)); opacity: 0.5; } 75% { transform: translateY(75vh) translateX(var(--particle-sway-amplitude)); opacity: 0.25; } 100% { transform: translateY(100vh) translateX(0); opacity: 0; } } .particle { position: absolute; top: 0; width: 5px; height: 5px; background: var(--particle-color); border-radius: 50%; animation: particle-move var(--particle-move-duration, 10s) linear infinite; } /* Note Styling */ .note { font-style: italic; font-size: 0.9em; color: #ccc; margin-left: 5px; } /* Update additional elements' colors with gradient text */ .reputation_positive { color: var(--reputation-positive-color) !important; } .helpdocs-number { color: var(--helpdocs-number-color) !important; } .theme_text, td.forumdisplay_sticky>.thread_status:before, .thread_status.stick_folder:before, .thread-lastpost svg:hover, .thread_status.newfolder:before, .thread_status.dot_newfolder:before, .subforum_minion, .stat-icon, .forum .row .icon, .table .stats .flex-one .number, .footer-nav h3, .rps-stat-icon, .forumtabs li a i, .credits_nav_item:hover:before, .usercp_nav_item:hover:before { background: -webkit-linear-gradient(var(--gradient-1), var(--gradient-2)); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; color: transparent; } #panel .upper i { color: var(--panel-upper-icon-color) !important; } /* Update .trow1 and .trow2 styles */ .trow1, .trow2 { border-top: 1px solid var(--trow-border-top-color); border-bottom: 1px solid var(--trow-border-bottom-color); padding: 12px; color: var(--trow-text-color); transition: border-color 0.5s ease, color 0.5s ease; } /* New Styles for Element Removal */ .spectify-hidden { opacity: 0; transition: opacity 0.5s ease, transform 0.5s ease; pointer-events: none; transform: translateY(-20px); } .spectify-visible { opacity: 1; transition: opacity 0.5s ease, transform 0.5s ease; pointer-events: auto; transform: translateY(0); } /* New Buttons for Removing Elements */ .remove-element-button { width: 100%; padding: 10px; background: var(--btn); color: #fff; border: none; border-radius: 8px; cursor: pointer; font-size: 14px; transition: background 0.3s, transform 0.3s; margin-top: 10px; } .remove-element-button:hover { background: var(--btn-hover); transform: scale(1.02); } .remove-element-button:active { transform: scale(0.98); } `; document.head.appendChild(style); // Create Spectify Panel const spectifyPanel = document.createElement('div'); spectifyPanel.id = 'spectify-panel'; spectifyPanel.innerHTML = ` <h2>Spectify Settings</h2> <div class="spectify-section"> <label for="hue-slider">Adjust Hue:</label> <input type="range" id="hue-slider" min="0" max="360" value="${savedSettings.hue}"> </div> <div class="spectify-section"> <label for="saturation-slider">Adjust Saturation:</label> <input type="range" id="saturation-slider" min="-100" max="100" value="${savedSettings.saturation}"> </div> <div class="spectify-section"> <label>Choose Theme:</label> <div class="theme-buttons"> ${Object.keys(baseThemes).map(theme => `<button class="theme-button" data-theme="${theme}">${theme}</button>`).join('')} </div> </div> <div class="spectify-section"> <h3>Music Player</h3> <label for="music-url">Custom Music (YouTube URL):</label> <input type="text" id="music-url" placeholder="https://www.youtube.com/watch?v=VIDEO_ID" value="${savedSettings.musicURL}"> <button id="save-music" class="control-button">Save Music</button> <div class="button-group"> <button id="play-pause-music" class="control-button">${savedSettings.musicPlaying ? 'Pause Music' : 'Play Music'}</button> <button id="loop-button" class="control-button">${savedSettings.musicLoop ? 'Disable Loop' : 'Enable Loop'}</button> </div> <button id="open-music-player-button" class="control-button">Open Music Player</button> </div> <div class="spectify-section"> <h3>Particle Effects</h3> <label> <input type="checkbox" id="particles-toggle" ${savedSettings.particlesEnabled ? 'checked' : ''}> Enable Falling Particles <span class="note">| Only snow if enabled</span> </label> <label for="particle-color">Particle Color:</label> <input type="color" id="particle-color" value="${savedSettings.particleColor}"> <label for="particle-wind">Falling Randomness:</label> <input type="range" id="particle-wind" min="0" max="100" value="${savedSettings.particleWind}"> </div> <div class="spectify-section"> <h3>Additional Elements</h3> <label for="reputation-positive-color">Reputation Positive Color:</label> <input type="color" id="reputation-positive-color" value="${savedSettings.reputationPositiveColor || baseThemes[savedSettings.theme]['--reputation-positive-color']}"> <label for="helpdocs-number-color">Helpdocs Number Color:</label> <input type="color" id="helpdocs-number-color" value="${savedSettings.helpdocsNumberColor || baseThemes[savedSettings.theme]['--helpdocs-number-color']}"> <label for="panel-upper-icon-color">Panel Upper Icon Color:</label> <input type="color" id="panel-upper-icon-color" value="${savedSettings.panelUpperIconColor || baseThemes[savedSettings.theme]['--panel-upper-icon-color']}"> <label for="trow-border-top-color">Table Row Border Top Color:</label> <input type="color" id="trow-border-top-color" value="${savedSettings.trowBorderTopColor || baseThemes[savedSettings.theme]['--trow-border-top-color']}"> <label for="footer-color">Footer Color:</label> <input type="color" id="footer-color" value="${savedSettings.footerColor || baseThemes[savedSettings.theme]['--footer-color']}"> </div> <div class="spectify-section"> <h3>Element Removal</h3> <button id="remove-shoutbox-button" class="remove-element-button">${savedSettings.shoutboxRemoved ? 'Show Shoutbox' : 'Remove Shoutbox'}</button> <button id="remove-pinned-tools-button" class="remove-element-button">${savedSettings.pinnedToolsRemoved ? 'Show Pinned Tools' : 'Remove Pinned Tools'}</button> </div> <div class="spectify-section"> <button id="reset-spectify" class="control-button">Reset to Default</button> </div> <div class="spectify-section" style="margin-top: 20px; text-align: center; font-size: 14px;"> <em>Press <strong>F4</strong> to hide/show the Spectify button.</em> </div> `; document.body.appendChild(spectifyPanel); // Create Notification Element const notification = document.createElement('div'); notification.id = 'spectify-notification'; document.body.appendChild(notification); // ========================= // 6. Apply Theme Adjustments and Custom Colors // ========================= // Function to save settings to localStorage function saveSettings(settings) { localStorage.setItem('spectifySettings', JSON.stringify(settings)); // Update particlesEnabled in cookie for cross-subdomain persistence setCookie('spectifyParticlesEnabled', settings.particlesEnabled, 365); // Expires in 1 year } // Function to apply custom color settings function applyCustomColorSettings() { if (savedSettings.reputationPositiveColor) { document.documentElement.style.setProperty('--reputation-positive-color', savedSettings.reputationPositiveColor); } if (savedSettings.helpdocsNumberColor) { document.documentElement.style.setProperty('--helpdocs-number-color', savedSettings.helpdocsNumberColor); } if (savedSettings.panelUpperIconColor) { document.documentElement.style.setProperty('--panel-upper-icon-color', savedSettings.panelUpperIconColor); } if (savedSettings.trowBorderTopColor) { document.documentElement.style.setProperty('--trow-border-top-color', savedSettings.trowBorderTopColor); } if (savedSettings.footerColor) { document.documentElement.style.setProperty('--footer-color', savedSettings.footerColor); } } // Apply custom color settings on initialization applyCustomColorSettings(); // ========================= // 7. Initialize Sliders and Color Pickers // ========================= // Initialize Hue Slider const hueSlider = spectifyPanel.querySelector('#hue-slider'); hueSlider.value = savedSettings.hue; // Initialize Saturation Slider const saturationSlider = spectifyPanel.querySelector('#saturation-slider'); saturationSlider.value = savedSettings.saturation; // Handle Hue Slider Change hueSlider.addEventListener('input', (e) => { const hueValue = parseInt(e.target.value, 10); savedSettings.hue = hueValue; applyAdjustments(baseThemes[savedSettings.theme], savedSettings.hue, savedSettings.saturation); saveSettings(savedSettings); }); // Handle Saturation Slider Change saturationSlider.addEventListener('input', (e) => { const saturationValue = parseInt(e.target.value, 10); savedSettings.saturation = saturationValue; applyAdjustments(baseThemes[savedSettings.theme], savedSettings.hue, savedSettings.saturation); saveSettings(savedSettings); }); // ========================= // 8. Handle Theme Selection // ========================= const themeButtons = spectifyPanel.querySelectorAll('.theme-button'); themeButtons.forEach(button => { button.addEventListener('click', () => { const selectedTheme = button.getAttribute('data-theme'); savedSettings.theme = selectedTheme; // Apply the selected theme applyCSSVariables(baseThemes[selectedTheme]); // Re-apply adjustments applyAdjustments(baseThemes[selectedTheme], savedSettings.hue, savedSettings.saturation); // Apply custom color settings applyCustomColorSettings(); // Apply theme-specific enhancements applyThemeEnhancements(selectedTheme); // Save settings saveSettings(savedSettings); showNotification(`🎨 Theme "${selectedTheme}" applied.`); }); }); // ========================= // 9. Handle Reset Button // ========================= const resetButton = spectifyPanel.querySelector('#reset-spectify'); resetButton.addEventListener('click', () => { createResetOverlay(); }); // Function to create Reset Confirmation Overlay function createResetOverlay() { // Prevent multiple overlays if (document.getElementById('spectify-reset-overlay')) return; const resetOverlay = document.createElement('div'); resetOverlay.id = 'spectify-reset-overlay'; resetOverlay.innerHTML = ` <h1>Confirm Reset</h1> <p>Are you sure you want to reset all settings to default? This will delete all saved settings and configurations.</p> <div style="margin-top: 20px;"> <button id="confirm-reset" class="control-button" style="margin-right: 10px;">Yes, Reset</button> <button id="cancel-reset" class="control-button">Cancel</button> </div> `; document.body.appendChild(resetOverlay); // Event Listener for Confirm Reset const confirmReset = resetOverlay.querySelector('#confirm-reset'); confirmReset.addEventListener('click', () => { // Reset settings to default Object.assign(savedSettings, { theme: 'Custom Theme', hue: 0, saturation: 0, buttonHidden: false, particlesEnabled: false, particleColor: '#FFFFFF', particleWind: 50, reputationPositiveColor: baseThemes['Custom Theme']['--reputation-positive-color'], helpdocsNumberColor: baseThemes['Custom Theme']['--helpdocs-number-color'], panelUpperIconColor: baseThemes['Custom Theme']['--panel-upper-icon-color'], trowBorderTopColor: baseThemes['Custom Theme']['--trow-border-top-color'], footerColor: baseThemes['Custom Theme']['--footer-color'], musicURL: '', musicLoop: true, musicPlayerOpen: false, musicPlaying: false, adsRemoved: false, shoutboxRemoved: false, pinnedToolsRemoved: false }); applyCSSVariables(baseThemes['Custom Theme']); applyAdjustments(baseThemes['Custom Theme'], 0, 0); applyCustomColorSettings(); // Update sliders hueSlider.value = 0; saturationSlider.value = 0; // Clear music settings removeMusicPlayer(); spectifyPanel.querySelector('#music-url').value = ''; // Reset play/pause button spectifyPanel.querySelector('#play-pause-music').textContent = 'Play Music'; // Reset loop button spectifyPanel.querySelector('#loop-button').textContent = 'Enable Loop'; // Reset particle settings spectifyPanel.querySelector('#particles-toggle').checked = false; spectifyPanel.querySelector('#particle-color').value = '#FFFFFF'; spectifyPanel.querySelector('#particle-wind').value = 50; // Reset panel upper icon color spectifyPanel.querySelector('#panel-upper-icon-color').value = '#ff302e'; // Reset table row border top color spectifyPanel.querySelector('#trow-border-top-color').value = baseThemes['Custom Theme']['--trow-border-top-color']; // Reset element removal settings resetElementRemovalSettings(); // Remove reset overlay resetOverlay.remove(); // Remove particle effects removeParticleEffects(); // Erase the particlesEnabled cookie eraseCookie('spectifyParticlesEnabled'); // Save settings saveSettings(savedSettings); showNotification('✅ Settings have been reset to default.'); }); // Event Listener for Cancel Reset const cancelReset = resetOverlay.querySelector('#cancel-reset'); cancelReset.addEventListener('click', () => { resetOverlay.remove(); }); } // Function to reset element removal settings function resetElementRemovalSettings() { // Show Shoutbox showShoutbox(); // Show Pinned Tools showPinnedTools(); } // ========================= // 10. Show Notification Function // ========================= function showNotification(message) { notification.innerHTML = `<span>${message}</span>`; notification.style.display = 'flex'; notification.style.animation = 'slideIn 0.5s forwards'; // After 3 seconds, slide out and hide setTimeout(() => { notification.style.animation = 'slideOut 0.5s forwards'; // Hide after animation completes setTimeout(() => { notification.style.display = 'none'; }, 500); }, 3000); } // ========================= // 11. Toggle Panel Visibility // ========================= // Toggle panel visibility with animation via button click spectifyButton.addEventListener('click', (e) => { e.stopPropagation(); // Prevent event from bubbling to document if (spectifyPanel.classList.contains('visible')) { spectifyPanel.classList.remove('visible'); spectifyPanel.classList.add('hidden'); // Wait for the transition to complete before hiding setTimeout(() => { spectifyPanel.style.display = 'none'; }, 400); // Match the CSS transition duration } else { spectifyPanel.style.display = 'block'; // Force reflow to enable the transition void spectifyPanel.offsetWidth; spectifyPanel.classList.remove('hidden'); spectifyPanel.classList.add('visible'); } }); // Close panel when clicking outside with animation document.addEventListener('click', (e) => { if (!spectifyPanel.contains(e.target) && !spectifyButton.contains(e.target)) { if (spectifyPanel.classList.contains('visible')) { spectifyPanel.classList.remove('visible'); spectifyPanel.classList.add('hidden'); // Wait for the transition to complete before hiding setTimeout(() => { spectifyPanel.style.display = 'none'; }, 400); // Match the CSS transition duration } } }); // ========================= // 12. Toggle Spectify Button Visibility via F4 Key // ========================= // Hide the main Spectify button if it was previously hidden if (savedSettings.buttonHidden) { spectifyButton.style.display = 'none'; } // Function to toggle the Spectify button via F4 key function toggleSpectifyButton() { if (spectifyButton.style.display === 'none') { spectifyButton.style.display = 'flex'; savedSettings.buttonHidden = false; saveSettings(savedSettings); showNotification('✅ Spectify menu shown.'); } else { spectifyButton.style.display = 'none'; savedSettings.buttonHidden = true; saveSettings(savedSettings); showNotification('❌ Spectify menu hidden.'); // Also close the settings panel if open if (spectifyPanel.classList.contains('visible')) { spectifyPanel.classList.remove('visible'); spectifyPanel.classList.add('hidden'); setTimeout(() => { spectifyPanel.style.display = 'none'; }, 400); } } } // Listen for F4 key to toggle Spectify button document.addEventListener('keydown', (e) => { if (e.key === 'F4') { e.preventDefault(); // Prevent default action if necessary toggleSpectifyButton(); } }); // ========================= // 13. Handle Music Player Integration // ========================= const musicURLInput = spectifyPanel.querySelector('#music-url'); const saveMusicButton = spectifyPanel.querySelector('#save-music'); const playPauseButton = spectifyPanel.querySelector('#play-pause-music'); const loopButton = spectifyPanel.querySelector('#loop-button'); const openMusicPlayerButton = spectifyPanel.querySelector('#open-music-player-button'); let musicPlayerWindow = null; // Reset musicPlaying to false on script load if musicPlayerWindow is not open if (!savedSettings.musicPlayerOpen) { savedSettings.musicPlaying = false; saveSettings(savedSettings); playPauseButton.textContent = 'Play Music'; } // Listen for messages from the music player window window.addEventListener('message', (event) => { // Ensure the message is coming from the same origin if (!event.origin.includes('cracked.io')) return; const data = event.data; if (data.type === 'playerClosed') { // Update settings savedSettings.musicPlayerOpen = false; savedSettings.musicPlaying = false; saveSettings(savedSettings); playPauseButton.textContent = 'Play Music'; showNotification('🎵 Music Player Closed.'); } }); // Save Music Button Click Event saveMusicButton.addEventListener('click', () => { const url = musicURLInput.value.trim(); if (validateYouTubeURL(url)) { const videoID = extractYouTubeID(url); if (videoID) { savedSettings.musicURL = url; // Save the full URL saveSettings(savedSettings); showNotification('🎵 Custom music saved.'); } else { showNotification('❌ Unable to extract Video ID from the provided URL.'); } } else { showNotification('❌ Invalid YouTube URL.'); } }); // Handle Play/Pause Button playPauseButton.addEventListener('click', () => { if (savedSettings.musicPlaying && musicPlayerWindow && !musicPlayerWindow.closed) { // If music is playing, close the music player window to pause removeMusicPlayer(); playPauseButton.textContent = 'Play Music'; showNotification('⏸️ Music Paused.'); } else { if (savedSettings.musicURL) { checkAndOpenMusicPlayer(); playPauseButton.textContent = 'Pause Music'; showNotification('🎵 Music Playing.'); savedSettings.musicPlaying = true; saveSettings(savedSettings); } else { showNotification('❌ No music URL set.'); } } }); // Handle Loop Toggle Button loopButton.addEventListener('click', () => { savedSettings.musicLoop = !savedSettings.musicLoop; saveSettings(savedSettings); if (musicPlayerWindow && !musicPlayerWindow.closed) { // Send a message to toggle loop musicPlayerWindow.postMessage({ type: 'toggleLoop', loop: savedSettings.musicLoop }, '*'); loopButton.textContent = savedSettings.musicLoop ? 'Disable Loop' : 'Enable Loop'; showNotification(`🔁 Loop ${savedSettings.musicLoop ? 'Enabled' : 'Disabled'}.`); } else { // If music is not playing, just update the loop button text loopButton.textContent = savedSettings.musicLoop ? 'Disable Loop' : 'Enable Loop'; showNotification(`🔁 Loop ${savedSettings.musicLoop ? 'Enabled' : 'Disabled'}.`); } }); // Handle Open Music Player Button openMusicPlayerButton.addEventListener('click', () => { if (savedSettings.musicURL) { checkAndOpenMusicPlayer(); } else { showNotification('❌ No music URL set.'); } }); // Function to validate YouTube URL function validateYouTubeURL(url) { const regex = /^(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/watch\?v=|youtube\.com\/embed\/|youtu\.be\/)([\w-]{11})(?:\S+)?$/; return regex.test(url); } // ========================= // 14. Handle Remove Music Player // ========================= // Function to remove existing music player window function removeMusicPlayer() { if (savedSettings.musicPlayerOpen) { if (musicPlayerWindow && !musicPlayerWindow.closed) { // Send a message to close the music player musicPlayerWindow.postMessage({ type: 'playerClosed' }, '*'); musicPlayerWindow.close(); savedSettings.musicPlayerOpen = false; savedSettings.musicPlaying = false; saveSettings(savedSettings); showNotification('🎵 Music Player Closed.'); // Reset play/pause button const playPauseButton = spectifyPanel.querySelector('#play-pause-music'); if (playPauseButton) playPauseButton.textContent = 'Play Music'; } } } // ========================= // 15. Apply Theme-Specific Enhancements // ========================= function applyThemeEnhancements(theme) { if (theme === 'Christmas') { // Always enable particles with white color for snow effect savedSettings.particlesEnabled = true; savedSettings.particleColor = '#FFFFFF'; // White color spectifyPanel.querySelector('#particle-color').value = '#FFFFFF'; spectifyPanel.querySelector('#particle-color').disabled = true; // Disable color picker spectifyPanel.querySelector('#particles-toggle').checked = true; spectifyPanel.querySelector('#particles-toggle').disabled = true; // Disable toggle addParticleEffects(); // Apply color-scheme: light; document.documentElement.style.colorScheme = 'light'; // Reset element removal settings resetElementRemovalSettings(); saveSettings(savedSettings); showNotification('🎄 Christmas enhancements applied.'); } else if (theme === 'Space Theme') { // Handle Space Theme // Enable particles by default savedSettings.particlesEnabled = true; spectifyPanel.querySelector('#particles-toggle').checked = true; spectifyPanel.querySelector('#particles-toggle').disabled = false; // Ensure toggle is enabled addParticleEffects(); // Apply color-scheme: dark; document.documentElement.style.colorScheme = 'dark'; saveSettings(savedSettings); showNotification(`🌌 "${theme}" theme applied with particles enabled.`); } else if (theme === 'Forest Green') { // Handle Forest Green theme // Enable particles based on user preference if (savedSettings.particlesEnabled) { addParticleEffects(); } // Apply color-scheme: light; document.documentElement.style.colorScheme = 'light'; saveSettings(savedSettings); showNotification(`🌲 "${theme}" theme applied.`); } else { // Remove color-scheme if not specified document.documentElement.style.colorScheme = ''; // Restore particle settings based on user preference if (savedSettings.particlesEnabled) { removeParticleEffects(); // Remove existing particles to prevent duplication addParticleEffects(); // Add particles with current settings } else { removeParticleEffects(); } saveSettings(savedSettings); showNotification(`🌈 "${theme}" theme applied.`); } } // ========================= // 17. Handle Particle Settings // ========================= const particlesToggle = spectifyPanel.querySelector('#particles-toggle'); const particleColorInput = spectifyPanel.querySelector('#particle-color'); const particleWindSlider = spectifyPanel.querySelector('#particle-wind'); // Initialize Particle Settings particlesToggle.checked = savedSettings.particlesEnabled; particleColorInput.value = savedSettings.particleColor; particleWindSlider.value = savedSettings.particleWind; // Handle Particle Toggle particlesToggle.addEventListener('change', (e) => { // Prevent disabling particles if theme is Christmas or Space Theme if (savedSettings.theme === 'Christmas' || savedSettings.theme === 'Space Theme') { showNotification('❗ Particles are always enabled for the selected theme.'); particlesToggle.checked = true; return; } savedSettings.particlesEnabled = e.target.checked; saveSettings(savedSettings); if (savedSettings.particlesEnabled) { addParticleEffects(); showNotification('✨ Particle Effects Enabled.'); } else { removeParticleEffects(); showNotification('✨ Particle Effects Disabled.'); } }); // Handle Particle Color Change particleColorInput.addEventListener('input', (e) => { if (savedSettings.theme === 'Christmas') { // Force particle color to white for Christmas savedSettings.particleColor = '#FFFFFF'; particleColorInput.value = '#FFFFFF'; updateParticleStyles(); showNotification('🎨 Particle color is fixed for the selected theme.'); return; } savedSettings.particleColor = e.target.value; updateParticleStyles(); saveSettings(savedSettings); }); // Handle Falling Randomness Change particleWindSlider.addEventListener('input', (e) => { savedSettings.particleWind = parseInt(e.target.value, 10); updateParticleStyles(); saveSettings(savedSettings); }); // Function to update particle styles based on settings function updateParticleStyles() { const root = document.documentElement; root.style.setProperty('--particle-color', savedSettings.particleColor); // Set particle-sway-amplitude based on Falling Randomness const swayAmplitude = savedSettings.particleWind; root.style.setProperty('--particle-sway-amplitude', `${swayAmplitude}px`); } // Function to add particle effects function addParticleEffects() { if (document.getElementById('spectify-particles')) return; // Prevent duplicates const particles = document.createElement('div'); particles.id = 'spectify-particles'; // Create multiple particles with random sway amplitudes for (let i = 0; i < 100; i++) { // Increased to 100 for a denser snow-like effect const particle = document.createElement('div'); particle.classList.add('particle'); particle.style.left = `${Math.random() * 100}%`; particle.style.animationDuration = `${Math.random() * 5 + 5}s`; // 5-10 seconds const swayAmplitude = Math.random() * savedSettings.particleWind; // Random amplitude up to Falling Randomness particle.style.setProperty('--particle-sway-amplitude', `${swayAmplitude}px`); particles.appendChild(particle); } document.body.appendChild(particles); updateParticleStyles(); } // Function to remove particle effects function removeParticleEffects() { const particles = document.getElementById('spectify-particles'); if (particles) { particles.remove(); } } // ========================= // 18. Handle Additional Color Pickers // ========================= const reputationPositiveColorInput = spectifyPanel.querySelector('#reputation-positive-color'); const helpdocsNumberColorInput = spectifyPanel.querySelector('#helpdocs-number-color'); const themeTextColorInput = spectifyPanel.querySelector('#theme-text-color'); // Removed const panelUpperIconColorInput = spectifyPanel.querySelector('#panel-upper-icon-color'); // New color picker const trowBorderTopColorInput = spectifyPanel.querySelector('#trow-border-top-color'); // Table Row Border Top Color const footerColorInput = spectifyPanel.querySelector('#footer-color'); // Footer Color reputationPositiveColorInput.addEventListener('input', (e) => { const color = e.target.value; savedSettings.reputationPositiveColor = color; document.documentElement.style.setProperty('--reputation-positive-color', color); saveSettings(savedSettings); }); helpdocsNumberColorInput.addEventListener('input', (e) => { const color = e.target.value; savedSettings.helpdocsNumberColor = color; document.documentElement.style.setProperty('--helpdocs-number-color', color); saveSettings(savedSettings); }); panelUpperIconColorInput.addEventListener('input', (e) => { const color = e.target.value; savedSettings.panelUpperIconColor = color; document.documentElement.style.setProperty('--panel-upper-icon-color', color); saveSettings(savedSettings); }); // Handle Table Row Border Top Color Change trowBorderTopColorInput.addEventListener('input', (e) => { const color = e.target.value; savedSettings.trowBorderTopColor = color; document.documentElement.style.setProperty('--trow-border-top-color', color); saveSettings(savedSettings); }); // Handle Footer Color Change // Append the Footer Color input if not already present const footerColorLabel = spectifyPanel.querySelector('label[for="footer-color"]'); if (!footerColorLabel) { const additionalElementsSection = spectifyPanel.querySelector('.spectify-section:nth-child(4)'); additionalElementsSection.innerHTML += ` <label for="footer-color">Footer Color:</label> <input type="color" id="footer-color" value="${savedSettings.footerColor || baseThemes[savedSettings.theme]['--footer-color']}"> `; } const footerColorInputUpdated = spectifyPanel.querySelector('#footer-color'); footerColorInputUpdated.addEventListener('input', (e) => { const color = e.target.value; savedSettings.footerColor = color; document.documentElement.style.setProperty('--footer-color', color); saveSettings(savedSettings); }); // ========================= // 19. Hotkey F2 to Toggle Particle Effects // ========================= // Function to Toggle Particle Effects function toggleParticleEffects() { if (savedSettings.particlesEnabled) { // Prevent disabling particles if current theme enforces it if (savedSettings.theme === 'Christmas' || savedSettings.theme === 'Space Theme') { showNotification('❗ Particles are always enabled for the selected theme.'); spectifyPanel.querySelector('#particles-toggle').checked = true; return; } removeParticleEffects(); savedSettings.particlesEnabled = false; spectifyPanel.querySelector('#particles-toggle').checked = false; showNotification('✨ Particle Effects Disabled.'); } else { addParticleEffects(); savedSettings.particlesEnabled = true; spectifyPanel.querySelector('#particles-toggle').checked = true; showNotification('✨ Particle Effects Enabled.'); } saveSettings(savedSettings); } // Listen for F2 key to toggle Particle Effects document.addEventListener('keydown', (e) => { if (e.key === 'F2') { e.preventDefault(); toggleParticleEffects(); } }); // ========================= // 20. Final Initialization // ========================= // Apply theme-specific enhancements on initialization applyThemeEnhancements(savedSettings.theme); updateParticleStyles(); // ========================= // 21. Ensure Only One Music Player Instance // ========================= // Ensure the music player is only opened once function checkAndOpenMusicPlayer() { // Check if the window reference is still valid if (musicPlayerWindow && !musicPlayerWindow.closed) { // Music player is already open, focus on it musicPlayerWindow.focus(); showNotification('🎵 Music Player is already open.'); return; } // Music player is not open, open a new one openMusicPlayer(); } // ========================= // 22. Handle Music Player Messages // ========================= // Function to handle messages from the music player window window.addEventListener('message', (event) => { // Ensure the message is coming from the correct origin if (!event.origin.includes('cracked.io')) return; const data = event.data; if (data.type === 'playerClosed') { // Update settings savedSettings.musicPlayerOpen = false; savedSettings.musicPlaying = false; saveSettings(savedSettings); playPauseButton.textContent = 'Play Music'; showNotification('🎵 Music Player Closed.'); } }); // ========================= // Function Definitions // ========================= function openMusicPlayer() { const videoID = extractYouTubeID(savedSettings.musicURL); if (!videoID) { showNotification('❌ Invalid YouTube URL.'); return; } // Construct iframe src without autoplay const loopParam = savedSettings.musicLoop ? `&loop=1&playlist=${videoID}` : ''; const iframeSrc = `https://www.youtube.com/embed/${videoID}?${loopParam}&controls=0&showinfo=0&rel=0&modestbranding=1`; // Define the HTML content for the music player const htmlContent = ` <!DOCTYPE html> <html> <head> <title>Spectify Music Player</title> <style> body { margin: 0; padding: 0; background: #000; display: flex; align-items: center; justify-content: center; height: 100vh; overflow: hidden; position: relative; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } iframe#player { width: 100%; height: 100%; border: none; opacity: 0.9; border-radius: 8px; transition: opacity 0.3s; } #controls { position: absolute; bottom: 10px; left: 50%; transform: translateX(-50%); display: flex; gap: 10px; } .control-button { padding: 5px 10px; background: #2323237a; color: #fff; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; transition: background 0.3s, transform 0.3s; } .control-button:hover { background: #FF7518; transform: scale(1.05); } .control-button:active { transform: scale(0.95); } </style> </head> <body> <iframe id="player" src="${iframeSrc}" allow="autoplay; encrypted-media"></iframe> <div id="controls"> <button id="close-player" class="control-button">Close</button> </div> <script> // Function to handle messages from the parent window window.addEventListener('message', (event) => { // Ensure the message is coming from the correct origin if (!event.origin.includes('cracked.io')) return; const data = event.data; const iframe = document.getElementById('player'); if (data.type === 'toggleLoop') { const videoID = '${videoID}'; if (data.loop) { iframe.src = 'https://www.youtube.com/embed/' + videoID + '?loop=1&playlist=' + videoID + '&controls=0&showinfo=0&rel=0&modestbranding=1'; } else { iframe.src = 'https://www.youtube.com/embed/' + videoID + '?controls=0&showinfo=0&rel=0&modestbranding=1'; } } }); // Handle close button const closeButton = document.getElementById('close-player'); closeButton.addEventListener('click', () => { window.opener.postMessage({ type: 'playerClosed' }, '*'); window.close(); }); // Automatically inform the parent window if this window is closed window.addEventListener('beforeunload', () => { window.opener.postMessage({ type: 'playerClosed' }, '*'); }); </script> </body> </html> `; // Create a Blob from the HTML content const blob = new Blob([htmlContent], {type: 'text/html'}); const blobURL = URL.createObjectURL(blob); // Open a new window with desired features musicPlayerWindow = window.open(blobURL, 'SpectifyMusicPlayer', 'width=420,height=300,left=100,top=100,toolbar=no,menubar=no,location=no,status=no,scrollbars=no,resizable=no'); if (!musicPlayerWindow) { showNotification('❌ Unable to open music player window. Please allow popups for cracked.io.'); return; } // Update settings savedSettings.musicPlayerOpen = true; savedSettings.musicPlaying = true; saveSettings(savedSettings); showNotification('🎵 Music Player Opened.'); } // ========================= // 23. Handle Element Removal // ========================= const removeShoutboxButton = spectifyPanel.querySelector('#remove-shoutbox-button'); const removePinnedToolsButton = spectifyPanel.querySelector('#remove-pinned-tools-button'); // Event Listener for Remove Shoutbox Button removeShoutboxButton.addEventListener('click', () => { if (!savedSettings.shoutboxRemoved) { removeShoutbox(); } else { showShoutbox(); } }); // Event Listener for Remove Pinned Tools Button removePinnedToolsButton.addEventListener('click', () => { if (!savedSettings.pinnedToolsRemoved) { removePinnedTools(); } else { showPinnedTools(); } }); // Function to remove Shoutbox function removeShoutbox() { const shoutbox = document.getElementById('shoutbox'); if (shoutbox) { shoutbox.classList.add('spectify-transition', 'spectify-hidden'); setTimeout(() => { shoutbox.style.display = 'none'; }, 500); // Match the CSS transition duration removeShoutboxButton.textContent = 'Show Shoutbox'; savedSettings.shoutboxRemoved = true; saveSettings(savedSettings); showNotification('🛑 Shoutbox Removed.'); } } // Function to show Shoutbox function showShoutbox() { const shoutbox = document.getElementById('shoutbox'); if (shoutbox) { shoutbox.style.display = 'block'; shoutbox.classList.add('spectify-transition'); void shoutbox.offsetWidth; // Reflow to apply the transition shoutbox.classList.remove('spectify-hidden'); removeShoutboxButton.textContent = 'Remove Shoutbox'; savedSettings.shoutboxRemoved = false; saveSettings(savedSettings); showNotification('✅ Shoutbox Shown.'); } } function removePinnedTools() { const pinnedToolsContainers = document.querySelectorAll('div[align="center"]:not(.inner_stuff)'); pinnedToolsContainers.forEach(container => { container.classList.add('spectify-transition', 'spectify-hidden'); setTimeout(() => { container.style.display = 'none'; }, 500); }); removePinnedToolsButton.textContent = 'Show Pinned Tools'; savedSettings.pinnedToolsRemoved = true; saveSettings(savedSettings); showNotification('🛑 Pinned Tools Removed.'); } function showPinnedTools() { const pinnedToolsContainers = document.querySelectorAll('div[align="center"]:not(.inner_stuff)'); pinnedToolsContainers.forEach(container => { container.style.display = 'block'; container.classList.add('spectify-transition'); void container.offsetWidth; container.classList.remove('spectify-hidden'); }); removePinnedToolsButton.textContent = 'Remove Pinned Tools'; savedSettings.pinnedToolsRemoved = false; saveSettings(savedSettings); showNotification('✅ Pinned Tools Shown.'); } // ========================= // 24. Initialize Element Removal Based on Saved Settings // ========================= function initializeElementRemoval() { if (savedSettings.shoutboxRemoved) { removeShoutbox(); } if (savedSettings.pinnedToolsRemoved) { removePinnedTools(); } } // Initialize Element Removal on script load initializeElementRemoval(); document.documentElement.style.setProperty('--footer-color', savedSettings.footerColor || baseThemes[savedSettings.theme]['--footer-color']); // Update the footer background color const footer = document.getElementById('footer'); if (footer) { footer.style.background = 'var(--footer-color)'; footer.style.transition = 'background 0.5s ease'; } })();