forked from cs-util/TemplateJs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
466 lines (400 loc) · 16.4 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
<!-- User Stories & Requirements for the code below:
- This is a single-page HTML web app.
- A monospace font should be used.
- No backend; all data is stored locally (if needed).
- The app should be usable offline.
Main user stories:
- Prevent Microsoft Teams from marking the user as 'Away' due to inactivity.
- Simulate user activity through periodic mouse movements and keyboard inputs.
- Ensure the simulation runs seamlessly in the background without user intervention.
Keep this comment block in the code.
Simplify the code if possible (without removing the functionality described above).
You MUST keep all comments in the code below, even if you think they are redundant.
Always respond with the full new HTML file (including these comments here),
additional explanations of what you change are nice to have but not necessary.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Teams Status Preserver</title>
<!-- Favicon: An active status indicator -->
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ccircle cx='50' cy='50' r='40' fill='%2322c55e'/%3E%3Ccircle cx='50' cy='50' r='30' fill='%23dcfce7'/%3E%3Ccircle cx='50' cy='50' r='20' fill='%2322c55e'/%3E%3C/svg%3E" type="image/svg+xml">
<!-- Added Tailwind CSS via CDN -->
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="p-5 font-mono leading-relaxed max-w-3xl mx-auto">
<h1 class="text-2xl font-bold mb-4">Teams Status Preserver</h1>
<div class="border border-gray-300 p-5 mt-5 rounded-md">
<p><strong>How it works:</strong> This app simulates browser events to keep your Microsoft Teams status active even during periods of inactivity.</p>
<div class="p-2.5 my-2.5 bg-gray-100 rounded-md" id="statusDisplay">
Status: <span id="status" class="text-green-600">Active</span>
</div>
<div class="flex items-center">
<button id="toggleBtn" class="px-4 py-2 bg-blue-600 text-white rounded font-mono mr-2.5 cursor-pointer hover:bg-blue-700">Pause</button>
<span id="nextEvent"></span>
<button id="settingsBtn" class="ml-auto px-4 py-2 bg-gray-600 text-white rounded font-mono cursor-pointer hover:bg-gray-700">Settings</button>
</div>
<!-- Teams Quick Actions -->
<div class="mt-4 pt-4 border-t border-gray-300">
<h3 class="font-bold mb-2">Microsoft Teams Actions:</h3>
<div class="flex flex-wrap gap-2">
<button id="launchTeamsBtn" class="px-4 py-2 bg-indigo-600 text-white rounded font-mono cursor-pointer hover:bg-indigo-700">Launch Teams</button>
<button id="newMeetingBtn" class="px-4 py-2 bg-purple-600 text-white rounded font-mono cursor-pointer hover:bg-purple-700">New Meeting</button>
</div>
</div>
<h3 class="mt-4 font-bold">Recent Activity:</h3>
<div id="eventLog" class="h-24 overflow-y-auto border border-gray-300 p-2.5 mt-2.5 text-xs"></div>
</div>
<!-- Settings Modal -->
<div id="settingsModal" class="fixed inset-0 bg-black bg-opacity-50 hidden flex items-center justify-center">
<div class="bg-white p-6 rounded-lg shadow-lg w-96">
<h2 class="text-xl font-bold mb-4">Settings</h2>
<div class="mb-4">
<label class="block mb-2">Event Types:</label>
<div class="space-y-2">
<div>
<input type="checkbox" id="enableMouseMove" checked>
<label for="enableMouseMove">Mouse movements</label>
</div>
<div>
<input type="checkbox" id="enableMouseClick" checked>
<label for="enableMouseClick">Mouse clicks</label>
</div>
<div>
<input type="checkbox" id="enableKeyPress" checked>
<label for="enableKeyPress">Key presses</label>
</div>
<div>
<input type="checkbox" id="enableScroll" checked>
<label for="enableScroll">Scrolling</label>
</div>
</div>
</div>
<div class="mb-4">
<label for="eventFrequency" class="block mb-2">Event Frequency (seconds):</label>
<input type="range" id="eventFrequency" min="5" max="60" value="15" class="w-full">
<div class="flex justify-between text-xs">
<span>5s</span>
<span id="freqValue">15s</span>
<span>60s</span>
</div>
</div>
<div class="flex justify-end">
<button id="closeSettings" class="px-4 py-2 bg-gray-500 text-white rounded font-mono mr-2 hover:bg-gray-600">Cancel</button>
<button id="saveSettings" class="px-4 py-2 bg-blue-600 text-white rounded font-mono hover:bg-blue-700">Save</button>
</div>
</div>
</div>
<video class="hidden" autoplay loop muted playsinline>
<source src="https://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
<script>
// Configuration and state management
let active = true;
let eventIntervals = [];
let updateInterval;
let lastEvents = {
mouseMove: Date.now(),
mouseClick: Date.now(),
keyPress: Date.now(),
scroll: Date.now()
};
// Track next scheduled times
let nextScheduledTimes = {
mouseMove: 0,
mouseClick: 0,
keyPress: 0,
scroll: 0
};
// Settings with defaults
let settings = {
enableMouseMove: true,
enableMouseClick: true,
enableKeyPress: true,
enableScroll: true,
eventFrequency: 15
};
// DOM elements
const statusElement = document.getElementById('status');
const toggleBtn = document.getElementById('toggleBtn');
const eventLog = document.getElementById('eventLog');
const nextEventSpan = document.getElementById('nextEvent');
const settingsBtn = document.getElementById('settingsBtn');
const settingsModal = document.getElementById('settingsModal');
const closeSettings = document.getElementById('closeSettings');
const saveSettings = document.getElementById('saveSettings');
const freqSlider = document.getElementById('eventFrequency');
const freqValue = document.getElementById('freqValue');
const launchTeamsBtn = document.getElementById('launchTeamsBtn');
const newMeetingBtn = document.getElementById('newMeetingBtn');
// Load saved settings if available
loadSettings();
// Initialize settings UI
function updateSettingsUI() {
document.getElementById('enableMouseMove').checked = settings.enableMouseMove;
document.getElementById('enableMouseClick').checked = settings.enableMouseClick;
document.getElementById('enableKeyPress').checked = settings.enableKeyPress;
document.getElementById('enableScroll').checked = settings.enableScroll;
freqSlider.value = settings.eventFrequency;
freqValue.textContent = `${settings.eventFrequency}s`;
}
// Load settings from localStorage
function loadSettings() {
const savedSettings = localStorage.getItem('teamsPreserverSettings');
if (savedSettings) {
settings = {...settings, ...JSON.parse(savedSettings)};
}
updateSettingsUI();
}
// Save settings to localStorage
function saveSettingsToStorage() {
settings.enableMouseMove = document.getElementById('enableMouseMove').checked;
settings.enableMouseClick = document.getElementById('enableMouseClick').checked;
settings.enableKeyPress = document.getElementById('enableKeyPress').checked;
settings.enableScroll = document.getElementById('enableScroll').checked;
settings.eventFrequency = parseInt(freqSlider.value);
localStorage.setItem('teamsPreserverSettings', JSON.stringify(settings));
// Restart intervals with new settings
if (active) {
clearAllIntervals();
startIntervals();
logEvent("Settings updated, simulation restarted");
} else {
logEvent("Settings updated");
}
}
// Helper function to get randomized timing
function getRandomTiming() {
// Base frequency from settings with ±20% variation
const baseTime = settings.eventFrequency * 1000;
const variance = baseTime * 0.2; // 20% variance
return baseTime + (Math.random() * variance * 2 - variance);
}
// Get a random position within the viewport
function getRandomPosition() {
return {
x: Math.floor(Math.random() * window.innerWidth),
y: Math.floor(Math.random() * window.innerHeight)
};
}
// Microsoft Teams URL handlers
function launchTeams() {
window.open('https://teams.microsoft.com/', '_blank');
logEvent("Microsoft Teams launched in new tab");
}
function createNewMeeting() {
window.open('https://teams.microsoft.com/_#/calendarv2/createmeeting', '_blank');
logEvent("Microsoft Teams meeting creation opened in new tab");
}
// Simulates mouse movement with random positions
function simulateMouseMove() {
if (!active || !settings.enableMouseMove) return;
const pos = getRandomPosition();
const evt = new MouseEvent("mousemove", {
clientX: pos.x,
clientY: pos.y,
bubbles: true,
cancelable: true,
view: window
});
document.dispatchEvent(evt);
lastEvents.mouseMove = Date.now();
logEvent("Mouse movement simulated");
// Schedule next event with randomized timing
if (active && settings.enableMouseMove) {
const nextDelay = getRandomTiming();
nextScheduledTimes.mouseMove = Date.now() + nextDelay;
setTimeout(simulateMouseMove, nextDelay);
} else {
nextScheduledTimes.mouseMove = 0;
}
updateNextEventTime();
}
// Simulates mouse click
function simulateMouseClick() {
if (!active || !settings.enableMouseClick) return;
const pos = getRandomPosition();
const evt = new MouseEvent("click", {
clientX: pos.x,
clientY: pos.y,
bubbles: true,
cancelable: true,
view: window
});
document.dispatchEvent(evt);
lastEvents.mouseClick = Date.now();
logEvent("Mouse click simulated");
// Schedule next event with randomized timing
if (active && settings.enableMouseClick) {
const nextDelay = getRandomTiming() * 2; // Less frequent than moves
nextScheduledTimes.mouseClick = Date.now() + nextDelay;
setTimeout(simulateMouseClick, nextDelay);
} else {
nextScheduledTimes.mouseClick = 0;
}
updateNextEventTime();
}
// Simulates a key press (random keys)
function simulateKeyPress() {
if (!active || !settings.enableKeyPress) return;
// Array of safe keys to simulate
const keys = ['Shift', 'Control', 'Alt', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'];
const randomKey = keys[Math.floor(Math.random() * keys.length)];
const evt = new KeyboardEvent("keydown", {
key: randomKey,
code: randomKey + "Left",
bubbles: true
});
document.dispatchEvent(evt);
lastEvents.keyPress = Date.now();
logEvent(`Key press (${randomKey}) simulated`);
// Schedule next event with randomized timing
if (active && settings.enableKeyPress) {
const nextDelay = getRandomTiming() * 1.5;
nextScheduledTimes.keyPress = Date.now() + nextDelay;
setTimeout(simulateKeyPress, nextDelay);
} else {
nextScheduledTimes.keyPress = 0;
}
updateNextEventTime();
}
// Simulates scrolling
function simulateScroll() {
if (!active || !settings.enableScroll) return;
const scrollAmount = Math.floor(Math.random() * 100) - 50; // Random between -50 and 50
const evt = new WheelEvent("wheel", {
deltaY: scrollAmount,
bubbles: true
});
document.dispatchEvent(evt);
lastEvents.scroll = Date.now();
logEvent("Scroll event simulated");
// Schedule next event with randomized timing
if (active && settings.enableScroll) {
const nextDelay = getRandomTiming() * 2.5;
nextScheduledTimes.scroll = Date.now() + nextDelay;
setTimeout(simulateScroll, nextDelay);
} else {
nextScheduledTimes.scroll = 0;
}
updateNextEventTime();
}
// Log events to the UI
function logEvent(message) {
const timestamp = new Date().toLocaleTimeString();
const logEntry = document.createElement('div');
logEntry.textContent = `${timestamp}: ${message}`;
eventLog.prepend(logEntry);
// Limit log entries
if (eventLog.children.length > 20) {
eventLog.removeChild(eventLog.lastChild);
}
}
// Update the countdown to next event
function updateNextEventTime() {
const now = Date.now();
let nextTimes = [];
// Only include enabled and scheduled events
if (settings.enableMouseMove && nextScheduledTimes.mouseMove > now) {
nextTimes.push(nextScheduledTimes.mouseMove - now);
}
if (settings.enableMouseClick && nextScheduledTimes.mouseClick > now) {
nextTimes.push(nextScheduledTimes.mouseClick - now);
}
if (settings.enableKeyPress && nextScheduledTimes.keyPress > now) {
nextTimes.push(nextScheduledTimes.keyPress - now);
}
if (settings.enableScroll && nextScheduledTimes.scroll > now) {
nextTimes.push(nextScheduledTimes.scroll - now);
}
if (nextTimes.length === 0) {
nextEventSpan.textContent = "No events scheduled";
return;
}
const nextEvent = Math.min(...nextTimes);
nextEventSpan.textContent = `Next event in: ${Math.ceil(nextEvent / 1000)}s`;
}
// Clear all intervals and reset scheduled times
function clearAllIntervals() {
clearInterval(updateInterval);
nextScheduledTimes = {
mouseMove: 0,
mouseClick: 0,
keyPress: 0,
scroll: 0
};
}
// Toggle active state
function toggleActive() {
active = !active;
if (active) {
statusElement.textContent = "Active";
statusElement.className = "text-green-600";
toggleBtn.textContent = "Pause";
// Restart intervals
startIntervals();
logEvent("Simulation activated");
} else {
statusElement.textContent = "Paused";
statusElement.className = "text-red-600";
toggleBtn.textContent = "Resume";
// Clear intervals
clearAllIntervals();
logEvent("Simulation paused");
}
}
// Start all intervals
function startIntervals() {
// Start update interval for countdown
updateInterval = setInterval(updateNextEventTime, 1000);
// Start each enabled event type with its own timing
if (settings.enableMouseMove) {
const delay = 1000;
nextScheduledTimes.mouseMove = Date.now() + delay;
setTimeout(simulateMouseMove, delay);
}
if (settings.enableMouseClick) {
const delay = 2000;
nextScheduledTimes.mouseClick = Date.now() + delay;
setTimeout(simulateMouseClick, delay);
}
if (settings.enableKeyPress) {
const delay = 3000;
nextScheduledTimes.keyPress = Date.now() + delay;
setTimeout(simulateKeyPress, delay);
}
if (settings.enableScroll) {
const delay = 4000;
nextScheduledTimes.scroll = Date.now() + delay;
setTimeout(simulateScroll, delay);
}
// Initial update
updateNextEventTime();
}
// Setup event listeners
toggleBtn.addEventListener('click', toggleActive);
settingsBtn.addEventListener('click', () => {
updateSettingsUI();
settingsModal.classList.remove('hidden');
});
closeSettings.addEventListener('click', () => {
settingsModal.classList.add('hidden');
});
saveSettings.addEventListener('click', () => {
saveSettingsToStorage();
settingsModal.classList.add('hidden');
});
freqSlider.addEventListener('input', () => {
freqValue.textContent = `${freqSlider.value}s`;
});
// Microsoft Teams button event listeners
launchTeamsBtn.addEventListener('click', launchTeams);
newMeetingBtn.addEventListener('click', createNewMeeting);
// Initial setup
startIntervals();
logEvent("Application started");
</script>
</body>
</html>