diff --git a/cams.js b/cams.js
index 062d66f..e9b42a4 100644
--- a/cams.js
+++ b/cams.js
@@ -1,8 +1,8 @@
// ==UserScript==
// @name cams
// @namespace http://tampermonkey.net/
-// @version 1.0.1
-// @description Set maxDockedCamsForUser with a custom dialog
+// @version 1.2.0
+// @description Set maxDockedCamsForUser, keep-alive, and multi-poke
// @author You
// @match https://chat.fabswingers.com/*
// @updateURL https://git.upto.im/geekery/scripts/raw/branch/main/meta.js
@@ -15,7 +15,71 @@
'use strict';
const BUTTON_ID = 'maxDockedCamsButton_SINGLETON';
+ const KEEPALIVE_BUTTON_ID = 'keepAliveButton_SINGLETON';
+ const MULTIPOKE_BUTTON_ID = 'multiPokeButton_SINGLETON';
const LOCK_KEY = 'maxDockedCams_scriptLock';
+ const KEEPALIVE_SETTINGS_KEY = 'keepAlive_settings';
+ const MULTIPOKE_SETTINGS_KEY = 'multiPoke_settings';
+
+ // Public room names to match against
+ const PUBLIC_ROOMS = [
+ 'General Chat',
+ 'Directing Room',
+ 'Directing Room #2',
+ 'Directing Room #3',
+ 'Directing Room #4',
+ 'Directing Room #5',
+ 'Directing Room #6',
+ 'Site Supporters',
+ 'Verified Users',
+ 'Scotland Swingers',
+ 'Northern Swingers',
+ 'South East Swing',
+ 'South West Swing',
+ 'Midlands Swing',
+ 'East Anglia',
+ 'Ireland Swingers',
+ 'London Swingers',
+ 'Wales Swingers',
+ 'USA Swingers',
+ 'Canadian Swingers',
+ 'Bisexual Chat',
+ 'Bi Directing Room'
+ ];
+
+ const DEFAULT_INTERVAL = 10; // minutes
+ const DEFAULT_POKE_COUNT = 10;
+ const POKE_DELAY = 150; // ms between pokes
+
+ let keepAliveInterval = null;
+ let isKeepAliveRunning = false;
+ let keepAliveSettings = loadKeepAliveSettings();
+
+ let multiPokeEnabled = loadMultiPokeSettings();
+
+ function loadMultiPokeSettings() {
+ return localStorage.getItem(MULTIPOKE_SETTINGS_KEY) !== 'false';
+ }
+
+ function saveMultiPokeSettings() {
+ localStorage.setItem(MULTIPOKE_SETTINGS_KEY, multiPokeEnabled.toString());
+ }
+
+ function loadKeepAliveSettings() {
+ try {
+ const saved = localStorage.getItem(KEEPALIVE_SETTINGS_KEY);
+ if (saved) {
+ return JSON.parse(saved);
+ }
+ } catch (e) {
+ console.log('KeepAlive: Error loading settings', e);
+ }
+ return { intervalMinutes: DEFAULT_INTERVAL };
+ }
+
+ function saveKeepAliveSettings() {
+ localStorage.setItem(KEEPALIVE_SETTINGS_KEY, JSON.stringify(keepAliveSettings));
+ }
// Try to acquire lock
const lockValue = Date.now().toString();
@@ -33,17 +97,464 @@
}
});
- // Create custom dialog
- function showCustomPrompt() {
- // Create overlay
+ // Find a public room that the user has joined
+ function findPublicRoom() {
+ // Try multiple selectors for chat windows
+ const chatWindows = document.querySelectorAll('[id^="ChatWindow_"], [id^="chatwindow_"], .x-window');
+
+ for (const win of chatWindows) {
+ // Try multiple selectors for the title
+ const titleEl = win.querySelector('.x-window-header-text') ||
+ win.querySelector('.x-window-header span') ||
+ win.querySelector('[class*="header"] span');
+ if (titleEl) {
+ const title = titleEl.textContent.trim();
+ for (const publicRoom of PUBLIC_ROOMS) {
+ // Use startsWith to match "General Chat" in "General Chat (45)"
+ if (title.startsWith(publicRoom)) {
+ // Extract room ID from window ID
+ const idMatch = win.id.match(/(\d+)/);
+ const roomId = idMatch ? idMatch[1] : win.id.replace(/[^\d]/g, '');
+ if (roomId) {
+ console.log(`KeepAlive: Found public room "${title}" with ID ${roomId}`);
+ return { roomId, title };
+ }
+ }
+ }
+ }
+ }
+
+ // Fallback: check RoomListStore
+ if (typeof RoomListStore !== 'undefined' && RoomListStore.data) {
+ const rooms = RoomListStore.data.items || [];
+ for (const room of rooms) {
+ const roomData = room.data || room;
+ const name = roomData.Name || '';
+ for (const publicRoom of PUBLIC_ROOMS) {
+ if (name.startsWith(publicRoom)) {
+ console.log(`KeepAlive: Found public room "${name}" with ID ${roomData.ID}`);
+ return { roomId: roomData.ID, title: name };
+ }
+ }
+ }
+ }
+
+ // Debug: log what windows we can find
+ console.log('KeepAlive: Debug - searching for windows...');
+ document.querySelectorAll('.x-window').forEach(w => {
+ console.log('KeepAlive: Found window:', w.id, w.querySelector('.x-window-header-text')?.textContent);
+ });
+
+ return null;
+ }
+
+ function getUserId() {
+ if (typeof userID !== 'undefined') return userID;
+ if (typeof window.userID !== 'undefined') return window.userID;
+ if (typeof _currentUserID !== 'undefined') return _currentUserID;
+ if (typeof currentUserID !== 'undefined') return currentUserID;
+ return null;
+ }
+
+ function getAuthCode() {
+ if (typeof auth_code !== 'undefined') return auth_code;
+ if (typeof window.auth_code !== 'undefined') return window.auth_code;
+ if (typeof _authCode !== 'undefined') return _authCode;
+ if (typeof authCode !== 'undefined') return authCode;
+ return null;
+ }
+
+ function sendKeepAlive() {
+ const room = findPublicRoom();
+ if (!room) {
+ console.log('KeepAlive: No public room found');
+ return false;
+ }
+
+ // Find the chat input field for this room
+ // Look for input field within the chat window
+ const chatWindow = document.getElementById('ChatWindow_' + room.roomId) ||
+ document.querySelector(`[id*="${room.roomId}"].x-window`);
+
+ if (!chatWindow) {
+ console.log('KeepAlive: Could not find chat window element');
+ return sendKeepAliveViaAPI(room);
+ }
+
+ // Find the text input field - usually a textarea or input within the window
+ const inputField = chatWindow.querySelector('textarea') ||
+ chatWindow.querySelector('input[type="text"]') ||
+ chatWindow.querySelector('.x-form-text');
+
+ if (!inputField) {
+ console.log('KeepAlive: Could not find input field, trying API method');
+ return sendKeepAliveViaAPI(room);
+ }
+
+ // Store current value, set our message, trigger submit, restore
+ const originalValue = inputField.value;
+ inputField.value = ' ';
+ inputField.focus();
+
+ // Trigger input event
+ inputField.dispatchEvent(new Event('input', { bubbles: true }));
+ inputField.dispatchEvent(new Event('change', { bubbles: true }));
+
+ // Simulate Enter key press to submit
+ const enterEvent = new KeyboardEvent('keydown', {
+ key: 'Enter',
+ code: 'Enter',
+ keyCode: 13,
+ which: 13,
+ bubbles: true
+ });
+ inputField.dispatchEvent(enterEvent);
+
+ const enterPress = new KeyboardEvent('keypress', {
+ key: 'Enter',
+ code: 'Enter',
+ keyCode: 13,
+ which: 13,
+ bubbles: true
+ });
+ inputField.dispatchEvent(enterPress);
+
+ const enterUp = new KeyboardEvent('keyup', {
+ key: 'Enter',
+ code: 'Enter',
+ keyCode: 13,
+ which: 13,
+ bubbles: true
+ });
+ inputField.dispatchEvent(enterUp);
+
+ console.log(`KeepAlive: Simulated input to "${room.title}" at ${new Date().toLocaleTimeString()}`);
+ return true;
+ }
+
+ function sendKeepAliveViaAPI(room) {
+ const userId = getUserId();
+ if (!userId) {
+ console.log('KeepAlive: User ID not found');
+ return false;
+ }
+
+ const authCodeVal = getAuthCode();
+
+ if (typeof Coolite !== 'undefined' && Coolite.AjaxMethods && Coolite.AjaxMethods.AddChatLine) {
+ Coolite.AjaxMethods.AddChatLine(
+ room.roomId,
+ ' ',
+ userId,
+ window._ipaddress,
+ window._urlwebchatid,
+ window._urlwebchatkey,
+ false,
+ false,
+ false,
+ '',
+ authCodeVal,
+ {
+ success: function() {
+ console.log(`KeepAlive: Sent via API to "${room.title}" at ${new Date().toLocaleTimeString()}`);
+ },
+ failure: function(error) {
+ console.log('KeepAlive: Failed to send message', error);
+ }
+ }
+ );
+ return true;
+ } else {
+ console.log('KeepAlive: Coolite.AjaxMethods.AddChatLine not available');
+ return false;
+ }
+ }
+
+ function startKeepAlive() {
+ if (isKeepAliveRunning) return;
+
+ const intervalMs = keepAliveSettings.intervalMinutes * 60 * 1000;
+ keepAliveInterval = setInterval(sendKeepAlive, intervalMs);
+ isKeepAliveRunning = true;
+ updateKeepAliveButtonState();
+ console.log(`KeepAlive: Started with ${keepAliveSettings.intervalMinutes} minute interval`);
+
+ sendKeepAlive();
+ }
+
+ function stopKeepAlive() {
+ if (keepAliveInterval) {
+ clearInterval(keepAliveInterval);
+ keepAliveInterval = null;
+ }
+ isKeepAliveRunning = false;
+ updateKeepAliveButtonState();
+ console.log('KeepAlive: Stopped');
+ }
+
+ function updateKeepAliveButtonState() {
+ const button = document.getElementById(KEEPALIVE_BUTTON_ID);
+ if (button) {
+ if (isKeepAliveRunning) {
+ button.style.backgroundColor = '#f44336';
+ button.textContent = `Keep Alive ON (${keepAliveSettings.intervalMinutes}m)`;
+ } else {
+ button.style.backgroundColor = '#2196F3';
+ button.textContent = 'Keep Alive OFF';
+ }
+ }
+ }
+
+ function showKeepAliveDialog() {
+ const overlay = document.createElement('div');
+ overlay.style.cssText = 'position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.7); z-index: 9999999; display: flex; align-items: center; justify-content: center;';
+
+ const dialog = document.createElement('div');
+ dialog.style.cssText = 'background: white; padding: 20px; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.5); min-width: 300px;';
+
+ dialog.innerHTML = `
+
+
Keep Alive Settings
+
Interval (minutes):
+
+
Status: ${isKeepAliveRunning ? 'Running' : 'Stopped'}
+
+
+
+
+
+
+ `;
+
+ overlay.appendChild(dialog);
+ document.body.appendChild(overlay);
+
+ const input = document.getElementById('keepAliveIntervalInput');
+ const saveBtn = document.getElementById('keepAliveSaveBtn');
+ const cancelBtn = document.getElementById('keepAliveCancelBtn');
+ const toggleBtn = document.getElementById('keepAliveToggleBtn');
+
+ setTimeout(() => input.focus(), 100);
+
+ saveBtn.onclick = function() {
+ const value = parseInt(input.value, 10);
+ if (value >= 1 && value <= 30) {
+ keepAliveSettings.intervalMinutes = value;
+ saveKeepAliveSettings();
+
+ if (isKeepAliveRunning) {
+ stopKeepAlive();
+ startKeepAlive();
+ }
+
+ updateKeepAliveButtonState();
+ overlay.remove();
+ } else {
+ alert('Please enter a number between 1 and 30');
+ }
+ };
+
+ cancelBtn.onclick = function() {
+ overlay.remove();
+ };
+
+ toggleBtn.onclick = function() {
+ if (isKeepAliveRunning) {
+ stopKeepAlive();
+ } else {
+ const value = parseInt(input.value, 10);
+ if (value >= 1 && value <= 30) {
+ keepAliveSettings.intervalMinutes = value;
+ saveKeepAliveSettings();
+ }
+ startKeepAlive();
+ }
+ overlay.remove();
+ };
+
+ input.onkeypress = function(e) {
+ if (e.key === 'Enter') {
+ saveBtn.click();
+ }
+ };
+
+ overlay.onkeydown = function(e) {
+ if (e.key === 'Escape') {
+ cancelBtn.click();
+ }
+ };
+ }
+
+ // ==================== MULTI-POKE FUNCTIONALITY ====================
+
+ function performMultiPoke(roomId, userId, buttonElement) {
+ const originalText = buttonElement.textContent;
+ let pokeCount = 0;
+ const totalPokes = DEFAULT_POKE_COUNT;
+
+ // Disable the button during multi-poke
+ buttonElement.style.opacity = '0.5';
+ buttonElement.style.pointerEvents = 'none';
+
+ function sendPoke() {
+ if (pokeCount < totalPokes) {
+ try {
+ if (typeof window.PK === 'function') {
+ window.PK(roomId, userId);
+ } else if (typeof Coolite !== 'undefined' && Coolite.AjaxMethods && Coolite.AjaxMethods.Poke) {
+ Coolite.AjaxMethods.Poke(roomId, '', userId, '', '');
+ } else {
+ const tempPokeLink = document.createElement('a');
+ tempPokeLink.href = `javascript:PK('${roomId}','${userId}')`;
+ tempPokeLink.style.display = 'none';
+ document.body.appendChild(tempPokeLink);
+ tempPokeLink.click();
+ document.body.removeChild(tempPokeLink);
+ }
+ } catch (error) {
+ console.log('Poke error:', error);
+ }
+
+ pokeCount++;
+ buttonElement.textContent = `${totalPokes - pokeCount}x`;
+
+ if (pokeCount < totalPokes) {
+ setTimeout(sendPoke, POKE_DELAY);
+ } else {
+ setTimeout(() => {
+ buttonElement.textContent = originalText;
+ buttonElement.style.opacity = '';
+ buttonElement.style.pointerEvents = '';
+ }, 500);
+ }
+ }
+ }
+
+ sendPoke();
+ }
+
+ function addMultiPokeButtons() {
+ if (!multiPokeEnabled) return;
+
+ const userRows = document.querySelectorAll('.ur');
+
+ userRows.forEach(userRow => {
+ const allDiv = userRow.querySelector('.all');
+ if (!allDiv) return;
+ if (allDiv.innerHTML.trim() === '') return;
+ if (allDiv.querySelector('.multi-poke-btn')) return;
+
+ const pokeButton = allDiv.querySelector('a[href*="PK("]');
+ if (!pokeButton) return;
+
+ const pokeHref = pokeButton.getAttribute('href');
+ const match = pokeHref.match(/PK\('([^']+)','([^']+)'\)/);
+ if (!match) return;
+
+ const roomId = match[1];
+ const odlUserId = match[2];
+
+ const multiPokeBtn = document.createElement('a');
+ multiPokeBtn.className = 'multi-poke-btn';
+ multiPokeBtn.href = 'javascript:void(0)';
+ multiPokeBtn.textContent = '10x';
+ multiPokeBtn.title = 'Send 10 pokes';
+ multiPokeBtn.setAttribute('data-multi-poke', 'true');
+ multiPokeBtn.setAttribute('data-user-id', odlUserId);
+
+ multiPokeBtn.addEventListener('click', function(e) {
+ e.preventDefault();
+ performMultiPoke(roomId, odlUserId, this);
+ });
+
+ const space = document.createTextNode('\u00A0');
+ pokeButton.parentNode.insertBefore(space, pokeButton.nextSibling);
+ pokeButton.parentNode.insertBefore(multiPokeBtn, space.nextSibling);
+ });
+ }
+
+ function removeMultiPokeButtons() {
+ const multiPokeElements = document.querySelectorAll('.multi-poke-btn, [data-multi-poke="true"]');
+ multiPokeElements.forEach(element => {
+ if (element.previousSibling && element.previousSibling.nodeType === Node.TEXT_NODE) {
+ element.previousSibling.remove();
+ }
+ element.remove();
+ });
+ }
+
+ function toggleMultiPoke() {
+ multiPokeEnabled = !multiPokeEnabled;
+ saveMultiPokeSettings();
+ updateMultiPokeButtonState();
+
+ if (multiPokeEnabled) {
+ addMultiPokeButtons();
+ } else {
+ removeMultiPokeButtons();
+ }
+
+ console.log('Multi-poke', multiPokeEnabled ? 'enabled' : 'disabled');
+ }
+
+ function updateMultiPokeButtonState() {
+ const button = document.getElementById(MULTIPOKE_BUTTON_ID);
+ if (button) {
+ if (multiPokeEnabled) {
+ button.style.backgroundColor = '#ff6b35';
+ button.textContent = '10x ON';
+ } else {
+ button.style.backgroundColor = '#6c757d';
+ button.textContent = '10x OFF';
+ }
+ }
+ }
+
+ function observeUserList() {
+ const targetNode = document.querySelector('div[id*="CHATUSERLABEL"]') ||
+ document.querySelector('.x-panel-body') ||
+ document.body;
+
+ const observer = new MutationObserver(function(mutations) {
+ let shouldUpdate = false;
+ mutations.forEach(function(mutation) {
+ if (mutation.type === 'childList') {
+ mutation.addedNodes.forEach(node => {
+ if (node.nodeType === Node.ELEMENT_NODE &&
+ (node.classList && node.classList.contains('ur') || node.querySelector && node.querySelector('.ur'))) {
+ shouldUpdate = true;
+ }
+ });
+ }
+ if (mutation.type === 'childList' && mutation.target.classList && mutation.target.classList.contains('ur')) {
+ shouldUpdate = true;
+ }
+ });
+
+ if (shouldUpdate && multiPokeEnabled) {
+ clearTimeout(window.multiPokeUpdateDebounce);
+ window.multiPokeUpdateDebounce = setTimeout(() => {
+ addMultiPokeButtons();
+ }, 200);
+ }
+ });
+
+ observer.observe(targetNode, {
+ childList: true,
+ subtree: true
+ });
+ }
+
+ // ==================== END MULTI-POKE ====================
+
+ // Create custom dialog for MaxDockedCams
+ function showCustomPrompt() {
const overlay = document.createElement('div');
overlay.style.cssText = 'position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.7); z-index: 9999999; display: flex; align-items: center; justify-content: center;';
- // Create dialog box
const dialog = document.createElement('div');
dialog.style.cssText = 'background: white; padding: 20px; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.5); min-width: 300px;';
- // Add content
dialog.innerHTML = `
Set MaxDockedCams
@@ -63,10 +574,8 @@
const okBtn = document.getElementById('okBtn');
const cancelBtn = document.getElementById('cancelBtn');
- // Focus input
setTimeout(() => input.focus(), 100);
- // Handle OK button
okBtn.onclick = function() {
const value = input.value;
if (value === '') {
@@ -85,20 +594,17 @@
}
};
- // Handle Cancel button
cancelBtn.onclick = function() {
console.log('User cancelled');
overlay.remove();
};
- // Handle Enter key
input.onkeypress = function(e) {
if (e.key === 'Enter') {
okBtn.click();
}
};
- // Handle Escape key
overlay.onkeydown = function(e) {
if (e.key === 'Escape') {
cancelBtn.click();
@@ -106,34 +612,125 @@
};
}
- // Wait and create button
+ // Wait and create buttons
setTimeout(function() {
+ // Cleanup existing buttons
document.querySelectorAll(`[id^="maxDockedCamsButton"]`).forEach(btn => btn.remove());
+ document.querySelectorAll(`[id^="keepAliveButton"]`).forEach(btn => btn.remove());
- const button = document.createElement('button');
- button.id = BUTTON_ID;
- button.textContent = 'Set MaxDockedCams';
- button.type = 'button';
- button.style.cssText = 'position: fixed; top: 10px; right: 10px; z-index: 999999; padding: 8px 12px; background-color: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer; font-weight: bold; box-shadow: 0 2px 5px rgba(0,0,0,0.3);';
+ // MaxDockedCams button
+ const maxDockedButton = document.createElement('button');
+ maxDockedButton.id = BUTTON_ID;
+ maxDockedButton.textContent = 'Set MaxDockedCams';
+ maxDockedButton.type = 'button';
+ maxDockedButton.style.cssText = 'position: fixed; top: 10px; right: 10px; z-index: 999999; padding: 8px 12px; background-color: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer; font-weight: bold; box-shadow: 0 2px 5px rgba(0,0,0,0.3);';
- button.addEventListener('click', function(e) {
+ maxDockedButton.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
showCustomPrompt();
});
- document.body.appendChild(button);
+ document.body.appendChild(maxDockedButton);
console.log('MaxDockedCams button created');
+ // Keep Alive button
+ const keepAliveButton = document.createElement('button');
+ keepAliveButton.id = KEEPALIVE_BUTTON_ID;
+ keepAliveButton.type = 'button';
+ keepAliveButton.style.cssText = 'position: fixed; top: 10px; right: 170px; z-index: 999999; padding: 8px 12px; background-color: #2196F3; color: white; border: none; border-radius: 4px; cursor: pointer; font-weight: bold; box-shadow: 0 2px 5px rgba(0,0,0,0.3);';
+
+ keepAliveButton.addEventListener('click', function(e) {
+ e.preventDefault();
+ e.stopPropagation();
+ showKeepAliveDialog();
+ });
+
+ document.body.appendChild(keepAliveButton);
+ updateKeepAliveButtonState();
+ console.log('KeepAlive button created');
+
+ // Multi-Poke toggle button
+ document.querySelectorAll(`[id^="multiPokeButton"]`).forEach(btn => btn.remove());
+ const multiPokeButton = document.createElement('button');
+ multiPokeButton.id = MULTIPOKE_BUTTON_ID;
+ multiPokeButton.type = 'button';
+ multiPokeButton.style.cssText = 'position: fixed; top: 10px; right: 340px; z-index: 999999; padding: 8px 12px; background-color: #ff6b35; color: white; border: none; border-radius: 4px; cursor: pointer; font-weight: bold; box-shadow: 0 2px 5px rgba(0,0,0,0.3);';
+
+ multiPokeButton.addEventListener('click', function(e) {
+ e.preventDefault();
+ e.stopPropagation();
+ toggleMultiPoke();
+ });
+
+ document.body.appendChild(multiPokeButton);
+ updateMultiPokeButtonState();
+ console.log('MultiPoke button created');
+
+ // Auto-start keep-alive
+ setTimeout(function() {
+ startKeepAlive();
+ }, 2000);
+
+ // Initialize multi-poke if enabled
+ setTimeout(function() {
+ if (multiPokeEnabled) {
+ addMultiPokeButtons();
+ }
+ observeUserList();
+
+ // Periodic check for new users
+ setInterval(() => {
+ if (multiPokeEnabled) {
+ addMultiPokeButtons();
+ }
+ }, 2000);
+ }, 1000);
+
+ // Cleanup duplicate buttons periodically
setInterval(function() {
- const buttons = document.querySelectorAll(`#${BUTTON_ID}`);
- if (buttons.length > 1) {
- for (let i = 1; i < buttons.length; i++) {
- buttons[i].remove();
+ const maxDockedButtons = document.querySelectorAll(`#${BUTTON_ID}`);
+ if (maxDockedButtons.length > 1) {
+ for (let i = 1; i < maxDockedButtons.length; i++) {
+ maxDockedButtons[i].remove();
+ }
+ }
+
+ const keepAliveButtons = document.querySelectorAll(`#${KEEPALIVE_BUTTON_ID}`);
+ if (keepAliveButtons.length > 1) {
+ for (let i = 1; i < keepAliveButtons.length; i++) {
+ keepAliveButtons[i].remove();
+ }
+ }
+
+ const multiPokeButtons = document.querySelectorAll(`#${MULTIPOKE_BUTTON_ID}`);
+ if (multiPokeButtons.length > 1) {
+ for (let i = 1; i < multiPokeButtons.length; i++) {
+ multiPokeButtons[i].remove();
}
}
}, 500);
}, 100);
-})();
\ No newline at end of file
+ // Add CSS for multi-poke buttons
+ const style = document.createElement('style');
+ style.textContent = `
+ .multi-poke-btn {
+ background-color: #ff6b35 !important;
+ color: white !important;
+ padding: 1px 4px !important;
+ border-radius: 3px !important;
+ text-decoration: none !important;
+ font-weight: bold !important;
+ font-size: 10px !important;
+ margin-left: 2px !important;
+ }
+ .multi-poke-btn:hover {
+ background-color: #ff8c42 !important;
+ color: white !important;
+ }
+ `;
+ document.head.appendChild(style);
+
+})();
diff --git a/meta.js b/meta.js
index 8efcca0..1741f3a 100644
--- a/meta.js
+++ b/meta.js
@@ -1,9 +1,12 @@
// ==UserScript==
-// @name Button for more
-// @namespace https://git.upto.im/geekery/
-// @version 1.0.1
-// @description Button to add more portals
-// @author TheMonitor
+// @name cams
+// @namespace http://tampermonkey.net/
+// @version 1.2.0
+// @description Set maxDockedCamsForUser, keep-alive, and multi-poke
+// @author You
// @match https://chat.fabswingers.com/*
+// @updateURL https://git.upto.im/geekery/scripts/raw/branch/main/meta.js
+// @downloadURL https://git.upto.im/geekery/scripts/raw/branch/main/cams.js
// @grant none
-// ==/UserScript==
\ No newline at end of file
+// @run-at document-idle
+// ==/UserScript==