Skip to content

Instantly share code, notes, and snippets.

@octoshrimpy
Last active June 10, 2022 21:53
Show Gist options
  • Save octoshrimpy/29d26ad2b427179187551d614f50ab25 to your computer and use it in GitHub Desktop.
Save octoshrimpy/29d26ad2b427179187551d614f50ab25 to your computer and use it in GitHub Desktop.
yoinks emotes from electronJS applications
/**
* @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