2019-12-27 21:26:03 +01:00
//META{"name":"UnreadBadgesRedux","source":"https://github.com/1Lighty/BetterDiscordPlugins/blob/master/Plugins/UnreadBadgesRedux/","website":"https://1lighty.github.io/BetterDiscordStuff/?plugin=UnreadBadgesRedux"}*//
/ * @ c c _ o n
@ 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 reload Discord with Ctrl+R.' , 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 reload Discord with Ctrl+R.' , 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 .
* /
var UnreadBadgesRedux = ( ( ) => {
/* Setup */
const config = {
main : 'index.js' ,
info : {
name : 'UnreadBadgesRedux' ,
authors : [
{
name : 'Lighty' ,
discord _id : '239513071272329217' ,
github _username : 'LightyPon' ,
twitter _username : ''
}
] ,
2020-02-02 22:53:23 +01:00
version : '1.0.1' ,
2019-12-27 21:26:03 +01:00
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 : [
{
2020-02-02 22:53:23 +01:00
title : 'sad' ,
type : 'fixed' ,
items : [ 'Fixed crash if XenoLib or ZeresPluginLib were missing' ]
2019-12-27 21:26:03 +01:00
}
] ,
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 } = 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 getUnreadCount = ( guildId , includeMuted ) => {
const channels = ChannelStore . getChannels ( ) ;
const guildChannels = [ ] ;
for ( const channelId in channels ) {
const channel = channels [ channelId ] ;
if ( channel . guild _id === guildId ) guildChannels . push ( channel ) ;
}
let count = 0 ;
for ( let i = 0 ; i < guildChannels . length ; i ++ ) {
const channel = guildChannels [ i ] ;
if ( ( ! MuteModule . isChannelMuted ( channel . guild _id , channel . id ) && ( ! channel . parent _id || ! MuteModule . isChannelMuted ( channel . guild _id , channel . parent _id ) ) ) || includeMuted ) count += UnreadStore . getUnreadCount ( channel . id ) ;
}
return count ;
} ;
class Slider extends Settings . SettingField {
/ * r i p p e d o u t o f Z e r e s P l u g i n L i b r a r y , b e c a u s e i t d o e s t h i n g s i n a w a y I D I S L I K E !
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' ) ;
}
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 ( ) ;
}
/* zlib uses reference to defaultSettings instead of a cloned object, which sets settings as default settings, messing everything up */
loadSettings ( defaultSettings ) {
return PluginUtilities . loadSettings ( this . name , Utilities . deepclone ( this . defaultSettings ? this . defaultSettings : defaultSettings ) ) ;
}
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 ChannelItem = await ReactComponents . getComponentByName ( 'ChannelItem' , ` . ${ XenoLib . getSingleClass ( 'modeUnread wrapper' ) } ` ) ;
if ( promiseState . cancelled ) return ;
const settings = this . settings ;
const MentionsBadgeClassname = XenoLib . getClass ( 'iconVisibility mentionsBadge' ) ;
const IconsChildren = XenoLib . getClass ( 'modeMuted children' ) ;
function UnreadBadge ( e ) {
const unreadCount = StoresModule . useStateFromStores ( [ UnreadStore ] , ( ) => ( ( e . muted && ! settings . misc . mutedChannels ) || ! settings . misc . channels ? 0 : UnreadStore . getUnreadCount ( e . channelId ) ) ) ;
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 ( ChannelItem . component . prototype , 'renderIcons' , ( _this , args , ret ) => {
const badge = React . createElement ( UnreadBadge , { channelId : _this . props . channel . id , muted : _this . props . muted && ! _this . props . selected } ) ;
if ( ! ret ) {
return React . createElement (
'div' ,
{
onClick : e => e . stopPropagation ( ) ,
className : IconsChildren
} ,
badge
) ;
}
/ * c h i l d r e n i s a r e f e r n c e t o t h e c h i l d r e n p r o p w i t h i n t h e c o m p o n e n t , w h i c h i s b a d
so appending it without slicing first would append it to the components props
children array
* /
const buttons = ret . props . children . slice ( 0 ) ;
if ( ! buttons ) return ;
buttons . splice ( this . settings . misc . channelsDisplayOnLeft ? 0 : 2 , 0 , badge ) ;
ret . props . children = buttons ;
} ) ;
ChannelItem . forceUpdateAll ( ) ;
}
async patchGuildFolder ( promiseState ) {
const GuildFolder = await ReactComponents . getComponentByName ( 'GuildFolder' , ` . ${ XenoLib . getSingleClass ( 'folder wrapper' ) } ` ) ;
if ( promiseState . cancelled ) return ;
const settings = this . settings ;
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 ) ;
}
return count ;
} ) ;
return React . createElement ( e . _ _UBR _old _type , e ) ;
}
BlobMaskWrapper . displayName = 'BlobMask' ;
Patcher . after ( GuildFolder . component . prototype , 'render' , ( _this , args , ret ) => {
const mask = Utilities . getNestedProp ( ret , 'props.children.1.props.children.props.children.1.props.children.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 ConnectedGuild = await ReactComponents . getComponentByName ( 'DragSource(ConnectedGuild)' , ` . ${ XenoLib . getSingleClass ( 'listItem' ) } ` ) ;
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 , args , 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 Guild = await ReactComponents . getComponentByName ( 'Guild' , ` . ${ XenoLib . getSingleClass ( 'listItem' ) } ` ) ;
if ( promiseState . cancelled ) return ;
Patcher . after ( Guild . component . prototype , 'render' , ( _this , args , ret ) => {
const props = Utilities . getNestedProp ( ret , 'props.children.props.children.1.props.children.props.children.props' ) ;
if ( ! props ) return ;
props . _ _UBR _unread _count = _this . props . _ _UBR _unread _count ;
props . guildId = _this . props . guildId ;
} ) ;
Guild . forceUpdateAll ( ) ;
}
async patchBlobMask ( promiseState ) {
const BlobMask = await ReactComponents . getComponentByName ( 'BlobMask' , ` . ${ XenoLib . getSingleClass ( 'lowerBadge wrapper' ) } ` ) ;
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 , args , ret ) => {
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 , args , ret ) => {
if ( typeof _this . props . _ _UBR _unread _count !== 'number' ) return ;
if ( ! _this . state . unreadBadgeMask ) return ;
_this . state . unreadBadgeMask . destroy ( ) ;
} ) ;
Patcher . after ( BlobMask . component . prototype , 'componentDidUpdate' , ( _this , args , ret ) => {
if ( typeof _this . props . _ _UBR _unread _count !== 'number' ) 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 , args , ret ) => {
if ( typeof _this . props . _ _UBR _unread _count !== 'number' ) return ;
const badges = Utilities . getNestedProp ( ret , 'props.children.1.props.children' ) ;
const masks = Utilities . getNestedProp ( ret , 'props.children.0.props.children.0.props.children' ) ;
if ( ! badges || ! masks ) return ;
ensureUnreadBadgeMask ( _this ) ;
/ * i f c o u n t i s 0 , w e ' r e a n i m a t i n g o u t , a n d a s s u c h , i t ' s b e t t e r t o a t l e a s t s t i l l d i s p l a y t h e o l d
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 . spring ;
masks . push (
React . createElement ( ReactSpring . animated . rect , {
x : - 4 ,
y : 28 ,
width : width + 8 ,
height : 24 ,
rx : 12 ,
ry : 12 ,
transform : unreadCountMaskSpring . to ( [ 0 , 1 ] , [ - 20 , 0 ] ) . to ( e => ` translate( ${ e } ${ - e } ) ` ) ,
fill : 'black'
} )
) ;
badges . 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 } ${ - 20 + 20 * e } ) ` )
}
} ,
BadgesModule . NumberBadge ( { count : counter , color : this . settings . misc . backgroundColor , style : { color : this . settings . misc . textColor } } )
)
) ;
} ) ;
BlobMask . forceUpdateAll ( ) ;
}
/* PATCHES */
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 */
return ! global . ZeresPluginLibrary || ! global . XenoLib
? class {
getName ( ) {
return this . name . replace ( /\s+/g , '' ) ;
}
getAuthor ( ) {
return this . author ;
}
getVersion ( ) {
return this . version ;
}
getDescription ( ) {
return this . description ;
}
stop ( ) { }
load ( ) {
const XenoLibMissing = ! global . XenoLib ;
const zlibMissing = ! global . ZeresPluginLibrary ;
const bothLibsMissing = XenoLibMissing && zlibMissing ;
const header = ` Missing ${ ( bothLibsMissing && 'Libraries' ) || 'Library' } ` ;
const content = ` The ${ ( bothLibsMissing && 'Libraries' ) || 'Library' } ${ ( zlibMissing && 'ZeresPluginLibrary' ) || '' } ${ ( XenoLibMissing && ( zlibMissing ? 'and XenoLib' : 'XenoLib' ) ) || '' } required for ${ this . name } ${ ( bothLibsMissing && 'are' ) || 'is' } missing. ` ;
const ModalStack = BdApi . findModuleByProps ( 'push' , 'update' , 'pop' , 'popWithKey' ) ;
const TextElement = BdApi . findModuleByProps ( 'Sizes' , 'Weights' ) ;
const ConfirmationModal = BdApi . findModule ( m => m . defaultProps && m . key && m . key ( ) === 'confirm-modal' ) ;
const onFail = ( ) => BdApi . getCore ( ) . alert ( header , ` ${ content } <br/>Due to a slight mishap however, you'll have to download the libraries yourself. After opening the links, do CTRL + S to download the library.<br/> ${ ( zlibMissing && '<br/><a href="https://rauenzi.github.io/BDPluginLibrary/release/0PluginLibrary.plugin.js"target="_blank">Click here to download ZeresPluginLibrary</a>' ) || '' } ${ ( zlibMissing && '<br/><a href="http://localhost:7474/XenoLib.js"target="_blank">Click here to download XenoLib</a>' ) || '' } ` ) ;
if ( ! ModalStack || ! ConfirmationModal || ! TextElement ) return onFail ( ) ;
2020-02-03 17:34:05 +01:00
class TempErrorBoundary extends BdApi . React . PureComponent {
constructor ( props ) {
super ( props ) ;
this . state = { hasError : false } ;
}
componentDidCatch ( err , inf ) {
console . error ( ` Error in ${ this . props . label } , screenshot or copy paste the error above to Lighty for help. ` ) ;
this . setState ( { hasError : true } ) ;
if ( typeof this . props . onError === 'function' ) this . props . onError ( err ) ;
}
render ( ) {
if ( this . state . hasError ) return null ;
return this . props . children ;
}
}
let modalId ;
const onHeckWouldYouLookAtThat = ( ( ) => {
if ( ! global . pluginModule || ! global . BDEvents ) return ;
if ( XenoLibMissing ) {
const listener = ( ) => {
BDEvents . off ( 'xenolib-loaded' , listener ) ;
ModalStack . popWithKey ( modalId ) ; /* make it easier on the user */
pluginModule . reloadPlugin ( this . name ) ;
} ;
BDEvents . on ( 'xenolib-loaded' , listener ) ;
return ( ) => BDEvents . off ( 'xenolib-loaded' , listener ) ;
} else {
const onLoaded = e => {
if ( e !== 'ZeresPluginLibrary' ) return ;
BDEvents . off ( 'plugin-loaded' , onLoaded ) ;
ModalStack . popWithKey ( modalId ) ; /* make it easier on the user */
pluginModule . reloadPlugin ( this . name ) ;
} ;
BDEvents . on ( 'plugin-loaded' , onLoaded ) ;
return ( ) => BDEvents . off ( 'plugin-loaded' , onLoaded ) ;
}
} ) ( ) ;
modalId = ModalStack . push ( props => {
2019-12-27 21:26:03 +01:00
return BdApi . React . createElement (
2020-02-03 17:34:05 +01:00
TempErrorBoundary ,
{
label : 'missing dependency modal' ,
onError : ( ) => {
ModalStack . popWithKey ( modalId ) ; /* smh... */
onFail ( ) ;
}
} ,
BdApi . React . createElement (
ConfirmationModal ,
Object . assign (
{
header ,
children : [ BdApi . React . createElement ( TextElement , { color : TextElement . Colors . PRIMARY , children : [ ` ${ content } Please click Download Now to install ${ ( bothLibsMissing && 'them' ) || 'it' } . ` ] } ) ] ,
red : false ,
confirmText : 'Download Now' ,
cancelText : 'Cancel' ,
onConfirm : ( ) => {
onHeckWouldYouLookAtThat ( ) ;
const request = require ( 'request' ) ;
const fs = require ( 'fs' ) ;
const path = require ( 'path' ) ;
const waitForLibLoad = callback => {
if ( ! global . BDEvents ) return callback ( ) ;
const onLoaded = e => {
if ( e !== 'ZeresPluginLibrary' ) return ;
BDEvents . off ( 'plugin-loaded' , onLoaded ) ;
callback ( ) ;
2019-12-27 21:26:03 +01:00
} ;
2020-02-03 17:34:05 +01:00
BDEvents . on ( 'plugin-loaded' , onLoaded ) ;
} ;
const onDone = ( ) => {
if ( ! global . pluginModule || ( ! global . BDEvents && ! global . XenoLib ) ) return ;
if ( ! global . BDEvents || global . XenoLib ) pluginModule . reloadPlugin ( this . name ) ;
else {
const listener = ( ) => {
BDEvents . off ( 'xenolib-loaded' , listener ) ;
pluginModule . reloadPlugin ( this . name ) ;
} ;
BDEvents . on ( 'xenolib-loaded' , listener ) ;
}
} ;
const downloadXenoLib = ( ) => {
if ( global . XenoLib ) return onDone ( ) ;
request ( 'https://raw.githubusercontent.com/1Lighty/BetterDiscordPlugins/master/Plugins/1XenoLib.plugin.js' , ( error , response , body ) => {
if ( error ) return onFail ( ) ;
onDone ( ) ;
fs . writeFile ( path . join ( window . ContentManager . pluginsFolder , '1XenoLib.plugin.js' ) , body , ( ) => { } ) ;
} ) ;
} ;
if ( ! global . ZeresPluginLibrary ) {
request ( 'https://rauenzi.github.io/BDPluginLibrary/release/0PluginLibrary.plugin.js' , ( error , response , body ) => {
if ( error ) return onFail ( ) ;
waitForLibLoad ( downloadXenoLib ) ;
fs . writeFile ( path . join ( window . ContentManager . pluginsFolder , '0PluginLibrary.plugin.js' ) , body , ( ) => { } ) ;
} ) ;
} else downloadXenoLib ( ) ;
}
} ,
props
)
2019-12-27 21:26:03 +01:00
)
) ;
} ) ;
}
start ( ) { }
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@*/