Last active
June 10, 2022 21:53
-
-
Save octoshrimpy/29d26ad2b427179187551d614f50ab25 to your computer and use it in GitHub Desktop.
yoinks emotes from electronJS applications
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @name yoinker | |
* @author octoshrimpy | |
* @authorId 133721498421559296 | |
* @version 0.0.1 | |
* @description yoinks emotes from others, use with yent's emoteReplacer | |
*/ | |
// @todo add setting to auto-grab emotes as they appear | |
// @todo check if emote exists already (url, name, image comparison?) | |
// @todo test custom popout | |
//========================================================== | |
let popout = ` | |
<div class="custom"> | |
<div class="header"> | |
<span class="label">emoji matching</span> | |
<span class="catch"></span> | |
</div> | |
<div class="matches"> | |
</div> | |
` | |
let styles = ` | |
<style> | |
:root { | |
--modal-footer-background: #2f3136; | |
--interactive-normal: #b9bbbe; | |
--background-modifier-hover: rgba(136, 136, 136, 0.25); | |
--discord-blue: #2e438f; | |
} | |
.custom { | |
color: var(--interactive-normal); | |
background: var(--modal-footer-background); | |
padding: 0.5rem; | |
z-index: 3; | |
border-radius: 5px; | |
position: absolute; | |
left: 0; | |
margin: 8px; | |
right: 0; | |
/* bottom: calc(100% + 8px) */; | |
overflow: hidden; | |
box-shadow: var(--elevation-stroke),var(--elevation-high); | |
font-size: 100%; | |
vertical-align: baseline; | |
white-space: nowrap; | |
text-overflow: ellipsis; | |
} | |
.custom .label { | |
text-transform: uppercase; | |
font-family: inherit ; | |
} | |
.custom .catch { | |
font-weight: bold; | |
color: white; | |
} | |
.custom .catch:before { | |
content: ":"; | |
} | |
.custom .emote { | |
padding: 0.5rem; | |
} | |
.custom .emote:hover { | |
background: rgba(136, 136, 136, 0.25); | |
} | |
.custom .emote .name:before, | |
.custom .emote .name:after { | |
content: ":"; | |
} | |
.button.yoinked { | |
background: transparent; | |
cursor: default; | |
} | |
.button { | |
text-transform: uppercase; | |
padding: 0.5rem; | |
background: #2e438f; | |
color: white; | |
display: inline-block; | |
margin: 0.5rem 0 1rem; | |
float: right; | |
box-sizing: border-box; | |
font-size: 0.8em; | |
border-radius: 5px; | |
cursor: pointer; | |
font-weight: bold; | |
user-select: none; | |
} | |
</style> | |
` | |
// on click of emote | |
addCustomEventListener('.emoji', 'click', addYoinkButton) | |
addCustomEventListener('.button.yoink', 'click', yoinkEmote) | |
async function yoinkEmote(e) { | |
let img = e.target.closest('[id^="popout"]').querySelector('img') | |
let url = img.getAttribute('src') | |
let name = img.getAttribute("alt") | |
name = name.replaceAll(":", "") | |
if (url.match(/webp/g)) { | |
url = url.split('.webp')[0] + '.png' | |
} else | |
if (url.match(/gif/g)){ | |
url = url.split('.gif')[0] + '.gif' | |
} | |
let addedCorrectly = addEmoteToYent(name, url) | |
if (addedCorrectly) { | |
btn = e.target | |
let yoinkedBtn = createYoinkButton("", true) | |
btn.parentNode.insertBefore(yoinkedBtn, e.target) | |
e.target.parentNode.removeChild(e.target) | |
} | |
} | |
async function addYoinkButton(e) { | |
let emojiElm = e.target | |
if (emojiElm.getAttribute("data-name")) { return } | |
let emojiSelector = emojiElm.getAttribute("alt") | |
emojiSelector = emojiSelector.replaceAll(":", "") | |
let button = createYoinkButton(emojiSelector) | |
let img = await waitForElm('[id^="popout"] img') | |
img.parentElement.parentElement.appendChild(button) | |
} | |
// on user input | |
// let emoteSearchMatch = /(?:(?<=:)(?!\s))([\w\-\_]+)(?!:)(?=(\s|$))/g | |
// document.querySelector('[role="textbox"]').addEventListener("keyup", ((e) => { | |
// const lastTypedElm = e.target.querySelector("[data-slate-node='element']:last-child") | |
// const latestString = lastTypedElm.innerText | |
// const match = latestString.match(emoteSearchMatch) | |
// if (!!match) { | |
// let insertChildWithin = document.querySelector('form [class^="channelTextArea-"]') | |
// let popoutElm = insertChildWithin.querySelector('[role="listbox"]') | |
// if (!!popoutElm) { | |
// var tempDiv = document.createElement('div') | |
// tempDiv.innerHTML = popout | |
// popoutElm = tempDiv.innerHTML | |
// } | |
// insertChildWithin.appendChild(popoutElm) | |
// // for each match from our database | |
// // append a new matched elm | |
// // @todo | |
// // let match = new Match(name, url) | |
// } | |
// })) | |
class Match { | |
constructor(label, imgUrl) { | |
let img = this.createImg(imgUrl) | |
let name = this.createLabel(label) | |
return this.createWrap(img, name) | |
} | |
static createImg(url) { | |
let img = document.createElement('span') | |
img.classList.add('img') | |
img.style.backgroundImage = imgUrl | |
return img | |
} | |
static createLabel(label) { | |
let name = document.createElement('span') | |
name.classList.add('name') | |
name.innerText = label | |
return name | |
} | |
static createWrap(img, name) { | |
let wrap = document.createElement('div') | |
wrap.classList.add('emote') | |
wrap.appendChild(img) | |
wrap.appendChild(name) | |
return wrap | |
} | |
} | |
function createYoinkButton(emoteName, yoinked=false) { | |
let repl = BdApi.Plugins.get("EmoteReplacer").instance | |
let btn = document.createElement('div') | |
btn.classList.add('button') | |
if (checkIfNameUsedInYent(repl, emoteName) || yoinked){ | |
btn.innerText = "yoinked already" | |
btn.classList.add('yoinked') | |
} else { | |
btn.classList.add('yoink') | |
btn.innerText = "yoink emote" | |
} | |
return btn | |
} | |
// https://stackoverflow.com/a/61511955 | |
async function waitForElm(selector) { | |
return new Promise(resolve => { | |
if (document.querySelector(selector)) { | |
return resolve(document.querySelector(selector)) | |
} | |
const observer = new MutationObserver(mutations => { | |
if (document.querySelector(selector)) { | |
resolve(document.querySelector(selector)) | |
observer.disconnect() | |
} | |
}) | |
observer.observe(document.body, { | |
childList: true, | |
subtree: true | |
}) | |
}) | |
} | |
// https://dev.to/akhil_001/adding-event-listeners-to-the-future-dom-elements-using-event-bubbling-3cp1 | |
function addCustomEventListener(selector, event, handler) { | |
let rootElement = document.querySelector('body') | |
//since the root element is set to be body for our current dealings | |
rootElement.addEventListener(event, function (evt) { | |
var targetElement = evt.target | |
while (targetElement != null) { | |
if (targetElement.matches(selector)) { | |
handler(evt) | |
return | |
} | |
targetElement = targetElement.parentElement | |
} | |
}, | |
true) | |
} | |
// https://stackoverflow.com/q/3922139 | |
function addcss(css){ | |
var head = document.getElementsByTagName('head')[0]; | |
var s = document.createElement('style'); | |
s.setAttribute('type', 'text/css'); | |
if (s.styleSheet) { // IE | |
s.styleSheet.cssText = css; | |
} else { // the world | |
s.appendChild(document.createTextNode(css)); | |
} | |
head.appendChild(s); | |
} | |
addcss(styles) | |
function addEmoteToYent(emoteName, imageUrl) { | |
console.log(emoteName, imageUrl) | |
let repl = BdApi.Plugins.get("EmoteReplacer").instance | |
if (checkIfNameUsedInYent(repl, emoteName)) { | |
BdApi.showToast('Emote name already exists!', { type: 'error' }); | |
return false | |
} else { | |
repl.settings.customEmotes[emoteName] = imageUrl; | |
repl.emoteNames[repl.getPrefixedName(emoteName)] = imageUrl; | |
ZeresPluginLibrary.PluginUtilities.saveSettings(repl.getName(), repl.settings); | |
BdApi.showToast(`Emote ${emoteName} has been saved!`, { type: 'success' }); | |
} | |
return true | |
} | |
function checkIfNameUsedInYent(repl, name) { | |
console.log(name, !!repl.emoteNames[repl.getPrefixedName(name)]) | |
return repl.emoteNames[repl.getPrefixedName(name)] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment