您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Beep when a new message div is created or a key is pressed
- // ==UserScript==
- // @name AOPS classroom notification sound
- // @namespace http://tampermonkey.net/
- // @version 0.6
- // @description Beep when a new message div is created or a key is pressed
- // @author Shaun Wang
- // @match https://artofproblemsolving.com/classroom/*
- // @icon https://www.google.com/s2/favicons?sz=64&domain=artofproblemsolving.com
- // @grant none
- // ==/UserScript==
- (function() {
- 'use strict';
- // notification sound
- function notificationSound() {
- var context = new (window.AudioContext || window.webkitAudioContext)();
- // Oscillators and gain nodes for A and E notes
- var oscillatorA = context.createOscillator();
- var oscillatorE = context.createOscillator();
- var gainNodeA = context.createGain(); // Gain node for A note
- var gainNodeE = context.createGain(); // Gain node for E note
- oscillatorA.type = 'sine';
- oscillatorE.type = 'sine';
- // Connect oscillators to their respective gain nodes
- oscillatorA.connect(gainNodeA);
- oscillatorE.connect(gainNodeE);
- // Connect gain nodes to context destination
- gainNodeA.connect(context.destination);
- gainNodeE.connect(context.destination);
- // A note settings
- oscillatorA.frequency.setValueAtTime(440, context.currentTime);
- gainNodeA.gain.setValueAtTime(1, context.currentTime);
- gainNodeA.gain.exponentialRampToValueAtTime(0.00001, context.currentTime + 1);
- oscillatorA.start(context.currentTime);
- oscillatorA.stop(context.currentTime + 1);
- // E note settings (starts shortly after A)
- oscillatorE.frequency.setValueAtTime(659.25, context.currentTime);
- gainNodeE.gain.setValueAtTime(1, context.currentTime);
- gainNodeE.gain.exponentialRampToValueAtTime(0.00001, context.currentTime + 1);
- oscillatorE.start(context.currentTime + 0.05);
- oscillatorE.stop(context.currentTime + 1);
- }
- // 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';
- });
- }
- // monitors 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 });
- notificationSound();
- });
- })();