Size
10.1 KB
Version
1.1.2
Created
Oct 17, 2025
Updated
about 1 month ago
1// ==UserScript==
2// @name Stripchat Chat Logger
3// @description Extracts chat messages and saves them as JSON files every minute
4// @version 1.1.2
5// @match https://*.stripchat.com/*
6// @icon https://assets.striiiipst.com/assets/icons/favicon-32x32.png?v=9670c787
7// @grant GM.xmlhttpRequest
8// @grant GM.setClipboard
9// ==/UserScript==
10(function() {
11 'use strict';
12
13 console.log('[Stripchat Chat Logger] Extension started');
14
15 let isLogging = false;
16 let loggingInterval = null;
17 let controlButton = null;
18 let autoHideTimeout = null;
19
20 // Extract username from URL
21 function getUsername() {
22 const pathParts = window.location.pathname.split('/');
23 return pathParts[1] || 'unknown';
24 }
25
26 // Format date as YYMMDD_HHMM
27 function formatDateTime() {
28 const now = new Date();
29 const yy = String(now.getFullYear()).slice(-2);
30 const mm = String(now.getMonth() + 1).padStart(2, '0');
31 const dd = String(now.getDate()).padStart(2, '0');
32 const hh = String(now.getHours()).padStart(2, '0');
33 const min = String(now.getMinutes()).padStart(2, '0');
34 return `${yy}${mm}${dd}_${hh}${min}`;
35 }
36
37 // Extract chat messages from the DOM
38 function extractChatMessages() {
39 const messagesContainer = document.querySelector('#app > div > div.main-layout-main-content > div > div > div > div.page > div > div.ViewCamWrapper__chatLayout\\#n4.chat > div.ViewCamWrapper__chat\\#MZ.model-chat.model-chat-normal.model-chat-size-medium > div > div.model-chat-container.public > div > div.model-chat-content > div.scroll-bar-container > div > div.messages');
40
41 if (!messagesContainer) {
42 console.error('[Stripchat Chat Logger] Messages container not found');
43 return [];
44 }
45
46 const messageElements = messagesContainer.querySelectorAll('.message');
47 const messages = [];
48
49 messageElements.forEach((msgElement, index) => {
50 try {
51 const messageBody = msgElement.querySelector('.message-body');
52 if (!messageBody) return;
53
54 // Extract username
55 const usernameElement = msgElement.querySelector('.user-levels-username-text, .message-username');
56 const username = usernameElement ? usernameElement.textContent.trim() : 'Unknown';
57
58 // Extract message text (everything after username)
59 const messageText = messageBody.textContent.replace(username, '').trim();
60
61 // Determine message type
62 let messageType = 'regular';
63 if (msgElement.classList.contains('tip-message')) {
64 messageType = 'tip';
65 } else if (msgElement.classList.contains('system-message')) {
66 messageType = 'system';
67 }
68
69 // Extract user level/league if available
70 const userLevel = msgElement.querySelector('[class*="color-league-"]');
71 const league = userLevel ? Array.from(userLevel.classList).find(c => c.startsWith('color-league-'))?.replace('color-league-', '') : null;
72
73 messages.push({
74 index: index,
75 timestamp: new Date().toISOString(),
76 username: username,
77 message: messageText,
78 type: messageType,
79 league: league
80 });
81 } catch (error) {
82 console.error('[Stripchat Chat Logger] Error extracting message:', error);
83 }
84 });
85
86 console.log(`[Stripchat Chat Logger] Extracted ${messages.length} messages`);
87 return messages;
88 }
89
90 // Save messages to JSON file and clipboard
91 async function saveMessagesToFile() {
92 const username = getUsername();
93 const dateTime = formatDateTime();
94 const filename = `sc_${username}_${dateTime}.json`;
95
96 const messages = extractChatMessages();
97
98 if (messages.length === 0) {
99 console.log('[Stripchat Chat Logger] No messages to save');
100 return;
101 }
102
103 const jsonData = {
104 metadata: {
105 username: username,
106 url: window.location.href,
107 captureTime: new Date().toISOString(),
108 messageCount: messages.length
109 },
110 messages: messages
111 };
112
113 const jsonString = JSON.stringify(jsonData, null, 2);
114
115 // Copy to clipboard
116 try {
117 await GM.setClipboard(jsonString);
118 console.log('[Stripchat Chat Logger] Copied to clipboard');
119 } catch (error) {
120 console.error('[Stripchat Chat Logger] Failed to copy to clipboard:', error);
121 }
122
123 // Save to file
124 const blob = new Blob([jsonString], { type: 'application/json' });
125 const url = URL.createObjectURL(blob);
126
127 const downloadLink = document.createElement('a');
128 downloadLink.href = url;
129 downloadLink.download = filename;
130 downloadLink.style.display = 'none';
131 document.body.appendChild(downloadLink);
132 downloadLink.click();
133 document.body.removeChild(downloadLink);
134 URL.revokeObjectURL(url);
135
136 console.log(`[Stripchat Chat Logger] Saved ${messages.length} messages to ${filename}`);
137 console.log(`[Stripchat Chat Logger] Recommended path: ~/Downloads/${username}/${filename}`);
138 }
139
140 // Update button appearance based on logging state
141 function updateButtonState() {
142 if (!controlButton) return;
143
144 if (isLogging) {
145 controlButton.style.backgroundColor = '#00ff00';
146 controlButton.title = 'Chat Logger: Active (Click to stop)';
147 } else {
148 controlButton.style.backgroundColor = '#ff0000';
149 controlButton.title = 'Chat Logger: Inactive (Click to start)';
150 }
151 }
152
153 // Start logging
154 function startLogging() {
155 if (isLogging) return;
156
157 isLogging = true;
158 console.log('[Stripchat Chat Logger] Starting logging...');
159
160 // Save immediately
161 saveMessagesToFile();
162
163 // Then save every minute
164 loggingInterval = setInterval(saveMessagesToFile, 60000);
165
166 updateButtonState();
167 console.log('[Stripchat Chat Logger] Logger active - saving every 60 seconds');
168 }
169
170 // Stop logging
171 function stopLogging() {
172 if (!isLogging) return;
173
174 isLogging = false;
175 console.log('[Stripchat Chat Logger] Stopping logging...');
176
177 if (loggingInterval) {
178 clearInterval(loggingInterval);
179 loggingInterval = null;
180 }
181
182 updateButtonState();
183 console.log('[Stripchat Chat Logger] Logger stopped');
184 }
185
186 // Toggle logging state
187 function toggleLogging() {
188 if (isLogging) {
189 stopLogging();
190 } else {
191 startLogging();
192 }
193 }
194
195 // Auto-hide button after delay
196 function scheduleAutoHide() {
197 if (autoHideTimeout) {
198 clearTimeout(autoHideTimeout);
199 }
200
201 controlButton.style.opacity = '1';
202
203 autoHideTimeout = setTimeout(() => {
204 controlButton.style.opacity = '0.3';
205 }, 2000);
206 }
207
208 // Create floating control button
209 function createControlButton() {
210 const videoArea = document.querySelector('#app > div > div.main-layout-main-content > div > div > div > div.page > div > div.ViewCamWrapper__chatLayout\\#n4.chat');
211
212 if (!videoArea) {
213 console.error('[Stripchat Chat Logger] Video area not found');
214 return;
215 }
216
217 controlButton = document.createElement('button');
218 controlButton.innerHTML = '📹';
219 controlButton.style.cssText = `
220 position: fixed;
221 bottom: 10px;
222 right: 10px;
223 width: 50px;
224 height: 50px;
225 border-radius: 50%;
226 border: 2px solid #ffffff;
227 background-color: #ff0000;
228 color: #ffffff;
229 font-size: 24px;
230 cursor: pointer;
231 z-index: 10000;
232 box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
233 transition: opacity 0.3s ease, transform 0.2s ease;
234 opacity: 0.3;
235 display: flex;
236 align-items: center;
237 justify-content: center;
238 `;
239
240 // Click to toggle logging
241 controlButton.addEventListener('click', (e) => {
242 e.stopPropagation();
243 toggleLogging();
244 });
245
246 // Hover effects
247 controlButton.addEventListener('mouseenter', () => {
248 controlButton.style.opacity = '1';
249 controlButton.style.transform = 'scale(1.1)';
250 if (autoHideTimeout) {
251 clearTimeout(autoHideTimeout);
252 }
253 });
254
255 controlButton.addEventListener('mouseleave', () => {
256 controlButton.style.transform = 'scale(1)';
257 scheduleAutoHide();
258 });
259
260 document.body.appendChild(controlButton);
261 updateButtonState();
262 scheduleAutoHide();
263
264 console.log('[Stripchat Chat Logger] Control button created');
265 }
266
267 // Initialize the logger
268 function init() {
269 console.log('[Stripchat Chat Logger] Initializing...');
270
271 // Wait for page to load
272 const checkPageLoaded = setInterval(() => {
273 const videoArea = document.querySelector('#app > div > div.main-layout-main-content > div > div > div > div.page > div > div.ViewCamWrapper__chatLayout\\#n4.chat');
274
275 if (videoArea) {
276 clearInterval(checkPageLoaded);
277 console.log('[Stripchat Chat Logger] Page loaded, creating control button');
278
279 createControlButton();
280 }
281 }, 1000);
282
283 // Stop checking after 30 seconds if page doesn't load
284 setTimeout(() => {
285 clearInterval(checkPageLoaded);
286 }, 30000);
287 }
288
289 // Start when page is ready
290 if (document.readyState === 'loading') {
291 document.addEventListener('DOMContentLoaded', init);
292 } else {
293 init();
294 }
295
296})();