Size
9.5 KB
Version
1.0.1
Created
Nov 18, 2025
Updated
24 days ago
1// ==UserScript==
2// @name Snapchat Profile Options Manager
3// @description Adds custom profile options to Snapchat Web
4// @version 1.0.1
5// @match https://*.snapchat.com/*
6// @icon https://www.snapchat.com/web/version/22849690/favicon-badged.svg
7// ==/UserScript==
8(function() {
9 'use strict';
10
11 console.log('Snapchat Profile Options Manager loaded');
12
13 // Debounce function to prevent excessive calls
14 function debounce(func, wait) {
15 let timeout;
16 return function executedFunction(...args) {
17 const later = () => {
18 clearTimeout(timeout);
19 func(...args);
20 };
21 clearTimeout(timeout);
22 timeout = setTimeout(later, wait);
23 };
24 }
25
26 // Add custom profile option to the dropdown menu
27 function addProfileOption() {
28 // Find the dropdown menu container
29 const menuContainer = document.querySelector('#downshift-85-menu .VoxbS');
30
31 if (!menuContainer) {
32 console.log('Menu container not found yet');
33 return;
34 }
35
36 // Check if our custom option already exists
37 if (document.querySelector('#custom-profile-option')) {
38 return;
39 }
40
41 console.log('Adding custom profile option to menu');
42
43 // Create the custom profile option element
44 const profileOption = document.createElement('div');
45 profileOption.id = 'custom-profile-option';
46 profileOption.className = 'CeO6L';
47 profileOption.setAttribute('role', 'option');
48 profileOption.setAttribute('aria-selected', 'false');
49
50 profileOption.innerHTML = `
51 <div class="KT6b1" style="cursor: pointer;">
52 <div class="PXgY2">
53 <span class="nonIntl">Profile Options</span>
54 </div>
55 <div class="tvg6i">
56 <span class="nonIntl">Manage your profile</span>
57 </div>
58 </div>
59 `;
60
61 // Add click handler
62 profileOption.addEventListener('click', async function(e) {
63 e.preventDefault();
64 e.stopPropagation();
65 console.log('Profile Options clicked');
66
67 // Close the dropdown
68 const toggleButton = document.querySelector('#downshift-85-toggle-button');
69 if (toggleButton) {
70 toggleButton.click();
71 }
72
73 // Show profile options modal
74 showProfileOptionsModal();
75 });
76
77 // Add hover effect
78 profileOption.addEventListener('mouseenter', function() {
79 this.style.backgroundColor = 'rgba(0, 0, 0, 0.05)';
80 });
81
82 profileOption.addEventListener('mouseleave', function() {
83 this.style.backgroundColor = '';
84 });
85
86 // Insert the option at the top of the menu
87 menuContainer.insertBefore(profileOption, menuContainer.firstChild);
88 }
89
90 // Show profile options modal
91 async function showProfileOptionsModal() {
92 // Get stored profile data
93 const profileData = await GM.getValue('snapchat_profile_data', {
94 bio: '',
95 status: '',
96 theme: 'default'
97 });
98
99 // Create modal overlay
100 const overlay = document.createElement('div');
101 overlay.id = 'profile-options-modal';
102 overlay.style.cssText = `
103 position: fixed;
104 top: 0;
105 left: 0;
106 width: 100%;
107 height: 100%;
108 background: rgba(0, 0, 0, 0.7);
109 display: flex;
110 justify-content: center;
111 align-items: center;
112 z-index: 10000;
113 `;
114
115 // Create modal content
116 const modal = document.createElement('div');
117 modal.style.cssText = `
118 background: white;
119 border-radius: 12px;
120 padding: 24px;
121 width: 90%;
122 max-width: 500px;
123 box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
124 `;
125
126 modal.innerHTML = `
127 <div style="margin-bottom: 20px;">
128 <h2 style="margin: 0 0 8px 0; font-size: 24px; font-weight: 600; color: #000;">Profile Options</h2>
129 <p style="margin: 0; font-size: 14px; color: #666;">Customize your Snapchat profile settings</p>
130 </div>
131
132 <div style="margin-bottom: 20px;">
133 <label style="display: block; margin-bottom: 8px; font-weight: 500; color: #000;">Custom Bio</label>
134 <textarea id="profile-bio" style="width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 8px; font-size: 14px; font-family: inherit; resize: vertical; min-height: 80px;" placeholder="Enter your custom bio...">${profileData.bio}</textarea>
135 </div>
136
137 <div style="margin-bottom: 20px;">
138 <label style="display: block; margin-bottom: 8px; font-weight: 500; color: #000;">Status Message</label>
139 <input type="text" id="profile-status" style="width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 8px; font-size: 14px;" placeholder="What's on your mind?" value="${profileData.status}">
140 </div>
141
142 <div style="margin-bottom: 24px;">
143 <label style="display: block; margin-bottom: 8px; font-weight: 500; color: #000;">Theme</label>
144 <select id="profile-theme" style="width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 8px; font-size: 14px; background: white;">
145 <option value="default" ${profileData.theme === 'default' ? 'selected' : ''}>Default</option>
146 <option value="dark" ${profileData.theme === 'dark' ? 'selected' : ''}>Dark Mode</option>
147 <option value="colorful" ${profileData.theme === 'colorful' ? 'selected' : ''}>Colorful</option>
148 </select>
149 </div>
150
151 <div style="display: flex; gap: 12px; justify-content: flex-end;">
152 <button id="cancel-btn" style="padding: 10px 20px; border: 1px solid #ddd; border-radius: 8px; background: white; color: #000; font-size: 14px; font-weight: 500; cursor: pointer;">Cancel</button>
153 <button id="save-btn" style="padding: 10px 20px; border: none; border-radius: 8px; background: #FFFC00; color: #000; font-size: 14px; font-weight: 600; cursor: pointer;">Save Changes</button>
154 </div>
155 `;
156
157 overlay.appendChild(modal);
158 document.body.appendChild(overlay);
159
160 // Add event listeners
161 document.getElementById('cancel-btn').addEventListener('click', () => {
162 overlay.remove();
163 });
164
165 document.getElementById('save-btn').addEventListener('click', async () => {
166 const bio = document.getElementById('profile-bio').value;
167 const status = document.getElementById('profile-status').value;
168 const theme = document.getElementById('profile-theme').value;
169
170 // Save to storage
171 await GM.setValue('snapchat_profile_data', {
172 bio: bio,
173 status: status,
174 theme: theme
175 });
176
177 console.log('Profile options saved:', { bio, status, theme });
178
179 // Apply theme
180 applyTheme(theme);
181
182 // Show success message
183 const saveBtn = document.getElementById('save-btn');
184 saveBtn.textContent = 'Saved!';
185 saveBtn.style.background = '#00C853';
186 saveBtn.style.color = 'white';
187
188 setTimeout(() => {
189 overlay.remove();
190 }, 1000);
191 });
192
193 // Close on overlay click
194 overlay.addEventListener('click', (e) => {
195 if (e.target === overlay) {
196 overlay.remove();
197 }
198 });
199 }
200
201 // Apply theme to the page
202 function applyTheme(theme) {
203 // Remove existing theme
204 const existingStyle = document.getElementById('custom-theme-style');
205 if (existingStyle) {
206 existingStyle.remove();
207 }
208
209 if (theme === 'default') {
210 return;
211 }
212
213 const style = document.createElement('style');
214 style.id = 'custom-theme-style';
215
216 if (theme === 'dark') {
217 style.textContent = `
218 body { filter: invert(1) hue-rotate(180deg); }
219 img, video { filter: invert(1) hue-rotate(180deg); }
220 `;
221 } else if (theme === 'colorful') {
222 style.textContent = `
223 body { filter: saturate(1.5) brightness(1.1); }
224 `;
225 }
226
227 document.head.appendChild(style);
228 console.log('Theme applied:', theme);
229 }
230
231 // Initialize - load saved theme
232 async function init() {
233 console.log('Initializing Snapchat Profile Options Manager');
234
235 // Load and apply saved theme
236 const profileData = await GM.getValue('snapchat_profile_data', { theme: 'default' });
237 applyTheme(profileData.theme);
238
239 // Watch for the dropdown menu to appear
240 const debouncedAddOption = debounce(addProfileOption, 100);
241
242 const observer = new MutationObserver(debouncedAddOption);
243
244 observer.observe(document.body, {
245 childList: true,
246 subtree: true
247 });
248
249 // Try to add option immediately if menu is already open
250 addProfileOption();
251 }
252
253 // Start when page is ready
254 if (document.readyState === 'loading') {
255 document.addEventListener('DOMContentLoaded', init);
256 } else {
257 init();
258 }
259})();