您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Allows you to use many custom emotes in the Geoguessr chat
当前为
// ==UserScript== // @name Geoguessr Custom Emotes // @description Allows you to use many custom emotes in the Geoguessr chat // @version 2.0.2 // @author victheturtle#5159 // @license MIT // @match https://www.geoguessr.com/* // @icon https://www.geoguessr.com/_next/static/images/emote-gg-cf17a1f5d51d0ed53f01c65e941beb6d.png // @namespace https://greasyfork.org/users/967692-victheturtle // ==/UserScript== let geoguessrCustomEmotes = {}; const customEmotesInjectedClass = "custom-emotes-injected"; const getAllNewMessages = () => document.querySelectorAll(`div[class*="chat-message_messageContent__"]:not([class*="${customEmotesInjectedClass}"])`); const _cndic = {}; const hrefset = new Set(); async function scanStyles() { for (let node of document.querySelectorAll('head link[rel="preload"], head style[data-n-href*=".css"]')) { const href = node.href || location.origin+node.dataset.nHref; if (hrefset.has(href)) continue; hrefset.add(href); await fetch(href) .then(res => res.text()) .then(stylesheet => { for (let className of stylesheet.split(".")) { const ind = className.indexOf("__"); if (ind != -1) _cndic[className.substr(0, ind+2)] = className.substr(0, ind+7); }; }); }; } const cn = (classNameStart) => _cndic[classNameStart]; // cn("status_section__") -> "status_section__8uP8o" const emoteInjectionTemplate = (emoteSrc) => `</span> <span class="${cn("chat-message_emoteWrapper__")}"><img src="${emoteSrc}" class="${cn("chat-message_messageEmote__")}"></span> <span class="${cn("chat-message_messageText__")}">`; let observer = new MutationObserver((mutations) => { let newMessages = getAllNewMessages(); if (newMessages.length == 0) return; scanStyles().then(() => { for (let message of newMessages) { let words = message.innerHTML.split(/((?:<|>|<|>|,| |\.)+)/g); for (let i=0; i<words.length; i+=2) { if (words[i] == "") continue; let lowercaseWord = words[i].toLowerCase(); for (let emoteName in geoguessrCustomEmotes) { if (lowercaseWord == emoteName.toLowerCase()) { words[i] = emoteInjectionTemplate(geoguessrCustomEmotes[emoteName]); break; } } } message.innerHTML = words.join(""); message.classList.add(customEmotesInjectedClass); }}) }); async function fetchEmotesRepository() { const lastTimeFetched = localStorage.getItem("CustomEmotesLastFetched")*1 if (Date.now() - lastTimeFetched < 60*1000) { // Github API has a limit rate of 60 requests per hour so prevent more than 1 request per minute return localStorage.getItem("CustomEmotesStored") } else { const emotesRepositoryContent = await fetch("https://api.github.com/gists/7e5046589b0f020c1ec80629c582cca6") .then(it => it.json()) .then(it => it.files["GeoguessrCustomEmotesRepository.json"].content); localStorage.setItem("CustomEmotesStored", emotesRepositoryContent); localStorage.setItem("CustomEmotesLastFetched", Date.now()); return emotesRepositoryContent; } } (() => { fetchEmotesRepository().then(emotesRepositoryContent => { geoguessrCustomEmotes = JSON.parse(emotesRepositoryContent); observer.observe(document.body, { subtree: true, childList: true }); }).catch(err => console.log(`Geoguessr Custom Emotes error at fetchEmotesRepository(): ${err}`)); })();