This repository has been archived by the owner on Jun 27, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #93 from joe27g/avatar_links
rewrite avatar_links | fixes #91
- Loading branch information
Showing
1 changed file
with
98 additions
and
118 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,127 +1,107 @@ | ||
const Plugin = require('../plugin'); | ||
|
||
function copyToClipboard(text) { | ||
let textArea = document.createElement("textarea"); | ||
textArea.value = text; | ||
document.body.appendChild(textArea); | ||
|
||
textArea.focus(); | ||
textArea.select(); | ||
document.execCommand('copy'); | ||
|
||
document.body.removeChild(textArea); | ||
} | ||
function addMenuItem(imageURL, d, text) { | ||
let cmGroups = document.getElementsByClassName('itemGroup-1tL0uz'); | ||
if (!cmGroups || cmGroups.length == 0) return; | ||
|
||
let newCmItem = document.createElement('div'); | ||
newCmItem.className = 'item-1Yvehc'; | ||
let newCmItemContent = document.createElement('span'); | ||
newCmItemContent.innerHTML = text; | ||
newCmItem.appendChild(newCmItemContent); | ||
|
||
let lastGroup = cmGroups[cmGroups.length-1]; | ||
lastGroup.appendChild(newCmItem); | ||
|
||
// adjust context menu placement | ||
let cm = lastGroup.parentElement; | ||
let top = parseInt(cm.style.top); | ||
cm.style.top = (top - 28)+'px'; | ||
|
||
newCmItem.onclick = function(e) { | ||
copyToClipboard(imageURL); | ||
d.dispatch({ type: "CONTEXT_MENU_CLOSE" }); | ||
} | ||
} | ||
const Plugin = require("../plugin"); | ||
const Clipboard = require("electron").clipboard; | ||
|
||
let cm = {}, Dispatcher, ImageResolver, ContextMenuActions, ree; | ||
|
||
module.exports = new Plugin({ | ||
name: 'Avatar Links', | ||
author: 'Joe 🎸#7070', | ||
description: `Lets you copy a user or guild's avatar URL by right-clicking on their avatar.`, | ||
color: '#ffe000', | ||
name: "Avatar Links", | ||
author: "Joe 🎸#7070", | ||
description: "Lets you copy a user or guild's avatar URL by right-clicking on it.", | ||
color: "#ffe000", | ||
|
||
load: async function() { | ||
const d = findModule('dispatch'); | ||
|
||
monkeyPatch(d, 'dispatch', function(b) { | ||
let og = b.callOriginalMethod(b.methodArguments); | ||
if (b.methodArguments[0] && b.methodArguments[0].type == 'CONTEXT_MENU_OPEN') { | ||
let elem = b.methodArguments[0].contextMenu.target; | ||
//console.log(elem); | ||
if (elem && elem.tagName == 'STRONG' && elem.parentElement.className && elem.parentElement.className == 'activityText-OW8WYb') { | ||
elem.className = 'strongTempClass'; | ||
} | ||
if (elem && elem.tagName == 'STRONG' && elem.parentElement.className && elem.parentElement.className == 'activityText-sLG0UL') { | ||
elem.className = 'strongTempClass2'; | ||
} | ||
else if (elem && elem.tagName == 'path' && elem.parentElement.parentElement.getAttribute("class") && elem.parentElement.parentElement.getAttribute("class").indexOf('ownerIcon-uZ6mE7') > -1){ | ||
elem.setAttribute('class', 'pathTempClass'); | ||
} | ||
else if (elem && elem.tagName == 'A' && elem.href && elem.href.startsWith('https://discordapp.com/channels/@me/')){ | ||
elem.className = 'dmTempClass'; | ||
} | ||
|
||
let cn = elem ? elem.getAttribute("class") : null; | ||
if (!elem || !cn || typeof cn !== 'string') return og; | ||
|
||
let isGuild = (elem.tagName == 'DIV' && cn.indexOf('guildIcon-CT-ZDq') > -1); | ||
|
||
let imageElem; | ||
if (cn.indexOf('large-3ChYtB') > -1 || cn.indexOf('image-33JSyf') > -1 || isGuild || cn.startsWith('inner-1W0Bkn')) { | ||
imageElem = elem; | ||
} else if (cn.indexOf('status-oxiHuE') > -1) { | ||
imageElem = elem.previousElementSibling; | ||
} else if (cn.indexOf('avatar-16XVId') > -1 || cn.indexOf('small-5Os1Bb') > -1 || cn == 'dmTempClass') { | ||
imageElem = elem.firstElementChild; | ||
} else if ((cn == 'name-2WpE7M' && elem.parentElement.className !== 'nameWrapper-10v56U') || cn == 'headerCozyMeta-rdohGq') { | ||
imageElem = elem.previousElementSibling.firstElementChild; | ||
} else if ((elem.tagName == 'BUTTON' && cn == 'close-3hZ5Ni') || cn == 'nameWithActivity-1ceSyU' || cn.indexOf('activity-525YDR') > -1 || (cn == 'name-2WpE7M' && elem.parentElement.className == 'nameWrapper-10v56U')) { | ||
imageElem = elem.parentElement.previousElementSibling.firstElementChild; | ||
} else if (cn == 'avatarWrapper-3B0ndJ' || cn == 'headerCozy-2N9HOL' || cn == 'guildInner-3DSoA4') { | ||
imageElem = elem.firstElementChild.firstElementChild; | ||
} else if (cn == 'content-OzHfo4' || cn.indexOf('channel-2QD9_O') > -1) { | ||
imageElem = elem.firstElementChild.firstElementChild.firstElementChild; | ||
} else if (cn.indexOf('member-3W1lQa') > -1 || cn == 'guild-1EfMGQ') { | ||
imageElem = elem.firstElementChild.firstElementChild.firstElementChild.firstElementChild; | ||
} else if (cn == 'memberInner-2CPc3V') { | ||
imageElem = elem.parentElement.firstElementChild.firstElementChild.firstElementChild; | ||
} else if (cn.indexOf('nameTag-m8r81H') > -1 || cn.indexOf('activity-1IYsbk') > -1) { | ||
imageElem = elem.parentElement.parentElement.firstElementChild.firstElementChild.firstElementChild; | ||
} else if (cn.indexOf('username-1cB_5E') > -1 || cn.indexOf('ownerIcon-uZ6mE7') > -1) { | ||
imageElem = elem.parentElement.parentElement.parentElement.firstElementChild.firstElementChild.firstElementChild; | ||
} else if (cn == 'pathTempClass') { | ||
imageElem = elem.parentElement.parentElement.parentElement.parentElement.parentElement.firstElementChild.firstElementChild.firstElementChild; | ||
} else if (cn == 'activityText-OW8WYb' || cn == 'username-_4ZSMR' || cn == 'activityIcon-1mtTk4') { | ||
imageElem = elem.parentElement.parentElement.previousElementSibling.firstElementChild; | ||
} else if (cn == 'strongTempClass') { | ||
imageElem = elem.parentElement.parentElement.parentElement.previousElementSibling.firstElementChild; | ||
} else if (cn == 'activityText-sLG0UL' || cn == 'activityIcon-S3CciC' || cn.indexOf('botTagRegular-2HEhHi') > -1) { | ||
imageElem = elem.parentElement.parentElement.previousElementSibling.firstElementChild.firstElementChild; | ||
} else if (cn == 'strongTempClass2') { | ||
imageElem = elem.parentElement.parentElement.parentElement.previousElementSibling.firstElementChild.firstElementChild; | ||
} | ||
//console.log(imageElem); | ||
if (!imageElem || !imageElem.style || !imageElem.style['background-image']) return og; | ||
|
||
let avatarURL = imageElem.style['background-image'] | ||
.replace('url("/', 'https://discordapp.com/') | ||
.replace('url("', '') | ||
.replace('128")', '2048') | ||
.replace('")', ''); | ||
|
||
if (isGuild) | ||
avatarURL = avatarURL.replace('.webp', '.png?size=2048'); | ||
|
||
setTimeout(() => addMenuItem(avatarURL, d, isGuild ? 'Copy Icon URL' : 'Copy Avatar URL'), 5); | ||
} | ||
return og; | ||
}); | ||
ree = this; | ||
cm = findModule('contextMenu'); | ||
Dispatcher = findModule("dispatch"); | ||
ImageResolver = findModule("getUserAvatarURL"); | ||
ContextMenuActions = findModule("closeContextMenu"); | ||
|
||
Dispatcher.subscribe("CONTEXT_MENU_OPEN", this.checkMenu); | ||
}, | ||
|
||
unload: function() { | ||
let d = findModule('dispatch').dispatch; | ||
if (d && d.__monkeyPatched && d.unpatch) | ||
d.unpatch(); | ||
Dispatcher.unsubscribe("CONTEXT_MENU_OPEN", this.checkMenu); | ||
}, | ||
|
||
checkMenu: async function() { | ||
// Make sure it's already in the DOM | ||
await new Promise(r => {setTimeout(r, 5)}); | ||
const theMenu = document.querySelector('.'+cm.contextMenu); | ||
const reactData = theMenu.__reactInternalInstance$; | ||
|
||
let label = ""; | ||
let url = ""; | ||
let props = {onHeightUpdate: () => {}}; | ||
|
||
// For users | ||
if ( | ||
reactData.return && | ||
reactData.return.return && | ||
reactData.return.return.return && | ||
reactData.return.return.return.return && | ||
reactData.return.return.return.return.memoizedProps && | ||
reactData.return.return.return.return.memoizedProps.user && | ||
reactData.return.return.return.return.memoizedProps.type && | ||
reactData.return.return.return.return.memoizedProps.type.startsWith("USER_") | ||
) { | ||
props = reactData.return.return.return.return.memoizedProps; | ||
label = "Copy Avatar URL"; | ||
const user = props.user; | ||
const imageType = ImageResolver.hasAnimatedAvatar(user) ? "gif" : "png"; | ||
|
||
// Internal module maxes at 1024 hardcoded, so do that and change to 2048. | ||
url = ImageResolver.getUserAvatarURL(user, imageType, 1024).replace("size=1024", "size=2048"); | ||
|
||
// For default avatars | ||
if (!url.startsWith("http") && url.startsWith("/assets")) | ||
url = `https://discordapp.com${url}`; | ||
} | ||
|
||
// For guilds | ||
if ( | ||
reactData.return && | ||
reactData.return.memoizedProps && | ||
reactData.return.memoizedProps.guild && | ||
reactData.return.memoizedProps.type == "GUILD_ICON_BAR" | ||
) { | ||
props = reactData.return.memoizedProps; | ||
label = "Copy Icon URL"; | ||
const guild = props.guild; | ||
|
||
// Internal module maxes at 1024 hardcoded, so do that and change to 2048. | ||
url = ImageResolver.getGuildIconURL({id: guild.id, icon: guild.icon, size: 1024}).replace("size=1024", "size=2048"); | ||
|
||
// No way to make it return the animated version, do it manually | ||
if (ImageResolver.hasAnimatedGuildIcon(guild)) | ||
url = url.replace(".webp?", ".gif?"); | ||
else | ||
url = url.replace(".webp?", ".png?"); | ||
} | ||
|
||
// Assume it is already in the DOM and add item ASAP | ||
if (label && url) | ||
ree.addMenuItem(url, label, props); | ||
}, | ||
|
||
addMenuItem: function(imageURL, text, menu) { | ||
let cmGroups = document.getElementsByClassName(cm.itemGroup); | ||
if (!cmGroups || cmGroups.length == 0) return; | ||
|
||
let newCmItem = document.createElement("div"); | ||
newCmItem.className = cm.item+' '+cm.clickable; | ||
let newCmItemContent = document.createElement("div"); | ||
newCmItemContent.className = cm.label; | ||
newCmItemContent.innerHTML = text; | ||
newCmItem.appendChild(newCmItemContent); | ||
|
||
let lastGroup = cmGroups[cmGroups.length-1]; | ||
lastGroup.appendChild(newCmItem); | ||
|
||
menu.onHeightUpdate(); | ||
|
||
newCmItem.onclick = function(e) { | ||
Clipboard.write({text: imageURL}); | ||
ContextMenuActions.closeContextMenu(); | ||
} | ||
} | ||
}); |