// Reimplement PopupManager.open (() => { const pv = window.PvInternals; pv.popupMap = { [pv.Modal.BAN]: pv.components_popups_pv_ban_pv_ban, [pv.Modal.PROFILE]: pv.components_popups_pv_profile_pv_profile, [pv.Modal.SETTINGS]: pv.components_popups_pv_settings_pv_settings, [pv.Modal.MESSAGE]: pv.components_popups_pv_message_pv_message, [pv.Modal.NEW_ROOM]: pv.components_popups_pv_new_room_pv_new_room, [pv.Dialog.ROOMS]: pv.components_popups_pv_rooms_pv_rooms, [pv.Dialog.ACTIONS]: pv.components_popups_pv_actions_pv_actions, [pv.Dialog.DEVICES]: pv.components_popups_pv_devices_pv_devices, [pv.Dialog.SOUNDS]: pv.components_popups_pv_sounds_pv_sounds, [pv.Dialog.TRANSPOSE]: pv.components_popups_pv_transpose_pv_transpose, [pv.Dialog.VELOCITY]: pv.components_popups_pv_velocity_pv_velocity, }; pv.PopupManager.open = (popupName, ...args) => { let dialogElement = document.querySelector(popupName) if (dialogElement && !dialogElement.querySelector("dialog").hasAttribute("closing")) { dialogElement.close(); return dialogElement; } const popupClass = pv.popupMap[popupName]; if (!popupClass) { throw new Error(`Popup ${popupName} not found`); } dialogElement = new popupClass(); document.body.append(dialogElement); dialogElement.open(...args); return dialogElement; } })(); // custom rules (() => { const pv = window.PvInternals; class PvmeRulesModal extends pv.components_pv_popup_pv_popup { constructor() { super(); this.innerHTML = `
Rules
pianoverse.me rules are very simple.
  • Don't be annoying
  • Don't be racist
  • Do not argue punishments
That's it! :)
`; } } customElements.define("pvme-rules-modal", PvmeRulesModal); pv.Modal.RULES = "pvme-rules-modal"; pv.popupMap[pv.Modal.RULES] = PvmeRulesModal class PvmeRules extends HTMLElement {} customElements.define("pvme-rules", PvmeRules); let g = document.querySelector("body > pv-header > div.left"); { let a = document.createElement("div"); a.className = "divider"; a.style.marginLeft = "20px"; g.appendChild(a); } { let a = document.createElement("pvme-rules"); a.innerHTML = `
`; a.addEventListener("click", () => { pv.PopupManager.open(pv.Modal.RULES, null); }) g.appendChild(a); } })(); // change title (() => { const pv = window.PvInternals; document.querySelector("pv-room").updateBrowserTab = function () { if(pv.services_client.room.id) { if(pv.services_client.isConnected()) { document.title = `pv.me - ${pv.services_client.room.id} (${1 + pv.services_client.users.length})` } else { document.title = `pv.me - ${pv.services_client.room.id}` } } else { document.title = "pv.me" } } document.querySelector("body > pv-header > div.left > div.pianoverse > span").innerText = "pv.me" })(); (async () => { const pv = window.PvInternals; const style = document.createElement("style"); style.innerHTML = `pv-chat>div button:nth-child(3){position:absolute;right:40px;z-index:26;cursor:url(88b4a467a18e813218f8.cur),auto;font-size:1em;border:none;height:46px;aspect-ratio:1;padding:0;border-radius:0;box-shadow:none;margin:0;flex:0;color:var(--color-text)}pv-chat>div button:nth-child(3)>img:hover{transform-origin:50% 50%;transform:scale(1.4);transition:.1s}pv-chat>div input[type=text]{padding:0 90px 0 14px}.emoji-container{display:grid;grid-template-columns:auto auto auto auto auto auto}.emoji-container>*{text-align:center;margin:2px}` document.head.appendChild(style); let shiftHeldDown = false; // ShiftLeft/Right or False document.addEventListener("keydown", (e) => { if(!shiftHeldDown) shiftHeldDown = e.code; }) document.addEventListener("keyup", (e) => { if(e.code == shiftHeldDown) shiftHeldDown = false; }) const emojiRequest = await fetch("emojis.json"); let emojis = await emojiRequest.json() const discordEmojis = ["<:silly:1287108299057266850>", '<:bratkanye:1271842184798273668>', '', '<:blobpensive:978314885337346089>', '<:blobsip:978314935077597231>', '<:blobheart:856700296302428170>', '<:blobsaluteban:463464097137295392>', '<:blobthinkban:812905997034061834>', '<:blobreach:474817265339203584>', '', '<:nixos:1252753664397934646>', '<:archlinux:1252754080640667658>', '<:rust:1263598244588425388>', '<:perfect:1243013970764370061>', '<:True:811294080662896640>', '<:froglove:1228043131430240407>', '', '', '<:pianoverse:1218346119705133116>', '<:restart:1257118826106064899>', '<:tape:1274061265714811054>', '<:what:1279839007714316392>', '<:boof:1261047926088663161>', '<:CHECK_CHECK_1:1075442774649872384>', '<:CHECK_CROSS_1:1075442781708898414>', '', '', '', '<:cat:1184105614994063410>', '<:MBDTF:1263773146972946442>', '', '', '', '', '', '<:shut:714946339850420324>', '', '', '', '']; const discordEmojiRegex = /<(a?):(.*?):(\d+)>/g; const discordEmojiRegexWeb = /<(a?):(.*?):(\d+)>/g; function renderEmoji(emoji, size = "64") { const id = emoji.replace(discordEmojiRegex, "$3"); const isAnimated = !!emoji.replace(discordEmojiRegex, "$1") const img = document.createElement("img"); img.src = `https://cdn.discordapp.com/emojis/${id}.${isAnimated ? "gif" : "png"}?size=${size}`; img.alt = "emoji"; img.width = size; img.height = size; return img; } //#region Modal class PvmeEmojiPicker extends pv.components_pv_popup_pv_popup { constructor() { super(); const dialog = document.createElement("dialog"); dialog.className = "popup" dialog.setAttribute("modal", "") dialog.setAttribute("blocking", "") const header = document.createElement("div"); header.className = "header"; header.innerHTML = `
Emoji picker
` dialog.appendChild(header) const content = document.createElement("div") content.className = "content" // #region Modal search input const input = document.createElement("input") input.type = "text" input.value = pv.settingsmanager.get("latestEmojiLookup") || "" input.addEventListener("keyup", () => { pv.settingsmanager.set("latestEmojiLookup", input.value); this.renderContainer(document.querySelector(".emoji-container"), input.value) }); content.appendChild(input) // #endregion // #region Modal info const info = document.createElement("p") info.innerText = "Write 'discord' for discord emoijs, anything else for normal ones.\nHold shift before opening emoji picker to spam emojis." content.appendChild(info); //#endregion const container = document.createElement("div") container.className = "emoji-container" this.renderContainer(container, pv.settingsmanager.get("latestEmojiLookup") || "discord") content.append(container); dialog.appendChild(content) this.appendChild(dialog) } renderContainer(container, value) { container.innerHTML = "" if(value !== "discord") { emojis.filter(z => z[0].replace("_", " ").includes(value.toLowerCase()) || value.toLowerCase().includes(z[0].replace("_", " "))).slice(0, 30).forEach(z => { const div = document.createElement("div") div.innerText = z[1]; div.style.fontSize = "30px" div.addEventListener("click", () => { const chat = document.querySelector("pv-chat"); chat.input.value += z[1] + " "; console.log(shiftHeldDown) if(!shiftHeldDown) pv.PopupManager.closeModals(); setTimeout(() => { document.querySelector("pv-chat").input.scrollLeft = document.querySelector("pv-chat").input.scrollWidth; }, 50) }) container.appendChild(div); }) } else { discordEmojis.forEach((z) => { const img = renderEmoji(z, "64") img.addEventListener("click", () => { const chat = document.querySelector("pv-chat"); chat.input.value += z + " "; console.log(shiftHeldDown) if(!shiftHeldDown) pv.PopupManager.closeModals(); setTimeout(() => { document.querySelector("pv-chat").input.scrollLeft = document.querySelector("pv-chat").input.scrollWidth; }, 50) }) container.appendChild(img); }) } } } customElements.define("pvme-emoji-picker", PvmeEmojiPicker); pv.Modal.EMOJIS = "pvme-emoji-picker"; pv.popupMap[pv.Modal.EMOJIS] = PvmeEmojiPicker //#endregion //#region Button const button = document.createElement("button"); button.className = "send"; button.type = "button" button.ariaLabel = "Pick a emoji!" function changeEmoji(emoji) { button.firstElementChild?.remove() button.appendChild(renderEmoji(emoji, "32")); } changeEmoji(discordEmojis[Math.floor(Math.random() * discordEmojis.length)]); button.addEventListener("click", () => { pv.PopupManager.open(pv.Modal.EMOJIS); changeEmoji(discordEmojis[Math.floor(Math.random() * discordEmojis.length)]); }) document.querySelector("body > div > div.chat > pv-chat > div").appendChild(button) //#endregion let chatComponent = document.querySelector("pv-chat"); const proxied = new Proxy(chatComponent.sendChatMessage, { apply: async function (target, thisArg, argumentsList) { let result = chatComponent.input.value const normalEmojiMatches = result.matchAll(/(? z[0] == normalEmojiMatch[1]); if(emoji) { result = result.replaceAll(":"+emoji[0]+":", emoji[1]) } } chatComponent.input.value = result; return target(); } }); chatComponent.sendChatMessage = proxied; })();