// ==UserScript== // @name AOPS classroom notification sound // @namespace http://tampermonkey.net/ // @version 0.1 // @description Beep when a new message div is created // @author Shaun Wang // @match https://artofproblemsolving.com/classroom/room/* // @grant none // @downloadURL none // ==/UserScript== (function() { 'use strict'; // Create a notification sound function notificationSound() { var context = new (window.AudioContext || window.webkitAudioContext)(); var oscillator = context.createOscillator(); var gainNode = context.createGain(); oscillator.connect(gainNode); gainNode.connect(context.destination); oscillator.type = 'sine'; // First beep (A note) oscillator.frequency.setValueAtTime(440, context.currentTime); gainNode.gain.setValueAtTime(1, context.currentTime); gainNode.gain.exponentialRampToValueAtTime(0.2, context.currentTime + 0.15); // Second beep (E note) oscillator.frequency.setValueAtTime(659.25, context.currentTime + 0.4); gainNode.gain.setValueAtTime(0.2, context.currentTime + 0.4); gainNode.gain.exponentialRampToValueAtTime(0.00001, context.currentTime + 1); oscillator.start(context.currentTime); oscillator.stop(context.currentTime + 1); } // Function to check if the new node has the required classes function isTargetNode(node) { return node.nodeType === 1 && node.classList.contains('styles_thread__3HaEQ') && node.classList.contains('styles_topTracked__wDRH_'); } // Mark existing messages to avoid triggering sound on them function markExistingMessages() { const existingMessages = document.querySelectorAll('.styles_thread__3HaEQ.styles_topTracked__wDRH_'); existingMessages.forEach(message => { message.dataset.seen = 'true'; }); } // Create a MutationObserver to monitor the page var observer = new MutationObserver(function(mutationsList) { for (var mutation of mutationsList) { if (mutation.type === 'childList') { for (var addedNode of mutation.addedNodes) { if (isTargetNode(addedNode) && !addedNode.dataset.seen) { addedNode.dataset.seen = 'true'; notificationSound(); } } } } }); // Mark existing messages and start observing for new ones window.addEventListener('load', function() { markExistingMessages(); observer.observe(document.body, { childList: true, subtree: true }); }); })();