Sniffies Saved Phrases

Adds an overlay for quick phrase selection and user blocking on Sniffies.com

  1. // ==UserScript==
  2. // @name Sniffies Saved Phrases
  3. // @version 1.4
  4. // @description Adds an overlay for quick phrase selection and user blocking on Sniffies.com
  5. // @author LiveCamShow
  6. // @match *://sniffies.com/*
  7. // @grant GM_xmlhttpRequest
  8. // @homepageURL https://gitlab.com/livecamshow/UserScripts
  9. // @namespace LiveCamShow.scripts
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13.  
  14. (function () {
  15. 'use strict';
  16.  
  17. const phrases = [
  18. "Hey man, what's up?",
  19. "Hey man, looking good!",
  20. "Wanna hang out?",
  21. "I'm into...."
  22. ];
  23.  
  24. let currentIndex = 0;
  25. let overlayVisible = false;
  26.  
  27. const overlay = document.createElement("div");
  28. overlay.id = "phraseOverlay";
  29. const style = document.createElement("style");
  30. style.textContent = `
  31. #phraseOverlay {
  32. position: absolute;
  33. width: 320px;
  34. max-height: 90%;
  35. background: #0f1e35;
  36. border-radius: 8px;
  37. padding: 12px;
  38. box-shadow: 0 4px 12px rgba(14, 22, 33, .25);
  39. color: #d4d9e4;
  40. border-top: 4px solid #4b84e6;
  41. border-bottom: 4px solid #4b84e6;
  42. font-family: "Arial", sans-serif;
  43. z-index: 9999;
  44. display: none;
  45. animation: fadeIn 0.25s cubic-bezier(.165, .84, .44, 1);
  46. overflow-y: auto;
  47. }
  48.  
  49. #phraseOverlay ul {
  50. padding: 0;
  51. margin: 0;
  52. list-style: none;
  53. }
  54.  
  55. #phraseOverlay li {
  56. padding: 8px;
  57. cursor: pointer;
  58. background-color: #2e3d51;
  59. color: #d4d9e4;
  60. border-radius: 4px;
  61. margin-bottom: 4px;
  62. }
  63.  
  64. #phraseOverlay li:hover {
  65. background-color: #3c5f9c;
  66. }
  67.  
  68. #phraseOverlay li.active {
  69. background-color: #4b84e6;
  70. color: #ffffff;
  71. }
  72.  
  73. @keyframes fadeIn {
  74. from {
  75. opacity: 0;
  76. transform: translateY(-10px);
  77. }
  78. to {
  79. opacity: 1;
  80. transform: translateY(0);
  81. }
  82. }
  83. `;
  84. document.head.appendChild(style);
  85. document.body.appendChild(overlay);
  86.  
  87. const phraseList = document.createElement("ul");
  88. phrases.forEach((phrase, index) => {
  89. const listItem = document.createElement("li");
  90. listItem.textContent = phrase;
  91. listItem.classList.toggle("active", index === currentIndex);
  92. listItem.addEventListener("click", () => selectPhrase(index));
  93. phraseList.appendChild(listItem);
  94. });
  95. overlay.appendChild(phraseList);
  96.  
  97. // Helper function to update the overlay display
  98. function updateOverlay() {
  99. const listItems = Array.from(phraseList.children);
  100. listItems.forEach((li, index) => li.classList.toggle("active", index === currentIndex));
  101. }
  102.  
  103. // Optimized positioning function
  104. function positionOverlay() {
  105. const chatInputPanel = document.getElementById("chat-input-panel");
  106. if (!chatInputPanel) return; // If panel doesn't exist, no need to position the overlay
  107.  
  108. const chatInputRect = chatInputPanel.getBoundingClientRect();
  109. overlay.style.left = `${chatInputRect.left + (chatInputRect.width / 2) - (overlay.offsetWidth / 2)}px`;
  110. overlay.style.top = `${chatInputRect.top - overlay.offsetHeight}px`;
  111. }
  112.  
  113. // Event listener to toggle the overlay visibility
  114. document.addEventListener("keydown", (e) => {
  115. if (e.shiftKey && e.ctrlKey && window.location.pathname.endsWith('/chat')) {
  116. overlayVisible = !overlayVisible;
  117. overlay.style.display = overlayVisible ? "block" : "none";
  118. if (overlayVisible) {
  119. currentIndex = 0;
  120. updateOverlay();
  121. positionOverlay(); // Only update position when overlay is visible
  122. }
  123. }
  124.  
  125. if (overlayVisible) {
  126. if (e.key === "ArrowDown") {
  127. currentIndex = (currentIndex + 1) % phrases.length;
  128. updateOverlay();
  129. e.preventDefault();
  130. } else if (e.key === "ArrowUp") {
  131. currentIndex = (currentIndex - 1 + phrases.length) % phrases.length;
  132. updateOverlay();
  133. e.preventDefault();
  134. } else if (e.key === "Enter") {
  135. selectPhrase(currentIndex);
  136. e.preventDefault();
  137. }
  138. }
  139. });
  140.  
  141. // Function to handle the phrase selection
  142. function selectPhrase(index) {
  143. const selectedPhrase = phrases[index];
  144. overlay.style.display = "none";
  145. overlayVisible = false;
  146.  
  147. const inputField = document.querySelector("input[type='text'], textarea");
  148. const submitButton = document.querySelector('#chat-input-send-text-or-saved-photo');
  149.  
  150. if (inputField) {
  151. inputField.value = selectedPhrase;
  152. inputField.dispatchEvent(new Event("input", { bubbles: true }));
  153. if (submitButton) {
  154. submitButton.click();
  155. }
  156. }
  157. }
  158.  
  159. // Mutation observer to handle removal of the chat input panel
  160. const observer = new MutationObserver(() => {
  161. if (!document.getElementById("chat-input-panel")) {
  162. overlay.style.display = "none";
  163. overlayVisible = false;
  164. }
  165. });
  166. observer.observe(document.body, { childList: true, subtree: true });
  167.  
  168. // Ensure overlay is positioned correctly when the page is loaded
  169. window.addEventListener('load', positionOverlay);
  170. })();