pianoverse_client/extra.js

252 lines
No EOL
12 KiB
JavaScript

// 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 = `<dialog blocking class=popup modal><div class=header><div class=title style=margin-right:20px><i class="fas fa-info-circle"></i> Rules</div><div class=x><i class="fas fa-xmark"></i></div></div><div class=content><div class=message><b>pianoverse.me rules are very simple.</b><ul><li>Don't be annoying<li>Don't be racist<li>Do not argue punishments</ul>That's it! :)</div></div></dialog>`;
}
}
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 = `<div class="icon" aria-label="Rules" data-tooltip="Rules"><i class="fas fa-scale-balanced"></i></div>`;
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 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 pv = window.PvInternals;
const emojiRequest = await fetch("emojis.json");
let emojis = await emojiRequest.json()
const discordEmojis = ["<:silly:1287108299057266850>", '<:bratkanye:1271842184798273668>', '<a:aniblobsweat:586029851870363660>', '<:blobpensive:978314885337346089>', '<:blobsip:978314935077597231>', '<:blobheart:856700296302428170>', '<:blobsaluteban:463464097137295392>', '<:blobthinkban:812905997034061834>', '<:blobreach:474817265339203584>', '<a:blobReachAustralia:1247812442239795282>', '<:nixos:1252753664397934646>', '<:archlinux:1252754080640667658>', '<:rust:1263598244588425388>', '<:perfect:1243013970764370061>', '<:True:811294080662896640>', '<:froglove:1228043131430240407>', '<a:frogpop:1228043129811374081>', '<a:frogwave:1228043128871845979>', '<:pianoverse:1218346119705133116>', '<:restart:1257118826106064899>', '<:tape:1274061265714811054>', '<:what:1279839007714316392>', '<:boof:1261047926088663161>', '<:CHECK_CHECK_1:1075442774649872384>', '<:CHECK_CROSS_1:1075442781708898414>', '<a:pogg:947236908256362496>', '<a:peeposhy:1052873747561971732>', '<a:catfbi:1292722712212672582>', '<:cat:1184105614994063410>', '<:MBDTF:1263773146972946442>', '<a:SpeedL:906979227939778580>', '<a:SpeedR:906979227876864051>', '<a:newports:1005206666792419458>', '<a:myman:829624853845245953>', '<a:skyperock:937848388685279262>', '<:shut:714946339850420324>', '<a:sponge:854419399871561800>', '<a:weedwalker:855115903426625578>', '<a:furret:791595456147750943>', '<a:weewoo_red:706925335228317868>'];
const discordEmojiRegex = /<(a?):(.*?):(\d+)>/g;
const discordEmojiRegexWeb = /&lt;(a?):(.*?):(\d+)&gt;/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 = `<div class="title"><i class="fas fa-info-circle" aria-hidden="true"></i>Emoji picker</div><div class="x"><i class="fas fa-xmark" aria-hidden="true"></i></div>`
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(/(?<!&lt;)(?<!<):([a-z0-9A-Z]*):/gm);
for (const normalEmojiMatch of normalEmojiMatches) {
let emoji = emojis.find(z => z[0] == normalEmojiMatch[1]);
if(emoji) {
result = result.replaceAll(":"+emoji[0]+":", emoji[1])
}
}
chatComponent.input.value = result;
return target();
}
});
chatComponent.sendChatMessage = proxied;
})();