Skip to content
This repository has been archived by the owner on Jun 27, 2021. It is now read-only.

Commit

Permalink
Merge pull request #93 from joe27g/avatar_links
Browse files Browse the repository at this point in the history
rewrite avatar_links | fixes #91
  • Loading branch information
joe27g committed Oct 16, 2019
2 parents bc9b7d3 + f461227 commit f7b1059
Showing 1 changed file with 98 additions and 118 deletions.
216 changes: 98 additions & 118 deletions plugins/avatar_links.js
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();
}
}
});

0 comments on commit f7b1059

Please sign in to comment.