您需要先安装一个扩展,例如 篡改猴、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.3 // @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 = reject; document.head.appendChild(s); }); } await injectScript("https://code.jquery.com/ui/1.12.1/jquery-ui.js"); if (!MPP.chat.sendPrivate) { MPP.chat.sendPrivate = ({ name, color, message }) => { MPP.chat.receive({ m: "a", t: Date.now(), a: message, p: { _id: "usrscr", id: "userscript", name, color } }); }; } const builtin = [ { NAME: "Default [Zacki]", MENTION: "https://files.catbox.moe/f5tzag.mp3", JOIN: "https://files.catbox.moe/t3ztlz.mp3", LEAVE: "https://files.catbox.moe/kmpz7e.mp3" }, { NAME: "PRISM [ccjit]", MENTION: "https://file.garden/aHFDYCLeNBLSceNi/Swoosh.wav", JOIN: "https://file.garden/aHFDYCLeNBLSceNi/Plug%20In.wav", LEAVE: "https://file.garden/aHFDYCLeNBLSceNi/Plug%20Out.wav" }, { NAME: "Win11 [ccjit]", 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" }, { NAME: "Discord [ccjit]", MENTION: "https://file.garden/aHFDYCLeNBLSceNi/Discord%20Ping.mp3", JOIN: "https://file.garden/aHFDYCLeNBLSceNi/Discord%20Join.mp3", LEAVE: "https://file.garden/aHFDYCLeNBLSceNi/Discord%20Leave.mp3" }, { NAME: "Xylo [cheezburger0]", MENTION: "https://file.garden/ZXdl6GMYuz15ftGp/mention.wav", JOIN: "https://file.garden/ZXdl6GMYuz15ftGp/join.wav", LEAVE: "https://file.garden/ZXdl6GMYuz15ftGp/leave.wav" } ]; const defaultName = builtin[0].NAME; class SoundManager { constructor(version) { this.version = version; this.GAP_MS = 200; this.volume = 1.0; this.lastPlayed = {}; this._loadSoundpacks(); const stored = localStorage.getItem("currentSoundpack") || defaultName; this.currentSoundpack = this.soundpacks[stored] ? stored : defaultName; this.SOUNDS = this.soundpacks[this.currentSoundpack]; } _loadSoundpacks() { let saved = {}; try { saved = JSON.parse(localStorage.getItem("savedSoundpacks")) || {}; } catch (err) { console.warn("Invalid savedSoundpacks JSON, reverting to builtin only.", err); } this.soundpacks = { ...saved }; builtin.forEach(soundpack => { this.saveSoundpack(soundpack, true); }); localStorage.setItem("savedSoundpacks", JSON.stringify(this.soundpacks)); } setCurrentSoundpack(name) { if (!this.soundpacks[name]) { console.warn(`Soundpack "${name}" does not exist.`); return; } this.currentSoundpack = name; this.SOUNDS = this.soundpacks[name]; localStorage.setItem("currentSoundpack", name); this._refreshDropdown(); } saveSoundpack({ NAME, MENTION, JOIN, LEAVE }, loading = false) { if (!NAME || !MENTION || !JOIN || !LEAVE) { if (!loading) alert("All fields (NAME, MENTION, JOIN, LEAVE) are required."); return; } for (const [existingName, sp] of Object.entries(this.soundpacks)) { if (sp.MENTION === MENTION && sp.JOIN === JOIN && sp.LEAVE === LEAVE) { if (!loading) alert(`This soundpack is identical to "${existingName}".`); return; } } let unique = NAME; let counter = 1; while (this.soundpacks[unique]) { unique = `${NAME} (${counter++})`; } this.soundpacks[unique] = { MENTION, JOIN, LEAVE }; localStorage.setItem("savedSoundpacks", JSON.stringify(this.soundpacks)); if (!loading) alert(`Imported soundpack "${unique}".`); this._refreshDropdown?.(); } 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; audio.play().catch(() => { }); } } _refreshDropdown() { const select = document.querySelector("#soundpack-select"); if (!select) return; select.innerHTML = ""; for (const name of Object.keys(this.soundpacks)) { const opt = document.createElement("option"); opt.value = name; opt.textContent = name; if (name === this.currentSoundpack) { opt.selected = true; } select.appendChild(opt); } } } const soundManager = new SoundManager(GM_info.script.version); let replyTo = {}; let users = {}; function onMessage(msg) { const sender = msg.p ?? msg.sender; replyTo[msg.id] = sender._id; const me = MPP.client.user._id; const mention = msg.a.includes(`@${me}`); const replyMention = msg.r && replyTo[msg.r] === me; if ((mention || replyMention) && !document.hasFocus()) { soundManager.play(soundManager.SOUNDS.MENTION); } } MPP.client.on("a", onMessage); MPP.client.on("dm", onMessage); 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." }); }); // check for compatibility with hri mpp-hats const $btn = $(`<button id="soundpack-btn" class="ugly-button top-button" style="position: fixed; right: 6px; top: ${$('.mpp-hats-button').length ? 84 : 58}px; z-index: 100; padding: 5px;">MPP Sounds</button>`); $("body").append($btn); const $modal = $(` <div id="soundpack-modal" class="dialog" style="height: 240px; margin-top: -120px; display: none;"> <h3>MPP Soundpacks</h3><hr> <p> <label>Select soundpack: <select id="soundpack-select" class="text"></select> </label> </p> <p> <label>Import from JSON: <input type="file" id="soundpack-file" accept=".json"/> </label> </p> <p> <label>Reset Soundpacks: <button id="reset-soundpacks">Reset to default</button> </label> </p> <p><button id="soundpack-submit" class="submit">OK</button></p> </div> `); $("#modal #modals").append($modal); function hideAllModals() { $("#modal #modals > *").hide(); $("#modal").hide(); } function showModal() { if (MPP.chat) MPP.chat.blur(); hideAllModals(); soundManager._refreshDropdown(); $("#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 data = JSON.parse(e.target.result); soundManager.saveSoundpack(data); } catch { alert("Invalid JSON file."); } finally { this.value = ""; } }; reader.onerror = () => alert("Failed to read file."); reader.readAsText(file); }); $("#soundpack-submit").on("click", () => { const sel = $("#soundpack-select").val(); soundManager.setCurrentSoundpack(sel); hideAllModals(); }); $("#reset-soundpacks").on("click", () => { if (confirm("Are you sure you want to reset your soundpacks?")) { soundManager.soundpacks = {}; builtin.forEach(soundpack => { soundManager.saveSoundpack(soundpack, true); }); localStorage.setItem("savedSoundpacks", JSON.stringify(soundManager.soundpacks)); alert("Successfully reset your soundpacks!"); soundManager.setCurrentSoundpack(defaultName); } }); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址