您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Play sounds when users join, leave, or mention you in Multiplayer Piano
当前为
// ==UserScript== // @name Multiplayer Piano Optimizations [Sounds] // @namespace https://tampermonkey.net/ // @version 1.1.0 // @description Play sounds when users join, leave, or mention you in Multiplayer Piano // @author zackiboiz, cheezburger0, ccjit // @match *://multiplayerpiano.com/* // @match *://multiplayerpiano.net/* // @match *://multiplayerpiano.org/* // @match *://piano.mpp.community/* // @match *://mpp.7458.space/* // @match *://qmppv2.qwerty0301.repl.co/* // @match *://mpp.8448.space/* // @match *://mpp.autoplayer.xyz/* // @match *://mpp.hyye.xyz/* // @icon https://www.google.com/s2/favicons?sz=64&domain=multiplayerpiano.net // @grant GM_info // @license MIT // ==/UserScript== (async () => { function injectScript(src) { return new Promise((resolve, reject) => { const s = document.createElement("script"); s.src = src; s.async = false; s.onload = resolve; s.onerror = e => reject(e); document.head.appendChild(s); }); } await injectScript("https://code.jquery.com/ui/1.12.1/jquery-ui.js"); class SoundManager { constructor(version) { this.version = version; this.GAP_MS = 200; this.volume = 100; this.lastPlayed = {}; this.loadPacks(); } loadPacks() { const defaultPacks = { "Default": { MENTION: "https://files.catbox.moe/f5tzag.mp3", JOIN: "https://files.catbox.moe/t3ztlz.mp3", LEAVE: "https://files.catbox.moe/kmpz7e.mp3" }, "PRISM": { MENTION: "https://file.garden/aHFDYCLeNBLSceNi/Swoosh.wav", JOIN: "https://file.garden/aHFDYCLeNBLSceNi/Plug%20In.wav", LEAVE: "https://file.garden/aHFDYCLeNBLSceNi/Plug%20Out.wav" }, "Win11": { MENTION: "https://file.garden/aHFDYCLeNBLSceNi/Win11%20Notify.wav", JOIN: "https://file.garden/aHFDYCLeNBLSceNi/Win11%20Plug%20In.wav", LEAVE: "https://file.garden/aHFDYCLeNBLSceNi/Win11%20Plug%20Out.wav" }, "Discord": { MENTION: "https://file.garden/aHFDYCLeNBLSceNi/Discord%20Ping.mp3", JOIN: "https://file.garden/aHFDYCLeNBLSceNi/Discord%20Join.mp3", LEAVE: "https://file.garden/aHFDYCLeNBLSceNi/Discord%20Leave.mp3" } }; const stored = localStorage.getItem('savedSoundPacks'); if (stored) { try { this.packs = JSON.parse(stored); } catch (e) { console.error("Invalid saved sound packs, resetting to defaults.", e); this.packs = defaultPacks; } } else { this.packs = defaultPacks; } localStorage.setItem('savedSoundPacks', JSON.stringify(this.packs)); this.defaultPack = localStorage.getItem('defaultSoundPack') || 'Default'; if (!this.packs[this.defaultPack]) this.defaultPack = 'Default'; this.currentPack = this.defaultPack; this.SOUNDS = this.packs[this.currentPack]; } saveSoundPack({ NAME, MENTION, JOIN, LEAVE }) { if (!NAME || !MENTION || !JOIN || !LEAVE) { alert("All fields (NAME, MENTION, JOIN, LEAVE) are required."); return; } for (const [existingName, pack] of Object.entries(this.packs)) { if (pack.MENTION === MENTION && pack.JOIN === JOIN && pack.LEAVE === LEAVE) { alert(`Sound pack matches existing pack "${existingName}".`); return; } } let uniqueName = NAME; let i = 1; while (this.packs[uniqueName]) { uniqueName = `${NAME} (${i++})`; } this.packs[uniqueName] = { MENTION, JOIN, LEAVE }; localStorage.setItem('savedSoundPacks', JSON.stringify(this.packs)); alert(`Sound pack "${uniqueName}" imported successfully.`); this.updateDropdown(); } setSoundPack(name) { if (this.packs[name]) { this.SOUNDS = this.packs[name]; this.currentPack = name; } } setDefaultSoundPack(name) { if (this.packs[name]) { localStorage.setItem('defaultSoundPack', name); this.defaultPack = name; this.setSoundPack(name); } } play(src) { const now = Date.now(); if (!this.lastPlayed[src] || now - this.lastPlayed[src] >= this.GAP_MS) { this.lastPlayed[src] = now; const audio = new Audio(src); audio.volume = this.volume / 100; audio.play().catch(() => {}); } } updateDropdown() { const sel = $("#soundpack-select").empty(); Object.keys(this.packs).forEach(name => { const selAttr = name === this.currentPack ? ' selected' : ''; sel.append(`<option value="${name}"${selAttr}>${name}</option>`); }); } } const soundManager = new SoundManager(GM_info.script.version); let replyMap = {}; let users = {}; function handleMessage(msg) { const sender = msg.p ?? msg.sender; replyMap[msg.id] = sender._id; const you = MPP.client.user._id; const isMention = msg.a.includes(`@${you}`); const isReplyToYou = msg.r && replyMap[msg.r] === you; if ((isMention || isReplyToYou) && !document.hasFocus()) { soundManager.play(soundManager.SOUNDS.MENTION); } } MPP.client.on("a", handleMessage); MPP.client.on("dm", handleMessage); MPP.client.on("ch", ch => { users = {}; ch.ppl.forEach(u => users[u._id] = u); }); MPP.client.on("p", p => { if (!users[p._id]) soundManager.play(soundManager.SOUNDS.JOIN); users[p._id] = p; }); MPP.client.on("bye", u => { soundManager.play(soundManager.SOUNDS.LEAVE); delete users[u.p]; }); MPP.client.on("c", () => { MPP.chat.sendPrivate({ name: `[MPP Sounds] v${soundManager.version}`, color: "#ffaa00", message: "Sound alerts loaded." }); }); const $btn = $(`<div id="sounds-btn" class="ugly-button">MPP Sounds</div>`); $("#buttons").append($btn); const $modal = $(` <div id="sound-modal" class="dialog" style="height: 200px; margin-top: -100px;"> <h3>MPP Sounds</h3><hr> <p><label>Select pack: <select id="soundpack-select" class="text"></select></label></p> <p><label>Import JSON file: <input type="file" id="soundpack-file" accept=".json" /></label></p> <p><button id="set-soundpack" class="submit">SUBMIT</button></p> </div> `); $("#modal #modals").append($modal); function hideModals() { $("#modal #modals > *").hide(); $("#modal").hide(); } function showModal() { if (MPP.chat) MPP.chat.blur(); hideModals(); soundManager.updateDropdown(); $("#modal").fadeIn(250); $modal.show(); } $btn.on("click", showModal); $("#soundpack-file").on("change", function() { const file = this.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = e => { try { const json = JSON.parse(e.target.result); soundManager.saveSoundPack(json); } catch (err) { alert("Invalid JSON file."); } finally { this.value = ""; } }; reader.onerror = () => alert("Failed to read file."); reader.readAsText(file); }); $("#set-soundpack").on("click", () => { const name = $("#soundpack-select").val(); soundManager.setDefaultSoundPack(name); hideModals(); }); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址