1Lighty-BetterDiscordPlugins/Plugins/UnreadBadgesRedux/UnreadBadgesRedux.plugin.js

714 lines
31 KiB
JavaScript

//META{"name":"UnreadBadgesRedux","source":"https://github.com/1Lighty/BetterDiscordPlugins/blob/master/Plugins/UnreadBadgesRedux/","website":"https://1lighty.github.io/BetterDiscordStuff/?plugin=UnreadBadgesRedux","authorId":"239513071272329217","invite":"NYvWdN5","donate":"https://paypal.me/lighty13"}*//
/*@cc_on
@if (@_jscript)
// Offer to self-install for clueless users that try to run this directly.
var shell = WScript.CreateObject('WScript.Shell');
var fs = new ActiveXObject('Scripting.FileSystemObject');
var pathPlugins = shell.ExpandEnvironmentStrings('%APPDATA%\\BetterDiscord\\plugins');
var pathSelf = WScript.ScriptFullName;
// Put the user at ease by addressing them in the first person
shell.Popup('It looks like you\'ve mistakenly tried to run me directly. \n(Don\'t do that!)', 0, 'I\'m a plugin for BetterDiscord', 0x30);
if (fs.GetParentFolderName(pathSelf) === fs.GetAbsolutePathName(pathPlugins)) {
shell.Popup('I\'m in the correct folder already.\nJust go to settings, plugins and enable me.', 0, 'I\'m already installed', 0x40);
} else if (!fs.FolderExists(pathPlugins)) {
shell.Popup('I can\'t find the BetterDiscord plugins folder.\nAre you sure it\'s even installed?', 0, 'Can\'t install myself', 0x10);
} else if (shell.Popup('Should I copy myself to BetterDiscord\'s plugins folder for you?', 0, 'Do you need some help?', 0x34) === 6) {
fs.CopyFile(pathSelf, fs.BuildPath(pathPlugins, fs.GetFileName(pathSelf)), true);
// Show the user where to put plugins in the future
shell.Exec('explorer ' + pathPlugins);
shell.Popup('I\'m installed!\nJust go to settings, plugins and enable me!', 0, 'Successfully installed', 0x40);
}
WScript.Quit();
@else@*/
/*
* Copyright© 2019-2020, _Lighty_
* All rights reserved.
* Code may not be redistributed, modified or otherwise taken without explicit permission.
*/
module.exports = (() => {
/* Setup */
const config = {
main: 'index.js',
info: {
name: 'UnreadBadgesRedux',
authors: [
{
name: 'Lighty',
discord_id: '239513071272329217',
github_username: 'LightyPon',
twitter_username: ''
}
],
version: '1.0.9',
description: 'Adds a number badge to server icons and channels.',
github: 'https://github.com/1Lighty',
github_raw: 'https://raw.githubusercontent.com/1Lighty/BetterDiscordPlugins/master/Plugins/UnreadBadgesRedux/UnreadBadgesRedux.plugin.js'
},
changelog: [
{
title: 'fixed',
type: 'fixed',
items: ['Fixed not working on channels, again.']
}
],
defaultConfig: [
{
type: 'category',
id: 'misc',
name: 'Display settings',
collapsible: true,
shown: true,
settings: [
{
name: 'Display badge on folders',
id: 'folders',
type: 'switch',
value: true
},
{
name: 'Ignore muted servers in folders unread badge count',
id: 'noMutedGuildsInFolderCount',
type: 'switch',
value: true
},
{
name: 'Ignore muted channels in servers in folders unread badge count',
id: 'noMutedChannelsInGuildsInFolderCount',
type: 'switch',
value: true
},
{
name: "Don't display badge on expanded folders",
id: 'expandedFolders',
type: 'switch',
value: true
},
{
name: 'Display badge on servers',
id: 'guilds',
type: 'switch',
value: true
},
{
name: 'Display badge on muted servers',
id: 'mutedGuilds',
type: 'switch',
value: true
},
{
name: 'Ignore muted channels in server unread badge count',
id: 'noMutedInGuildCount',
type: 'switch',
value: true
},
{
name: 'Display badge on channels',
id: 'channels',
type: 'switch',
value: true
},
{
name: 'Display badge on muted channels',
id: 'mutedChannels',
type: 'switch',
value: true
},
{
name: 'Display badge on left side on channels',
note: "In case you want the settings button to stay where it always is. This however doesn't move it before the NSFW tag if you use the BetterNsfwTag plugin",
id: 'channelsDisplayOnLeft',
type: 'switch',
value: false
},
{
name: 'Background color',
id: 'backgroundColor',
type: 'color',
value: '#7289da',
options: {
defaultColor: '#7289da'
}
},
{
name: 'Text color',
id: 'textColor',
type: 'color',
value: '#ffffff',
options: {
defaultColor: '#ffffff'
}
},
{
name: 'Muted channel badge darkness',
id: 'mutedChannelBadgeDarkness',
type: 'slider',
value: 0.25,
min: 0,
max: 1,
equidistant: true,
options: {
equidistant: true
}
}
]
}
]
};
/* Build */
const buildPlugin = ([Plugin, Api]) => {
const { Settings, Utilities, WebpackModules, DiscordModules, ColorConverter, ReactComponents, Patcher, PluginUtilities, Logger, ReactTools, ModalStack } = Api;
const { React, ChannelStore } = DiscordModules;
const ReactSpring = WebpackModules.getByProps('useTransition');
const BadgesModule = WebpackModules.getByProps('NumberBadge');
const StoresModule = WebpackModules.getByProps('useStateFromStores');
/* discord won't let me access it, so I remade it :( */
class BadgeContainer extends React.PureComponent {
componentDidMount() {
this.forceUpdate();
}
componentWillAppear(e) {
e();
}
componentWillEnter(e) {
e();
}
componentWillLeave(e) {
this.timeoutId = setTimeout(e, 300);
}
componentWillUnmount() {
clearTimeout(this.timeoutId);
}
render() {
return React.createElement(
ReactSpring.animated.div,
{
className: this.props.className,
style: this.props.animatedStyle
},
this.props.children
);
}
}
const UnreadStore = WebpackModules.getByProps('getUnreadCount');
const MuteModule = WebpackModules.getByProps('isMuted');
const AltChannelStore = WebpackModules.find(m => m.getChannels && m.getChannels.length === 1);
const getUnreadCount = (guildId, includeMuted) => {
const channels = AltChannelStore.getChannels(guildId);
let count = 0;
for (const { channel } of channels.SELECTABLE) {
/* isChannelMuted is SLOW! */
if (includeMuted || (!MuteModule.isChannelMuted(channel.guild_id, channel.id) && (!channel.parent_id || !MuteModule.isChannelMuted(channel.guild_id, channel.parent_id)))) count += UnreadStore.getUnreadCount(channel.id);
}
return count;
};
class Slider extends Settings.SettingField {
/* ripped out of ZeresPluginLibrary, because it does thingsin a way I DISLIKE!
but otherwise full credits to Zerebos
https://github.com/rauenzi/BDPluginLibrary/blob/master/src/ui/settings/types/slider.js
*/
constructor(name, note, min, max, value, onChange, options = {}) {
const props = {
onChange: _ => _,
defaultValue: value,
disabled: options.disabled ? true : false,
minValue: min,
maxValue: max,
handleSize: 10,
initialValue: value /* added this */
};
if (options.fillStyles) props.fillStyles = options.fillStyles;
if (options.markers) props.markers = options.markers;
if (options.stickToMarkers) props.stickToMarkers = options.stickToMarkers;
if (typeof options.equidistant != 'undefined') props.equidistant = options.equidistant;
super(name, note, onChange, DiscordModules.Slider, Object.assign(props, { onValueChange: v => this.onChange(v) }));
}
}
return class UnreadBadgesRedux extends Plugin {
constructor() {
super();
XenoLib.changeName(__filename, 'UnreadBadgesRedux');
const oOnStart = this.onStart.bind(this);
this.onStart = () => {
try {
oOnStart();
} catch (e) {
Logger.stacktrace('Failed to start!', e);
PluginUpdater.checkForUpdate(this.name, this.version, this._config.info.github_raw);
XenoLib.Notifications.error(`[**${this.name}**] Failed to start! Please update it, press CTRL + R, or ${GuildStore.getGuild(XenoLib.supportServerId) ? 'go to <#639665366380838924>' : '[join my support server](https://discord.gg/NYvWdN5)'} for further assistance.`, { timeout: 0 });
try {
this.onStop();
} catch (e) { }
}
};
try {
ModalStack.popWithKey(`${this.name}_DEP_MODAL`);
} catch (e) { }
}
onStart() {
this.promises = { state: { cancelled: false } };
this.patchedModules = [];
this.patchAll();
PluginUtilities.addStyle(
this.short + '-CSS',
`
.unread-badge {
right: unset;
}
`
);
}
onStop() {
this.promises.state.cancelled = true;
Patcher.unpatchAll();
PluginUtilities.removeStyle(this.short + '-CSS');
this.forceUpdateAll();
}
buildSetting(data) {
if (data.type === 'color') {
const setting = new XenoLib.Settings.ColorPicker(data.name, data.note, data.value, data.onChange, data.options);
if (data.id) setting.id = data.id;
return setting;
} else if (data.type === 'slider') {
const options = {};
const { name, note, value, onChange, min, max } = data;
if (typeof data.markers !== 'undefined') options.markers = data.markers;
if (typeof data.stickToMarkers !== 'undefined') options.stickToMarkers = data.stickToMarkers;
const setting = new Slider(name, note, min, max, value, onChange, options);
if (data.id) setting.id = data.id;
return setting;
}
return super.buildSetting(data);
}
saveSettings(_, setting, value) {
super.saveSettings(_, setting, value);
this.forceUpdateAll();
}
forceUpdateAll() {
this.patchedModules.forEach(e => e());
}
/* PATCHES */
patchAll() {
Utilities.suppressErrors(this.patchBlobMask.bind(this), 'BlobMask patch')(this.promises.state);
Utilities.suppressErrors(this.patchGuildIcon.bind(this), 'GuildIcon patch')(this.promises.state);
Utilities.suppressErrors(this.patchChannelItem.bind(this), 'ChannelItem patch')(this.promises.state);
Utilities.suppressErrors(this.patchConnectedGuild.bind(this), 'ConnectedGuild patch')(this.promises.state);
Utilities.suppressErrors(this.patchGuildFolder.bind(this), 'GuildFolder patch')(this.promises.state);
}
async patchChannelItem(promiseState) {
const TextChannel = await ReactComponents.getComponentByName('TextChannel', `.${XenoLib.getSingleClass('mentionsBadge containerDefault')}`);
if (promiseState.cancelled) return;
const settings = this.settings;
const MentionsBadgeClassname = XenoLib.getClass('iconVisibility mentionsBadge');
function UnreadBadge(e) {
const unreadCount = StoresModule.useStateFromStores([UnreadStore], () => {
if ((e.muted && !settings.misc.mutedChannels) || !settings.misc.channels) return 0;
const count = UnreadStore.getUnreadCount(e.channelId);
if (count > 1000) return Math.floor(count / 1000) * 1000; /* only trigger rerender if it changes in thousands */
return count;
});
if (!unreadCount) return null;
return React.createElement(
'div',
{
className: MentionsBadgeClassname
},
BadgesModule.NumberBadge({ count: unreadCount, color: e.muted ? ColorConverter.darkenColor(settings.misc.backgroundColor, settings.misc.mutedChannelBadgeDarkness * 100) : settings.misc.backgroundColor, style: { color: e.muted ? ColorConverter.darkenColor(settings.misc.textColor, settings.misc.mutedChannelBadgeDarkness * 100) : settings.misc.textColor } })
);
}
Patcher.after(TextChannel.component.prototype, 'render', (_this, _, ret) => {
const props = Utilities.findInReactTree(ret, e => e && Array.isArray(e.children) && e.children.find(e => e && e.type && e.type.displayName === 'ConnectedEditButton'));
if (!props || !props.children) return;
const badge = React.createElement(UnreadBadge, { channelId: _this.props.channel.id, muted: _this.props.muted && !_this.props.selected });
props.children.splice(this.settings.misc.channelsDisplayOnLeft ? 0 : 2, 0, badge);
});
TextChannel.forceUpdateAll();
}
async patchGuildFolder(promiseState) {
const settings = this.settings;
const FolderStore = WebpackModules.getByProps('isFolderExpanded');
function BlobMaskWrapper(e) {
e.__UBR_unread_count = StoresModule.useStateFromStores([UnreadStore, MuteModule], () => {
if ((e.__UBR_folder_expanded && settings.misc.expandedFolders) || !settings.misc.folders) return 0;
let count = 0;
for (let i = 0; i < e.__UBR_guildIds.length; i++) {
const guildId = e.__UBR_guildIds[i];
if (!settings.misc.noMutedGuildsInFolderCount || (settings.misc.noMutedGuildsInFolderCount && !MuteModule.isMuted(guildId))) count += getUnreadCount(guildId, !settings.misc.noMutedChannelsInGuildsInFolderCount);
}
if (count > 1000) return Math.floor(count / 1000) * 1000; /* only trigger rerender if it changes in thousands */
return count;
});
return React.createElement(e.__UBR_old_type, e);
}
BlobMaskWrapper.displayName = 'BlobMask';
const GuildFolderMemo = WebpackModules.find(m => m.type && m.type.toString().indexOf('.Messages.SERVER_FOLDER_PLACEHOLDER') !== -1);
if (GuildFolderMemo) {
Patcher.after(GuildFolderMemo, 'type', (_, [props], ret) => {
const mask = Utilities.findInReactTree(ret, e => e && e.type && e.type.displayName === 'BlobMask');
if (!mask) return;
mask.props.__UBR_old_type = mask.type;
mask.props.__UBR_guildIds = props.guildIds;
mask.props.__UBR_folder_expanded = FolderStore.isFolderExpanded(props.folderId);
mask.type = BlobMaskWrapper;
});
const instance = ReactTools.getOwnerInstance(document.querySelector('.wrapper-21YSNc'));
if (!instance) return;
const unpatch = Patcher.after(instance, 'render', (_, __, ret) => {
unpatch();
if (!ret) return;
ret.key = `GETGOOD${Math.random()}`;
const oRef = ret.props.setFolderRef;
ret.props.setFolderRef = (e, n) => {
_.forceUpdate();
return oRef(e, n);
};
});
instance.forceUpdate();
return;
}
const selector = `.${XenoLib.getSingleClass('folder wrapper', true)}`;
const GuildFolder = await ReactComponents.getComponentByName('GuildFolder', selector);
if (!GuildFolder.selector) GuildFolder.selector = selector;
if (promiseState.cancelled) return;
Patcher.after(GuildFolder.component.prototype, 'render', (_this, _, ret) => {
const mask = Utilities.findInTree(ret, e => e && e.type && e.type.displayName === 'BlobMask', { walkable: ['props', 'children'] });
if (!mask) return;
mask.props.__UBR_old_type = mask.type;
mask.props.__UBR_guildIds = _this.props.guildIds;
mask.props.__UBR_folder_expanded = _this.props.expanded;
mask.type = BlobMaskWrapper;
});
GuildFolder.forceUpdateAll();
this.patchedModules.push(GuildFolder.forceUpdateAll.bind(GuildFolder));
}
async patchConnectedGuild(promiseState) {
const selector = `.${XenoLib.getSingleClass('listItem', true)}`;
const ConnectedGuild = await ReactComponents.getComponentByName('DragSource(ConnectedGuild)', selector);
if (!ConnectedGuild.selector) ConnectedGuild.selector = selector;
if (promiseState.cancelled) return;
const settings = this.settings;
function PatchedConnectedGuild(e) {
/* get on my level scrublords */
e.__UBR_unread_count = StoresModule.useStateFromStores([UnreadStore, MuteModule], () => (!settings.misc.guilds || (!settings.misc.mutedGuilds && MuteModule.isMuted(e.guildId)) ? 0 : getUnreadCount(e.guildId, !settings.misc.noMutedInGuildCount)));
return e.__UBR_old_type(e);
}
PatchedConnectedGuild.displayName = 'ConnectedGuild';
Patcher.after(ConnectedGuild.component.prototype, 'render', (_this, _, ret) => {
const old = ret.props.children;
ret.props.children = e => {
const ret2 = old(e);
ret2.props.__UBR_old_type = ret2.type;
ret2.type = PatchedConnectedGuild;
return ret2;
};
});
ConnectedGuild.forceUpdateAll();
this.patchedModules.push(ConnectedGuild.forceUpdateAll.bind(ConnectedGuild));
}
async patchGuildIcon(promiseState) {
const selector = `.${XenoLib.getSingleClass('listItem', true)}`;
const Guild = await ReactComponents.getComponentByName('Guild', selector);
if (!Guild.selector) Guild.selector = selector;
if (promiseState.cancelled) return;
Patcher.after(Guild.component.prototype, 'render', (_this, _, ret) => {
const mask = Utilities.findInTree(ret, e => e && e.type && e.type.displayName === 'BlobMask', { walkable: ['props', 'children'] });
if (!mask) return;
mask.props.__UBR_unread_count = _this.props.__UBR_unread_count;
mask.props.guildId = _this.props.guildId;
});
Guild.forceUpdateAll();
}
async patchBlobMask(promiseState) {
const selector = `.${XenoLib.getSingleClass('lowerBadge wrapper')}`;
const BlobMask = await ReactComponents.getComponentByName('BlobMask', selector);
if (!BlobMask.selector) BlobMask.selector = selector;
if (promiseState.cancelled) return;
const ensureUnreadBadgeMask = _this => {
if (_this.state.unreadBadgeMask) return;
_this.state.unreadBadgeMask = new ReactSpring.Controller({
spring: 0
});
};
Patcher.after(BlobMask.component.prototype, 'componentDidMount', _this => {
if (typeof _this.props.__UBR_unread_count !== 'number') return;
ensureUnreadBadgeMask(_this);
_this.state.unreadBadgeMask
.update({
spring: !!_this.props.__UBR_unread_count,
immediate: true
})
.start();
});
Patcher.after(BlobMask.component.prototype, 'componentWillUnmount', _this => {
if (typeof _this.props.__UBR_unread_count !== 'number') return;
if (!_this.state.unreadBadgeMask) return;
if (typeof _this.state.unreadBadgeMask.destroy === 'function') _this.state.unreadBadgeMask.destroy();
else _this.state.unreadBadgeMask.dispose();
_this.state.unreadBadgeMask = null;
});
Patcher.after(BlobMask.component.prototype, 'componentDidUpdate', (_this, [{ __UBR_unread_count }]) => {
if (typeof _this.props.__UBR_unread_count !== 'number' || _this.props.__UBR_unread_count === __UBR_unread_count) return;
ensureUnreadBadgeMask(_this);
_this.state.unreadBadgeMask
.update({
spring: !!_this.props.__UBR_unread_count,
immediate: !document.hasFocus(),
config: {
friction: 40,
tension: 900,
mass: 1
}
})
.start();
});
const LowerBadgeClassname = XenoLib.joinClassNames(XenoLib.getClass('wrapper lowerBadge'), 'unread-badge');
Patcher.after(BlobMask.component.prototype, 'render', (_this, _, ret) => {
if (typeof _this.props.__UBR_unread_count !== 'number') return;
const badges = Utilities.findInTree(ret, e => e && e.type && e.type.displayName === 'TransitionGroup', { walkable: ['props', 'children'] });
const masks = Utilities.findInTree(ret, e => e && e.type === 'mask', { walkable: ['props', 'children'] });
if (!badges || !masks) return;
ensureUnreadBadgeMask(_this);
/* if count is 0, we're animating out, and as such, it's better to at least still display the old
count while animating out
*/
const counter = _this.props.__UBR_unread_count || _this.state.__UBR_old_unread_count;
if (_this.props.__UBR_unread_count) _this.state.__UBR_old_unread_count = _this.props.__UBR_unread_count;
const width = BadgesModule.getBadgeWidthForValue(counter);
const unreadCountMaskSpring = (_this.state.unreadBadgeMask.animated || _this.state.unreadBadgeMask.springs).spring;
masks.props.children.push(
React.createElement(ReactSpring.animated.rect, {
x: -4,
y: 28,
width: width + 8,
height: 24,
rx: 12,
ry: 12,
opacity: unreadCountMaskSpring.to([0, 0.5, 1], [0, 0, 1]),
transform: unreadCountMaskSpring.to([0, 1], [-16, 0]).to(e => `translate(${e} ${-e})`),
fill: 'black'
})
);
badges.props.children.unshift(
React.createElement(
BadgeContainer,
{
className: LowerBadgeClassname,
animatedStyle: {
opacity: unreadCountMaskSpring.to([0, 0.5, 1], [0, 0, 1]),
transform: unreadCountMaskSpring.to(e => `translate(${-20 + 20 * e} ${-1 * (16 - 16 * e)})`)
}
},
React.createElement(BadgesModule.NumberBadge, { count: counter, color: this.settings.misc.backgroundColor, style: { color: this.settings.misc.textColor } })
)
);
});
BlobMask.forceUpdateAll();
}
/* PATCHES */
showChangelog(footer) {
XenoLib.showChangelog(`${this.name} has been updated!`, this.version, this._config.changelog);
}
getSettingsPanel() {
return this.buildSettingsPanel().getElement();
}
get [Symbol.toStringTag]() {
return 'Plugin';
}
get css() {
return this._css;
}
get name() {
return config.info.name;
}
get short() {
let string = '';
for (let i = 0, len = config.info.name.length; i < len; i++) {
const char = config.info.name[i];
if (char === char.toUpperCase()) string += char;
}
return string;
}
get author() {
return config.info.authors.map(author => author.name).join(', ');
}
get version() {
return config.info.version;
}
get description() {
return config.info.description;
}
};
};
/* Finalize */
let ZeresPluginLibraryOutdated = false;
let XenoLibOutdated = false;
try {
if (global.BdApi && 'function' == typeof BdApi.getPlugin) {
const i = (i, n) => ((i = i.split('.').map(i => parseInt(i))), (n = n.split('.').map(i => parseInt(i))), !!(n[0] > i[0]) || !!(n[0] == i[0] && n[1] > i[1]) || !!(n[0] == i[0] && n[1] == i[1] && n[2] > i[2])),
n = (n, e) => n && n._config && n._config.info && n._config.info.version && i(n._config.info.version, e),
e = BdApi.getPlugin('ZeresPluginLibrary'),
o = BdApi.getPlugin('XenoLib');
n(e, '1.2.14') && (ZeresPluginLibraryOutdated = !0), n(o, '1.3.17') && (XenoLibOutdated = !0);
}
} catch (i) {
console.error('Error checking if libraries are out of date', i);
}
return !global.ZeresPluginLibrary || !global.XenoLib || ZeresPluginLibraryOutdated || XenoLibOutdated
? class {
constructor() {
this._XL_PLUGIN = true;
this.start = this.load = this.handleMissingLib;
}
getName() {
return this.name.replace(/\s+/g, '');
}
getAuthor() {
return this.author;
}
getVersion() {
return this.version;
}
getDescription() {
return this.description + ' You are missing libraries for this plugin, please enable the plugin and click Download Now.';
}
stop() { }
handleMissingLib() {
const a = BdApi.findModuleByProps('openModal', 'hasModalOpen');
if (a && a.hasModalOpen(`${this.name}_DEP_MODAL`)) return;
const b = !global.XenoLib,
c = !global.ZeresPluginLibrary,
d = (b && c) || ((b || c) && (XenoLibOutdated || ZeresPluginLibraryOutdated)),
e = (() => {
let a = '';
return b || c ? (a += `Missing${XenoLibOutdated || ZeresPluginLibraryOutdated ? ' and outdated' : ''} `) : (XenoLibOutdated || ZeresPluginLibraryOutdated) && (a += `Outdated `), (a += `${d ? 'Libraries' : 'Library'} `), a;
})(),
f = (() => {
let a = `The ${d ? 'libraries' : 'library'} `;
return b || XenoLibOutdated ? ((a += 'XenoLib '), (c || ZeresPluginLibraryOutdated) && (a += 'and ZeresPluginLibrary ')) : (c || ZeresPluginLibraryOutdated) && (a += 'ZeresPluginLibrary '), (a += `required for ${this.name} ${d ? 'are' : 'is'} ${b || c ? 'missing' : ''}${XenoLibOutdated || ZeresPluginLibraryOutdated ? (b || c ? ' and/or outdated' : 'outdated') : ''}.`), a;
})(),
g = BdApi.findModuleByDisplayName('Text'),
h = BdApi.findModuleByDisplayName('ConfirmModal'),
i = () => BdApi.alert(e, BdApi.React.createElement('span', {}, BdApi.React.createElement('div', {}, f), `Due to a slight mishap however, you'll have to download the libraries yourself. This is not intentional, something went wrong, errors are in console.`, c || ZeresPluginLibraryOutdated ? BdApi.React.createElement('div', {}, BdApi.React.createElement('a', { href: 'https://betterdiscord.net/ghdl?id=2252', target: '_blank' }, 'Click here to download ZeresPluginLibrary')) : null, b || XenoLibOutdated ? BdApi.React.createElement('div', {}, BdApi.React.createElement('a', { href: 'https://betterdiscord.net/ghdl?id=3169', target: '_blank' }, 'Click here to download XenoLib')) : null));
if (!a || !h || !g) return console.error(`Missing components:${(a ? '' : ' ModalStack') + (h ? '' : ' ConfirmationModalComponent') + (g ? '' : 'TextElement')}`), i();
class j extends BdApi.React.PureComponent {
constructor(a) {
super(a), (this.state = { hasError: !1 }), (this.componentDidCatch = a => (console.error(`Error in ${this.props.label}, screenshot or copy paste the error above to Lighty for help.`), this.setState({ hasError: !0 }), 'function' == typeof this.props.onError && this.props.onError(a))), (this.render = () => (this.state.hasError ? null : this.props.children));
}
}
let k = !1,
l = !1;
const m = a.openModal(
b => {
if (l) return null;
try {
return BdApi.React.createElement(
j,
{ label: 'missing dependency modal', onError: () => (a.closeModal(m), i()) },
BdApi.React.createElement(
h,
Object.assign(
{
header: e,
children: BdApi.React.createElement(g, { size: g.Sizes.SIZE_16, children: [`${f} Please click Download Now to download ${d ? 'them' : 'it'}.`] }),
red: !1,
confirmText: 'Download Now',
cancelText: 'Cancel',
onCancel: b.onClose,
onConfirm: () => {
if (k) return;
k = !0;
const b = require('request'),
c = require('fs'),
d = require('path'),
e = BdApi.Plugins && BdApi.Plugins.folder ? BdApi.Plugins.folder : window.ContentManager.pluginsFolder,
f = () => {
(global.XenoLib && !XenoLibOutdated) ||
b('https://raw.githubusercontent.com/1Lighty/BetterDiscordPlugins/master/Plugins/1XenoLib.plugin.js', (b, f, g) => {
try {
if (b || 200 !== f.statusCode) return a.closeModal(m), i();
c.writeFile(d.join(e, '1XenoLib.plugin.js'), g, () => { });
} catch (b) {
console.error('Fatal error downloading XenoLib', b), a.closeModal(m), i();
}
});
};
!global.ZeresPluginLibrary || ZeresPluginLibraryOutdated
? b('https://raw.githubusercontent.com/rauenzi/BDPluginLibrary/master/release/0PluginLibrary.plugin.js', (b, g, h) => {
try {
if (b || 200 !== g.statusCode) return a.closeModal(m), i();
c.writeFile(d.join(e, '0PluginLibrary.plugin.js'), h, () => { }), f();
} catch (b) {
console.error('Fatal error downloading ZeresPluginLibrary', b), a.closeModal(m), i();
}
})
: f();
}
},
b,
{ onClose: () => { } }
)
)
);
} catch (b) {
return console.error('There has been an error constructing the modal', b), (l = !0), a.closeModal(m), i(), null;
}
},
{ modalKey: `${this.name}_DEP_MODAL` }
);
}
get [Symbol.toStringTag]() {
return 'Plugin';
}
get name() {
return config.info.name;
}
get short() {
let string = '';
for (let i = 0, len = config.info.name.length; i < len; i++) {
const char = config.info.name[i];
if (char === char.toUpperCase()) string += char;
}
return string;
}
get author() {
return config.info.authors.map(author => author.name).join(', ');
}
get version() {
return config.info.version;
}
get description() {
return config.info.description;
}
}
: buildPlugin(global.ZeresPluginLibrary.buildPlugin(config));
})();
/*@end@*/